Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 May 2010 04:04:44 +0000 (21:04 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 May 2010 04:04:44 +0000 (21:04 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1674 commits)
  qlcnic: adding co maintainer
  ixgbe: add support for active DA cables
  ixgbe: dcb, do not tag tc_prio_control frames
  ixgbe: fix ixgbe_tx_is_paused logic
  ixgbe: always enable vlan strip/insert when DCB is enabled
  ixgbe: remove some redundant code in setting FCoE FIP filter
  ixgbe: fix wrong offset to fc_frame_header in ixgbe_fcoe_ddp
  ixgbe: fix header len when unsplit packet overflows to data buffer
  ipv6: Never schedule DAD timer on dead address
  ipv6: Use POSTDAD state
  ipv6: Use state_lock to protect ifa state
  ipv6: Replace inet6_ifaddr->dead with state
  cxgb4: notify upper drivers if the device is already up when they load
  cxgb4: keep interrupts available when the ports are brought down
  cxgb4: fix initial addition of MAC address
  cnic: Return SPQ credit to bnx2x after ring setup and shutdown.
  cnic: Convert cnic_local_flags to atomic ops.
  can: Fix SJA1000 command register writes on SMP systems
  bridge: fix build for CONFIG_SYSFS disabled
  ARCNET: Limit com20020 PCI ID matches for SOHARD cards
  ...

Fix up various conflicts with pcmcia tree drivers/net/
{pcmcia/3c589_cs.c, wireless/orinoco/orinoco_cs.c and
wireless/orinoco/spectrum_cs.c} and feature removal
(Documentation/feature-removal-schedule.txt).

Also fix a non-content conflict due to pm_qos_requirement getting
renamed in the PM tree (now pm_qos_request) in net/mac80211/scan.c

1455 files changed:
Documentation/ABI/obsolete/sysfs-class-rfkill [new file with mode: 0644]
Documentation/ABI/stable/sysfs-class-rfkill [new file with mode: 0644]
Documentation/Changes
Documentation/feature-removal-schedule.txt
Documentation/networking/caif/Linux-CAIF.txt [new file with mode: 0644]
Documentation/networking/caif/README [new file with mode: 0644]
Documentation/networking/ip-sysctl.txt
Documentation/networking/l2tp.txt
Documentation/networking/x25-iface.txt
Documentation/rfkill.txt
Documentation/sysctl/net.txt
MAINTAINERS
arch/arm/mach-mx2/pcm970-baseboard.c
arch/arm/mach-mx3/mach-pcm037.c
arch/arm/mach-pxa/icontrol.c
arch/arm/mach-pxa/zeus.c
arch/microblaze/include/asm/system.h
arch/mips/sibyte/swarm/platform.c
drivers/atm/Kconfig
drivers/atm/atmtcp.c
drivers/atm/eni.c
drivers/atm/he.c
drivers/bluetooth/btmrvl_drv.h
drivers/bluetooth/btmrvl_main.c
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_ll.c
drivers/bluetooth/hci_vhci.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
drivers/isdn/i4l/isdn_x25iface.c
drivers/media/dvb/dvb-core/dvb_net.c
drivers/net/3c501.c
drivers/net/3c503.c
drivers/net/3c505.c
drivers/net/3c507.c
drivers/net/3c509.c
drivers/net/3c515.c
drivers/net/3c523.c
drivers/net/3c527.c
drivers/net/3c59x.c
drivers/net/7990.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/82596.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/a2065.c
drivers/net/ac3200.c
drivers/net/acenic.c
drivers/net/acenic.h
drivers/net/amd8111e.c
drivers/net/apne.c
drivers/net/appletalk/cops.c
drivers/net/appletalk/ltpc.c
drivers/net/arcnet/arcnet.c
drivers/net/arcnet/com20020-pci.c
drivers/net/ariadne.c
drivers/net/arm/am79c961a.c
drivers/net/arm/at91_ether.c
drivers/net/arm/ep93xx_eth.c
drivers/net/arm/ether1.c
drivers/net/arm/ether3.c
drivers/net/arm/ixp4xx_eth.c
drivers/net/arm/ks8695net.c
drivers/net/arm/w90p910_ether.c
drivers/net/at1700.c
drivers/net/atarilance.c
drivers/net/atl1c/atl1c_ethtool.c
drivers/net/atl1c/atl1c_main.c
drivers/net/atl1e/atl1e_ethtool.c
drivers/net/atl1e/atl1e_main.c
drivers/net/atlx/atl1.c
drivers/net/atlx/atl2.c
drivers/net/atlx/atlx.c
drivers/net/atp.c
drivers/net/au1000_eth.c
drivers/net/au1000_eth.h
drivers/net/ax88796.c
drivers/net/b44.c
drivers/net/bcm63xx_enet.c
drivers/net/benet/be.h
drivers/net/benet/be_cmds.c
drivers/net/benet/be_cmds.h
drivers/net/benet/be_ethtool.c
drivers/net/benet/be_hw.h
drivers/net/benet/be_main.c
drivers/net/bfin_mac.c
drivers/net/bfin_mac.h
drivers/net/bmac.c
drivers/net/bnx2.c
drivers/net/bnx2.h
drivers/net/bnx2x.h
drivers/net/bnx2x_link.c
drivers/net/bnx2x_main.c
drivers/net/bnx2x_reg.h
drivers/net/bonding/bond_ipv6.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/caif/Kconfig [new file with mode: 0644]
drivers/net/caif/Makefile [new file with mode: 0644]
drivers/net/caif/caif_serial.c [new file with mode: 0644]
drivers/net/can/at91_can.c
drivers/net/can/bfin_can.c
drivers/net/can/mcp251x.c
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/can/mscan/mscan.c
drivers/net/can/sja1000/Kconfig
drivers/net/can/sja1000/ems_pci.c
drivers/net/can/sja1000/kvaser_pci.c
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/sja1000/sja1000.h
drivers/net/can/sja1000/sja1000_isa.c
drivers/net/can/sja1000/sja1000_of_platform.c
drivers/net/can/sja1000/sja1000_platform.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/cassini.c
drivers/net/chelsio/pm3393.c
drivers/net/chelsio/sge.c
drivers/net/cnic.c
drivers/net/cnic.h
drivers/net/cpmac.c
drivers/net/cris/eth_v10.c
drivers/net/cs89x0.c
drivers/net/cxgb3/l2t.c
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/xgmac.c
drivers/net/cxgb4/cxgb4.h
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4/sge.c
drivers/net/cxgb4/t4_hw.c
drivers/net/cxgb4/t4_msg.h
drivers/net/cxgb4/t4fw_api.h
drivers/net/davinci_emac.c
drivers/net/de600.c
drivers/net/de620.c
drivers/net/declance.c
drivers/net/defxx.c
drivers/net/depca.c
drivers/net/dl2k.c
drivers/net/dm9000.c
drivers/net/dnet.c
drivers/net/e100.c
drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_hw.c
drivers/net/e1000/e1000_hw.h
drivers/net/e1000/e1000_main.c
drivers/net/e1000/e1000_osdep.h
drivers/net/e1000/e1000_param.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/es2lan.c
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/lib.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/param.c
drivers/net/e1000e/phy.c
drivers/net/e2100.c
drivers/net/eepro.c
drivers/net/eexpress.c
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_main.c
drivers/net/ehea/ehea_qmr.c
drivers/net/ehea/ehea_qmr.h
drivers/net/enc28j60.c
drivers/net/enic/Makefile
drivers/net/enic/cq_enet_desc.h
drivers/net/enic/enic.h
drivers/net/enic/enic_main.c
drivers/net/enic/enic_res.c
drivers/net/enic/enic_res.h
drivers/net/enic/vnic_dev.c
drivers/net/enic/vnic_dev.h
drivers/net/enic/vnic_rq.c
drivers/net/enic/vnic_vic.c [new file with mode: 0644]
drivers/net/enic/vnic_vic.h [new file with mode: 0644]
drivers/net/enic/vnic_wq.c
drivers/net/epic100.c
drivers/net/eql.c
drivers/net/es3210.c
drivers/net/eth16i.c
drivers/net/ethoc.c
drivers/net/ewrk3.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/fec_mpc52xx.c
drivers/net/forcedeth.c
drivers/net/fs_enet/fs_enet-main.c
drivers/net/fs_enet/mac-fcc.c
drivers/net/fs_enet/mac-fec.c
drivers/net/fs_enet/mac-scc.c
drivers/net/fsl_pq_mdio.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/greth.c
drivers/net/hamachi.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/scc.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/hp100.c
drivers/net/ibm_newemac/core.c
drivers/net/ibmlana.c
drivers/net/ibmveth.c
drivers/net/ifb.c
drivers/net/igb/e1000_82575.c
drivers/net/igb/e1000_82575.h
drivers/net/igb/e1000_defines.h
drivers/net/igb/e1000_hw.h
drivers/net/igb/e1000_mac.c
drivers/net/igb/igb.h
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c
drivers/net/igbvf/ethtool.c
drivers/net/igbvf/netdev.c
drivers/net/ioc3-eth.c
drivers/net/ipg.c
drivers/net/ipg.h
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/ali-ircc.c
drivers/net/irda/au1k_ir.c
drivers/net/irda/donauboe.c
drivers/net/irda/irda-usb.c
drivers/net/irda/mcs7780.c
drivers/net/irda/pxaficp_ir.c
drivers/net/irda/sa1100_ir.c
drivers/net/irda/sh_irda.c [new file with mode: 0644]
drivers/net/irda/sh_sir.c
drivers/net/irda/sir_dev.c
drivers/net/irda/smsc-ircc2.c
drivers/net/irda/via-ircc.h
drivers/net/irda/vlsi_ir.c
drivers/net/irda/w83977af_ir.c
drivers/net/iseries_veth.c
drivers/net/ixgb/ixgb.h
drivers/net/ixgb/ixgb_ee.c
drivers/net/ixgb/ixgb_hw.c
drivers/net/ixgb/ixgb_hw.h
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgb/ixgb_osdep.h
drivers/net/ixgb/ixgb_param.c
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_common.h
drivers/net/ixgbe/ixgbe_dcb_nl.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_fcoe.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/ixgbe/ixgbe_phy.h
drivers/net/ixgbe/ixgbe_sriov.c
drivers/net/ixgbe/ixgbe_sriov.h
drivers/net/ixgbe/ixgbe_type.h
drivers/net/ixgbevf/defines.h
drivers/net/ixgbevf/ixgbevf_main.c
drivers/net/ixgbevf/vf.c
drivers/net/ixgbevf/vf.h
drivers/net/ixp2000/ixpdev.c
drivers/net/jme.c
drivers/net/korina.c
drivers/net/ks8842.c
drivers/net/ks8851.c
drivers/net/ks8851.h
drivers/net/ks8851_mll.c
drivers/net/ksz884x.c
drivers/net/lance.c
drivers/net/lib82596.c
drivers/net/lib8390.c
drivers/net/ll_temac.h
drivers/net/ll_temac_main.c
drivers/net/lne390.c
drivers/net/lp486e.c
drivers/net/mac8390.c
drivers/net/mac89x0.c
drivers/net/macb.c
drivers/net/mace.c
drivers/net/macmace.c
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/meth.c
drivers/net/mlx4/en_ethtool.c
drivers/net/mlx4/en_netdev.c
drivers/net/mlx4/eq.c
drivers/net/mlx4/mlx4_en.h
drivers/net/mv643xx_eth.c
drivers/net/myri10ge/myri10ge.c
drivers/net/myri_sbus.c
drivers/net/natsemi.c
drivers/net/ne-h8300.c
drivers/net/ne.c
drivers/net/ne2.c
drivers/net/ne2k-pci.c
drivers/net/ne3210.c
drivers/net/netconsole.c
drivers/net/netx-eth.c
drivers/net/netxen/netxen_nic.h
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_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/ni5010.c
drivers/net/ni52.c
drivers/net/ni65.c
drivers/net/niu.c
drivers/net/niu.h
drivers/net/octeon/octeon_mgmt.c
drivers/net/pasemi_mac.c
drivers/net/pci-skeleton.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/pcnet32.c
drivers/net/phy/bcm63xx.c
drivers/net/phy/broadcom.c
drivers/net/phy/cicada.c
drivers/net/phy/davicom.c
drivers/net/phy/et1011c.c
drivers/net/phy/icplus.c
drivers/net/phy/lxt.c
drivers/net/phy/marvell.c
drivers/net/phy/mdio-bitbang.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/micrel.c
drivers/net/phy/national.c
drivers/net/phy/phy_device.c
drivers/net/phy/qsemi.c
drivers/net/phy/realtek.c
drivers/net/phy/smsc.c
drivers/net/phy/ste10Xp.c
drivers/net/phy/vitesse.c
drivers/net/plip.c
drivers/net/ppp_generic.c
drivers/net/pppoe.c
drivers/net/pppol2tp.c [deleted file]
drivers/net/ps3_gelic_net.c
drivers/net/ps3_gelic_wireless.c
drivers/net/qla3xxx.c
drivers/net/qla3xxx.h
drivers/net/qlcnic/qlcnic.h
drivers/net/qlcnic/qlcnic_ctx.c
drivers/net/qlcnic/qlcnic_ethtool.c
drivers/net/qlcnic/qlcnic_hdr.h
drivers/net/qlcnic/qlcnic_hw.c
drivers/net/qlcnic/qlcnic_init.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/qlge/qlge.h
drivers/net/qlge/qlge_dbg.c
drivers/net/qlge/qlge_ethtool.c
drivers/net/qlge/qlge_main.c
drivers/net/r6040.c
drivers/net/r8169.c
drivers/net/rrunner.c
drivers/net/s2io.c
drivers/net/s6gmac.c
drivers/net/sb1000.c
drivers/net/sb1250-mac.c
drivers/net/sc92031.c
drivers/net/seeq8005.c
drivers/net/sfc/efx.c
drivers/net/sfc/efx.h
drivers/net/sfc/ethtool.c
drivers/net/sfc/falcon.c
drivers/net/sfc/falcon_xmac.c
drivers/net/sfc/mcdi.c
drivers/net/sfc/mcdi_mac.c
drivers/net/sfc/mcdi_pcol.h
drivers/net/sfc/mcdi_phy.c
drivers/net/sfc/net_driver.h
drivers/net/sfc/nic.c
drivers/net/sfc/nic.h
drivers/net/sfc/selftest.c
drivers/net/sfc/selftest.h
drivers/net/sfc/siena.c
drivers/net/sfc/tx.c
drivers/net/sfc/workarounds.h
drivers/net/sgiseeq.c
drivers/net/sh_eth.c
drivers/net/sis190.c
drivers/net/sis900.c
drivers/net/skfp/fplustm.c
drivers/net/skfp/pcmplc.c
drivers/net/skfp/skfddi.c
drivers/net/skfp/smt.c
drivers/net/skfp/srf.c
drivers/net/skge.c
drivers/net/skge.h
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/slhc.c
drivers/net/slip.c
drivers/net/smc-mca.c
drivers/net/smc-ultra.c
drivers/net/smc-ultra32.c
drivers/net/smc911x.c
drivers/net/smc9194.c
drivers/net/smc91x.c
drivers/net/smsc911x.c
drivers/net/smsc9420.c
drivers/net/sonic.c
drivers/net/spider_net.c
drivers/net/starfire.c
drivers/net/stmmac/Makefile
drivers/net/stmmac/common.h
drivers/net/stmmac/dwmac100.c [deleted file]
drivers/net/stmmac/dwmac100.h
drivers/net/stmmac/dwmac1000.h
drivers/net/stmmac/dwmac1000_core.c
drivers/net/stmmac/dwmac1000_dma.c
drivers/net/stmmac/dwmac100_core.c [new file with mode: 0644]
drivers/net/stmmac/dwmac100_dma.c [new file with mode: 0644]
drivers/net/stmmac/dwmac_dma.h
drivers/net/stmmac/dwmac_lib.c
drivers/net/stmmac/enh_desc.c [new file with mode: 0644]
drivers/net/stmmac/norm_desc.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_timer.c
drivers/net/stnic.c
drivers/net/sun3_82586.c
drivers/net/sun3lance.c
drivers/net/sunbmac.c
drivers/net/sundance.c
drivers/net/sungem.c
drivers/net/sunhme.c
drivers/net/sunlance.c
drivers/net/sunqe.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/tokenring/3c359.c
drivers/net/tokenring/ibmtr.c
drivers/net/tokenring/lanstreamer.c
drivers/net/tokenring/madgemc.c
drivers/net/tokenring/olympic.c
drivers/net/tokenring/smctr.c
drivers/net/tokenring/tms380tr.c
drivers/net/tsi108_eth.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/de4x5.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/media.c
drivers/net/tulip/pnic.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/asix.c
drivers/net/usb/catc.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/dm9601.c
drivers/net/usb/hso.c
drivers/net/usb/kaweth.c
drivers/net/usb/mcs7830.c
drivers/net/usb/pegasus.c
drivers/net/usb/pegasus.h
drivers/net/usb/rndis_host.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/via-velocity.h
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxge/vxge-config.c
drivers/net/vxge/vxge-config.h
drivers/net/vxge/vxge-ethtool.c
drivers/net/vxge/vxge-main.c
drivers/net/vxge/vxge-main.h
drivers/net/vxge/vxge-traffic.c
drivers/net/vxge/vxge-traffic.h
drivers/net/vxge/vxge-version.h
drivers/net/wan/cycx_x25.c
drivers/net/wan/dscc4.c
drivers/net/wan/hd64570.c
drivers/net/wan/hd64572.c
drivers/net/wan/hdlc_x25.c
drivers/net/wan/ixp4xx_hss.c
drivers/net/wan/lapbether.c
drivers/net/wan/lmc/lmc_main.c
drivers/net/wan/pc300_drv.c
drivers/net/wan/pc300_tty.c
drivers/net/wan/sdla.c
drivers/net/wan/wanxl.c
drivers/net/wan/x25_asy.c
drivers/net/wd.c
drivers/net/wimax/i2400m/control.c
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/i2400m-sdio.h
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/rx.c
drivers/net/wimax/i2400m/sdio-rx.c
drivers/net/wimax/i2400m/sdio-tx.c
drivers/net/wimax/i2400m/sdio.c
drivers/net/wimax/i2400m/tx.c
drivers/net/wimax/i2400m/usb-notif.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/Kconfig
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/ath/ar9170/ar9170.h
drivers/net/wireless/ath/ar9170/cmd.h
drivers/net/wireless/ath/ar9170/eeprom.h
drivers/net/wireless/ath/ar9170/hw.h
drivers/net/wireless/ath/ar9170/main.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/Makefile
drivers/net/wireless/ath/ath5k/ani.c [new file with mode: 0644]
drivers/net/wireless/ath/ath5k/ani.h [new file with mode: 0644]
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/caps.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/debug.h
drivers/net/wireless/ath/ath5k/desc.c
drivers/net/wireless/ath/ath5k/desc.h
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/eeprom.h
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/qcu.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_initvals.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar5008_phy.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9001_initvals.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9002_calib.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9002_hw.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9002_initvals.h [moved from drivers/net/wireless/ath/ath9k/initvals.h with 77% similarity]
drivers/net/wireless/ath/ath9k/ar9002_mac.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9002_phy.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9002_phy.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_calib.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_hw.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_initvals.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_mac.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_mac.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_phy.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ar9003_phy.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/calib.h
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hif_usb.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/hif_usb.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_drv_init.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_drv_main.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_hst.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/htc_hst.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/hw-ops.h [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
drivers/net/wireless/ath/ath9k/mac.c
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/phy.c [deleted file]
drivers/net/wireless/ath/ath9k/phy.h
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/virtual.c
drivers/net/wireless/ath/ath9k/wmi.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/wmi.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/debug.h
drivers/net/wireless/ath/hw.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/hostap/hostap_80211_rx.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_download.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-3945-hw.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-3945.h
drivers/net/wireless/iwlwifi/iwl-4965-hw.h
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000-hw.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-hw.h [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-ict.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-lib.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
drivers/net/wireless/iwlwifi/iwl-agn-tx.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h [new file with mode: 0644]
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-csr.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-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-hcmd.c
drivers/net/wireless/iwlwifi/iwl-helpers.h
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-power.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/iwmc3200wifi/Kconfig
drivers/net/wireless/iwmc3200wifi/Makefile
drivers/net/wireless/iwmc3200wifi/bus.h
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/iwmc3200wifi/commands.c
drivers/net/wireless/iwmc3200wifi/commands.h
drivers/net/wireless/iwmc3200wifi/debug.h
drivers/net/wireless/iwmc3200wifi/debugfs.c
drivers/net/wireless/iwmc3200wifi/hal.c
drivers/net/wireless/iwmc3200wifi/hal.h
drivers/net/wireless/iwmc3200wifi/iwm.h
drivers/net/wireless/iwmc3200wifi/main.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/iwmc3200wifi/sdio.c
drivers/net/wireless/iwmc3200wifi/trace.c [new file with mode: 0644]
drivers/net/wireless/iwmc3200wifi/trace.h [new file with mode: 0644]
drivers/net/wireless/iwmc3200wifi/tx.c
drivers/net/wireless/iwmc3200wifi/umac.h
drivers/net/wireless/libertas/assoc.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/debugfs.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/libertas/tx.c
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/libertas_tf/cmd.c
drivers/net/wireless/libertas_tf/deb_defs.h [new file with mode: 0644]
drivers/net/wireless/libertas_tf/if_usb.c
drivers/net/wireless/libertas_tf/libertas_tf.h
drivers/net/wireless/libertas_tf/main.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/Kconfig
drivers/net/wireless/orinoco/Makefile
drivers/net/wireless/orinoco/airport.c
drivers/net/wireless/orinoco/cfg.c
drivers/net/wireless/orinoco/fw.c
drivers/net/wireless/orinoco/hermes.c
drivers/net/wireless/orinoco/hermes.h
drivers/net/wireless/orinoco/hermes_dld.c
drivers/net/wireless/orinoco/hw.c
drivers/net/wireless/orinoco/hw.h
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/orinoco/main.h
drivers/net/wireless/orinoco/orinoco.h
drivers/net/wireless/orinoco/orinoco_cs.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/orinoco/orinoco_usb.c [new file with mode: 0644]
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/orinoco/wext.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/prism54/isl_ioctl.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/prism54/islpci_mgt.c
drivers/net/wireless/prism54/oid_mgt.c
drivers/net/wireless/ray_cs.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/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2800usb.h
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00crypto.c
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00dump.h
drivers/net/wireless/rt2x00/rt2x00firmware.c
drivers/net/wireless/rt2x00/rt2x00ht.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00pci.h
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00queue.h
drivers/net/wireless/rt2x00/rt2x00reg.h
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt2x00usb.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/Kconfig [new file with mode: 0644]
drivers/net/wireless/rtl818x/rtl8180.h
drivers/net/wireless/rtl818x/rtl8180_dev.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/wl12xx/Kconfig
drivers/net/wireless/wl12xx/Makefile
drivers/net/wireless/wl12xx/wl1251.h
drivers/net/wireless/wl12xx/wl1251_boot.c
drivers/net/wireless/wl12xx/wl1251_io.h
drivers/net/wireless/wl12xx/wl1251_main.c
drivers/net/wireless/wl12xx/wl1251_ps.c
drivers/net/wireless/wl12xx/wl1251_reg.h
drivers/net/wireless/wl12xx/wl1251_rx.c
drivers/net/wireless/wl12xx/wl1251_sdio.c
drivers/net/wireless/wl12xx/wl1251_spi.c
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_boot.h
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_io.c
drivers/net/wireless/wl12xx/wl1271_io.h
drivers/net/wireless/wl12xx/wl1271_main.c
drivers/net/wireless/wl12xx/wl1271_ps.c
drivers/net/wireless/wl12xx/wl1271_rx.c
drivers/net/wireless/wl12xx/wl1271_rx.h
drivers/net/wireless/wl12xx/wl1271_sdio.c [new file with mode: 0644]
drivers/net/wireless/wl12xx/wl1271_spi.c
drivers/net/wireless/wl12xx/wl1271_spi.h [deleted file]
drivers/net/wireless/wl12xx/wl1271_testmode.c
drivers/net/wireless/wl12xx/wl1271_tx.c
drivers/net/wireless/wl12xx/wl1271_tx.h
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1201.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/xilinx_emaclite.c
drivers/net/yellowfin.c
drivers/net/znet.c
drivers/net/zorro8390.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/ctcm_mpc.c
drivers/s390/net/lcs.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_main.c
drivers/s390/net/qeth_l3_sys.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/iscsi_tcp.c
drivers/ssb/driver_chipcommon.c
drivers/ssb/main.c
drivers/ssb/pci.c
drivers/ssb/sprom.c
drivers/staging/arlan/arlan-main.c
drivers/staging/et131x/et131x_netdev.c
drivers/staging/slicoss/slicoss.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6656/main_usb.c
drivers/staging/wavelan/wavelan.c
drivers/staging/wavelan/wavelan_cs.c
drivers/staging/winbond/wbusb.c
drivers/staging/wlags49_h2/wl_netdev.c
drivers/vhost/net.c
drivers/vhost/vhost.c
firmware/Makefile
firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex [new file with mode: 0644]
firmware/bnx2/bnx2-mips-09-5.0.0.j9.fw.ihex [deleted file]
fs/fcntl.c
fs/sysfs/symlink.c
include/linux/Kbuild
include/linux/caif/caif_socket.h [new file with mode: 0644]
include/linux/caif/if_caif.h [new file with mode: 0644]
include/linux/can/dev.h
include/linux/can/platform/mcp251x.h
include/linux/can/platform/sja1000.h
include/linux/dcbnl.h
include/linux/ethtool.h
include/linux/filter.h
include/linux/fs.h
include/linux/genetlink.h
include/linux/ieee80211.h
include/linux/if.h
include/linux/if_arp.h
include/linux/if_ether.h
include/linux/if_link.h
include/linux/if_macvlan.h
include/linux/if_packet.h
include/linux/if_pppol2tp.h
include/linux/if_pppox.h
include/linux/if_tun.h
include/linux/if_x25.h [new file with mode: 0644]
include/linux/in6.h
include/linux/ipv6.h
include/linux/kernel.h
include/linux/ks8842.h [new file with mode: 0644]
include/linux/l2tp.h [new file with mode: 0644]
include/linux/mmc/sdio.h
include/linux/mod_devicetable.h
include/linux/mroute.h
include/linux/mroute6.h
include/linux/net.h
include/linux/netdevice.h
include/linux/netfilter/Kbuild
include/linux/netfilter/nf_conntrack_common.h
include/linux/netfilter/nf_conntrack_tuple_common.h
include/linux/netfilter/x_tables.h
include/linux/netfilter/xt_CONNMARK.h
include/linux/netfilter/xt_MARK.h
include/linux/netfilter/xt_TEE.h [new file with mode: 0644]
include/linux/netfilter/xt_connmark.h
include/linux/netfilter/xt_mark.h
include/linux/netfilter/xt_recent.h
include/linux/netfilter_bridge.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netpoll.h
include/linux/nl80211.h
include/linux/notifier.h
include/linux/pci_regs.h
include/linux/phy.h
include/linux/ppp_channel.h
include/linux/rculist.h
include/linux/rtnetlink.h
include/linux/skbuff.h
include/linux/snmp.h
include/linux/socket.h
include/linux/spi/wl12xx.h
include/linux/ssb/ssb.h
include/linux/ssb/ssb_driver_chipcommon.h
include/linux/ssb/ssb_regs.h
include/linux/stmmac.h
include/linux/sysctl.h
include/linux/tipc.h
include/linux/tipc_config.h
include/linux/tty.h
include/linux/wireless.h
include/net/af_unix.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/caif/caif_dev.h [new file with mode: 0644]
include/net/caif/caif_device.h [new file with mode: 0644]
include/net/caif/caif_layer.h [new file with mode: 0644]
include/net/caif/cfcnfg.h [new file with mode: 0644]
include/net/caif/cfctrl.h [new file with mode: 0644]
include/net/caif/cffrml.h [new file with mode: 0644]
include/net/caif/cfmuxl.h [new file with mode: 0644]
include/net/caif/cfpkt.h [new file with mode: 0644]
include/net/caif/cfserl.h [new file with mode: 0644]
include/net/caif/cfsrvl.h [new file with mode: 0644]
include/net/cfg80211.h
include/net/dn_fib.h
include/net/dst.h
include/net/fib_rules.h
include/net/flow.h
include/net/icmp.h
include/net/if_inet6.h
include/net/inet6_connection_sock.h
include/net/inet_connection_sock.h
include/net/inet_sock.h
include/net/inet_timewait_sock.h
include/net/ip.h
include/net/ip6_fib.h
include/net/ip6_route.h
include/net/ipv6.h
include/net/iw_handler.h
include/net/mac80211.h
include/net/mld.h [new file with mode: 0644]
include/net/neighbour.h
include/net/netns/generic.h
include/net/netns/ipv4.h
include/net/netns/ipv6.h
include/net/pkt_sched.h
include/net/raw.h
include/net/route.h
include/net/sch_generic.h
include/net/sctp/sctp.h
include/net/sctp/sm.h
include/net/sctp/structs.h
include/net/snmp.h
include/net/sock.h
include/net/tcp.h
include/net/tipc/tipc.h
include/net/transp_v6.h
include/net/x25.h
include/net/x25device.h
include/net/xfrm.h
kernel/sysctl.c
kernel/sysctl_binary.c
net/802/garp.c
net/8021q/vlan.c
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/9p/trans_rdma.c
net/Kconfig
net/Makefile
net/appletalk/ddp.c
net/atm/br2684.c
net/atm/common.c
net/atm/lec.c
net/atm/mpc.c
net/atm/mpoa_caches.c
net/atm/proc.c
net/atm/signaling.c
net/atm/svc.c
net/ax25/af_ax25.c
net/bluetooth/Kconfig
net/bluetooth/af_bluetooth.c
net/bluetooth/bnep/core.c
net/bluetooth/bnep/netdev.c
net/bluetooth/cmtp/cmtp.h
net/bluetooth/cmtp/core.c
net/bluetooth/hci_core.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/hidp/hidp.h
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bridge/Kconfig
net/bridge/br.c
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_input.c
net/bridge/br_ioctl.c
net/bridge/br_multicast.c
net/bridge/br_netfilter.c
net/bridge/br_netlink.c
net/bridge/br_notify.c
net/bridge/br_private.h
net/bridge/br_stp.c
net/bridge/br_stp_bpdu.c
net/bridge/br_stp_if.c
net/bridge/br_stp_timer.c
net/bridge/br_sysfs_if.c
net/bridge/netfilter/ebt_802_3.c
net/bridge/netfilter/ebt_among.c
net/bridge/netfilter/ebt_arp.c
net/bridge/netfilter/ebt_arpreply.c
net/bridge/netfilter/ebt_dnat.c
net/bridge/netfilter/ebt_ip.c
net/bridge/netfilter/ebt_ip6.c
net/bridge/netfilter/ebt_limit.c
net/bridge/netfilter/ebt_log.c
net/bridge/netfilter/ebt_mark.c
net/bridge/netfilter/ebt_mark_m.c
net/bridge/netfilter/ebt_nflog.c
net/bridge/netfilter/ebt_pkttype.c
net/bridge/netfilter/ebt_redirect.c
net/bridge/netfilter/ebt_snat.c
net/bridge/netfilter/ebt_stp.c
net/bridge/netfilter/ebt_ulog.c
net/bridge/netfilter/ebt_vlan.c
net/bridge/netfilter/ebtables.c
net/caif/Kconfig [new file with mode: 0644]
net/caif/Makefile [new file with mode: 0644]
net/caif/caif_config_util.c [new file with mode: 0644]
net/caif/caif_dev.c [new file with mode: 0644]
net/caif/caif_socket.c [new file with mode: 0644]
net/caif/cfcnfg.c [new file with mode: 0644]
net/caif/cfctrl.c [new file with mode: 0644]
net/caif/cfdbgl.c [new file with mode: 0644]
net/caif/cfdgml.c [new file with mode: 0644]
net/caif/cffrml.c [new file with mode: 0644]
net/caif/cfmuxl.c [new file with mode: 0644]
net/caif/cfpkt_skbuff.c [new file with mode: 0644]
net/caif/cfrfml.c [new file with mode: 0644]
net/caif/cfserl.c [new file with mode: 0644]
net/caif/cfsrvl.c [new file with mode: 0644]
net/caif/cfutill.c [new file with mode: 0644]
net/caif/cfveil.c [new file with mode: 0644]
net/caif/cfvidl.c [new file with mode: 0644]
net/caif/chnl_net.c [new file with mode: 0644]
net/can/bcm.c
net/core/Makefile
net/core/datagram.c
net/core/dev.c
net/core/dev_addr_lists.c [new file with mode: 0644]
net/core/dev_mcast.c [deleted file]
net/core/dst.c
net/core/ethtool.c
net/core/fib_rules.c
net/core/filter.c
net/core/flow.c
net/core/net-sysfs.c
net/core/net_namespace.c
net/core/netpoll.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/stream.c
net/core/sysctl_net_core.c
net/dccp/ccids/ccid3.c
net/dccp/dccp.h
net/dccp/input.c
net/dccp/ipv4.c
net/dccp/ipv6.c
net/dccp/output.c
net/dccp/proto.c
net/dccp/timer.c
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_neigh.c
net/decnet/dn_nsp_in.c
net/decnet/dn_route.c
net/decnet/dn_rules.c
net/dsa/slave.c
net/ethernet/eth.c
net/ipv4/Kconfig
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/cipso_ipv4.c
net/ipv4/devinet.c
net/ipv4/fib_rules.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/igmp.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_forward.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipconfig.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/netfilter.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/arpt_mangle.c
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_LOG.c
net/ipv4/netfilter/ipt_MASQUERADE.c
net/ipv4/netfilter/ipt_NETMAP.c
net/ipv4/netfilter/ipt_REDIRECT.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_ULOG.c
net/ipv4/netfilter/ipt_addrtype.c
net/ipv4/netfilter/ipt_ah.c
net/ipv4/netfilter/ipt_ecn.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/netfilter/nf_nat_rule.c
net/ipv4/netfilter/nf_nat_snmp_basic.c
net/ipv4/netfilter/nf_nat_standalone.c
net/ipv4/netfilter/nf_nat_tftp.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/xfrm4_input.c
net/ipv4/xfrm4_output.c
net/ipv4/xfrm4_policy.c
net/ipv6/Kconfig
net/ipv6/addrconf.c
net/ipv6/addrlabel.c
net/ipv6/af_inet6.c
net/ipv6/datagram.c
net/ipv6/fib6_rules.c
net/ipv6/icmp.c
net/ipv6/inet6_connection_sock.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6mr.c
net/ipv6/ipv6_sockglue.c
net/ipv6/mcast.c
net/ipv6/ndisc.c
net/ipv6/netfilter.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_LOG.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/ip6t_ah.c
net/ipv6/netfilter/ip6t_eui64.c
net/ipv6/netfilter/ip6t_frag.c
net/ipv6/netfilter/ip6t_hbh.c
net/ipv6/netfilter/ip6t_ipv6header.c
net/ipv6/netfilter/ip6t_mh.c
net/ipv6/netfilter/ip6t_rt.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/proc.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/ipv6/xfrm6_input.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/irda/af_irda.c
net/irda/ircomm/ircomm_param.c
net/irda/iriap.c
net/irda/irnet/irnet_irda.c
net/iucv/af_iucv.c
net/key/af_key.c
net/l2tp/Kconfig [new file with mode: 0644]
net/l2tp/Makefile [new file with mode: 0644]
net/l2tp/l2tp_core.c [new file with mode: 0644]
net/l2tp/l2tp_core.h [new file with mode: 0644]
net/l2tp/l2tp_debugfs.c [new file with mode: 0644]
net/l2tp/l2tp_eth.c [new file with mode: 0644]
net/l2tp/l2tp_ip.c [new file with mode: 0644]
net/l2tp/l2tp_netlink.c [new file with mode: 0644]
net/l2tp/l2tp_ppp.c [new file with mode: 0644]
net/llc/af_llc.c
net/llc/llc_core.c
net/mac80211/Kconfig
net/mac80211/Makefile
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c [new file with mode: 0644]
net/mac80211/debugfs.h
net/mac80211/debugfs_netdev.c
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/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel.h
net/mac80211/rc80211_minstrel_debugfs.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/work.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/ipvs/ip_vs_ftp.c
net/netfilter/ipvs/ip_vs_proto.c
net/netfilter/ipvs/ip_vs_proto_ah_esp.c
net/netfilter/ipvs/ip_vs_sync.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nf_conntrack_amanda.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_ftp.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_irc.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_conntrack_tftp.c
net/netfilter/nf_internals.h
net/netfilter/nf_log.c
net/netfilter/nf_queue.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c
net/netfilter/x_tables.c
net/netfilter/xt_CLASSIFY.c
net/netfilter/xt_CONNMARK.c [deleted file]
net/netfilter/xt_CONNSECMARK.c
net/netfilter/xt_CT.c
net/netfilter/xt_DSCP.c
net/netfilter/xt_HL.c
net/netfilter/xt_LED.c
net/netfilter/xt_MARK.c [deleted file]
net/netfilter/xt_NFLOG.c
net/netfilter/xt_NFQUEUE.c
net/netfilter/xt_NOTRACK.c
net/netfilter/xt_RATEEST.c
net/netfilter/xt_SECMARK.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_TCPOPTSTRIP.c
net/netfilter/xt_TEE.c [new file with mode: 0644]
net/netfilter/xt_TPROXY.c
net/netfilter/xt_TRACE.c
net/netfilter/xt_cluster.c
net/netfilter/xt_comment.c
net/netfilter/xt_connbytes.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_connmark.c
net/netfilter/xt_conntrack.c
net/netfilter/xt_dccp.c
net/netfilter/xt_dscp.c
net/netfilter/xt_esp.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_helper.c
net/netfilter/xt_hl.c
net/netfilter/xt_iprange.c
net/netfilter/xt_length.c
net/netfilter/xt_limit.c
net/netfilter/xt_mac.c
net/netfilter/xt_mark.c
net/netfilter/xt_multiport.c
net/netfilter/xt_osf.c
net/netfilter/xt_owner.c
net/netfilter/xt_physdev.c
net/netfilter/xt_pkttype.c
net/netfilter/xt_policy.c
net/netfilter/xt_quota.c
net/netfilter/xt_rateest.c
net/netfilter/xt_realm.c
net/netfilter/xt_recent.c
net/netfilter/xt_sctp.c
net/netfilter/xt_socket.c
net/netfilter/xt_state.c
net/netfilter/xt_statistic.c
net/netfilter/xt_string.c
net/netfilter/xt_tcpmss.c
net/netfilter/xt_tcpudp.c
net/netfilter/xt_time.c
net/netfilter/xt_u32.c
net/netlabel/netlabel_addrlist.h
net/netlabel/netlabel_unlabeled.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/netrom/af_netrom.c
net/packet/af_packet.c
net/phonet/pep.c
net/phonet/pn_dev.c
net/phonet/socket.c
net/rds/af_rds.c
net/rds/cong.c
net/rds/ib_cm.c
net/rds/ib_rdma.c
net/rds/ib_recv.c
net/rds/ib_send.c
net/rds/iw_cm.c
net/rds/iw_recv.c
net/rds/iw_send.c
net/rds/loop.c
net/rds/rdma.c
net/rds/rdma_transport.c
net/rds/rds.h
net/rds/recv.c
net/rds/send.c
net/rds/tcp_connect.c
net/rds/tcp_recv.c
net/rds/tcp_send.c
net/rds/threads.c
net/rfkill/core.c
net/rose/af_rose.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-recvmsg.c
net/sched/act_api.c
net/sched/act_gact.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_pedit.c
net/sched/act_simple.c
net/sched/cls_api.c
net/sched/cls_flow.c
net/sched/cls_u32.c
net/sched/ematch.c
net/sched/sch_api.c
net/sched/sch_generic.c
net/sched/sch_hfsc.c
net/sched/sch_ingress.c
net/sched/sch_mq.c
net/sched/sch_multiq.c
net/sched/sch_prio.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/sched/sch_tbf.c
net/sctp/Kconfig
net/sctp/Makefile
net/sctp/associola.c
net/sctp/chunk.c
net/sctp/endpointola.c
net/sctp/ipv6.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/probe.c [new file with mode: 0644]
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/socket.c
net/sctp/transport.c
net/sctp/ulpqueue.c
net/socket.c
net/sunrpc/auth_gss/gss_spkm3_token.c
net/sunrpc/bc_svc.c
net/sunrpc/clnt.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
net/sysctl_net.c
net/tipc/addr.c
net/tipc/addr.h
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/cluster.c
net/tipc/config.c
net/tipc/core.c
net/tipc/core.h
net/tipc/discover.c
net/tipc/link.c
net/tipc/link.h
net/tipc/msg.c
net/tipc/msg.h
net/tipc/name_distr.c
net/tipc/name_table.c
net/tipc/net.c
net/tipc/node.c
net/tipc/port.c
net/tipc/port.h
net/tipc/socket.c
net/tipc/subscr.c
net/unix/af_unix.c
net/unix/garbage.c
net/wimax/op-reset.c
net/wimax/op-state-get.c
net/wimax/stack.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/sme.c
net/wireless/util.c
net/wireless/wext-compat.c
net/wireless/wext-core.c
net/wireless/wext-sme.c
net/x25/af_x25.c
net/x25/x25_dev.c
net/x25/x25_in.c
net/x25/x25_out.c
net/xfrm/xfrm_hash.h
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/mod/file2alias.c

diff --git a/Documentation/ABI/obsolete/sysfs-class-rfkill b/Documentation/ABI/obsolete/sysfs-class-rfkill
new file mode 100644 (file)
index 0000000..4201d5b
--- /dev/null
@@ -0,0 +1,29 @@
+rfkill - radio frequency (RF) connector kill switch support
+
+For details to this subsystem look at Documentation/rfkill.txt.
+
+What:          /sys/class/rfkill/rfkill[0-9]+/state
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   Current state of the transmitter.
+               This file is deprecated and sheduled to be removed in 2014,
+               because its not possible to express the 'soft and hard block'
+               state of the rfkill driver.
+Values:        A numeric value.
+               0: RFKILL_STATE_SOFT_BLOCKED
+                       transmitter is turned off by software
+               1: RFKILL_STATE_UNBLOCKED
+                       transmitter is (potentially) active
+               2: RFKILL_STATE_HARD_BLOCKED
+                       transmitter is forced off by something outside of
+                       the driver's control.
+
+What:          /sys/class/rfkill/rfkill[0-9]+/claim
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   This file is deprecated because there no longer is a way to
+               claim just control over a single rfkill instance.
+               This file is scheduled to be removed in 2012.
+Values:        0: Kernel handles events
diff --git a/Documentation/ABI/stable/sysfs-class-rfkill b/Documentation/ABI/stable/sysfs-class-rfkill
new file mode 100644 (file)
index 0000000..097f522
--- /dev/null
@@ -0,0 +1,67 @@
+rfkill - radio frequency (RF) connector kill switch support
+
+For details to this subsystem look at Documentation/rfkill.txt.
+
+For the deprecated /sys/class/rfkill/*/state and
+/sys/class/rfkill/*/claim knobs of this interface look in
+Documentation/ABI/obsolete/sysfs-class-rfkill.
+
+What:          /sys/class/rfkill
+Date:          09-Jul-2007
+KernelVersion: v2.6.22
+Contact:       linux-wireless@vger.kernel.org,
+Description:   The rfkill class subsystem folder.
+               Each registered rfkill driver is represented by an rfkillX
+               subfolder (X being an integer > 0).
+
+
+What:          /sys/class/rfkill/rfkill[0-9]+/name
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   Name assigned by driver to this key (interface or driver name).
+Values:        arbitrary string.
+
+
+What:          /sys/class/rfkill/rfkill[0-9]+/type
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   Driver type string ("wlan", "bluetooth", etc).
+Values:        See include/linux/rfkill.h.
+
+
+What:          /sys/class/rfkill/rfkill[0-9]+/persistent
+Date:          09-Jul-2007
+KernelVersion  v2.6.22
+Contact:       linux-wireless@vger.kernel.org
+Description:   Whether the soft blocked state is initialised from non-volatile
+               storage at startup.
+Values:        A numeric value.
+               0: false
+               1: true
+
+
+What:          /sys/class/rfkill/rfkill[0-9]+/hard
+Date:          12-March-2010
+KernelVersion  v2.6.34
+Contact:       linux-wireless@vger.kernel.org
+Description:   Current hardblock state. This file is read only.
+Values:        A numeric value.
+               0: inactive
+                       The transmitter is (potentially) active.
+               1: active
+                       The transmitter is forced off by something outside of
+                       the driver's control.
+
+
+What:          /sys/class/rfkill/rfkill[0-9]+/soft
+Date:          12-March-2010
+KernelVersion  v2.6.34
+Contact:       linux-wireless@vger.kernel.org
+Description:   Current softblock state. This file is read and write.
+Values:        A numeric value.
+               0: inactive
+                       The transmitter is (potentially) active.
+               1: active
+                       The transmitter is turned off by software.
index f08b313cd235fa6728f7780f3b4812eae543f971..eca9f6e6fbe65ffe6deef3c4a8aa0e869c2f98e8 100644 (file)
@@ -49,7 +49,7 @@ o  oprofile               0.9                     # oprofiled --version
 o  udev                   081                     # udevinfo -V
 o  grub                   0.93                    # grub --version
 o  mcelog                0.6
-o  iptables               1.4.1                   # iptables -V
+o  iptables               1.4.2                   # iptables -V
 
 
 Kernel compilation
index e7965f4a385a72d386bf809b7ff61ecf142df2c8..a86152ae2f6f6b5fc8e43b458f750d58df2e700d 100644 (file)
@@ -241,16 +241,6 @@ Who:       Thomas Gleixner <tglx@linutronix.de>
 
 ---------------------------
 
-What (Why):
-       - xt_recent: the old ipt_recent proc dir
-         (superseded by /proc/net/xt_recent)
-
-When:  January 2009 or Linux 2.7.0, whichever comes first
-Why:   Superseded by newer revisions or modules
-Who:   Jan Engelhardt <jengelh@computergmbh.de>
-
----------------------------
-
 What:  GPIO autorequest on gpio_direction_{input,output}() in gpiolib
 When:  February 2010
 Why:   All callers should use explicit gpio_request()/gpio_free().
@@ -520,6 +510,24 @@ Who:       Hans de Goede <hdegoede@redhat.com>
 
 ----------------------------
 
+What:  sysfs-class-rfkill state file
+When:  Feb 2014
+Files: net/rfkill/core.c
+Why:   Documented as obsolete since Feb 2010. This file is limited to 3
+       states while the rfkill drivers can have 4 states.
+Who:   anybody or Florian Mickler <florian@mickler.org>
+
+----------------------------
+
+What:  sysfs-class-rfkill claim file
+When:  Feb 2012
+Files: net/rfkill/core.c
+Why:   It is not possible to claim an rfkill driver since 2007. This is
+       Documented as obsolete since Feb 2010.
+Who:   anybody or Florian Mickler <florian@mickler.org>
+
+----------------------------
+
 What:  capifs
 When:  February 2011
 Files: drivers/isdn/capi/capifs.*
@@ -579,6 +587,35 @@ Who:       Len Brown <len.brown@intel.com>
 
 ----------------------------
 
+What:  iwlwifi 50XX module parameters
+When:  2.6.40
+Why:   The "..50" modules parameters were used to configure 5000 series and
+       up devices; different set of module parameters also available for 4965
+       with same functionalities. Consolidate both set into single place
+       in drivers/net/wireless/iwlwifi/iwl-agn.c
+
+Who:   Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+----------------------------
+
+What:  iwl4965 alias support
+When:  2.6.40
+Why:   Internal alias support has been present in module-init-tools for some
+       time, the MODULE_ALIAS("iwl4965") boilerplate aliases can be removed
+       with no impact.
+
+Who:   Wey-Yi Guy <wey-yi.w.guy@intel.com>
+
+---------------------------
+
+What:  xt_NOTRACK
+Files: net/netfilter/xt_NOTRACK.c
+When:  April 2011
+Why:   Superseded by xt_CT
+Who:   Netfilter developer team <netfilter-devel@vger.kernel.org>
+
+---------------------------
+
 What:  video4linux /dev/vtx teletext API support
 When:  2.6.35
 Files: drivers/media/video/saa5246a.c drivers/media/video/saa5249.c
diff --git a/Documentation/networking/caif/Linux-CAIF.txt b/Documentation/networking/caif/Linux-CAIF.txt
new file mode 100644 (file)
index 0000000..7fe7a9a
--- /dev/null
@@ -0,0 +1,212 @@
+Linux CAIF
+===========
+copyright (C) ST-Ericsson AB 2010
+Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+License terms: GNU General Public License (GPL) version 2
+
+
+Introduction
+------------
+CAIF is a MUX protocol used by ST-Ericsson cellular modems for
+communication between Modem and host. The host processes can open virtual AT
+channels, initiate GPRS Data connections, Video channels and Utility Channels.
+The Utility Channels are general purpose pipes between modem and host.
+
+ST-Ericsson modems support a number of transports between modem
+and host. Currently, UART and Loopback are available for Linux.
+
+
+Architecture:
+------------
+The implementation of CAIF is divided into:
+* CAIF Socket Layer, Kernel API, and  Net Device.
+* CAIF Core Protocol Implementation
+* CAIF Link Layer, implemented as NET devices.
+
+
+  RTNL
+   !
+   !    +------+   +------+   +------+
+   !   +------+!  +------+!  +------+!
+   !   ! Sock !!  !Kernel!!  ! Net  !!
+   !   ! API  !+  ! API  !+  ! Dev  !+   <- CAIF Client APIs
+   !   +------+   +------!   +------+
+   !      !          !          !
+   !      +----------!----------+
+   !              +------+               <- CAIF Protocol Implementation
+   +------->      ! CAIF !
+                  ! Core !
+                  +------+
+            +--------!--------+
+            !                 !
+         +------+          +-----+
+         !      !          ! TTY !       <- Link Layer (Net Devices)
+         +------+          +-----+
+
+
+Using the Kernel API
+----------------------
+The Kernel API is used for accessing CAIF channels from the
+kernel.
+The user of the API has to implement two callbacks for receive
+and control.
+The receive callback gives a CAIF packet as a SKB. The control
+callback will
+notify of channel initialization complete, and flow-on/flow-
+off.
+
+
+  struct caif_device caif_dev = {
+    .caif_config = {
+     .name = "MYDEV"
+     .type = CAIF_CHTY_AT
+    }
+   .receive_cb = my_receive,
+   .control_cb = my_control,
+  };
+  caif_add_device(&caif_dev);
+  caif_transmit(&caif_dev, skb);
+
+See the caif_kernel.h for details about the CAIF kernel API.
+
+
+I M P L E M E N T A T I O N
+===========================
+===========================
+
+CAIF Core Protocol Layer
+=========================================
+
+CAIF Core layer implements the CAIF protocol as defined by ST-Ericsson.
+It implements the CAIF protocol stack in a layered approach, where
+each layer described in the specification is implemented as a separate layer.
+The architecture is inspired by the design patterns "Protocol Layer" and
+"Protocol Packet".
+
+== CAIF structure ==
+The Core CAIF implementation contains:
+      -        Simple implementation of CAIF.
+      -        Layered architecture (a la Streams), each layer in the CAIF
+       specification is implemented in a separate c-file.
+      -        Clients must implement PHY layer to access physical HW
+       with receive and transmit functions.
+      -        Clients must call configuration function to add PHY layer.
+      -        Clients must implement CAIF layer to consume/produce
+       CAIF payload with receive and transmit functions.
+      -        Clients must call configuration function to add and connect the
+       Client layer.
+      - When receiving / transmitting CAIF Packets (cfpkt), ownership is passed
+       to the called function (except for framing layers' receive functions
+       or if a transmit function returns an error, in which case the caller
+       must free the packet).
+
+Layered Architecture
+--------------------
+The CAIF protocol can be divided into two parts: Support functions and Protocol
+Implementation. The support functions include:
+
+      - CFPKT CAIF Packet. Implementation of CAIF Protocol Packet. The
+       CAIF Packet has functions for creating, destroying and adding content
+       and for adding/extracting header and trailers to protocol packets.
+
+      - CFLST CAIF list implementation.
+
+      - CFGLUE CAIF Glue. Contains OS Specifics, such as memory
+       allocation, endianness, etc.
+
+The CAIF Protocol implementation contains:
+
+      - CFCNFG CAIF Configuration layer. Configures the CAIF Protocol
+       Stack and provides a Client interface for adding Link-Layer and
+       Driver interfaces on top of the CAIF Stack.
+
+      - CFCTRL CAIF Control layer. Encodes and Decodes control messages
+       such as enumeration and channel setup. Also matches request and
+       response messages.
+
+      - CFSERVL General CAIF Service Layer functionality; handles flow
+       control and remote shutdown requests.
+
+      - CFVEI CAIF VEI layer. Handles CAIF AT Channels on VEI (Virtual
+        External Interface). This layer encodes/decodes VEI frames.
+
+      - CFDGML CAIF Datagram layer. Handles CAIF Datagram layer (IP
+       traffic), encodes/decodes Datagram frames.
+
+      - CFMUX CAIF Mux layer. Handles multiplexing between multiple
+       physical bearers and multiple channels such as VEI, Datagram, etc.
+       The MUX keeps track of the existing CAIF Channels and
+       Physical Instances and selects the apropriate instance based
+       on Channel-Id and Physical-ID.
+
+      - CFFRML CAIF Framing layer. Handles Framing i.e. Frame length
+       and frame checksum.
+
+      - CFSERL CAIF Serial layer. Handles concatenation/split of frames
+       into CAIF Frames with correct length.
+
+
+
+                   +---------+
+                   | Config  |
+                   | CFCNFG  |
+                   +---------+
+                        !
+    +---------+            +---------+     +---------+
+    |  AT    |     | Control |     | Datagram|
+    | CFVEIL  |            | CFCTRL  |     | CFDGML  |
+    +---------+            +---------+     +---------+
+          \_____________!______________/
+                        !
+                   +---------+
+                   |   MUX   |
+                   |         |
+                   +---------+
+                   _____!_____
+                  /           \
+           +---------+     +---------+
+           | CFFRML  |     | CFFRML  |
+           | Framing |     | Framing |
+           +---------+     +---------+
+                !              !
+           +---------+     +---------+
+           |         |     | Serial  |
+           |         |     | CFSERL  |
+           +---------+     +---------+
+
+
+In this layered approach the following "rules" apply.
+      - All layers embed the same structure "struct cflayer"
+      - A layer does not depend on any other layer's private data.
+      - Layers are stacked by setting the pointers
+                 layer->up , layer->dn
+      -        In order to send data upwards, each layer should do
+                layer->up->receive(layer->up, packet);
+      - In order to send data downwards, each layer should do
+                layer->dn->transmit(layer->dn, packet);
+
+
+Linux Driver Implementation
+===========================
+
+Linux GPRS Net Device and CAIF socket are implemented on top of the
+CAIF Core protocol. The Net device and CAIF socket have an instance of
+'struct cflayer', just like the CAIF Core protocol stack.
+Net device and Socket implement the 'receive()' function defined by
+'struct cflayer', just like the rest of the CAIF stack. In this way, transmit and
+receive of packets is handled as by the rest of the layers: the 'dn->transmit()'
+function is called in order to transmit data.
+
+The layer on top of the CAIF Core implementation is
+sometimes referred to as the "Client layer".
+
+
+Configuration of Link Layer
+---------------------------
+The Link Layer is implemented as Linux net devices (struct net_device).
+Payload handling and registration is done using standard Linux mechanisms.
+
+The CAIF Protocol relies on a loss-less link layer without implementing
+retransmission. This implies that packet drops must not happen.
+Therefore a flow-control mechanism is implemented where the physical
+interface can initiate flow stop for all CAIF Channels.
diff --git a/Documentation/networking/caif/README b/Documentation/networking/caif/README
new file mode 100644 (file)
index 0000000..757ccfa
--- /dev/null
@@ -0,0 +1,109 @@
+Copyright (C) ST-Ericsson AB 2010
+Author: Sjur Brendeland/ sjur.brandeland@stericsson.com
+License terms: GNU General Public License (GPL) version 2
+---------------------------------------------------------
+
+=== Start ===
+If you have compiled CAIF for modules do:
+
+$modprobe crc_ccitt
+$modprobe caif
+$modprobe caif_socket
+$modprobe chnl_net
+
+
+=== Preparing the setup with a STE modem ===
+
+If you are working on integration of CAIF you should make sure
+that the kernel is built with module support.
+
+There are some things that need to be tweaked to get the host TTY correctly
+set up to talk to the modem.
+Since the CAIF stack is running in the kernel and we want to use the existing
+TTY, we are installing our physical serial driver as a line discipline above
+the TTY device.
+
+To achieve this we need to install the N_CAIF ldisc from user space.
+The benefit is that we can hook up to any TTY.
+
+The use of Start-of-frame-extension (STX) must also be set as
+module parameter "ser_use_stx".
+
+Normally Frame Checksum is always used on UART, but this is also provided as a
+module parameter "ser_use_fcs".
+
+$ modprobe caif_serial ser_ttyname=/dev/ttyS0 ser_use_stx=yes
+$ ifconfig caif_ttyS0 up
+
+PLEASE NOTE:   There is a limitation in Android shell.
+               It only accepts one argument to insmod/modprobe!
+
+=== Trouble shooting ===
+
+There are debugfs parameters provided for serial communication.
+/sys/kernel/debug/caif_serial/<tty-name>/
+
+* ser_state:   Prints the bit-mask status where
+  - 0x02 means SENDING, this is a transient state.
+  - 0x10 means FLOW_OFF_SENT, i.e. the previous frame has not been sent
+       and is blocking further send operation. Flow OFF has been propagated
+       to all CAIF Channels using this TTY.
+
+* tty_status: Prints the bit-mask tty status information
+  - 0x01 - tty->warned is on.
+  - 0x02 - tty->low_latency is on.
+  - 0x04 - tty->packed is on.
+  - 0x08 - tty->flow_stopped is on.
+  - 0x10 - tty->hw_stopped is on.
+  - 0x20 - tty->stopped is on.
+
+* last_tx_msg: Binary blob Prints the last transmitted frame.
+       This can be printed with
+       $od --format=x1 /sys/kernel/debug/caif_serial/<tty>/last_rx_msg.
+       The first two tx messages sent look like this. Note: The initial
+       byte 02 is start of frame extension (STX) used for re-syncing
+       upon errors.
+
+  - Enumeration:
+        0000000  02 05 00 00 03 01 d2 02
+                 |  |     |  |  |  |
+                 STX(1)   |  |  |  |
+                    Length(2)|  |  |
+                          Control Channel(1)
+                             Command:Enumeration(1)
+                                Link-ID(1)
+                                    Checksum(2)
+  - Channel Setup:
+        0000000  02 07 00 00 00 21 a1 00 48 df
+                 |  |     |  |  |  |  |  |
+                 STX(1)   |  |  |  |  |  |
+                    Length(2)|  |  |  |  |
+                          Control Channel(1)
+                             Command:Channel Setup(1)
+                                Channel Type(1)
+                                    Priority and Link-ID(1)
+                                     Endpoint(1)
+                                         Checksum(2)
+
+* last_rx_msg: Prints the last transmitted frame.
+       The RX messages for LinkSetup look almost identical but they have the
+       bit 0x20 set in the command bit, and Channel Setup has added one byte
+       before Checksum containing Channel ID.
+       NOTE: Several CAIF Messages might be concatenated. The maximum debug
+       buffer size is 128 bytes.
+
+== Error Scenarios:
+- last_tx_msg contains channel setup message and last_rx_msg is empty ->
+  The host seems to be able to send over the UART, at least the CAIF ldisc get
+  notified that sending is completed.
+
+- last_tx_msg contains enumeration message and last_rx_msg is empty ->
+  The host is not able to send the message from UART, the tty has not been
+  able to complete the transmit operation.
+
+- if /sys/kernel/debug/caif_serial/<tty>/tty_status is non-zero there
+  might be problems transmitting over UART.
+  E.g. host and modem wiring is not correct you will typically see
+  tty_status = 0x10 (hw_stopped) and ser_state = 0x10 (FLOW_OFF_SENT).
+  You will probably see the enumeration message in last_tx_message
+  and empty last_rx_message.
index 8b72c88ba21391329300f0a1c25440b8520b28c1..d0536b5a4e014afc6aa48f5d0c9a2f36ff91969a 100644 (file)
@@ -588,6 +588,37 @@ ip_local_port_range - 2 INTEGERS
        (i.e. by default) range 1024-4999 is enough to issue up to
        2000 connections per second to systems supporting timestamps.
 
+ip_local_reserved_ports - list of comma separated ranges
+       Specify the ports which are reserved for known third-party
+       applications. These ports will not be used by automatic port
+       assignments (e.g. when calling connect() or bind() with port
+       number 0). Explicit port allocation behavior is unchanged.
+
+       The format used for both input and output is a comma separated
+       list of ranges (e.g. "1,2-4,10-10" for ports 1, 2, 3, 4 and
+       10). Writing to the file will clear all previously reserved
+       ports and update the current list with the one given in the
+       input.
+
+       Note that ip_local_port_range and ip_local_reserved_ports
+       settings are independent and both are considered by the kernel
+       when determining which ports are available for automatic port
+       assignments.
+
+       You can reserve ports which are not in the current
+       ip_local_port_range, e.g.:
+
+       $ cat /proc/sys/net/ipv4/ip_local_port_range
+       32000   61000
+       $ cat /proc/sys/net/ipv4/ip_local_reserved_ports
+       8080,9148
+
+       although this is redundant. However such a setting is useful
+       if later the port range is changed to a value that will
+       include the reserved ports.
+
+       Default: Empty
+
 ip_nonlocal_bind - BOOLEAN
        If set, allows processes to bind() to non-local IP addresses,
        which can be quite useful - but may break some applications.
index 63214b280e0026c9711ea08ec0f1111e41524599..e7bf3979facb95005fdbae1070013d3953a1c822 100644 (file)
@@ -1,44 +1,95 @@
-This brief document describes how to use the kernel's PPPoL2TP driver
-to provide L2TP functionality. L2TP is a protocol that tunnels one or
-more PPP sessions over a UDP tunnel. It is commonly used for VPNs
+This document describes how to use the kernel's L2TP drivers to
+provide L2TP functionality. L2TP is a protocol that tunnels one or
+more sessions over an IP tunnel. It is commonly used for VPNs
 (L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP
-network infrastructure.
+network infrastructure. With L2TPv3, it is also useful as a Layer-2
+tunneling infrastructure.
+
+Features
+========
+
+L2TPv2 (PPP over L2TP (UDP tunnels)).
+L2TPv3 ethernet pseudowires.
+L2TPv3 PPP pseudowires.
+L2TPv3 IP encapsulation.
+Netlink sockets for L2TPv3 configuration management.
+
+History
+=======
+
+The original pppol2tp driver was introduced in 2.6.23 and provided
+L2TPv2 functionality (rfc2661). L2TPv2 is used to tunnel one or more PPP
+sessions over a UDP tunnel.
+
+L2TPv3 (rfc3931) changes the protocol to allow different frame types
+to be passed over an L2TP tunnel by moving the PPP-specific parts of
+the protocol out of the core L2TP packet headers. Each frame type is
+known as a pseudowire type. Ethernet, PPP, HDLC, Frame Relay and ATM
+pseudowires for L2TP are defined in separate RFC standards. Another
+change for L2TPv3 is that it can be carried directly over IP with no
+UDP header (UDP is optional). It is also possible to create static
+unmanaged L2TPv3 tunnels manually without a control protocol
+(userspace daemon) to manage them.
+
+To support L2TPv3, the original pppol2tp driver was split up to
+separate the L2TP and PPP functionality. Existing L2TPv2 userspace
+apps should be unaffected as the original pppol2tp sockets API is
+retained. L2TPv3, however, uses netlink to manage L2TPv3 tunnels and
+sessions.
 
 Design
 ======
 
-The PPPoL2TP driver, drivers/net/pppol2tp.c, provides a mechanism by
-which PPP frames carried through an L2TP session are passed through
-the kernel's PPP subsystem. The standard PPP daemon, pppd, handles all
-PPP interaction with the peer. PPP network interfaces are created for
-each local PPP endpoint.
-
-The L2TP protocol http://www.faqs.org/rfcs/rfc2661.html defines L2TP
-control and data frames. L2TP control frames carry messages between
-L2TP clients/servers and are used to setup / teardown tunnels and
-sessions. An L2TP client or server is implemented in userspace and
-will use a regular UDP socket per tunnel. L2TP data frames carry PPP
-frames, which may be PPP control or PPP data. The kernel's PPP
+The L2TP protocol separates control and data frames.  The L2TP kernel
+drivers handle only L2TP data frames; control frames are always
+handled by userspace. L2TP control frames carry messages between L2TP
+clients/servers and are used to setup / teardown tunnels and
+sessions. An L2TP client or server is implemented in userspace.
+
+Each L2TP tunnel is implemented using a UDP or L2TPIP socket; L2TPIP
+provides L2TPv3 IP encapsulation (no UDP) and is implemented using a
+new l2tpip socket family. The tunnel socket is typically created by
+userspace, though for unmanaged L2TPv3 tunnels, the socket can also be
+created by the kernel. Each L2TP session (pseudowire) gets a network
+interface instance. In the case of PPP, these interfaces are created
+indirectly by pppd using a pppol2tp socket. In the case of ethernet,
+the netdevice is created upon a netlink request to create an L2TPv3
+ethernet pseudowire.
+
+For PPP, the PPPoL2TP driver, net/l2tp/l2tp_ppp.c, provides a
+mechanism by which PPP frames carried through an L2TP session are
+passed through the kernel's PPP subsystem. The standard PPP daemon,
+pppd, handles all PPP interaction with the peer. PPP network
+interfaces are created for each local PPP endpoint. The kernel's PPP
 subsystem arranges for PPP control frames to be delivered to pppd,
 while data frames are forwarded as usual.
 
+For ethernet, the L2TPETH driver, net/l2tp/l2tp_eth.c, implements a
+netdevice driver, managing virtual ethernet devices, one per
+pseudowire. These interfaces can be managed using standard Linux tools
+such as "ip" and "ifconfig". If only IP frames are passed over the
+tunnel, the interface can be given an IP addresses of itself and its
+peer. If non-IP frames are to be passed over the tunnel, the interface
+can be added to a bridge using brctl. All L2TP datapath protocol
+functions are handled by the L2TP core driver.
+
 Each tunnel and session within a tunnel is assigned a unique tunnel_id
 and session_id. These ids are carried in the L2TP header of every
-control and data packet. The pppol2tp driver uses them to lookup
-internal tunnel and/or session contexts. Zero tunnel / session ids are
-treated specially - zero ids are never assigned to tunnels or sessions
-in the network. In the driver, the tunnel context keeps a pointer to
-the tunnel UDP socket. The session context keeps a pointer to the
-PPPoL2TP socket, as well as other data that lets the driver interface
-to the kernel PPP subsystem.
-
-Note that the pppol2tp kernel driver handles only L2TP data frames;
-L2TP control frames are simply passed up to userspace in the UDP
-tunnel socket. The kernel handles all datapath aspects of the
-protocol, including data packet resequencing (if enabled).
-
-There are a number of requirements on the userspace L2TP daemon in
-order to use the pppol2tp driver.
+control and data packet. (Actually, in L2TPv3, the tunnel_id isn't
+present in data frames - it is inferred from the IP connection on
+which the packet was received.) The L2TP driver uses the ids to lookup
+internal tunnel and/or session contexts to determine how to handle the
+packet. Zero tunnel / session ids are treated specially - zero ids are
+never assigned to tunnels or sessions in the network. In the driver,
+the tunnel context keeps a reference to the tunnel UDP or L2TPIP
+socket. The session context holds data that lets the driver interface
+to the kernel's network frame type subsystems, i.e. PPP, ethernet.
+
+Userspace Programming
+=====================
+
+For L2TPv2, there are a number of requirements on the userspace L2TP
+daemon in order to use the pppol2tp driver.
 
 1. Use a UDP socket per tunnel.
 
@@ -86,6 +137,35 @@ In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided
 to retrieve tunnel and session statistics from the kernel using the
 PPPoX socket of the appropriate tunnel or session.
 
+For L2TPv3, userspace must use the netlink API defined in
+include/linux/l2tp.h to manage tunnel and session contexts. The
+general procedure to create a new L2TP tunnel with one session is:-
+
+1. Open a GENL socket using L2TP_GENL_NAME for configuring the kernel
+   using netlink.
+
+2. Create a UDP or L2TPIP socket for the tunnel.
+
+3. Create a new L2TP tunnel using a L2TP_CMD_TUNNEL_CREATE
+   request. Set attributes according to desired tunnel parameters,
+   referencing the UDP or L2TPIP socket created in the previous step.
+
+4. Create a new L2TP session in the tunnel using a
+   L2TP_CMD_SESSION_CREATE request.
+
+The tunnel and all of its sessions are closed when the tunnel socket
+is closed. The netlink API may also be used to delete sessions and
+tunnels. Configuration and status info may be set or read using netlink.
+
+The L2TP driver also supports static (unmanaged) L2TPv3 tunnels. These
+are where there is no L2TP control message exchange with the peer to
+setup the tunnel; the tunnel is configured manually at each end of the
+tunnel. There is no need for an L2TP userspace application in this
+case -- the tunnel socket is created by the kernel and configured
+using parameters sent in the L2TP_CMD_TUNNEL_CREATE netlink
+request. The "ip" utility of iproute2 has commands for managing static
+L2TPv3 tunnels; do "ip l2tp help" for more information.
+
 Debugging
 =========
 
@@ -102,6 +182,69 @@ PPPOL2TP_MSG_CONTROL  userspace - kernel interface
 PPPOL2TP_MSG_SEQ      sequence numbers handling
 PPPOL2TP_MSG_DATA     data packets
 
+If enabled, files under a l2tp debugfs directory can be used to dump
+kernel state about L2TP tunnels and sessions. To access it, the
+debugfs filesystem must first be mounted.
+
+# mount -t debugfs debugfs /debug
+
+Files under the l2tp directory can then be accessed.
+
+# cat /debug/l2tp/tunnels
+
+The debugfs files should not be used by applications to obtain L2TP
+state information because the file format is subject to change. It is
+implemented to provide extra debug information to help diagnose
+problems.) Users should use the netlink API.
+
+/proc/net/pppol2tp is also provided for backwards compaibility with
+the original pppol2tp driver. It lists information about L2TPv2
+tunnels and sessions only. Its use is discouraged.
+
+Unmanaged L2TPv3 Tunnels
+========================
+
+Some commercial L2TP products support unmanaged L2TPv3 ethernet
+tunnels, where there is no L2TP control protocol; tunnels are
+configured at each side manually. New commands are available in
+iproute2's ip utility to support this.
+
+To create an L2TPv3 ethernet pseudowire between local host 192.168.1.1
+and peer 192.168.1.2, using IP addresses 10.5.1.1 and 10.5.1.2 for the
+tunnel endpoints:-
+
+# modprobe l2tp_eth
+# modprobe l2tp_netlink
+
+# ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 udp_sport 5000 \
+  udp_dport 5000 encap udp local 192.168.1.1 remote 192.168.1.2
+# ip l2tp add session tunnel_id 1 session_id 1 peer_session_id 1
+# ifconfig -a
+# ip addr add 10.5.1.2/32 peer 10.5.1.1/32 dev l2tpeth0
+# ifconfig l2tpeth0 up
+
+Choose IP addresses to be the address of a local IP interface and that
+of the remote system. The IP addresses of the l2tpeth0 interface can be
+anything suitable.
+
+Repeat the above at the peer, with ports, tunnel/session ids and IP
+addresses reversed.  The tunnel and session IDs can be any non-zero
+32-bit number, but the values must be reversed at the peer.
+
+Host 1                         Host2
+udp_sport=5000                 udp_sport=5001
+udp_dport=5001                 udp_dport=5000
+tunnel_id=42                   tunnel_id=45
+peer_tunnel_id=45              peer_tunnel_id=42
+session_id=128                 session_id=5196755
+peer_session_id=5196755        peer_session_id=128
+
+When done at both ends of the tunnel, it should be possible to send
+data over the network. e.g.
+
+# ping 10.5.1.1
+
+
 Sample Userspace Code
 =====================
 
@@ -158,12 +301,48 @@ Sample Userspace Code
         }
         return 0;
 
+Internal Implementation
+=======================
+
+The driver keeps a struct l2tp_tunnel context per L2TP tunnel and a
+struct l2tp_session context for each session. The l2tp_tunnel is
+always associated with a UDP or L2TP/IP socket and keeps a list of
+sessions in the tunnel. The l2tp_session context keeps kernel state
+about the session. It has private data which is used for data specific
+to the session type. With L2TPv2, the session always carried PPP
+traffic. With L2TPv3, the session can also carry ethernet frames
+(ethernet pseudowire) or other data types such as ATM, HDLC or Frame
+Relay.
+
+When a tunnel is first opened, the reference count on the socket is
+increased using sock_hold(). This ensures that the kernel socket
+cannot be removed while L2TP's data structures reference it.
+
+Some L2TP sessions also have a socket (PPP pseudowires) while others
+do not (ethernet pseudowires). We can't use the socket reference count
+as the reference count for session contexts. The L2TP implementation
+therefore has its own internal reference counts on the session
+contexts.
+
+To Do
+=====
+
+Add L2TP tunnel switching support. This would route tunneled traffic
+from one L2TP tunnel into another. Specified in
+http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08
+
+Add L2TPv3 VLAN pseudowire support.
+
+Add L2TPv3 IP pseudowire support.
+
+Add L2TPv3 ATM pseudowire support.
+
 Miscellaneous
-============
+=============
 
-The PPPoL2TP driver was developed as part of the OpenL2TP project by
+The L2TP drivers were developed as part of the OpenL2TP project by
 Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server,
 designed from the ground up to have the L2TP datapath in the
 kernel. The project also implemented the pppol2tp plugin for pppd
 which allows pppd to use the kernel driver. Details can be found at
-http://openl2tp.sourceforge.net.
+http://www.openl2tp.org.
index 975cc87ebdd158a264690c536ec8d253319d510a..78f662ee0622abb312aff56f13b97768c0bff81f 100644 (file)
@@ -20,23 +20,23 @@ the rest of the skbuff, if any more information does exist.
 Packet Layer to Device Driver
 -----------------------------
 
-First Byte = 0x00
+First Byte = 0x00 (X25_IFACE_DATA)
 
 This indicates that the rest of the skbuff contains data to be transmitted
 over the LAPB link. The LAPB link should already exist before any data is
 passed down.
 
-First Byte = 0x01
+First Byte = 0x01 (X25_IFACE_CONNECT)
 
 Establish the LAPB link. If the link is already established then the connect
 confirmation message should be returned as soon as possible.
 
-First Byte = 0x02
+First Byte = 0x02 (X25_IFACE_DISCONNECT)
 
 Terminate the LAPB link. If it is already disconnected then the disconnect
 confirmation message should be returned as soon as possible.
 
-First Byte = 0x03
+First Byte = 0x03 (X25_IFACE_PARAMS)
 
 LAPB parameters. To be defined.
 
@@ -44,22 +44,22 @@ LAPB parameters. To be defined.
 Device Driver to Packet Layer
 -----------------------------
 
-First Byte = 0x00
+First Byte = 0x00 (X25_IFACE_DATA)
 
 This indicates that the rest of the skbuff contains data that has been
 received over the LAPB link.
 
-First Byte = 0x01
+First Byte = 0x01 (X25_IFACE_CONNECT)
 
 LAPB link has been established. The same message is used for both a LAPB
 link connect_confirmation and a connect_indication.
 
-First Byte = 0x02
+First Byte = 0x02 (X25_IFACE_DISCONNECT)
 
 LAPB link has been terminated. This same message is used for both a LAPB
 link disconnect_confirmation and a disconnect_indication.
 
-First Byte = 0x03
+First Byte = 0x03 (X25_IFACE_PARAMS)
 
 LAPB parameters. To be defined.
 
index b4860509c319676b87f4a898f88eab15fe2cb08b..83668e5dd17f4b23dff1dfbb50ebe049c788a8a8 100644 (file)
@@ -99,37 +99,15 @@ system. Also, it is possible to switch all rfkill drivers (or all drivers of
 a specified type) into a state which also updates the default state for
 hotplugged devices.
 
-After an application opens /dev/rfkill, it can read the current state of
-all devices, and afterwards can poll the descriptor for hotplug or state
-change events.
-
-Applications must ignore operations (the "op" field) they do not handle,
-this allows the API to be extended in the future.
-
-Additionally, each rfkill device is registered in sysfs and there has the
-following attributes:
-
-       name: Name assigned by driver to this key (interface or driver name).
-       type: Driver type string ("wlan", "bluetooth", etc).
-       persistent: Whether the soft blocked state is initialised from
-                   non-volatile storage at startup.
-       state: Current state of the transmitter
-               0: RFKILL_STATE_SOFT_BLOCKED
-                       transmitter is turned off by software
-               1: RFKILL_STATE_UNBLOCKED
-                       transmitter is (potentially) active
-               2: RFKILL_STATE_HARD_BLOCKED
-                       transmitter is forced off by something outside of
-                       the driver's control.
-              This file is deprecated because it can only properly show
-              three of the four possible states, soft-and-hard-blocked is
-              missing.
-       claim: 0: Kernel handles events
-              This file is deprecated because there no longer is a way to
-              claim just control over a single rfkill instance.
-
-rfkill devices also issue uevents (with an action of "change"), with the
-following environment variables set:
+After an application opens /dev/rfkill, it can read the current state of all
+devices. Changes can be either obtained by either polling the descriptor for
+hotplug or state change events or by listening for uevents emitted by the
+rfkill core framework.
+
+Additionally, each rfkill device is registered in sysfs and emits uevents.
+
+rfkill devices issue uevents (with an action of "change"), with the following
+environment variables set:
 
 RFKILL_NAME
 RFKILL_STATE
@@ -137,3 +115,7 @@ RFKILL_TYPE
 
 The contents of these variables corresponds to the "name", "state" and
 "type" sysfs files explained above.
+
+
+For further details consult Documentation/ABI/stable/dev-rfkill and
+Documentation/ABI/stable/sysfs-class-rfkill.
index df38ef046f8d1372ef2ff0d45debb7b15c04f64c..cbd05ffc606baa1ca06c59ca0c2ab19cac6c8e62 100644 (file)
@@ -84,6 +84,16 @@ netdev_max_backlog
 Maximum number  of  packets,  queued  on  the  INPUT  side, when the interface
 receives packets faster than kernel can process them.
 
+netdev_tstamp_prequeue
+----------------------
+
+If set to 0, RX packet timestamps can be sampled after RPS processing, when
+the target CPU processes packets. It might give some delay on timestamps, but
+permit to distribute the load on several cpus.
+
+If set to 1 (default), timestamps are sampled as soon as possible, before
+queueing.
+
 optmem_max
 ----------
 
index 24490426750d9e8271e9cb00f4aea03b306c6c2b..22a49e68c8b9ef15bd5e6e51570d4bcf4f728bec 100644 (file)
@@ -1521,9 +1521,10 @@ M:       Andy Whitcroft <apw@canonical.com>
 S:     Supported
 F:     scripts/checkpatch.pl
 
-CISCO 10G ETHERNET DRIVER
+CISCO VIC ETHERNET NIC DRIVER
 M:     Scott Feldman <scofeldm@cisco.com>
-M:     Joe Eykholt <jeykholt@cisco.com>
+M:     Vasanthy Kolluri <vkolluri@cisco.com>
+M:     Roopa Prabhu <roprabhu@cisco.com>
 S:     Supported
 F:     drivers/net/enic/
 
@@ -3044,10 +3045,9 @@ F:       net/ipv4/netfilter/ipt_MASQUERADE.c
 IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
 M:     Francois Romieu <romieu@fr.zoreil.com>
 M:     Sorbica Shieh <sorbica@icplus.com.tw>
-M:     Jesse Huang <jesse@icplus.com.tw>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     drivers/net/ipg.c
+F:     drivers/net/ipg.*
 
 IPATH DRIVER
 M:     Ralph Campbell <infinipath@qlogic.com>
@@ -3895,7 +3895,6 @@ M:        Ramkrishna Vepa <ram.vepa@neterion.com>
 M:     Rastapur Santosh <santosh.rastapur@neterion.com>
 M:     Sivakumar Subramani <sivakumar.subramani@neterion.com>
 M:     Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
-M:     Anil Murthy <anil.murthy@neterion.com>
 L:     netdev@vger.kernel.org
 W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/Linux?Anonymous
 W:     http://trac.neterion.com/cgi-bin/trac.cgi/wiki/X3100Linux?Anonymous
@@ -4000,6 +3999,7 @@ F:        net/rfkill/
 F:     net/wireless/
 F:     include/net/ieee80211*
 F:     include/linux/wireless.h
+F:     include/linux/iw_handler.h
 F:     drivers/net/wireless/
 
 NETWORKING DRIVERS
@@ -4631,6 +4631,7 @@ F:        drivers/net/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
 M:     Amit Kumar Salecha <amit.salecha@qlogic.com>
+M:     Anirban Chakraborty <anirban.chakraborty@qlogic.com>
 M:     linux-driver@qlogic.com
 L:     netdev@vger.kernel.org
 S:     Supported
index 4aafd5b8b85b48d400cdf00841a8fdfa63ef33b9..f490a406d57e737b46a343cb0c780e83f72cb056 100644 (file)
@@ -201,9 +201,9 @@ static struct resource pcm970_sja1000_resources[] = {
 };
 
 struct sja1000_platform_data pcm970_sja1000_platform_data = {
-       .clock          = 16000000 / 2,
-       .ocr            = 0x40 | 0x18,
-       .cdr            = 0x40,
+       .osc_freq       = 16000000,
+       .ocr            = OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL,
+       .cdr            = CDR_CBP,
 };
 
 static struct platform_device pcm970_sja1000 = {
index 2df1ec55a97e6565980b27fd0ade0754921b20e1..78ecd751549b68e0ef2894ad49fba56208601b24 100644 (file)
@@ -530,9 +530,9 @@ static struct resource pcm970_sja1000_resources[] = {
 };
 
 struct sja1000_platform_data pcm970_sja1000_platform_data = {
-       .clock          = 16000000 / 2,
-       .ocr            = 0x40 | 0x18,
-       .cdr            = 0x40,
+       .osc_freq       = 16000000,
+       .ocr            = OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL,
+       .cdr            = CDR_CBP,
 };
 
 static struct platform_device pcm970_sja1000 = {
index 771137fc1a82c6a7e276b183940511f7eb3a9641..5ccb0ceff6c4160f153d795b1bbcfcf4e035facb 100644 (file)
@@ -73,7 +73,6 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = {
 
 static struct mcp251x_platform_data mcp251x_info = {
        .oscillator_frequency = 16E6,
-       .model                = CAN_MCP251X_MCP2515,
        .board_specific_setup = NULL,
        .power_enable         = NULL,
        .transceiver_enable   = NULL
@@ -81,7 +80,7 @@ static struct mcp251x_platform_data mcp251x_info = {
 
 static struct spi_board_info mcp251x_board_info[] = {
        {
-               .modalias        = "mcp251x",
+               .modalias        = "mcp2515",
                .max_speed_hz    = 6500000,
                .bus_num         = 3,
                .chip_select     = 0,
@@ -90,7 +89,7 @@ static struct spi_board_info mcp251x_board_info[] = {
                .irq             = gpio_to_irq(ICONTROL_MCP251x_nIRQ1)
        },
        {
-               .modalias        = "mcp251x",
+               .modalias        = "mcp2515",
                .max_speed_hz    = 6500000,
                .bus_num         = 3,
                .chip_select     = 1,
@@ -99,7 +98,7 @@ static struct spi_board_info mcp251x_board_info[] = {
                .irq             = gpio_to_irq(ICONTROL_MCP251x_nIRQ2)
        },
        {
-               .modalias        = "mcp251x",
+               .modalias        = "mcp2515",
                .max_speed_hz    = 6500000,
                .bus_num         = 4,
                .chip_select     = 0,
@@ -108,7 +107,7 @@ static struct spi_board_info mcp251x_board_info[] = {
                .irq             = gpio_to_irq(ICONTROL_MCP251x_nIRQ3)
        },
        {
-               .modalias        = "mcp251x",
+               .modalias        = "mcp2515",
                .max_speed_hz    = 6500000,
                .bus_num         = 4,
                .chip_select     = 1,
index 3680f6a9062376e7baa7806118ab18a1c733441e..03b9cb910e085b1911465e77d57a12ac11a71c9f 100644 (file)
@@ -414,15 +414,13 @@ static int zeus_mcp2515_transceiver_enable(int enable)
 
 static struct mcp251x_platform_data zeus_mcp2515_pdata = {
        .oscillator_frequency   = 16*1000*1000,
-       .model                  = CAN_MCP251X_MCP2515,
        .board_specific_setup   = zeus_mcp2515_setup,
-       .transceiver_enable     = zeus_mcp2515_transceiver_enable,
        .power_enable           = zeus_mcp2515_transceiver_enable,
 };
 
 static struct spi_board_info zeus_spi_board_info[] = {
        [0] = {
-               .modalias       = "mcp251x",
+               .modalias       = "mcp2515",
                .platform_data  = &zeus_mcp2515_pdata,
                .irq            = gpio_to_irq(ZEUS_CAN_GPIO),
                .max_speed_hz   = 1*1000*1000,
index 59efb3fef9577d93d83ad2bf6ce7a15ab8128144..48c4f0335e3f51b74413a93783da6f1fb8f0970d 100644 (file)
@@ -12,6 +12,7 @@
 #include <asm/registers.h>
 #include <asm/setup.h>
 #include <asm/irqflags.h>
+#include <asm/cache.h>
 
 #include <asm-generic/cmpxchg.h>
 #include <asm-generic/cmpxchg-local.h>
@@ -96,4 +97,14 @@ extern struct dentry *of_debugfs_root;
 
 #define arch_align_stack(x) (x)
 
+/*
+ * MicroBlaze doesn't handle unaligned accesses in hardware.
+ *
+ * Based on this we force the IP header alignment in network drivers.
+ * We also modify NET_SKB_PAD to be a cacheline in size, thus maintaining
+ * cacheline alignment of buffers.
+ */
+#define NET_IP_ALIGN   2
+#define NET_SKB_PAD    L1_CACHE_BYTES
+
 #endif /* _ASM_MICROBLAZE_SYSTEM_H */
index 54847fe1e564d5ef2cdd985f27511f0dc7ba599a..097335262fb3f3abad4f5850636ee03d67e2c5a5 100644 (file)
@@ -83,3 +83,57 @@ static int __init swarm_pata_init(void)
 device_initcall(swarm_pata_init);
 
 #endif /* defined(CONFIG_SIBYTE_SWARM) || defined(CONFIG_SIBYTE_LITTLESUR) */
+
+#define sb1250_dev_struct(num) \
+       static struct resource sb1250_res##num = {              \
+               .name = "SB1250 MAC " __stringify(num),         \
+               .flags = IORESOURCE_MEM,                \
+               .start = A_MAC_CHANNEL_BASE(num),       \
+               .end = A_MAC_CHANNEL_BASE(num + 1) -1,  \
+       };\
+       static struct platform_device sb1250_dev##num = {       \
+               .name = "sb1250-mac",                   \
+       .id = num,                                      \
+       .resource = &sb1250_res##num,                   \
+       .num_resources = 1,                             \
+       }
+
+sb1250_dev_struct(0);
+sb1250_dev_struct(1);
+sb1250_dev_struct(2);
+sb1250_dev_struct(3);
+
+static struct platform_device *sb1250_devs[] __initdata = {
+       &sb1250_dev0,
+       &sb1250_dev1,
+       &sb1250_dev2,
+       &sb1250_dev3,
+};
+
+static int __init sb1250_device_init(void)
+{
+       int ret;
+
+       /* Set the number of available units based on the SOC type.  */
+       switch (soc_type) {
+       case K_SYS_SOC_TYPE_BCM1250:
+       case K_SYS_SOC_TYPE_BCM1250_ALT:
+               ret = platform_add_devices(sb1250_devs, 3);
+               break;
+       case K_SYS_SOC_TYPE_BCM1120:
+       case K_SYS_SOC_TYPE_BCM1125:
+       case K_SYS_SOC_TYPE_BCM1125H:
+       case K_SYS_SOC_TYPE_BCM1250_ALT2:       /* Hybrid */
+               ret = platform_add_devices(sb1250_devs, 2);
+               break;
+       case K_SYS_SOC_TYPE_BCM1x55:
+       case K_SYS_SOC_TYPE_BCM1x80:
+               ret = platform_add_devices(sb1250_devs, 4);
+               break;
+       default:
+               ret = -ENODEV;
+               break;
+       }
+       return ret;
+}
+device_initcall(sb1250_device_init);
index 191b85e857e0a3f0ef9055c27dd2408812ad1268..f1a0a00b3b07c8f8563f1cbac1304f9fd8a5f5b3 100644 (file)
@@ -394,6 +394,7 @@ config ATM_HE_USE_SUNI
 config ATM_SOLOS
        tristate "Solos ADSL2+ PCI Multiport card driver"
        depends on PCI
+       select FW_LOADER
        help
          Support for the Solos multiport ADSL2+ card.
 
index b86712167eb8fddc08d4be0cfe1843550ab9df2d..b9101818b47b4012d9c5589d7b8ffd672cb26fc7 100644 (file)
@@ -68,7 +68,7 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type,
        *(struct atm_vcc **) &new_msg->vcc = vcc;
        old_test = test_bit(flag,&vcc->flags);
        out_vcc->push(out_vcc,skb);
-       add_wait_queue(sk_atm(vcc)->sk_sleep, &wait);
+       add_wait_queue(sk_sleep(sk_atm(vcc)), &wait);
        while (test_bit(flag,&vcc->flags) == old_test) {
                mb();
                out_vcc = PRIV(vcc->dev) ? PRIV(vcc->dev)->vcc : NULL;
@@ -80,7 +80,7 @@ static int atmtcp_send_control(struct atm_vcc *vcc,int type,
                schedule();
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk_atm(vcc)->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk_atm(vcc)), &wait);
        return error;
 }
 
@@ -105,7 +105,7 @@ static int atmtcp_recv_control(const struct atmtcp_control *msg)
                    msg->type);
                return -EINVAL;
        }
-       wake_up(sk_atm(vcc)->sk_sleep);
+       wake_up(sk_sleep(sk_atm(vcc)));
        return 0;
 }
 
index 719ec5a0dca547091df22ef8464a5bf2dcbfe241..90a5a7cac740ed195c9a73b62d3288ec3db697fe 100644 (file)
@@ -1131,7 +1131,7 @@ DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */
                        if (i == -1)
                                put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
                                    skb->data,
-                                   skb->len - skb->data_len);
+                                   skb_headlen(skb));
                        else
                                put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
                                    skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset,
index c213e0da0343d4d9cda4d7283664537939a3ab8a..56c2e99e458fd7ea85e25f4ee3d5b7e0ed9aa261 100644 (file)
@@ -2664,8 +2664,8 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb)
 
 #ifdef USE_SCATTERGATHER
        tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data,
-                               skb->len - skb->data_len, PCI_DMA_TODEVICE);
-       tpd->iovec[slot].len = skb->len - skb->data_len;
+                               skb_headlen(skb), PCI_DMA_TODEVICE);
+       tpd->iovec[slot].len = skb_headlen(skb);
        ++slot;
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
index 204727586ee913896b1511e87ceffe3fcf8d6d88..bed0ba630235b46fb796b20116f4ea11d414675b 100644 (file)
@@ -42,6 +42,8 @@ struct btmrvl_device {
        void *card;
        struct hci_dev *hcidev;
 
+       u8 dev_type;
+
        u8 tx_dnld_rdy;
 
        u8 psmode;
@@ -88,8 +90,11 @@ struct btmrvl_private {
 #define BT_CMD_HOST_SLEEP_ENABLE       0x5A
 #define BT_CMD_MODULE_CFG_REQ          0x5B
 
-/* Sub-commands: Module Bringup/Shutdown Request */
+/* Sub-commands: Module Bringup/Shutdown Request/Response */
 #define MODULE_BRINGUP_REQ             0xF1
+#define MODULE_BROUGHT_UP              0x00
+#define MODULE_ALREADY_UP              0x0C
+
 #define MODULE_SHUTDOWN_REQ            0xF2
 
 #define BT_EVENT_POWER_STATE           0x20
@@ -123,6 +128,7 @@ struct btmrvl_event {
 
 /* Prototype of global function */
 
+int btmrvl_register_hdev(struct btmrvl_private *priv);
 struct btmrvl_private *btmrvl_add_card(void *card);
 int btmrvl_remove_card(struct btmrvl_private *priv);
 
index 53a43adf2e21b3d342e9b2bb885716cdb3b810f2..ee37ef0caee269c0383fd9336ea9cf0d665ddba0 100644 (file)
@@ -66,7 +66,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
 {
        struct btmrvl_adapter *adapter = priv->adapter;
        struct btmrvl_event *event;
-       u8 ret = 0;
+       int ret = 0;
 
        event = (struct btmrvl_event *) skb->data;
        if (event->ec != 0xff) {
@@ -112,8 +112,17 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
        case BT_CMD_MODULE_CFG_REQ:
                if (priv->btmrvl_dev.sendcmdflag &&
                                event->data[1] == MODULE_BRINGUP_REQ) {
-                       BT_DBG("EVENT:%s", (event->data[2]) ?
-                               "Bring-up failed" : "Bring-up succeed");
+                       BT_DBG("EVENT:%s",
+                               ((event->data[2] == MODULE_BROUGHT_UP) ||
+                               (event->data[2] == MODULE_ALREADY_UP)) ?
+                               "Bring-up succeed" : "Bring-up failed");
+
+                       if (event->length > 3)
+                               priv->btmrvl_dev.dev_type = event->data[3];
+                       else
+                               priv->btmrvl_dev.dev_type = HCI_BREDR;
+
+                       BT_DBG("dev_type: %d", priv->btmrvl_dev.dev_type);
                } else if (priv->btmrvl_dev.sendcmdflag &&
                                event->data[1] == MODULE_SHUTDOWN_REQ) {
                        BT_DBG("EVENT:%s", (event->data[2]) ?
@@ -522,47 +531,20 @@ static int btmrvl_service_main_thread(void *data)
        return 0;
 }
 
-struct btmrvl_private *btmrvl_add_card(void *card)
+int btmrvl_register_hdev(struct btmrvl_private *priv)
 {
        struct hci_dev *hdev = NULL;
-       struct btmrvl_private *priv;
        int ret;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               BT_ERR("Can not allocate priv");
-               goto err_priv;
-       }
-
-       priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL);
-       if (!priv->adapter) {
-               BT_ERR("Allocate buffer for btmrvl_adapter failed!");
-               goto err_adapter;
-       }
-
-       btmrvl_init_adapter(priv);
-
        hdev = hci_alloc_dev();
        if (!hdev) {
                BT_ERR("Can not allocate HCI device");
                goto err_hdev;
        }
 
-       BT_DBG("Starting kthread...");
-       priv->main_thread.priv = priv;
-       spin_lock_init(&priv->driver_lock);
-
-       init_waitqueue_head(&priv->main_thread.wait_q);
-       priv->main_thread.task = kthread_run(btmrvl_service_main_thread,
-                               &priv->main_thread, "btmrvl_main_service");
-
        priv->btmrvl_dev.hcidev = hdev;
-       priv->btmrvl_dev.card = card;
-
        hdev->driver_data = priv;
 
-       priv->btmrvl_dev.tx_dnld_rdy = true;
-
        hdev->bus = HCI_SDIO;
        hdev->open = btmrvl_open;
        hdev->close = btmrvl_close;
@@ -572,6 +554,10 @@ struct btmrvl_private *btmrvl_add_card(void *card)
        hdev->ioctl = btmrvl_ioctl;
        hdev->owner = THIS_MODULE;
 
+       btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+
+       hdev->dev_type = priv->btmrvl_dev.dev_type;
+
        ret = hci_register_dev(hdev);
        if (ret < 0) {
                BT_ERR("Can not register HCI device");
@@ -582,16 +568,52 @@ struct btmrvl_private *btmrvl_add_card(void *card)
        btmrvl_debugfs_init(hdev);
 #endif
 
-       return priv;
+       return 0;
 
 err_hci_register_dev:
-       /* Stop the thread servicing the interrupts */
-       kthread_stop(priv->main_thread.task);
-
        hci_free_dev(hdev);
 
 err_hdev:
+       /* Stop the thread servicing the interrupts */
+       kthread_stop(priv->main_thread.task);
+
        btmrvl_free_adapter(priv);
+       kfree(priv);
+
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(btmrvl_register_hdev);
+
+struct btmrvl_private *btmrvl_add_card(void *card)
+{
+       struct btmrvl_private *priv;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               BT_ERR("Can not allocate priv");
+               goto err_priv;
+       }
+
+       priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL);
+       if (!priv->adapter) {
+               BT_ERR("Allocate buffer for btmrvl_adapter failed!");
+               goto err_adapter;
+       }
+
+       btmrvl_init_adapter(priv);
+
+       BT_DBG("Starting kthread...");
+       priv->main_thread.priv = priv;
+       spin_lock_init(&priv->driver_lock);
+
+       init_waitqueue_head(&priv->main_thread.wait_q);
+       priv->main_thread.task = kthread_run(btmrvl_service_main_thread,
+                               &priv->main_thread, "btmrvl_main_service");
+
+       priv->btmrvl_dev.card = card;
+       priv->btmrvl_dev.tx_dnld_rdy = true;
+
+       return priv;
 
 err_adapter:
        kfree(priv);
index 0dba76aa2232d9231e466ef2e610fffb29513df9..df0773ebd9e4fc4db3ef8d9d897adfd497d2eb31 100644 (file)
@@ -931,7 +931,12 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
        priv->hw_host_to_card = btmrvl_sdio_host_to_card;
        priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw;
 
-       btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+       if (btmrvl_register_hdev(priv)) {
+               BT_ERR("Register hdev failed!");
+               ret = -ENODEV;
+               goto disable_host_int;
+       }
+
        priv->btmrvl_dev.psmode = 1;
        btmrvl_enable_ps(priv);
 
index c0ce8134814e161e5da0b9f59635b9ce26e21983..3f038f5308a46064217b971f1f5cc6818d625553 100644 (file)
@@ -246,7 +246,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
                        BT_ERR("Can't allocate mem for new packet");
                        h4->rx_state = H4_W4_PACKET_TYPE;
                        h4->rx_count = 0;
-                       return 0;
+                       return -ENOMEM;
                }
 
                h4->rx_skb->dev = (void *) hu->hdev;
index 5c65014635bee18b493870f3a70b94b03b652df2..fb8445c7365ee0052fbd10284d0a895c12259fdf 100644 (file)
@@ -402,7 +402,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
                                continue;
 
                        case HCILL_W4_EVENT_HDR:
-                               eh = (struct hci_event_hdr *) ll->rx_skb->data;
+                               eh = hci_event_hdr(ll->rx_skb);
 
                                BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
 
@@ -410,7 +410,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
                                continue;
 
                        case HCILL_W4_ACL_HDR:
-                               ah = (struct hci_acl_hdr *) ll->rx_skb->data;
+                               ah = hci_acl_hdr(ll->rx_skb);
                                dlen = __le16_to_cpu(ah->dlen);
 
                                BT_DBG("ACL header: dlen %d", dlen);
@@ -419,7 +419,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
                                continue;
 
                        case HCILL_W4_SCO_HDR:
-                               sh = (struct hci_sco_hdr *) ll->rx_skb->data;
+                               sh = hci_sco_hdr(ll->rx_skb);
 
                                BT_DBG("SCO header: dlen %d", sh->dlen);
 
@@ -491,7 +491,7 @@ static int ll_recv(struct hci_uart *hu, void *data, int count)
                        BT_ERR("Can't allocate mem for new packet");
                        ll->rx_state = HCILL_W4_PACKET_TYPE;
                        ll->rx_count = 0;
-                       return 0;
+                       return -ENOMEM;
                }
 
                ll->rx_skb->dev = (void *) hu->hdev;
index bb0aefdb4267c47c88f408033a6998fdd408206a..3aa7b2a54b6f75b04014847e989bf7215dd41bc5 100644 (file)
@@ -157,7 +157,7 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
                break;
 
        case HCI_SCODATA_PKT:
-               data->hdev->stat.cmd_tx++;
+               data->hdev->stat.sco_tx++;
                break;
        };
 
index 9f4cadf9f851b0814a4d92b569e1fe061e2b073f..e95e8d09ff38ecc2911470cabe9d46e54108c6de 100644 (file)
@@ -877,7 +877,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
        if (!mc_all_on) {
                char *addrs;
                int i;
-               struct dev_mc_list *mcaddr;
+               struct netdev_hw_addr *ha;
 
                addrs = kmalloc(ETH_ALEN * mc_count, GFP_ATOMIC);
                if (!addrs) {
@@ -885,9 +885,8 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev)
                        goto unlock;
                }
                i = 0;
-               netdev_for_each_mc_addr(mcaddr, netdev)
-                       memcpy(get_addr(addrs, i++),
-                              mcaddr->dmi_addr, ETH_ALEN);
+               netdev_for_each_mc_addr(ha, netdev)
+                       memcpy(get_addr(addrs, i++), ha->addr, ETH_ALEN);
 
                perfect_filter_register_address = NES_IDX_PERFECT_FILTER_LOW +
                                                pft_entries_preallocated * 0x8;
index b166bb75753d07c8457cdb19c9874a1582a2cc90..3871ac663554339ac09766a5b3bdcc7c758a65e3 100644 (file)
@@ -768,11 +768,8 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
        }
 }
 
-static int ipoib_mcast_addr_is_valid(const u8 *addr, unsigned int addrlen,
-                                    const u8 *broadcast)
+static int ipoib_mcast_addr_is_valid(const u8 *addr, const u8 *broadcast)
 {
-       if (addrlen != INFINIBAND_ALEN)
-               return 0;
        /* reserved QPN, prefix, scope */
        if (memcmp(addr, broadcast, 6))
                return 0;
@@ -787,7 +784,7 @@ void ipoib_mcast_restart_task(struct work_struct *work)
        struct ipoib_dev_priv *priv =
                container_of(work, struct ipoib_dev_priv, restart_task);
        struct net_device *dev = priv->dev;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        struct ipoib_mcast *mcast, *tmcast;
        LIST_HEAD(remove_list);
        unsigned long flags;
@@ -812,15 +809,13 @@ void ipoib_mcast_restart_task(struct work_struct *work)
                clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags);
 
        /* Mark all of the entries that are found or don't exist */
-       netdev_for_each_mc_addr(mclist, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                union ib_gid mgid;
 
-               if (!ipoib_mcast_addr_is_valid(mclist->dmi_addr,
-                                              mclist->dmi_addrlen,
-                                              dev->broadcast))
+               if (!ipoib_mcast_addr_is_valid(ha->addr, dev->broadcast))
                        continue;
 
-               memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid);
+               memcpy(mgid.raw, ha->addr + 4, sizeof mgid);
 
                mcast = __ipoib_mcast_find(dev, &mgid);
                if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
index efcf1f9327e5cc408026e8535fab61a75942b091..fd10d7c785d4d7717de45c36c399fe33b19b7823 100644 (file)
@@ -194,7 +194,7 @@ static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb
        if ( ( (ix25_pdata_t*) (cprot->proto_data) ) 
             -> state == WAN_CONNECTED ){
                if( skb_push(skb, 1)){
-                       skb -> data[0]=0x00;
+                       skb->data[0] = X25_IFACE_DATA;
                        skb->protocol = x25_type_trans(skb, cprot->net_dev);
                        netif_rx(skb);
                        return 0;
@@ -224,7 +224,7 @@ static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
 
        skb = dev_alloc_skb(1);
        if( skb ){
-               *( skb_put(skb, 1) ) = 0x01;
+               *(skb_put(skb, 1)) = X25_IFACE_CONNECT;
                skb->protocol = x25_type_trans(skb, cprot->net_dev);
                netif_rx(skb);
                return 0;
@@ -253,7 +253,7 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
        *state_p = WAN_DISCONNECTED;
        skb = dev_alloc_skb(1);
        if( skb ){
-               *( skb_put(skb, 1) ) = 0x02;
+               *(skb_put(skb, 1)) = X25_IFACE_DISCONNECT;
                skb->protocol = x25_type_trans(skb, cprot->net_dev);
                netif_rx(skb);
                return 0;
@@ -272,9 +272,10 @@ static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
        unsigned char firstbyte = skb->data[0];
        enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state;
        int ret = 0;
-       IX25DEBUG( "isdn_x25iface_xmit: %s first=%x state=%d \n", MY_DEVNAME(cprot -> net_dev), firstbyte, *state );
+       IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n",
+               MY_DEVNAME(cprot->net_dev), firstbyte, *state);
        switch ( firstbyte ){
-       case 0x00: /* dl_data request */
+       case X25_IFACE_DATA:
                if( *state == WAN_CONNECTED ){
                        skb_pull(skb, 1);
                        cprot -> net_dev -> trans_start = jiffies;
@@ -285,7 +286,7 @@ static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
                }
                illegal_state_warn( *state, firstbyte ); 
                break;
-       case 0x01: /* dl_connect request */
+       case X25_IFACE_CONNECT:
                if( *state == WAN_DISCONNECTED ){
                        *state = WAN_CONNECTING;
                        ret = cprot -> dops -> connect_req(cprot);
@@ -298,7 +299,7 @@ static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
                        illegal_state_warn( *state, firstbyte );
                }
                break;
-       case 0x02: /* dl_disconnect request */
+       case X25_IFACE_DISCONNECT:
                switch ( *state ){
                case WAN_DISCONNECTED: 
                        /* Should not happen. However, give upper layer a
@@ -318,7 +319,7 @@ static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
                        illegal_state_warn( *state, firstbyte );
                }
                break;
-       case 0x03: /* changing lapb parameters requested */
+       case X25_IFACE_PARAMS:
                printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb"
                       " options not yet supported\n");
                break;
index 441c0642b30a11b7cd443125a97c490b2ba31d9b..cccea412088b29c0717cdcdaab349c092bf4cd01 100644 (file)
@@ -1109,14 +1109,14 @@ static int dvb_net_feed_stop(struct net_device *dev)
 }
 
 
-static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc)
+static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr)
 {
        struct dvb_net_priv *priv = netdev_priv(dev);
 
        if (priv->multi_num == DVB_NET_MULTICAST_MAX)
                return -ENOMEM;
 
-       memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);
+       memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN);
 
        priv->multi_num++;
        return 0;
@@ -1140,8 +1140,7 @@ static void wq_set_multicast_list (struct work_struct *work)
                dprintk("%s: allmulti mode\n", dev->name);
                priv->rx_mode = RX_MODE_ALL_MULTI;
        } else if (!netdev_mc_empty(dev)) {
-               int mci;
-               struct dev_mc_list *mc;
+               struct netdev_hw_addr *ha;
 
                dprintk("%s: set_mc_list, %d entries\n",
                        dev->name, netdev_mc_count(dev));
@@ -1149,11 +1148,8 @@ static void wq_set_multicast_list (struct work_struct *work)
                priv->rx_mode = RX_MODE_MULTI;
                priv->multi_num = 0;
 
-               for (mci = 0, mc=dev->mc_list;
-                    mci < netdev_mc_count(dev);
-                    mc = mc->next, mci++) {
-                       dvb_set_mc_filter(dev, mc);
-               }
+               netdev_for_each_mc_addr(ha, dev)
+                       dvb_set_mc_filter(dev, ha->addr);
        }
 
        netif_addr_unlock_bh(dev);
index 3ea42ff176577900c734b5e9d7bbd67973a1d324..1776ab61b05fffedc7a18eaa755de9a64451f15f 100644 (file)
@@ -480,7 +480,6 @@ static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        /* fire ... Trigger xmit.  */
                        outb(AX_XMIT, AX_CMD);
                        lp->loading = 0;
-                       dev->trans_start = jiffies;
                        if (el_debug > 2)
                                pr_debug(" queued xmit.\n");
                        dev_kfree_skb(skb);
@@ -727,7 +726,6 @@ static void el_receive(struct net_device *dev)
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += pkt_len;
        }
-       return;
 }
 
 /**
index 66e0323c183968aa394ee5b297872779eb2cfd4b..baac246561b9c99b6b1b15eaef7d8ddf5e5f1da9 100644 (file)
@@ -380,6 +380,12 @@ out:
     return retval;
 }
 
+static irqreturn_t el2_probe_interrupt(int irq, void *seen)
+{
+       *(bool *)seen = true;
+       return IRQ_HANDLED;
+}
+
 static int
 el2_open(struct net_device *dev)
 {
@@ -391,23 +397,35 @@ el2_open(struct net_device *dev)
 
        outb(EGACFR_NORM, E33G_GACFR);  /* Enable RAM and interrupts. */
        do {
-           retval = request_irq(*irqp, NULL, 0, "bogus", dev);
-           if (retval >= 0) {
+               bool seen;
+
+               retval = request_irq(*irqp, el2_probe_interrupt, 0,
+                                    dev->name, &seen);
+               if (retval == -EBUSY)
+                       continue;
+               if (retval < 0)
+                       goto err_disable;
+
                /* Twinkle the interrupt, and check if it's seen. */
-               unsigned long cookie = probe_irq_on();
+               seen = false;
+               smp_wmb();
                outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
                outb_p(0x00, E33G_IDCFR);
-               if (*irqp == probe_irq_off(cookie) &&   /* It's a good IRQ line! */
-                   ((retval = request_irq(dev->irq = *irqp,
-                                          eip_interrupt, 0,
-                                          dev->name, dev)) == 0))
-                   break;
-           } else {
-                   if (retval != -EBUSY)
-                           return retval;
-           }
+               msleep(1);
+               free_irq(*irqp, el2_probe_interrupt);
+               if (!seen)
+                       continue;
+
+               retval = request_irq(dev->irq = *irqp, eip_interrupt, 0,
+                                    dev->name, dev);
+               if (retval == -EBUSY)
+                       continue;
+               if (retval < 0)
+                       goto err_disable;
        } while (*++irqp);
+
        if (*irqp == 0) {
+       err_disable:
            outb(EGACFR_IRQOFF, E33G_GACFR);    /* disable interrupts. */
            return -EAGAIN;
        }
@@ -555,7 +573,6 @@ el2_block_output(struct net_device *dev, int count,
     }
     blocked:;
     outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-    return;
 }
 
 /* Read the 4 byte, page aligned 8390 specific header. */
@@ -671,7 +688,6 @@ el2_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring
     }
     blocked:;
     outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL);
-    return;
 }
 
 
index 29b8d1d63bdeacdfb6cc7b432590216a448ab7e5..88d766ee0e1bc35c89a53effa08d9c41b80fa198 100644 (file)
@@ -1055,7 +1055,7 @@ static void elp_timeout(struct net_device *dev)
                   (stat & ACRF) ? "interrupt" : "command");
        if (elp_debug >= 1)
                pr_debug("%s: status %#02x\n", dev->name, stat);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_dropped++;
        netif_wake_queue(dev);
 }
@@ -1093,11 +1093,6 @@ static netdev_tx_t elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (elp_debug >= 3)
                pr_debug("%s: packet of length %d sent\n", dev->name, (int) skb->len);
 
-       /*
-        * start the transmit timeout
-        */
-       dev->trans_start = jiffies;
-
        prime_rx(dev);
        spin_unlock_irqrestore(&adapter->lock, flags);
        netif_start_queue(dev);
@@ -1216,7 +1211,7 @@ static int elp_close(struct net_device *dev)
 static void elp_set_mc_list(struct net_device *dev)
 {
        elp_device *adapter = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int i;
        unsigned long flags;
 
@@ -1231,8 +1226,9 @@ static void elp_set_mc_list(struct net_device *dev)
                adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
                adapter->tx_pcb.length = 6 * netdev_mc_count(dev);
                i = 0;
-               netdev_for_each_mc_addr(dmi, dev)
-                       memcpy(adapter->tx_pcb.data.multicast[i++], dmi->dmi_addr, 6);
+               netdev_for_each_mc_addr(ha, dev)
+                       memcpy(adapter->tx_pcb.data.multicast[i++],
+                              ha->addr, 6);
                adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
                if (!send_pcb(dev, &adapter->tx_pcb))
                        pr_err("%s: couldn't send set_multicast command\n", dev->name);
index b32b7a1710b735dd3a074d4073baf94b3256b301..82eaf65d2d8580f66ec83e3fdd2082e492c57a33 100644 (file)
@@ -449,7 +449,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
                pr_debug("%s", version);
 
        lp = netdev_priv(dev);
-       memset(lp, 0, sizeof(*lp));
        spin_lock_init(&lp->lock);
        lp->base = ioremap(dev->mem_start, RX_BUF_END);
        if (!lp->base) {
@@ -505,7 +504,7 @@ static void el16_tx_timeout (struct net_device *dev)
                outb (0, ioaddr + SIGNAL_CA);   /* Issue channel-attn. */
                lp->last_restart = dev->stats.tx_packets;
        }
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue (dev);
 }
 
@@ -529,7 +528,6 @@ static netdev_tx_t el16_send_packet (struct sk_buff *skb,
 
        hardware_send_packet (dev, buf, skb->len, length - skb->len);
 
-       dev->trans_start = jiffies;
        /* Enable the 82586 interrupt input. */
        outb (0x84, ioaddr + MISC_CTRL);
 
@@ -766,7 +764,6 @@ static void init_82586_mem(struct net_device *dev)
        if (net_debug > 4)
                pr_debug("%s: Initialized 82586, status %04x.\n", dev->name,
                           readw(shmem+iSCB_STATUS));
-       return;
 }
 
 static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad)
index ab9bb3c520020f3a047181c58f957aadddd58f7a..91abb965fb44e04c0b0160e69e135ebd735a200b 100644 (file)
@@ -807,7 +807,7 @@ el3_tx_timeout (struct net_device *dev)
                   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
                   inw(ioaddr + TX_FREE));
        dev->stats.tx_errors++;
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        /* Issue TX_RESET and TX_START commands. */
        outw(TxReset, ioaddr + EL3_CMD);
        outw(TxEnable, ioaddr + EL3_CMD);
@@ -868,7 +868,6 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* ... and the packet rounded to a doubleword. */
        outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 
-       dev->trans_start = jiffies;
        if (inw(ioaddr + TX_FREE) > 1536)
                netif_start_queue(dev);
        else
@@ -1038,7 +1037,6 @@ static void update_stats(struct net_device *dev)
        /* Back to window 1, and turn statistics back on. */
        EL3WINDOW(1);
        outw(StatsEnable, ioaddr + EL3_CMD);
-       return;
 }
 
 static int
index 2e17837be546b2d5f0a90e7984ae80a4fc15ea6c..3bba835f1a214c875352c7335dd251b27e6286d6 100644 (file)
@@ -958,7 +958,6 @@ static void corkscrew_timer(unsigned long data)
                       dev->name, media_tbl[dev->if_port].name);
 
 #endif                         /* AUTOMEDIA */
-       return;
 }
 
 static void corkscrew_timeout(struct net_device *dev)
@@ -992,7 +991,7 @@ static void corkscrew_timeout(struct net_device *dev)
                if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
                        break;
        outw(TxEnable, ioaddr + EL3_CMD);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
        dev->stats.tx_dropped++;
        netif_wake_queue(dev);
@@ -1055,7 +1054,6 @@ static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb,
                                prev_entry->status &= ~0x80000000;
                        netif_wake_queue(dev);
                }
-               dev->trans_start = jiffies;
                return NETDEV_TX_OK;
        }
        /* Put out the doubleword header... */
@@ -1091,7 +1089,6 @@ static netdev_tx_t corkscrew_start_xmit(struct sk_buff *skb,
                outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);
 #endif                         /* bus master */
 
-       dev->trans_start = jiffies;
 
        /* Clear the Tx status stack. */
        {
@@ -1518,7 +1515,6 @@ static void update_stats(int ioaddr, struct net_device *dev)
 
        /* We change back to window 7 (not 1) with the Vortex. */
        EL3WINDOW(7);
-       return;
 }
 
 /* This new version of set_rx_mode() supports v1.4 kernels.
index 1719079cc498f86c0289e904c3f54ce16fcbf824..a7b0e5e43a529f6f5cb5ecf08f41d94ec97b5efb 100644 (file)
@@ -503,7 +503,6 @@ static int __init do_elmc_probe(struct net_device *dev)
                break;
        }
 
-       memset(pr, 0, sizeof(struct priv));
        pr->slot = slot;
 
        pr_info("%s: 3Com 3c523 Rev 0x%x at %#lx\n", dev->name, (int) revision,
@@ -624,7 +623,7 @@ static int init586(struct net_device *dev)
        volatile struct iasetup_cmd_struct *ias_cmd;
        volatile struct tdr_cmd_struct *tdr_cmd;
        volatile struct mcsetup_cmd_struct *mc_cmd;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int num_addrs = netdev_mc_count(dev);
 
        ptr = (void *) ((char *) p->scb + sizeof(struct scb_struct));
@@ -787,8 +786,9 @@ static int init586(struct net_device *dev)
                        mc_cmd->cmd_link = 0xffff;
                        mc_cmd->mc_cnt = num_addrs * 6;
                        i = 0;
-                       netdev_for_each_mc_addr(dmi, dev)
-                               memcpy((char *) mc_cmd->mc_list[i++], dmi->dmi_addr, 6);
+                       netdev_for_each_mc_addr(ha, dev)
+                               memcpy((char *) mc_cmd->mc_list[i++],
+                                      ha->addr, 6);
                        p->scb->cbl_offset = make16(mc_cmd);
                        p->scb->cmd = CUC_START;
                        elmc_id_attn586();
@@ -1152,7 +1152,6 @@ static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
                p->scb->cmd = CUC_START;
                p->xmit_cmds[0]->cmd_status = 0;
                        elmc_attn586();
-               dev->trans_start = jiffies;
                if (!i) {
                        dev_kfree_skb(skb);
                }
@@ -1176,7 +1175,6 @@ static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
        p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
 
        p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
-       dev->trans_start = jiffies;
        p->nop_point = next_nop;
        dev_kfree_skb(skb);
 #endif
@@ -1190,7 +1188,6 @@ static netdev_tx_t elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
            = make16((p->nop_cmds[next_nop]));
        p->nop_cmds[next_nop]->cmd_status = 0;
                p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
-       dev->trans_start = jiffies;
        p->xmit_count = next_nop;
        if (p->xmit_count != p->xmit_last)
                netif_wake_queue(dev);
index 5c07b147ec99bf9d11acf61c689a075c81691c83..38395dfa49639915715f3a43770e855b49dcb60a 100644 (file)
@@ -1533,7 +1533,7 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
        {
                unsigned char block[62];
                unsigned char *bp;
-               struct dev_mc_list *dmc;
+               struct netdev_hw_addr *ha;
 
                if(retry==0)
                        lp->mc_list_valid = 0;
@@ -1543,8 +1543,8 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
                        block[0]=netdev_mc_count(dev);
                        bp=block+2;
 
-                       netdev_for_each_mc_addr(dmc, dev) {
-                               memcpy(bp, dmc->dmi_addr, 6);
+                       netdev_for_each_mc_addr(ha, dev) {
+                               memcpy(bp, ha->addr, 6);
                                bp+=6;
                        }
                        if(mc32_command_nowait(dev, 2, block,
index 5f92fdbe66e2d3d43ab79f839e408adfd3978c6e..d75803e6e527b634d24d6d45ed8bc0962b17e535 100644 (file)
@@ -1855,7 +1855,6 @@ leave_media_alone:
        mod_timer(&vp->timer, RUN_AT(next_tick));
        if (vp->deferred)
                iowrite16(FakeIntr, ioaddr + EL3_CMD);
-       return;
 }
 
 static void vortex_tx_timeout(struct net_device *dev)
@@ -1917,7 +1916,7 @@ static void vortex_tx_timeout(struct net_device *dev)
 
        /* Issue Tx Enable */
        iowrite16(TxEnable, ioaddr + EL3_CMD);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 
        /* Switch to register set 7 for normal use. */
        EL3WINDOW(7);
@@ -2063,7 +2062,6 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       dev->trans_start = jiffies;
 
        /* Clear the Tx status stack. */
        {
@@ -2129,8 +2127,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
                int i;
 
                vp->tx_ring[entry].frag[0].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data,
-                                                                               skb->len-skb->data_len, PCI_DMA_TODEVICE));
-               vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb->len-skb->data_len);
+                                                                               skb_headlen(skb), PCI_DMA_TODEVICE));
+               vp->tx_ring[entry].frag[0].length = cpu_to_le32(skb_headlen(skb));
 
                for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2174,7 +2172,6 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        iowrite16(DownUnstall, ioaddr + EL3_CMD);
        spin_unlock_irqrestore(&vp->lock, flags);
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
@@ -2800,7 +2797,6 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
        }
 
        EL3WINDOW(old_window >> 13);
-       return;
 }
 
 static int vortex_nway_reset(struct net_device *dev)
@@ -3122,7 +3118,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
                iowrite16(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
                mdio_delay();
        }
-       return;
 }
 
 /* ACPI: Advanced Configuration and Power Interface. */
index 500e135723bd0f8ab4f0d031eba8db02f2d03c30..903bcb3ef5bd3f2bac81c76f7e4933bfefeed9e0 100644 (file)
@@ -262,7 +262,7 @@ static int lance_reset (struct net_device *dev)
 
         load_csrs (lp);
         lance_init_ring (dev);
-        dev->trans_start = jiffies;
+        dev->trans_start = jiffies; /* prevent tx timeout */
         status = init_restart_lance (lp);
 #ifdef DEBUG_DRIVER
         printk ("Lance restart=%d\n", status);
@@ -526,7 +526,7 @@ void lance_tx_timeout(struct net_device *dev)
 {
        printk("lance_tx_timeout\n");
        lance_reset(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue (dev);
 }
 EXPORT_SYMBOL_GPL(lance_tx_timeout);
@@ -574,7 +574,6 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
         outs++;
         /* Kick the lance: transmit now */
         WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
-        dev->trans_start = jiffies;
         dev_kfree_skb (skb);
 
        spin_lock_irqsave (&lp->devlock, flags);
@@ -594,7 +593,7 @@ static void lance_load_multicast (struct net_device *dev)
         struct lance_private *lp = netdev_priv(dev);
         volatile struct lance_init_block *ib = lp->init_block;
         volatile u16 *mcast_table = (u16 *)&ib->filter;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
         char *addrs;
         u32 crc;
 
@@ -609,8 +608,8 @@ static void lance_load_multicast (struct net_device *dev)
         ib->filter [1] = 0;
 
         /* Add addresses */
-       netdev_for_each_mc_addr(dmi, dev) {
-                addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrs = ha->addr;
 
                 /* multicast address? */
                 if (!(*addrs & 1))
@@ -620,7 +619,6 @@ static void lance_load_multicast (struct net_device *dev)
                 crc = crc >> 26;
                 mcast_table [crc >> 4] |= 1 << (crc & 0xf);
         }
-        return;
 }
 
 
index a09e6ce3eaa0a66f12b6efd93652bf8a2b2b2e23..9c149750e2bf9754518941e9233e94800d45b889 100644 (file)
@@ -882,7 +882,6 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
        spin_unlock_irqrestore(&cp->lock, intr_flags);
 
        cpw8(TxPoll, NormalTxPoll);
-       dev->trans_start = jiffies;
 
        return NETDEV_TX_OK;
 }
@@ -910,11 +909,11 @@ static void __cp_set_rx_mode (struct net_device *dev)
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                rx_mode = AcceptBroadcast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
 
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                        rx_mode |= AcceptMulticast;
@@ -1225,8 +1224,6 @@ static void cp_tx_timeout(struct net_device *dev)
        netif_wake_queue(dev);
 
        spin_unlock_irqrestore(&cp->lock, flags);
-
-       return;
 }
 
 #ifdef BROKEN
index f0d23de3296752e05fb4f0deeba538ff0d90e0c8..4ba72933f0da57b72f069e4d95a29fc1ad8da1f1 100644 (file)
@@ -1716,8 +1716,6 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
        RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
                   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
 
-       dev->trans_start = jiffies;
-
        tp->cur_tx++;
 
        if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
@@ -2503,11 +2501,11 @@ static void __set_rx_mode (struct net_device *dev)
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                rx_mode = AcceptBroadcast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
 
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                        rx_mode |= AcceptMulticast;
index 56e68db488610d4375445481c53bc1a189e9de86..dd8dc15556cbda41d26691fdbd42308e08a5c911 100644 (file)
@@ -1050,7 +1050,7 @@ static void i596_tx_timeout (struct net_device *dev)
                lp->last_restart = dev->stats.tx_packets;
        }
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue (dev);
 }
 
@@ -1060,7 +1060,6 @@ static netdev_tx_t i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct tx_cmd *tx_cmd;
        struct i596_tbd *tbd;
        short length = skb->len;
-       dev->trans_start = jiffies;
 
        DEB(DEB_STARTTX,printk(KERN_DEBUG "%s: i596_start_xmit(%x,%p) called\n",
                                dev->name, skb->len, skb->data));
@@ -1542,7 +1541,7 @@ static void set_multicast_list(struct net_device *dev)
        }
 
        if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                unsigned char *cp;
                struct mc_cmd *cmd;
 
@@ -1552,10 +1551,10 @@ static void set_multicast_list(struct net_device *dev)
                cmd->cmd.command = CmdMulticastList;
                cmd->mc_cnt = cnt * ETH_ALEN;
                cp = cmd->mc_addrs;
-               netdev_for_each_mc_addr(dmi, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        if (!cnt--)
                                break;
-                       memcpy(cp, dmi->dmi_addr, ETH_ALEN);
+                       memcpy(cp, ha->addr, ETH_ALEN);
                        if (i596_debug > 1)
                                DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n",
                                                dev->name, cp));
index 7b832c727f873b6964b1faa1c121a73796b113e4..2decc597bda704bd74fac951551517421fc0a4e1 100644 (file)
@@ -483,7 +483,7 @@ config XTENSA_XT2000_SONIC
          This is the driver for the onboard card of the Xtensa XT2000 board.
 
 config MIPS_AU1X00_ENET
-       bool "MIPS AU1000 Ethernet support"
+       tristate "MIPS AU1000 Ethernet support"
        depends on SOC_AU1X00
        select PHYLIB
        select CRC32
@@ -887,6 +887,13 @@ config BFIN_MAC_RMII
        help
          Use Reduced PHY MII Interface
 
+config BFIN_MAC_USE_HWSTAMP
+       bool "Use IEEE 1588 hwstamp"
+       depends on BFIN_MAC && BF518
+       default y
+       help
+         To support the IEEE 1588 Precision Time Protocol (PTP), select y here
+
 config SMC9194
        tristate "SMC 9194 support"
        depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
@@ -1453,20 +1460,6 @@ config FORCEDETH
          To compile this driver as a module, choose M here. The module
          will be called forcedeth.
 
-config FORCEDETH_NAPI
-       bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
-       depends on FORCEDETH && EXPERIMENTAL
-       help
-         NAPI is a new driver API designed to reduce CPU and interrupt load
-         when the driver is receiving lots of packets from the card. It is
-         still somewhat experimental and thus not yet enabled by default.
-
-         If your estimated Rx load is 10kpps or more, or if the card will be
-         deployed on potentially unfriendly networks (e.g. in a firewall),
-         then say Y here.
-
-         If in doubt, say N.
-
 config CS89x0
        tristate "CS89x0 support"
        depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \
@@ -1916,6 +1909,7 @@ config FEC
        bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)"
        depends on M523x || M527x || M5272 || M528x || M520x || M532x || \
                MACH_MX27 || ARCH_MX35 || ARCH_MX25 || ARCH_MX5
+       select PHYLIB
        help
          Say Y here if you want to use the built-in 10/100 Fast ethernet
          controller on some Motorola ColdFire and Freescale i.MX processors.
@@ -2434,8 +2428,8 @@ config MV643XX_ETH
 
 config XILINX_LL_TEMAC
        tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver"
+       depends on PPC || MICROBLAZE
        select PHYLIB
-       depends on PPC_DCR_NATIVE
        help
          This driver supports the Xilinx 10/100/1000 LocalLink TEMAC
          core used in Xilinx Spartan and Virtex FPGAs
@@ -2618,11 +2612,11 @@ config EHEA
          will be called ehea.
 
 config ENIC
-       tristate "Cisco 10G Ethernet NIC support"
+       tristate "Cisco VIC Ethernet NIC Support"
        depends on PCI && INET
        select INET_LRO
        help
-         This enables the support for the Cisco 10G Ethernet card.
+         This enables the support for the Cisco VIC Ethernet card.
 
 config IXGBE
        tristate "Intel(R) 10GbE PCI Express adapters support"
@@ -2862,6 +2856,8 @@ source "drivers/ieee802154/Kconfig"
 
 source "drivers/s390/net/Kconfig"
 
+source "drivers/net/caif/Kconfig"
+
 config XEN_NETDEV_FRONTEND
        tristate "Xen network device frontend driver"
        depends on XEN
@@ -3180,17 +3176,12 @@ config PPPOATM
 
 config PPPOL2TP
        tristate "PPP over L2TP (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && PPP && INET
+       depends on EXPERIMENTAL && L2TP && PPP
        help
          Support for PPP-over-L2TP socket family. L2TP is a protocol
          used by ISPs and enterprises to tunnel PPP traffic over UDP
          tunnels. L2TP is replacing PPTP for VPN uses.
 
-         This kernel component handles only L2TP data packets: a
-         userland daemon handles L2TP the control protocol (tunnel
-         and session setup). One such daemon is OpenL2TP
-         (http://openl2tp.sourceforge.net/).
-
 config SLIP
        tristate "SLIP (serial line) support"
        ---help---
@@ -3277,15 +3268,14 @@ config NET_FC
          "SCSI generic support".
 
 config NETCONSOLE
-       tristate "Network console logging support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
+       tristate "Network console logging support"
        ---help---
        If you want to log kernel messages over the network, enable this.
        See <file:Documentation/networking/netconsole.txt> for details.
 
 config NETCONSOLE_DYNAMIC
-       bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)"
-       depends on NETCONSOLE && SYSFS && EXPERIMENTAL
+       bool "Dynamic reconfiguration of logging targets"
+       depends on NETCONSOLE && SYSFS
        select CONFIGFS_FS
        help
          This option enables the ability to dynamically reconfigure target
index 12b280afdd5186216254b82c6b0f481e221de129..0a0512ae77da45c424e09e763545d6d8c7c14ca0 100644 (file)
@@ -161,7 +161,7 @@ obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
 obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
 obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
-obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o
+obj-$(CONFIG_PPPOL2TP) += pppox.o
 
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
@@ -292,5 +292,6 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
 
 obj-$(CONFIG_WIMAX) += wimax/
+obj-$(CONFIG_CAIF) += caif/
 
 obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
index a8f0512bad38a0035d92f934670f2765a47a5537..f142cc21e453dfddceabee7bd669171977622ed2 100644 (file)
@@ -525,7 +525,7 @@ static inline int lance_reset (struct net_device *dev)
        load_csrs (lp);
 
        lance_init_ring (dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_start_queue(dev);
 
        status = init_restart_lance (lp);
@@ -588,7 +588,6 @@ static netdev_tx_t lance_start_xmit (struct sk_buff *skb,
 
        /* Kick the lance: transmit now */
        ll->rdp = LE_C0_INEA | LE_C0_TDMD;
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
 
        local_irq_restore(flags);
@@ -602,7 +601,7 @@ static void lance_load_multicast (struct net_device *dev)
        struct lance_private *lp = netdev_priv(dev);
        volatile struct lance_init_block *ib = lp->init_block;
        volatile u16 *mcast_table = (u16 *)&ib->filter;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        u32 crc;
 
@@ -617,8 +616,8 @@ static void lance_load_multicast (struct net_device *dev)
        ib->filter [1] = 0;
 
        /* Add addresses */
-       netdev_for_each_mc_addr(dmi, dev) {
-               addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrs = ha->addr;
 
                /* multicast address? */
                if (!(*addrs & 1))
@@ -628,7 +627,6 @@ static void lance_load_multicast (struct net_device *dev)
                crc = crc >> 26;
                mcast_table [crc >> 4] |= 1 << (crc & 0xf);
        }
-       return;
 }
 
 static void lance_set_multicast (struct net_device *dev)
index eac73382c087523e03b38826d316338686ce3afc..b9115a776fddb31d998d1e24712214ef326c1343 100644 (file)
@@ -307,8 +307,6 @@ static void ac_reset_8390(struct net_device *dev)
        ei_status.txing = 0;
        outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
        if (ei_debug > 1) printk("reset done\n");
-
-       return;
 }
 
 /* Grab the 8390 specific header. Similar to the block_input routine, but
index 97a3dfd94dfa4878dc84c28ce0d1e710e46a816d..b9a591604e5b538b1d6c39bc8dea5abd82d13f01 100644 (file)
@@ -661,7 +661,7 @@ static void __devexit acenic_remove_one(struct pci_dev *pdev)
                        dma_addr_t mapping;
 
                        ringp = &ap->skb->rx_std_skbuff[i];
-                       mapping = pci_unmap_addr(ringp, mapping);
+                       mapping = dma_unmap_addr(ringp, mapping);
                        pci_unmap_page(ap->pdev, mapping,
                                       ACE_STD_BUFSIZE,
                                       PCI_DMA_FROMDEVICE);
@@ -681,7 +681,7 @@ static void __devexit acenic_remove_one(struct pci_dev *pdev)
                                dma_addr_t mapping;
 
                                ringp = &ap->skb->rx_mini_skbuff[i];
-                               mapping = pci_unmap_addr(ringp,mapping);
+                               mapping = dma_unmap_addr(ringp,mapping);
                                pci_unmap_page(ap->pdev, mapping,
                                               ACE_MINI_BUFSIZE,
                                               PCI_DMA_FROMDEVICE);
@@ -700,7 +700,7 @@ static void __devexit acenic_remove_one(struct pci_dev *pdev)
                        dma_addr_t mapping;
 
                        ringp = &ap->skb->rx_jumbo_skbuff[i];
-                       mapping = pci_unmap_addr(ringp, mapping);
+                       mapping = dma_unmap_addr(ringp, mapping);
                        pci_unmap_page(ap->pdev, mapping,
                                       ACE_JUMBO_BUFSIZE,
                                       PCI_DMA_FROMDEVICE);
@@ -1683,7 +1683,7 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
                                       ACE_STD_BUFSIZE,
                                       PCI_DMA_FROMDEVICE);
                ap->skb->rx_std_skbuff[idx].skb = skb;
-               pci_unmap_addr_set(&ap->skb->rx_std_skbuff[idx],
+               dma_unmap_addr_set(&ap->skb->rx_std_skbuff[idx],
                                   mapping, mapping);
 
                rd = &ap->rx_std_ring[idx];
@@ -1744,7 +1744,7 @@ static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
                                       ACE_MINI_BUFSIZE,
                                       PCI_DMA_FROMDEVICE);
                ap->skb->rx_mini_skbuff[idx].skb = skb;
-               pci_unmap_addr_set(&ap->skb->rx_mini_skbuff[idx],
+               dma_unmap_addr_set(&ap->skb->rx_mini_skbuff[idx],
                                   mapping, mapping);
 
                rd = &ap->rx_mini_ring[idx];
@@ -1800,7 +1800,7 @@ static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
                                       ACE_JUMBO_BUFSIZE,
                                       PCI_DMA_FROMDEVICE);
                ap->skb->rx_jumbo_skbuff[idx].skb = skb;
-               pci_unmap_addr_set(&ap->skb->rx_jumbo_skbuff[idx],
+               dma_unmap_addr_set(&ap->skb->rx_jumbo_skbuff[idx],
                                   mapping, mapping);
 
                rd = &ap->rx_jumbo_ring[idx];
@@ -2013,7 +2013,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
                skb = rip->skb;
                rip->skb = NULL;
                pci_unmap_page(ap->pdev,
-                              pci_unmap_addr(rip, mapping),
+                              dma_unmap_addr(rip, mapping),
                               mapsize,
                               PCI_DMA_FROMDEVICE);
                skb_put(skb, retdesc->size);
@@ -2078,18 +2078,16 @@ static inline void ace_tx_int(struct net_device *dev,
 
        do {
                struct sk_buff *skb;
-               dma_addr_t mapping;
                struct tx_ring_info *info;
 
                info = ap->skb->tx_skbuff + idx;
                skb = info->skb;
-               mapping = pci_unmap_addr(info, mapping);
 
-               if (mapping) {
-                       pci_unmap_page(ap->pdev, mapping,
-                                      pci_unmap_len(info, maplen),
+               if (dma_unmap_len(info, maplen)) {
+                       pci_unmap_page(ap->pdev, dma_unmap_addr(info, mapping),
+                                      dma_unmap_len(info, maplen),
                                       PCI_DMA_TODEVICE);
-                       pci_unmap_addr_set(info, mapping, 0);
+                       dma_unmap_len_set(info, maplen, 0);
                }
 
                if (skb) {
@@ -2377,14 +2375,12 @@ static int ace_close(struct net_device *dev)
 
        for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
                struct sk_buff *skb;
-               dma_addr_t mapping;
                struct tx_ring_info *info;
 
                info = ap->skb->tx_skbuff + i;
                skb = info->skb;
-               mapping = pci_unmap_addr(info, mapping);
 
-               if (mapping) {
+               if (dma_unmap_len(info, maplen)) {
                        if (ACE_IS_TIGON_I(ap)) {
                                /* NB: TIGON_1 is special, tx_ring is in io space */
                                struct tx_desc __iomem *tx;
@@ -2395,10 +2391,10 @@ static int ace_close(struct net_device *dev)
                        } else
                                memset(ap->tx_ring + i, 0,
                                       sizeof(struct tx_desc));
-                       pci_unmap_page(ap->pdev, mapping,
-                                      pci_unmap_len(info, maplen),
+                       pci_unmap_page(ap->pdev, dma_unmap_addr(info, mapping),
+                                      dma_unmap_len(info, maplen),
                                       PCI_DMA_TODEVICE);
-                       pci_unmap_addr_set(info, mapping, 0);
+                       dma_unmap_len_set(info, maplen, 0);
                }
                if (skb) {
                        dev_kfree_skb(skb);
@@ -2433,8 +2429,8 @@ ace_map_tx_skb(struct ace_private *ap, struct sk_buff *skb,
 
        info = ap->skb->tx_skbuff + idx;
        info->skb = tail;
-       pci_unmap_addr_set(info, mapping, mapping);
-       pci_unmap_len_set(info, maplen, skb->len);
+       dma_unmap_addr_set(info, mapping, mapping);
+       dma_unmap_len_set(info, maplen, skb->len);
        return mapping;
 }
 
@@ -2553,8 +2549,8 @@ restart:
                        } else {
                                info->skb = NULL;
                        }
-                       pci_unmap_addr_set(info, mapping, mapping);
-                       pci_unmap_len_set(info, maplen, frag->size);
+                       dma_unmap_addr_set(info, mapping, mapping);
+                       dma_unmap_len_set(info, maplen, frag->size);
                        ace_load_tx_bd(ap, desc, mapping, flagsize, vlan_tag);
                }
        }
@@ -2923,8 +2919,6 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz
                dest += tsize;
                size -= tsize;
        }
-
-       return;
 }
 
 
index 17079b927ffacec3926b6428efc5a392468054b5..0681da7e87531fb0ef9b7d1e3fab85291f1402a9 100644 (file)
@@ -589,7 +589,7 @@ struct ace_info {
 
 struct ring_info {
        struct sk_buff          *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
 
@@ -600,8 +600,8 @@ struct ring_info {
  */
 struct tx_ring_info {
        struct sk_buff          *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
-       DECLARE_PCI_UNMAP_LEN(maplen)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
+       DEFINE_DMA_UNMAP_LEN(maplen);
 };
 
 
index 8d58f0a8f42f74f16fa06a388aaf80a4434a557d..585c25f4b60c27437043eacbea291d137a60a210 100644 (file)
@@ -1339,8 +1339,6 @@ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb,
        writel( VAL1 | TDMD0, lp->mmio + CMD0);
        writel( VAL2 | RDMD0,lp->mmio + CMD0);
 
-       dev->trans_start = jiffies;
-
        if(amd8111e_tx_queue_avail(lp) < 0){
                netif_stop_queue(dev);
        }
@@ -1376,7 +1374,7 @@ list to the device.
 */
 static void amd8111e_set_multicast_list(struct net_device *dev)
 {
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        struct amd8111e_priv *lp = netdev_priv(dev);
        u32 mc_filter[2] ;
        int bit_num;
@@ -1407,8 +1405,8 @@ static void amd8111e_set_multicast_list(struct net_device *dev)
        /* load all the multicast addresses in the logic filter */
        lp->options |= OPTION_MULTICAST_ENABLE;
        mc_filter[1] = mc_filter[0] = 0;
-       netdev_for_each_mc_addr(mc_ptr, dev) {
-               bit_num = (ether_crc_le(ETH_ALEN, mc_ptr->dmi_addr) >> 26) & 0x3f;
+       netdev_for_each_mc_addr(ha, dev) {
+               bit_num = (ether_crc_le(ETH_ALEN, ha->addr) >> 26) & 0x3f;
                mc_filter[bit_num >> 5] |= 1 << (bit_num & 31);
        }
        amd8111e_writeq(*(u64*)mc_filter,lp->mmio+ LADRF);
index 1437f5d121214b18f6dcffe5e3a5937d17c03e95..2fe60f1681082d4c05a551c97af3ba09924045ee 100644 (file)
@@ -521,7 +521,6 @@ apne_block_output(struct net_device *dev, int count,
 
     outb(ENISR_RDC, nic_base + NE_EN0_ISR);    /* Ack intr. */
     ei_status.dmaing &= ~0x01;
-    return;
 }
 
 static irqreturn_t apne_interrupt(int irq, void *dev_id)
index 6f8d6206b5c483a6bbac6102a57a0a96813bcb59..748c9f526e713274d8d3c722bd321c0a0e845e28 100644 (file)
@@ -593,8 +593,6 @@ static void cops_load (struct net_device *dev)
                 tangent_wait_reset(ioaddr);
                 inb(ioaddr);   /* Clear initial ready signal. */
         }
-
-        return;
 }
 
 /*
@@ -701,8 +699,6 @@ static void cops_poll(unsigned long ltdev)
        /* poll 20 times per second */
        cops_timer.expires = jiffies + HZ/20;
        add_timer(&cops_timer);
-
-       return;
 }
 
 /*
@@ -866,7 +862,7 @@ static void cops_timeout(struct net_device *dev)
        }
        printk(KERN_WARNING "%s: Transmit timed out.\n", dev->name);
        cops_jumpstart(dev);    /* Restart the card. */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -919,9 +915,8 @@ static netdev_tx_t cops_send_packet(struct sk_buff *skb,
        /* Done sending packet, update counters and cleanup. */
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
-        return NETDEV_TX_OK;
+       return NETDEV_TX_OK;
 }
 
 /*
index 6af65b656f31e7e6e64a7234a53e385bc23168a3..adc07551739ec46cb123b00c040fd29581ffe071 100644 (file)
@@ -641,7 +641,6 @@ done:
                inb_p(base+7);
                inb_p(base+7);
        }
-       return;
 }
 
 
index d8f029303754a76c4feae384986b2b6efbc21ca1..a746ba272f04b5e3b77a4e45f65809a398c73585 100644 (file)
@@ -654,7 +654,6 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
                        }
                }
                retval = NETDEV_TX_OK;
-               dev->trans_start = jiffies;
                lp->next_tx = txbuf;
        } else {
                retval = NETDEV_TX_BUSY;
index 2c712af6c2653ba4de8694dae5b962cfb1a523ee..48a1dbf01e606ba880af6408abd0b8558b559fca 100644 (file)
@@ -164,8 +164,8 @@ static DEFINE_PCI_DEVICE_TABLE(com20020pci_id_table) = {
        { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
        { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
        { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
-       { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
-       { 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+       { 0x10B5, 0x9030, 0x10B5,     0x2978,     0, 0, ARC_CAN_10MBIT },
+       { 0x10B5, 0x9050, 0x10B5,     0x2273,     0, 0, ARC_CAN_10MBIT },
        { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
        { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
        {0,}
index 4b30a46486e2561333c58b1280b324abd286ad70..39214e51245225056c1cedf9c3404f6cdd51dc2f 100644 (file)
@@ -677,8 +677,6 @@ static netdev_tx_t ariadne_start_xmit(struct sk_buff *skb,
     lance->RAP = CSR0;         /* PCnet-ISA Controller Status */
     lance->RDP = INEA|TDMD;
 
-    dev->trans_start = jiffies;
-
     if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) != 0) {
        netif_stop_queue(dev);
        priv->tx_full = 1;
index f1f58c5e27bfd1abe9e388a8637e7087a964d537..8c496fb1ac9e5fc17108d9b14ba5ac489030740c 100644 (file)
@@ -383,12 +383,12 @@ static void am79c961_setmulticastlist (struct net_device *dev)
        } else if (dev->flags & IFF_ALLMULTI) {
                memset(multi_hash, 0xff, sizeof(multi_hash));
        } else {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
 
                memset(multi_hash, 0x00, sizeof(multi_hash));
 
-               netdev_for_each_mc_addr(dmi, dev)
-                       am79c961_mc_hash(dmi->dmi_addr, multi_hash);
+               netdev_for_each_mc_addr(ha, dev)
+                       am79c961_mc_hash(ha->addr, multi_hash);
        }
 
        spin_lock_irqsave(&priv->chip_lock, flags);
@@ -469,7 +469,6 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
 
        spin_lock_irqsave(&priv->chip_lock, flags);
        write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
-       dev->trans_start = jiffies;
        spin_unlock_irqrestore(&priv->chip_lock, flags);
 
        /*
index aed5b5479b505d1268bc31063edb1c40ba27bd02..e07b314ed8fdb0d90914da9271cc66bd18728035 100644 (file)
@@ -557,14 +557,14 @@ static int hash_get_index(__u8 *addr)
  */
 static void at91ether_sethashtable(struct net_device *dev)
 {
-       struct dev_mc_list *curr;
+       struct netdev_hw_addr *ha;
        unsigned long mc_filter[2];
        unsigned int bitnr;
 
        mc_filter[0] = mc_filter[1] = 0;
 
-       netdev_for_each_mc_addr(curr, dev) {
-               bitnr = hash_get_index(curr->dmi_addr);
+       netdev_for_each_mc_addr(ha, dev) {
+               bitnr = hash_get_index(ha->addr);
                mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
        }
 
@@ -824,7 +824,6 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Set length of the packet in the Transmit Control register */
                at91_emac_write(AT91_EMAC_TCR, skb->len);
 
-               dev->trans_start = jiffies;
        } else {
                printk(KERN_ERR "at91_ether.c: at91ether_start_xmit() called, but device is busy!\n");
                return NETDEV_TX_BUSY;  /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb)
index cd17d09f385cfc60d5e70eb555672e9b0c3b55d6..4a5ec9470aa1fca56d2be28893e54e39bed346ee 100644 (file)
@@ -374,8 +374,6 @@ static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
                                skb->len, DMA_TO_DEVICE);
        dev_kfree_skb(skb);
 
-       dev->trans_start = jiffies;
-
        spin_lock_irq(&ep->tx_pending_lock);
        ep->tx_pending++;
        if (ep->tx_pending == TX_QUEUE_ENTRIES)
index e47c0d9628579f50fc51a6a1bb32a85a70c66147..b17ab5153f51e5aca038cb7a32c9bde62a0496e5 100644 (file)
@@ -736,7 +736,6 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
        local_irq_restore(flags);
 
        /* handle transmit */
-       dev->trans_start = jiffies;
 
        /* check to see if we have room for a full sized ether frame */
        tmp = priv(dev)->tx_head;
index d9de9bce23957ca66847cf7f847620ec94602580..1361b7367c28bd86f6bbd63ad3816186ec55eaf8 100644 (file)
@@ -529,7 +529,6 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_BUSY;  /* unable to queue */
        }
 
-       dev->trans_start = jiffies;
        ptr              = 0x600 * priv(dev)->tx_head;
        priv(dev)->tx_head = next_ptr;
        next_ptr        *= 0x600;
index 6be8b098b8b48b58be55df6aaf529dabee07decc..24df0325090c8ae8075f09afcc3a60bb67ce972c 100644 (file)
@@ -708,7 +708,6 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
        /* NPE firmware pads short frames with zeros internally */
        wmb();
        queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
-       dev->trans_start = jiffies;
 
        if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
 #if DEBUG_TX
@@ -736,7 +735,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
 static void eth_set_mcast_list(struct net_device *dev)
 {
        struct port *port = netdev_priv(dev);
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        u8 diffs[ETH_ALEN], *addr;
        int i;
 
@@ -749,11 +748,11 @@ static void eth_set_mcast_list(struct net_device *dev)
        memset(diffs, 0, ETH_ALEN);
 
        addr = NULL;
-       netdev_for_each_mc_addr(mclist, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                if (!addr)
-                       addr = mclist->dmi_addr; /* first MAC address */
+                       addr = ha->addr; /* first MAC address */
                for (i = 0; i < ETH_ALEN; i++)
-                       diffs[i] |= addr[i] ^ mclist->dmi_addr[i];
+                       diffs[i] |= addr[i] ^ ha->addr[i];
        }
 
        for (i = 0; i < ETH_ALEN; i++) {
index 84f8a8f73802f4b6b54bbc51c3665a146185f102..54c6d849cf25683cf4d2831c2c7b5d50605ec452 100644 (file)
@@ -332,16 +332,16 @@ ks8695_init_partial_multicast(struct ks8695_priv *ksp,
 {
        u32 low, high;
        int i;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
        i = 0;
-       netdev_for_each_mc_addr(dmi, ndev) {
+       netdev_for_each_mc_addr(ha, ndev) {
                /* Ran out of space in chip? */
                BUG_ON(i == KS8695_NR_ADDRESSES);
 
-               low = (dmi->dmi_addr[2] << 24) | (dmi->dmi_addr[3] << 16) |
-                     (dmi->dmi_addr[4] << 8) | (dmi->dmi_addr[5]);
-               high = (dmi->dmi_addr[0] << 8) | (dmi->dmi_addr[1]);
+               low = (ha->addr[2] << 24) | (ha->addr[3] << 16) |
+                     (ha->addr[4] << 8) | (ha->addr[5]);
+               high = (ha->addr[0] << 8) | (ha->addr[1]);
 
                ks8695_writereg(ksp, KS8695_AAL_(i), low);
                ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high);
@@ -1302,8 +1302,6 @@ ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        if (++ksp->tx_ring_used == MAX_TX_DESC)
                netif_stop_queue(ndev);
 
-       ndev->trans_start = jiffies;
-
        /* Kick the TX DMA in case it decided to go IDLE */
        ks8695_writereg(ksp, KS8695_DTSC, 0);
 
@@ -1472,7 +1470,6 @@ ks8695_probe(struct platform_device *pdev)
 
        /* Configure our private structure a little */
        ksp = netdev_priv(ndev);
-       memset(ksp, 0, sizeof(struct ks8695_priv));
 
        ksp->dev = &pdev->dev;
        ksp->ndev = ndev;
index f7c9ca1dfb17b67664a7656ef2d74bf1105e5efa..2e852463382b3e166db62dfde492ba7d5141dd78 100644 (file)
@@ -483,7 +483,7 @@ static void w90p910_reset_mac(struct net_device *dev)
 
        w90p910_init_desc(dev);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        ether->cur_tx = 0x0;
        ether->finish_tx = 0x0;
        ether->cur_rx = 0x0;
@@ -497,7 +497,7 @@ static void w90p910_reset_mac(struct net_device *dev)
        w90p910_trigger_tx(dev);
        w90p910_trigger_rx(dev);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 
        if (netif_queue_stopped(dev))
                netif_wake_queue(dev);
@@ -634,8 +634,6 @@ static int w90p910_send_frame(struct net_device *dev,
 
        txbd = &ether->tdesc->desclist[ether->cur_tx];
 
-       dev->trans_start = jiffies;
-
        if (txbd->mode & TX_OWEN_DMA)
                netif_stop_queue(dev);
 
@@ -744,7 +742,6 @@ static void netdev_rx(struct net_device *dev)
                                return;
                        }
 
-                       skb->dev = dev;
                        skb_reserve(skb, 2);
                        skb_put(skb, length);
                        skb_copy_to_linear_data(skb, data, length);
index 10a20fb9ae6518f808232fd5439519cceffc9d4b..93185f5f09accd10ec947b2b30179071703e4f8e 100644 (file)
@@ -583,7 +583,7 @@ static void net_tx_timeout (struct net_device *dev)
        outb (0x00, ioaddr + TX_START);
        outb (0x03, ioaddr + COL16CNTL);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 
        lp->tx_started = 0;
        lp->tx_queue_ready = 1;
@@ -636,7 +636,6 @@ static netdev_tx_t net_send_packet (struct sk_buff *skb,
                outb (0x80 | lp->tx_queue, ioaddr + TX_START);
                lp->tx_queue = 0;
                lp->tx_queue_len = 0;
-               dev->trans_start = jiffies;
                lp->tx_started = 1;
                netif_start_queue (dev);
        } else if (lp->tx_queue_len < 4096 - 1502)
@@ -796,7 +795,6 @@ net_rx(struct net_device *dev)
                        printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",
                                   dev->name, inb(ioaddr + RX_MODE), i);
        }
-       return;
 }
 
 /* The inverse routine to net_open(). */
@@ -847,12 +845,12 @@ set_rx_mode(struct net_device *dev)
                memset(mc_filter, 0x00, sizeof(mc_filter));
                outb(1, ioaddr + RX_MODE);      /* Ignore almost all multicasts. */
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        unsigned int bit =
-                               ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
+                               ether_crc_le(ETH_ALEN, ha->addr) >> 26;
                        mc_filter[bit >> 3] |= (1 << bit);
                }
                outb(0x02, ioaddr + RX_MODE);   /* Use normal mode. */
@@ -870,7 +868,6 @@ set_rx_mode(struct net_device *dev)
                outw(saved_bank, ioaddr + CONFIG_0);
        }
        spin_unlock_irqrestore (&lp->lock, flags);
-       return;
 }
 
 #ifdef MODULE
index a8686bfec7a18c7c7537308b73750635aef33628..b57d7dee389a6b43d87c6556962270b0a1fead22 100644 (file)
@@ -767,8 +767,8 @@ static void lance_tx_timeout (struct net_device *dev)
        /* lance_restart, essentially */
        lance_init_ring(dev);
        REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
-       dev->trans_start = jiffies;
-       netif_wake_queue (dev);
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       netif_wake_queue(dev);
 }
 
 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
@@ -836,7 +836,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
 
        /* Trigger an immediate send poll. */
        DREG = CSR0_INEA | CSR0_TDMD;
-       dev->trans_start = jiffies;
 
        if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
                TMD1_OWN_HOST)
index 32339243d61f84dd4f644cbd04f033605ac634ba..7c521508313c28a300d264ad7a610e2c91732739 100644 (file)
@@ -263,8 +263,6 @@ static void atl1c_get_wol(struct net_device *netdev,
                wol->wolopts |= WAKE_MAGIC;
        if (adapter->wol & AT_WUFC_LNKC)
                wol->wolopts |= WAKE_PHY;
-
-       return;
 }
 
 static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
index 50dc531a02d83be01f0238c2106d246bee449cd9..1c3c046d5f34d610a05caed24fd69cff28042397 100644 (file)
@@ -317,8 +317,6 @@ static void atl1c_common_task(struct work_struct *work)
 
        if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE)
                atl1c_check_link_status(adapter);
-
-       return;
 }
 
 
@@ -354,7 +352,7 @@ static void atl1c_set_multi(struct net_device *netdev)
 {
        struct atl1c_adapter *adapter = netdev_priv(netdev);
        struct atl1c_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u32 mac_ctrl_data;
        u32 hash_value;
 
@@ -377,8 +375,8 @@ static void atl1c_set_multi(struct net_device *netdev)
        AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
 
        /* comoute mc addresses' hash value ,and put it into hash table */
-       netdev_for_each_mc_addr(mc_ptr, netdev) {
-               hash_value = atl1c_hash_mc_addr(hw, mc_ptr->dmi_addr);
+       netdev_for_each_mc_addr(ha, netdev) {
+               hash_value = atl1c_hash_mc_addr(hw, ha->addr);
                atl1c_hash_set(hw, hash_value);
        }
 }
@@ -1817,7 +1815,6 @@ rrs_checked:
                atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
                skb_put(skb, length - ETH_FCS_LEN);
                skb->protocol = eth_type_trans(skb, netdev);
-               skb->dev = netdev;
                atl1c_rx_checksum(adapter, skb, rrs);
                if (unlikely(adapter->vlgrp) && rrs->word3 & RRS_VLAN_INS) {
                        u16 vlan;
index ffd696ee7c8ed5ebc13e53438282424c24049317..6943a6c3b948cf56a93c0412b4b57ffc17a15b40 100644 (file)
@@ -338,8 +338,6 @@ static void atl1e_get_wol(struct net_device *netdev,
                wol->wolopts |= WAKE_MAGIC;
        if (adapter->wol & AT_WUFC_LNKC)
                wol->wolopts |= WAKE_PHY;
-
-       return;
 }
 
 static int atl1e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
index 73302ae468aad56d862f6fc58f954b49475c0d58..1acea5774e8936ed0b78352c871b8b0d9734b518 100644 (file)
@@ -284,7 +284,7 @@ static void atl1e_set_multi(struct net_device *netdev)
 {
        struct atl1e_adapter *adapter = netdev_priv(netdev);
        struct atl1e_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u32 mac_ctrl_data = 0;
        u32 hash_value;
 
@@ -307,8 +307,8 @@ static void atl1e_set_multi(struct net_device *netdev)
        AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
 
        /* comoute mc addresses' hash value ,and put it into hash table */
-       netdev_for_each_mc_addr(mc_ptr, netdev) {
-               hash_value = atl1e_hash_mc_addr(hw, mc_ptr->dmi_addr);
+       netdev_for_each_mc_addr(ha, netdev) {
+               hash_value = atl1e_hash_mc_addr(hw, ha->addr);
                atl1e_hash_set(hw, hash_value);
        }
 }
@@ -707,8 +707,6 @@ static void atl1e_init_ring_resources(struct atl1e_adapter *adapter)
        adapter->ring_vir_addr = NULL;
        adapter->rx_ring.desc = NULL;
        rwlock_init(&adapter->tx_ring.tx_lock);
-
-       return;
 }
 
 /*
@@ -905,8 +903,6 @@ static inline void atl1e_configure_des_ring(const struct atl1e_adapter *adapter)
        AT_WRITE_REG(hw, REG_HOST_RXFPAGE_SIZE, rx_ring->page_size);
        /* Load all of base address above */
        AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
-
-       return;
 }
 
 static inline void atl1e_configure_tx(struct atl1e_adapter *adapter)
@@ -950,7 +946,6 @@ static inline void atl1e_configure_tx(struct atl1e_adapter *adapter)
                        (((u16)hw->tpd_burst & TXQ_CTRL_NUM_TPD_BURST_MASK)
                         << TXQ_CTRL_NUM_TPD_BURST_SHIFT)
                        | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN);
-       return;
 }
 
 static inline void atl1e_configure_rx(struct atl1e_adapter *adapter)
@@ -1004,7 +999,6 @@ static inline void atl1e_configure_rx(struct atl1e_adapter *adapter)
                         RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
 
        AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
-       return;
 }
 
 static inline void atl1e_configure_dma(struct atl1e_adapter *adapter)
@@ -1024,7 +1018,6 @@ static inline void atl1e_configure_dma(struct atl1e_adapter *adapter)
                << DMA_CTRL_DMAW_DLY_CNT_SHIFT;
 
        AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data);
-       return;
 }
 
 static void atl1e_setup_mac_ctrl(struct atl1e_adapter *adapter)
@@ -1428,7 +1421,6 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que,
                                            "Memory squeeze, deferring packet\n");
                                goto skip_pkt;
                        }
-                       skb->dev = netdev;
                        memcpy(skb->data, (u8 *)(prrs + 1), packet_size);
                        skb_put(skb, packet_size);
                        skb->protocol = eth_type_trans(skb, netdev);
@@ -1680,7 +1672,7 @@ static void atl1e_tx_map(struct atl1e_adapter *adapter,
 {
        struct atl1e_tpd_desc *use_tpd = NULL;
        struct atl1e_tx_buffer *tx_buffer = NULL;
-       u16 buf_len = skb->len - skb->data_len;
+       u16 buf_len = skb_headlen(skb);
        u16 map_len = 0;
        u16 mapped_len = 0;
        u16 hdr_len = 0;
index 0ebd8208f606afdaf0f387ad3353ccb7b3d958e8..63b9ba0cc67e13c408686442f1e2fe984ee9b462 100644 (file)
@@ -1830,8 +1830,6 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter,
                adapter->hw_csum_good++;
                return;
        }
-
-       return;
 }
 
 /*
@@ -2347,7 +2345,7 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
 {
        struct atl1_adapter *adapter = netdev_priv(netdev);
        struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
-       int len = skb->len;
+       int len;
        int tso;
        int count = 1;
        int ret_val;
@@ -2359,7 +2357,7 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
        unsigned int f;
        unsigned int proto_hdr_len;
 
-       len -= skb->data_len;
+       len = skb_headlen(skb);
 
        if (unlikely(skb->len <= 0)) {
                dev_kfree_skb_any(skb);
@@ -3390,7 +3388,6 @@ static void atl1_get_wol(struct net_device *netdev,
        wol->wolopts = 0;
        if (adapter->wol & ATLX_WUFC_MAG)
                wol->wolopts |= WAKE_MAGIC;
-       return;
 }
 
 static int atl1_set_wol(struct net_device *netdev,
index 54662f24f9bb0587b841e43776ae0aa2a426bbcf..8da87383fb3938dc0fe8d9031ff3860a3f24ac97 100644 (file)
@@ -136,7 +136,7 @@ static void atl2_set_multi(struct net_device *netdev)
 {
        struct atl2_adapter *adapter = netdev_priv(netdev);
        struct atl2_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u32 rctl;
        u32 hash_value;
 
@@ -158,8 +158,8 @@ static void atl2_set_multi(struct net_device *netdev)
        ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
 
        /* comoute mc addresses' hash value ,and put it into hash table */
-       netdev_for_each_mc_addr(mc_ptr, netdev) {
-               hash_value = atl2_hash_mc_addr(hw, mc_ptr->dmi_addr);
+       netdev_for_each_mc_addr(ha, netdev) {
+               hash_value = atl2_hash_mc_addr(hw, ha->addr);
                atl2_hash_set(hw, hash_value);
        }
 }
@@ -422,7 +422,6 @@ static void atl2_intr_rx(struct atl2_adapter *adapter)
                                netdev->stats.rx_dropped++;
                                break;
                        }
-                       skb->dev = netdev;
                        memcpy(skb->data, rxd->packet, rx_size);
                        skb_put(skb, rx_size);
                        skb->protocol = eth_type_trans(skb, netdev);
@@ -893,7 +892,6 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb,
                (adapter->txd_write_ptr >> 2));
 
        mmiowb();
-       netdev->trans_start = jiffies;
        dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
index 72f3306352e2b901ec25035d1434e666e25b4755..f979ea2d6d3cd7cd6c080bfbd57cc8159b0d3279 100644 (file)
@@ -123,7 +123,7 @@ static void atlx_set_multi(struct net_device *netdev)
 {
        struct atlx_adapter *adapter = netdev_priv(netdev);
        struct atlx_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u32 rctl;
        u32 hash_value;
 
@@ -144,8 +144,8 @@ static void atlx_set_multi(struct net_device *netdev)
        iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
 
        /* compute mc addresses' hash value ,and put it into hash table */
-       netdev_for_each_mc_addr(mc_ptr, netdev) {
-               hash_value = atlx_hash_mc_addr(hw, mc_ptr->dmi_addr);
+       netdev_for_each_mc_addr(ha, netdev) {
+               hash_value = atlx_hash_mc_addr(hw, ha->addr);
                atlx_hash_set(hw, hash_value);
        }
 }
index 55039d44dc474545062e942a39b0b1ef46b4cb03..bd2f9d331dac79ee89d3729dce6b9072b91b6a0d 100644 (file)
@@ -547,7 +547,7 @@ static void tx_timeout(struct net_device *dev)
        dev->stats.tx_errors++;
        /* Try to restart the adapter. */
        hardware_init(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
        dev->stats.tx_errors++;
 }
@@ -586,7 +586,6 @@ static netdev_tx_t atp_send_packet(struct sk_buff *skb,
        write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
        write_reg_high(ioaddr, IMR, ISRh_RxErr);
 
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
        return NETDEV_TX_OK;
 }
@@ -803,7 +802,6 @@ static void net_rx(struct net_device *dev)
  done:
        write_reg(ioaddr, CMR1, CMR1_NextPkt);
        lp->last_rx_time = jiffies;
-       return;
 }
 
 static void read_block(long ioaddr, int length, unsigned char *p, int data_mode)
@@ -882,11 +880,11 @@ static void set_rx_mode_8012(struct net_device *dev)
                memset(mc_filter, 0xff, sizeof(mc_filter));
                new_mode = CMR2h_Normal;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int filterbit = ether_crc_le(ETH_ALEN, ha->addr) & 0x3f;
                        mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
                }
                new_mode = CMR2h_Normal;
index 4da191b87b0d9ee857dea8ef4fff0adc347a482b..ece6128bef146aa330f98f486d23f2bed1c15ed5 100644 (file)
@@ -75,14 +75,19 @@ static int au1000_debug = 5;
 static int au1000_debug = 3;
 #endif
 
+#define AU1000_DEF_MSG_ENABLE  (NETIF_MSG_DRV  | \
+                               NETIF_MSG_PROBE | \
+                               NETIF_MSG_LINK)
+
 #define DRV_NAME       "au1000_eth"
-#define DRV_VERSION    "1.6"
+#define DRV_VERSION    "1.7"
 #define DRV_AUTHOR     "Pete Popov <ppopov@embeddedalley.com>"
 #define DRV_DESC       "Au1xxx on-chip Ethernet driver"
 
 MODULE_AUTHOR(DRV_AUTHOR);
 MODULE_DESCRIPTION(DRV_DESC);
 MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
 
 /*
  * Theory of operation
@@ -148,7 +153,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
  * specific irq-map
  */
 
-static void enable_mac(struct net_device *dev, int force_reset)
+static void au1000_enable_mac(struct net_device *dev, int force_reset)
 {
        unsigned long flags;
        struct au1000_private *aup = netdev_priv(dev);
@@ -182,8 +187,7 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
        while (*mii_control_reg & MAC_MII_BUSY) {
                mdelay(1);
                if (--timedout == 0) {
-                       printk(KERN_ERR "%s: read_MII busy timeout!!\n",
-                                       dev->name);
+                       netdev_err(dev, "read_MII busy timeout!!\n");
                        return -1;
                }
        }
@@ -197,8 +201,7 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg)
        while (*mii_control_reg & MAC_MII_BUSY) {
                mdelay(1);
                if (--timedout == 0) {
-                       printk(KERN_ERR "%s: mdio_read busy timeout!!\n",
-                                       dev->name);
+                       netdev_err(dev, "mdio_read busy timeout!!\n");
                        return -1;
                }
        }
@@ -217,8 +220,7 @@ static void au1000_mdio_write(struct net_device *dev, int phy_addr,
        while (*mii_control_reg & MAC_MII_BUSY) {
                mdelay(1);
                if (--timedout == 0) {
-                       printk(KERN_ERR "%s: mdio_write busy timeout!!\n",
-                                       dev->name);
+                       netdev_err(dev, "mdio_write busy timeout!!\n");
                        return;
                }
        }
@@ -236,7 +238,7 @@ static int au1000_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
         * _NOT_ hold (e.g. when PHY is accessed through other MAC's MII bus) */
        struct net_device *const dev = bus->priv;
 
-       enable_mac(dev, 0); /* make sure the MAC associated with this
+       au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
                             * mii_bus is enabled */
        return au1000_mdio_read(dev, phy_addr, regnum);
 }
@@ -246,7 +248,7 @@ static int au1000_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
 {
        struct net_device *const dev = bus->priv;
 
-       enable_mac(dev, 0); /* make sure the MAC associated with this
+       au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
                             * mii_bus is enabled */
        au1000_mdio_write(dev, phy_addr, regnum, value);
        return 0;
@@ -256,28 +258,26 @@ static int au1000_mdiobus_reset(struct mii_bus *bus)
 {
        struct net_device *const dev = bus->priv;
 
-       enable_mac(dev, 0); /* make sure the MAC associated with this
+       au1000_enable_mac(dev, 0); /* make sure the MAC associated with this
                             * mii_bus is enabled */
        return 0;
 }
 
-static void hard_stop(struct net_device *dev)
+static void au1000_hard_stop(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
 
-       if (au1000_debug > 4)
-               printk(KERN_INFO "%s: hard stop\n", dev->name);
+       netif_dbg(aup, drv, dev, "hard stop\n");
 
        aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
        au_sync_delay(10);
 }
 
-static void enable_rx_tx(struct net_device *dev)
+static void au1000_enable_rx_tx(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
 
-       if (au1000_debug > 4)
-               printk(KERN_INFO "%s: enable_rx_tx\n", dev->name);
+       netif_dbg(aup, hw, dev, "enable_rx_tx\n");
 
        aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
        au_sync_delay(10);
@@ -297,16 +297,15 @@ au1000_adjust_link(struct net_device *dev)
        spin_lock_irqsave(&aup->lock, flags);
 
        if (phydev->link && (aup->old_speed != phydev->speed)) {
-               // speed changed
+               /* speed changed */
 
-               switch(phydev->speed) {
+               switch (phydev->speed) {
                case SPEED_10:
                case SPEED_100:
                        break;
                default:
-                       printk(KERN_WARNING
-                              "%s: Speed (%d) is not 10/100 ???\n",
-                              dev->name, phydev->speed);
+                       netdev_warn(dev, "Speed (%d) is not 10/100 ???\n",
+                                                       phydev->speed);
                        break;
                }
 
@@ -316,10 +315,10 @@ au1000_adjust_link(struct net_device *dev)
        }
 
        if (phydev->link && (aup->old_duplex != phydev->duplex)) {
-               // duplex mode changed
+               /* duplex mode changed */
 
                /* switching duplex mode requires to disable rx and tx! */
-               hard_stop(dev);
+               au1000_hard_stop(dev);
 
                if (DUPLEX_FULL == phydev->duplex)
                        aup->mac->control = ((aup->mac->control
@@ -331,14 +330,14 @@ au1000_adjust_link(struct net_device *dev)
                                             | MAC_DISABLE_RX_OWN);
                au_sync_delay(1);
 
-               enable_rx_tx(dev);
+               au1000_enable_rx_tx(dev);
                aup->old_duplex = phydev->duplex;
 
                status_change = 1;
        }
 
-       if(phydev->link != aup->old_link) {
-               // link state changed
+       if (phydev->link != aup->old_link) {
+               /* link state changed */
 
                if (!phydev->link) {
                        /* link went down */
@@ -354,15 +353,15 @@ au1000_adjust_link(struct net_device *dev)
 
        if (status_change) {
                if (phydev->link)
-                       printk(KERN_INFO "%s: link up (%d/%s)\n",
-                              dev->name, phydev->speed,
+                       netdev_info(dev, "link up (%d/%s)\n",
+                              phydev->speed,
                               DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
                else
-                       printk(KERN_INFO "%s: link down\n", dev->name);
+                       netdev_info(dev, "link down\n");
        }
 }
 
-static int mii_probe (struct net_device *dev)
+static int au1000_mii_probe (struct net_device *dev)
 {
        struct au1000_private *const aup = netdev_priv(dev);
        struct phy_device *phydev = NULL;
@@ -373,8 +372,7 @@ static int mii_probe (struct net_device *dev)
                if (aup->phy_addr)
                        phydev = aup->mii_bus->phy_map[aup->phy_addr];
                else
-                       printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
-                               dev->name);
+                       netdev_info(dev, "using PHY-less setup\n");
                return 0;
        } else {
                int phy_addr;
@@ -391,7 +389,7 @@ static int mii_probe (struct net_device *dev)
                        /* try harder to find a PHY */
                        if (!phydev && (aup->mac_id == 1)) {
                                /* no PHY found, maybe we have a dual PHY? */
-                               printk (KERN_INFO DRV_NAME ": no PHY found on MAC1, "
+                               dev_info(&dev->dev, ": no PHY found on MAC1, "
                                        "let's see if it's attached to MAC0...\n");
 
                                /* find the first (lowest address) non-attached PHY on
@@ -417,7 +415,7 @@ static int mii_probe (struct net_device *dev)
        }
 
        if (!phydev) {
-               printk (KERN_ERR DRV_NAME ":%s: no PHY found\n", dev->name);
+               netdev_err(dev, "no PHY found\n");
                return -1;
        }
 
@@ -428,7 +426,7 @@ static int mii_probe (struct net_device *dev)
                        0, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
-               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+               netdev_err(dev, "Could not attach to PHY\n");
                return PTR_ERR(phydev);
        }
 
@@ -449,8 +447,8 @@ static int mii_probe (struct net_device *dev)
        aup->old_duplex = -1;
        aup->phy_dev = phydev;
 
-       printk(KERN_INFO "%s: attached PHY driver [%s] "
-              "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name,
+       netdev_info(dev, "attached PHY driver [%s] "
+              "(mii_bus:phy_addr=%s, irq=%d)\n",
               phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
 
        return 0;
@@ -462,7 +460,7 @@ static int mii_probe (struct net_device *dev)
  * has the virtual and dma address of a buffer suitable for
  * both, receive and transmit operations.
  */
-static db_dest_t *GetFreeDB(struct au1000_private *aup)
+static db_dest_t *au1000_GetFreeDB(struct au1000_private *aup)
 {
        db_dest_t *pDB;
        pDB = aup->pDBfree;
@@ -473,7 +471,7 @@ static db_dest_t *GetFreeDB(struct au1000_private *aup)
        return pDB;
 }
 
-void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
+void au1000_ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
 {
        db_dest_t *pDBfree = aup->pDBfree;
        if (pDBfree)
@@ -481,12 +479,12 @@ void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
        aup->pDBfree = pDB;
 }
 
-static void reset_mac_unlocked(struct net_device *dev)
+static void au1000_reset_mac_unlocked(struct net_device *dev)
 {
        struct au1000_private *const aup = netdev_priv(dev);
        int i;
 
-       hard_stop(dev);
+       au1000_hard_stop(dev);
 
        *aup->enable = MAC_EN_CLOCK_ENABLE;
        au_sync_delay(2);
@@ -507,18 +505,17 @@ static void reset_mac_unlocked(struct net_device *dev)
 
 }
 
-static void reset_mac(struct net_device *dev)
+static void au1000_reset_mac(struct net_device *dev)
 {
        struct au1000_private *const aup = netdev_priv(dev);
        unsigned long flags;
 
-       if (au1000_debug > 4)
-               printk(KERN_INFO "%s: reset mac, aup %x\n",
-                      dev->name, (unsigned)aup);
+       netif_dbg(aup, hw, dev, "reset mac, aup %x\n",
+                                       (unsigned)aup);
 
        spin_lock_irqsave(&aup->lock, flags);
 
-       reset_mac_unlocked (dev);
+       au1000_reset_mac_unlocked (dev);
 
        spin_unlock_irqrestore(&aup->lock, flags);
 }
@@ -529,7 +526,7 @@ static void reset_mac(struct net_device *dev)
  * these are not descriptors sitting in memory.
  */
 static void
-setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
+au1000_setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
 {
        int i;
 
@@ -582,11 +579,25 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        info->regdump_len = 0;
 }
 
+static void au1000_set_msglevel(struct net_device *dev, u32 value)
+{
+       struct au1000_private *aup = netdev_priv(dev);
+       aup->msg_enable = value;
+}
+
+static u32 au1000_get_msglevel(struct net_device *dev)
+{
+       struct au1000_private *aup = netdev_priv(dev);
+       return aup->msg_enable;
+}
+
 static const struct ethtool_ops au1000_ethtool_ops = {
        .get_settings = au1000_get_settings,
        .set_settings = au1000_set_settings,
        .get_drvinfo = au1000_get_drvinfo,
        .get_link = ethtool_op_get_link,
+       .get_msglevel = au1000_get_msglevel,
+       .set_msglevel = au1000_set_msglevel,
 };
 
 
@@ -606,11 +617,10 @@ static int au1000_init(struct net_device *dev)
        int i;
        u32 control;
 
-       if (au1000_debug > 4)
-               printk("%s: au1000_init\n", dev->name);
+       netif_dbg(aup, hw, dev, "au1000_init\n");
 
        /* bring the device out of reset */
-       enable_mac(dev, 1);
+       au1000_enable_mac(dev, 1);
 
        spin_lock_irqsave(&aup->lock, flags);
 
@@ -649,7 +659,7 @@ static int au1000_init(struct net_device *dev)
        return 0;
 }
 
-static inline void update_rx_stats(struct net_device *dev, u32 status)
+static inline void au1000_update_rx_stats(struct net_device *dev, u32 status)
 {
        struct net_device_stats *ps = &dev->stats;
 
@@ -667,8 +677,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status)
                        ps->rx_crc_errors++;
                if (status & RX_COLL)
                        ps->collisions++;
-       }
-       else
+       } else
                ps->rx_bytes += status & RX_FRAME_LEN_MASK;
 
 }
@@ -685,15 +694,14 @@ static int au1000_rx(struct net_device *dev)
        db_dest_t *pDB;
        u32     frmlen;
 
-       if (au1000_debug > 5)
-               printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);
+       netif_dbg(aup, rx_status, dev, "au1000_rx head %d\n", aup->rx_head);
 
        prxd = aup->rx_dma_ring[aup->rx_head];
        buff_stat = prxd->buff_stat;
        while (buff_stat & RX_T_DONE)  {
                status = prxd->status;
                pDB = aup->rx_db_inuse[aup->rx_head];
-               update_rx_stats(dev, status);
+               au1000_update_rx_stats(dev, status);
                if (!(status & RX_ERROR))  {
 
                        /* good frame */
@@ -701,9 +709,7 @@ static int au1000_rx(struct net_device *dev)
                        frmlen -= 4; /* Remove FCS */
                        skb = dev_alloc_skb(frmlen + 2);
                        if (skb == NULL) {
-                               printk(KERN_ERR
-                                      "%s: Memory squeeze, dropping packet.\n",
-                                      dev->name);
+                               netdev_err(dev, "Memory squeeze, dropping packet.\n");
                                dev->stats.rx_dropped++;
                                continue;
                        }
@@ -713,8 +719,7 @@ static int au1000_rx(struct net_device *dev)
                        skb_put(skb, frmlen);
                        skb->protocol = eth_type_trans(skb, dev);
                        netif_rx(skb);  /* pass the packet to upper layers */
-               }
-               else {
+               } else {
                        if (au1000_debug > 4) {
                                if (status & RX_MISSED_FRAME)
                                        printk("rx miss\n");
@@ -747,7 +752,7 @@ static int au1000_rx(struct net_device *dev)
        return 0;
 }
 
-static void update_tx_stats(struct net_device *dev, u32 status)
+static void au1000_update_tx_stats(struct net_device *dev, u32 status)
 {
        struct au1000_private *aup = netdev_priv(dev);
        struct net_device_stats *ps = &dev->stats;
@@ -760,8 +765,7 @@ static void update_tx_stats(struct net_device *dev, u32 status)
                                ps->tx_errors++;
                                ps->tx_aborted_errors++;
                        }
-               }
-               else {
+               } else {
                        ps->tx_errors++;
                        ps->tx_aborted_errors++;
                        if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER))
@@ -783,7 +787,7 @@ static void au1000_tx_ack(struct net_device *dev)
        ptxd = aup->tx_dma_ring[aup->tx_tail];
 
        while (ptxd->buff_stat & TX_T_DONE) {
-               update_tx_stats(dev, ptxd->status);
+               au1000_update_tx_stats(dev, ptxd->status);
                ptxd->buff_stat &= ~TX_T_DONE;
                ptxd->len = 0;
                au_sync();
@@ -817,18 +821,18 @@ static int au1000_open(struct net_device *dev)
        int retval;
        struct au1000_private *aup = netdev_priv(dev);
 
-       if (au1000_debug > 4)
-               printk("%s: open: dev=%p\n", dev->name, dev);
+       netif_dbg(aup, drv, dev, "open: dev=%p\n", dev);
 
-       if ((retval = request_irq(dev->irq, au1000_interrupt, 0,
-                                       dev->name, dev))) {
-               printk(KERN_ERR "%s: unable to get IRQ %d\n",
-                               dev->name, dev->irq);
+       retval = request_irq(dev->irq, au1000_interrupt, 0,
+                                       dev->name, dev);
+       if (retval) {
+               netdev_err(dev, "unable to get IRQ %d\n", dev->irq);
                return retval;
        }
 
-       if ((retval = au1000_init(dev))) {
-               printk(KERN_ERR "%s: error in au1000_init\n", dev->name);
+       retval = au1000_init(dev);
+       if (retval) {
+               netdev_err(dev, "error in au1000_init\n");
                free_irq(dev->irq, dev);
                return retval;
        }
@@ -841,8 +845,7 @@ static int au1000_open(struct net_device *dev)
 
        netif_start_queue(dev);
 
-       if (au1000_debug > 4)
-               printk("%s: open: Initialization done.\n", dev->name);
+       netif_dbg(aup, drv, dev, "open: Initialization done.\n");
 
        return 0;
 }
@@ -852,15 +855,14 @@ static int au1000_close(struct net_device *dev)
        unsigned long flags;
        struct au1000_private *const aup = netdev_priv(dev);
 
-       if (au1000_debug > 4)
-               printk("%s: close: dev=%p\n", dev->name, dev);
+       netif_dbg(aup, drv, dev, "close: dev=%p\n", dev);
 
        if (aup->phy_dev)
                phy_stop(aup->phy_dev);
 
        spin_lock_irqsave(&aup->lock, flags);
 
-       reset_mac_unlocked (dev);
+       au1000_reset_mac_unlocked (dev);
 
        /* stop the device */
        netif_stop_queue(dev);
@@ -884,9 +886,8 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
        db_dest_t *pDB;
        int i;
 
-       if (au1000_debug > 5)
-               printk("%s: tx: aup %x len=%d, data=%p, head %d\n",
-                               dev->name, (unsigned)aup, skb->len,
+       netif_dbg(aup, tx_queued, dev, "tx: aup %x len=%d, data=%p, head %d\n",
+                               (unsigned)aup, skb->len,
                                skb->data, aup->tx_head);
 
        ptxd = aup->tx_dma_ring[aup->tx_head];
@@ -896,9 +897,8 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
                aup->tx_full = 1;
                return NETDEV_TX_BUSY;
-       }
-       else if (buff_stat & TX_T_DONE) {
-               update_tx_stats(dev, ptxd->status);
+       } else if (buff_stat & TX_T_DONE) {
+               au1000_update_tx_stats(dev, ptxd->status);
                ptxd->len = 0;
        }
 
@@ -910,12 +910,11 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
        pDB = aup->tx_db_inuse[aup->tx_head];
        skb_copy_from_linear_data(skb, (void *)pDB->vaddr, skb->len);
        if (skb->len < ETH_ZLEN) {
-               for (i=skb->len; i<ETH_ZLEN; i++) {
+               for (i = skb->len; i < ETH_ZLEN; i++) {
                        ((char *)pDB->vaddr)[i] = 0;
                }
                ptxd->len = ETH_ZLEN;
-       }
-       else
+       } else
                ptxd->len = skb->len;
 
        ps->tx_packets++;
@@ -925,7 +924,6 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
        au_sync();
        dev_kfree_skb(skb);
        aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
@@ -935,10 +933,10 @@ static netdev_tx_t au1000_tx(struct sk_buff *skb, struct net_device *dev)
  */
 static void au1000_tx_timeout(struct net_device *dev)
 {
-       printk(KERN_ERR "%s: au1000_tx_timeout: dev=%p\n", dev->name, dev);
-       reset_mac(dev);
+       netdev_err(dev, "au1000_tx_timeout: dev=%p\n", dev);
+       au1000_reset_mac(dev);
        au1000_init(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -946,8 +944,7 @@ static void au1000_multicast_list(struct net_device *dev)
 {
        struct au1000_private *aup = netdev_priv(dev);
 
-       if (au1000_debug > 4)
-               printk("%s: au1000_multicast_list: flags=%x\n", dev->name, dev->flags);
+       netif_dbg(aup, drv, dev, "au1000_multicast_list: flags=%x\n", dev->flags);
 
        if (dev->flags & IFF_PROMISC) {                 /* Set promiscuous. */
                aup->mac->control |= MAC_PROMISCUOUS;
@@ -955,14 +952,14 @@ static void au1000_multicast_list(struct net_device *dev)
                           netdev_mc_count(dev) > MULTICAST_FILTER_LIMIT) {
                aup->mac->control |= MAC_PASS_ALL_MULTI;
                aup->mac->control &= ~MAC_PROMISCUOUS;
-               printk(KERN_INFO "%s: Pass all multicast\n", dev->name);
+               netdev_info(dev, "Pass all multicast\n");
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                u32 mc_filter[2];       /* Multicast hash filter */
 
                mc_filter[1] = mc_filter[0] = 0;
-               netdev_for_each_mc_addr(mclist, dev)
-                       set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,
+               netdev_for_each_mc_addr(ha, dev)
+                       set_bit(ether_crc(ETH_ALEN, ha->addr)>>26,
                                        (long *)mc_filter);
                aup->mac->multi_hash_high = mc_filter[1];
                aup->mac->multi_hash_low = mc_filter[0];
@@ -975,9 +972,11 @@ static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct au1000_private *aup = netdev_priv(dev);
 
-       if (!netif_running(dev)) return -EINVAL;
+       if (!netif_running(dev))
+               return -EINVAL;
 
-       if (!aup->phy_dev) return -EINVAL; // PHY not controllable
+       if (!aup->phy_dev)
+               return -EINVAL; /* PHY not controllable */
 
        return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
 }
@@ -996,7 +995,7 @@ static const struct net_device_ops au1000_netdev_ops = {
 
 static int __devinit au1000_probe(struct platform_device *pdev)
 {
-       static unsigned version_printed = 0;
+       static unsigned version_printed;
        struct au1000_private *aup = NULL;
        struct au1000_eth_platform_data *pd;
        struct net_device *dev = NULL;
@@ -1007,40 +1006,40 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 
        base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!base) {
-               printk(KERN_ERR DRV_NAME ": failed to retrieve base register\n");
+               dev_err(&pdev->dev, "failed to retrieve base register\n");
                err = -ENODEV;
                goto out;
        }
 
        macen = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!macen) {
-               printk(KERN_ERR DRV_NAME ": failed to retrieve MAC Enable register\n");
+               dev_err(&pdev->dev, "failed to retrieve MAC Enable register\n");
                err = -ENODEV;
                goto out;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               printk(KERN_ERR DRV_NAME ": failed to retrieve IRQ\n");
+               dev_err(&pdev->dev, "failed to retrieve IRQ\n");
                err = -ENODEV;
                goto out;
        }
 
        if (!request_mem_region(base->start, resource_size(base), pdev->name)) {
-               printk(KERN_ERR DRV_NAME ": failed to request memory region for base registers\n");
+               dev_err(&pdev->dev, "failed to request memory region for base registers\n");
                err = -ENXIO;
                goto out;
        }
 
        if (!request_mem_region(macen->start, resource_size(macen), pdev->name)) {
-               printk(KERN_ERR DRV_NAME ": failed to request memory region for MAC enable register\n");
+               dev_err(&pdev->dev, "failed to request memory region for MAC enable register\n");
                err = -ENXIO;
                goto err_request;
        }
 
        dev = alloc_etherdev(sizeof(struct au1000_private));
        if (!dev) {
-               printk(KERN_ERR "%s: alloc_etherdev failed\n", DRV_NAME);
+               dev_err(&pdev->dev, "alloc_etherdev failed\n");
                err = -ENOMEM;
                goto err_alloc;
        }
@@ -1050,6 +1049,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        aup = netdev_priv(dev);
 
        spin_lock_init(&aup->lock);
+       aup->msg_enable = (au1000_debug < 4 ? AU1000_DEF_MSG_ENABLE : au1000_debug);
 
        /* Allocate the data buffers */
        /* Snooping works fine with eth on all au1xxx */
@@ -1057,7 +1057,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
                                                (NUM_TX_BUFFS + NUM_RX_BUFFS),
                                                &aup->dma_addr, 0);
        if (!aup->vaddr) {
-               printk(KERN_ERR DRV_NAME ": failed to allocate data buffers\n");
+               dev_err(&pdev->dev, "failed to allocate data buffers\n");
                err = -ENOMEM;
                goto err_vaddr;
        }
@@ -1065,7 +1065,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        /* aup->mac is the base address of the MAC's registers */
        aup->mac = (volatile mac_reg_t *)ioremap_nocache(base->start, resource_size(base));
        if (!aup->mac) {
-               printk(KERN_ERR DRV_NAME ": failed to ioremap MAC registers\n");
+               dev_err(&pdev->dev, "failed to ioremap MAC registers\n");
                err = -ENXIO;
                goto err_remap1;
        }
@@ -1073,7 +1073,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
         /* Setup some variables for quick register address access */
        aup->enable = (volatile u32 *)ioremap_nocache(macen->start, resource_size(macen));
        if (!aup->enable) {
-               printk(KERN_ERR DRV_NAME ": failed to ioremap MAC enable register\n");
+               dev_err(&pdev->dev, "failed to ioremap MAC enable register\n");
                err = -ENXIO;
                goto err_remap2;
        }
@@ -1083,14 +1083,13 @@ static int __devinit au1000_probe(struct platform_device *pdev)
                if (prom_get_ethernet_addr(ethaddr) == 0)
                        memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
                else {
-                       printk(KERN_INFO "%s: No MAC address found\n",
-                                        dev->name);
+                       netdev_info(dev, "No MAC address found\n");
                                /* Use the hard coded MAC addresses */
                }
 
-               setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
+               au1000_setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
        } else if (pdev->id == 1)
-               setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
+               au1000_setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
 
        /*
         * Assign to the Ethernet ports two consecutive MAC addresses
@@ -1104,7 +1103,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 
        pd = pdev->dev.platform_data;
        if (!pd) {
-               printk(KERN_INFO DRV_NAME ": no platform_data passed, PHY search on MAC0\n");
+               dev_info(&pdev->dev, "no platform_data passed, PHY search on MAC0\n");
                aup->phy1_search_mac0 = 1;
        } else {
                aup->phy_static_config = pd->phy_static_config;
@@ -1116,7 +1115,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        }
 
        if (aup->phy_busid && aup->phy_busid > 0) {
-               printk(KERN_ERR DRV_NAME ": MAC0-associated PHY attached 2nd MACs MII"
+               dev_err(&pdev->dev, "MAC0-associated PHY attached 2nd MACs MII"
                                "bus not supported yet\n");
                err = -ENODEV;
                goto err_mdiobus_alloc;
@@ -1124,7 +1123,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 
        aup->mii_bus = mdiobus_alloc();
        if (aup->mii_bus == NULL) {
-               printk(KERN_ERR DRV_NAME ": failed to allocate mdiobus structure\n");
+               dev_err(&pdev->dev, "failed to allocate mdiobus structure\n");
                err = -ENOMEM;
                goto err_mdiobus_alloc;
        }
@@ -1139,7 +1138,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        if (aup->mii_bus->irq == NULL)
                goto err_out;
 
-       for(i = 0; i < PHY_MAX_ADDR; ++i)
+       for (i = 0; i < PHY_MAX_ADDR; ++i)
                aup->mii_bus->irq[i] = PHY_POLL;
        /* if known, set corresponding PHY IRQs */
        if (aup->phy_static_config)
@@ -1148,11 +1147,11 @@ static int __devinit au1000_probe(struct platform_device *pdev)
 
        err = mdiobus_register(aup->mii_bus);
        if (err) {
-               printk(KERN_ERR DRV_NAME " failed to register MDIO bus\n");
+               dev_err(&pdev->dev, "failed to register MDIO bus\n");
                goto err_mdiobus_reg;
        }
 
-       if (mii_probe(dev) != 0)
+       if (au1000_mii_probe(dev) != 0)
                goto err_out;
 
        pDBfree = NULL;
@@ -1168,7 +1167,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        aup->pDBfree = pDBfree;
 
        for (i = 0; i < NUM_RX_DMA; i++) {
-               pDB = GetFreeDB(aup);
+               pDB = au1000_GetFreeDB(aup);
                if (!pDB) {
                        goto err_out;
                }
@@ -1176,7 +1175,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
                aup->rx_db_inuse[i] = pDB;
        }
        for (i = 0; i < NUM_TX_DMA; i++) {
-               pDB = GetFreeDB(aup);
+               pDB = au1000_GetFreeDB(aup);
                if (!pDB) {
                        goto err_out;
                }
@@ -1195,17 +1194,16 @@ static int __devinit au1000_probe(struct platform_device *pdev)
         * The boot code uses the ethernet controller, so reset it to start
         * fresh.  au1000_init() expects that the device is in reset state.
         */
-       reset_mac(dev);
+       au1000_reset_mac(dev);
 
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR DRV_NAME "%s: Cannot register net device, aborting.\n",
-                                       dev->name);
+               netdev_err(dev, "Cannot register net device, aborting.\n");
                goto err_out;
        }
 
-       printk("%s: Au1xx0 Ethernet found at 0x%lx, irq %d\n",
-                       dev->name, (unsigned long)base->start, irq);
+       netdev_info(dev, "Au1xx0 Ethernet found at 0x%lx, irq %d\n",
+                       (unsigned long)base->start, irq);
        if (version_printed++ == 0)
                printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);
 
@@ -1217,15 +1215,15 @@ err_out:
 
        /* here we should have a valid dev plus aup-> register addresses
         * so we can reset the mac properly.*/
-       reset_mac(dev);
+       au1000_reset_mac(dev);
 
        for (i = 0; i < NUM_RX_DMA; i++) {
                if (aup->rx_db_inuse[i])
-                       ReleaseDB(aup, aup->rx_db_inuse[i]);
+                       au1000_ReleaseDB(aup, aup->rx_db_inuse[i]);
        }
        for (i = 0; i < NUM_TX_DMA; i++) {
                if (aup->tx_db_inuse[i])
-                       ReleaseDB(aup, aup->tx_db_inuse[i]);
+                       au1000_ReleaseDB(aup, aup->tx_db_inuse[i]);
        }
 err_mdiobus_reg:
        mdiobus_free(aup->mii_bus);
@@ -1261,11 +1259,11 @@ static int __devexit au1000_remove(struct platform_device *pdev)
 
        for (i = 0; i < NUM_RX_DMA; i++)
                if (aup->rx_db_inuse[i])
-                       ReleaseDB(aup, aup->rx_db_inuse[i]);
+                       au1000_ReleaseDB(aup, aup->rx_db_inuse[i]);
 
        for (i = 0; i < NUM_TX_DMA; i++)
                if (aup->tx_db_inuse[i])
-                       ReleaseDB(aup, aup->tx_db_inuse[i]);
+                       au1000_ReleaseDB(aup, aup->tx_db_inuse[i]);
 
        dma_free_noncoherent(NULL, MAX_BUF_SIZE *
                        (NUM_TX_BUFFS + NUM_RX_BUFFS),
index f9d29a29b8fdfba046675e2b26e4742fb4527843..d06ec008fbf1756dee1545225d26fe25902a4054 100644 (file)
@@ -35,7 +35,7 @@
 #define NUM_TX_BUFFS 4
 #define MAX_BUF_SIZE 2048
 
-#define ETH_TX_TIMEOUT HZ/4
+#define ETH_TX_TIMEOUT (HZ/4)
 #define MAC_MIN_PKT_SIZE 64
 
 #define MULTICAST_FILTER_LIMIT 64
@@ -125,4 +125,6 @@ struct au1000_private {
        dma_addr_t dma_addr;      /* dma address of rx/tx buffers       */
 
        spinlock_t lock;       /* Serialise access to device */
+
+       u32 msg_enable;
 };
index b718dc60afc4114783c13697e88787f31077d94e..55c9958043c43266c0d5b67350648f03f58143ee 100644 (file)
@@ -303,7 +303,6 @@ static void ax_block_output(struct net_device *dev, int count,
 
        ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
        ei_status.dmaing &= ~0x01;
-       return;
 }
 
 /* definitions for accessing MII/EEPROM interface */
index 69d9f3d368aee82a817f6d5645df275a9f2497dc..293f9c16e7860b87944812c104a50804245326fe 100644 (file)
@@ -1014,8 +1014,6 @@ static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (TX_BUFFS_AVAIL(bp) < 1)
                netif_stop_queue(dev);
 
-       dev->trans_start = jiffies;
-
 out_unlock:
        spin_unlock_irqrestore(&bp->lock, flags);
 
@@ -1681,15 +1679,15 @@ static struct net_device_stats *b44_get_stats(struct net_device *dev)
 
 static int __b44_load_mcast(struct b44 *bp, struct net_device *dev)
 {
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        int i, num_ents;
 
        num_ents = min_t(int, netdev_mc_count(dev), B44_MCAST_TABLE_SIZE);
        i = 0;
-       netdev_for_each_mc_addr(mclist, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                if (i == num_ents)
                        break;
-               __b44_cam_write(bp, mclist->dmi_addr, i++ + 1);
+               __b44_cam_write(bp, ha->addr, i++ + 1);
        }
        return i+1;
 }
index 17460aba3baee4614e41b4222f131336580df8a5..faf5add894d7788ebb8b1621951f164d772505d8 100644 (file)
@@ -341,11 +341,9 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
                }
 
                skb_put(skb, len);
-               skb->dev = dev;
                skb->protocol = eth_type_trans(skb, dev);
                priv->stats.rx_packets++;
                priv->stats.rx_bytes += len;
-               dev->last_rx = jiffies;
                netif_receive_skb(skb);
 
        } while (--budget > 0);
@@ -567,7 +565,6 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        priv->stats.tx_bytes += skb->len;
        priv->stats.tx_packets++;
-       dev->trans_start = jiffies;
        ret = NETDEV_TX_OK;
 
 out_unlock:
@@ -605,7 +602,7 @@ static int bcm_enet_set_mac_address(struct net_device *dev, void *p)
 static void bcm_enet_set_multicast_list(struct net_device *dev)
 {
        struct bcm_enet_priv *priv;
-       struct dev_mc_list *mc_list;
+       struct netdev_hw_addr *ha;
        u32 val;
        int i;
 
@@ -633,14 +630,14 @@ static void bcm_enet_set_multicast_list(struct net_device *dev)
        }
 
        i = 0;
-       netdev_for_each_mc_addr(mc_list, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                u8 *dmi_addr;
                u32 tmp;
 
                if (i == 3)
                        break;
                /* update perfect match registers */
-               dmi_addr = mc_list->dmi_addr;
+               dmi_addr = ha->addr;
                tmp = (dmi_addr[2] << 24) | (dmi_addr[3] << 16) |
                        (dmi_addr[4] << 8) | dmi_addr[5];
                enet_writel(priv, tmp, ENET_PML_REG(i + 1));
@@ -960,7 +957,9 @@ static int bcm_enet_open(struct net_device *dev)
        /* all set, enable mac and interrupts, start dma engine and
         * kick rx dma channel */
        wmb();
-       enet_writel(priv, ENET_CTL_ENABLE_MASK, ENET_CTL_REG);
+       val = enet_readl(priv, ENET_CTL_REG);
+       val |= ENET_CTL_ENABLE_MASK;
+       enet_writel(priv, val, ENET_CTL_REG);
        enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
        enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
                        ENETDMA_CHANCFG_REG(priv->rx_chan));
@@ -1647,7 +1646,6 @@ static int __devinit bcm_enet_probe(struct platform_device *pdev)
        if (!dev)
                return -ENOMEM;
        priv = netdev_priv(dev);
-       memset(priv, 0, sizeof(*priv));
 
        ret = compute_hw_mtu(priv, dev->mtu);
        if (ret)
index 56387b191c963aed41549412b7f1697f72ac7424..373c1a563474d9540c43ae315bcab0185b813ddd 100644 (file)
@@ -84,6 +84,8 @@ static inline char *nic_name(struct pci_dev *pdev)
 
 #define FW_VER_LEN             32
 
+#define BE_MAX_VF              32
+
 struct be_dma_mem {
        void *va;
        dma_addr_t dma;
@@ -207,7 +209,7 @@ struct be_tx_obj {
 /* Struct to remember the pages posted for rx frags */
 struct be_rx_page_info {
        struct page *page;
-       dma_addr_t bus;
+       DEFINE_DMA_UNMAP_ADDR(bus);
        u16 page_offset;
        bool last_page_user;
 };
@@ -281,8 +283,15 @@ struct be_adapter {
        u8 port_type;
        u8 transceiver;
        u8 generation;          /* BladeEngine ASIC generation */
+
+       bool sriov_enabled;
+       u32 vf_if_handle[BE_MAX_VF];
+       u32 vf_pmac_id[BE_MAX_VF];
+       u8 base_eq_id;
 };
 
+#define be_physfn(adapter) (!adapter->pdev->is_virtfn)
+
 /* BladeEngine Generation numbers */
 #define BE_GEN2 2
 #define BE_GEN3 3
index d0ef4ac987cde52db2ecb24e2144c43d1339c997..e79bf8b9af3bc5e0a3034d9b3c9ab7d6f9dfef39 100644 (file)
@@ -843,7 +843,8 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
  * Uses mbox
  */
 int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
-               u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
+               u8 *mac, bool pmac_invalid, u32 *if_handle, u32 *pmac_id,
+               u32 domain)
 {
        struct be_mcc_wrb *wrb;
        struct be_cmd_req_if_create *req;
@@ -860,6 +861,7 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags,
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req));
 
+       req->hdr.domain = domain;
        req->capability_flags = cpu_to_le32(cap_flags);
        req->enable_flags = cpu_to_le32(en_flags);
        req->pmac_invalid = pmac_invalid;
@@ -1111,6 +1113,10 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en)
        be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
                OPCODE_ETH_PROMISCUOUS, sizeof(*req));
 
+       /* In FW versions X.102.149/X.101.487 and later,
+        * the port setting associated only with the
+        * issuing pci function will take effect
+        */
        if (port_num)
                req->port1_promiscuous = en;
        else
@@ -1157,13 +1163,13 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
        req->interface_id = if_id;
        if (netdev) {
                int i;
-               struct dev_mc_list *mc;
+               struct netdev_hw_addr *ha;
 
                req->num_mac = cpu_to_le16(netdev_mc_count(netdev));
 
                i = 0;
-               netdev_for_each_mc_addr(mc, netdev)
-                       memcpy(req->mac[i].byte, mc->dmi_addr, ETH_ALEN);
+               netdev_for_each_mc_addr(ha, netdev)
+                       memcpy(req->mac[i].byte, ha->addr, ETH_ALEN);
        } else {
                req->promiscuous = 1;
        }
index cce61f9a37146b2f9503269bbf289ab755edfe86..763dc199e337255bbb55f30c8f612c96f723abb5 100644 (file)
@@ -878,7 +878,7 @@ extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr,
 extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id);
 extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags,
                        u32 en_flags, u8 *mac, bool pmac_invalid,
-                       u32 *if_handle, u32 *pmac_id);
+                       u32 *if_handle, u32 *pmac_id, u32 domain);
 extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle);
 extern int be_cmd_eq_create(struct be_adapter *adapter,
                        struct be_queue_info *eq, int eq_delay);
index 51e1065e78977df6f27a06eaf58dcdba64da5502..200e98515909453a559e20926dc5090ded20a287 100644 (file)
@@ -276,8 +276,6 @@ be_get_ethtool_stats(struct net_device *netdev,
                data[i] = (et_stats[i].size == sizeof(u64)) ?
                                *(u64 *)p: *(u32 *)p;
        }
-
-       return;
 }
 
 static void
@@ -466,7 +464,6 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        else
                wol->wolopts = 0;
        memset(&wol->sopass, 0, sizeof(wol->sopass));
-       return;
 }
 
 static int
@@ -496,7 +493,7 @@ be_test_ddr_dma(struct be_adapter *adapter)
        ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size,
                                        &ddrdma_cmd.dma);
        if (!ddrdma_cmd.va) {
-               dev_err(&adapter->pdev->dev, "Memory allocation failure \n");
+               dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
                return -ENOMEM;
        }
 
index 2d4a4b827637dedb2337287a9c1bb4be31956dfe..063026de49571ae638dad9f604175bfd51ddfebf 100644 (file)
@@ -99,6 +99,9 @@
 /* Number of entries posted */
 #define DB_MCCQ_NUM_POSTED_SHIFT       (16)    /* bits 16 - 29 */
 
+/********** SRIOV VF PCICFG OFFSET ********/
+#define SRIOV_VF_PCICFG_OFFSET         (4096)
+
 /* Flashrom related descriptors */
 #define IMAGE_TYPE_FIRMWARE            160
 #define IMAGE_TYPE_BOOTCODE            224
index ec6ace802256087c4bd310c4669c48fc919999ae..058d7f95f5ae17df77c65c473a9683d4ec2a737a 100644 (file)
@@ -26,8 +26,11 @@ MODULE_AUTHOR("ServerEngines Corporation");
 MODULE_LICENSE("GPL");
 
 static unsigned int rx_frag_size = 2048;
+static unsigned int num_vfs;
 module_param(rx_frag_size, uint, S_IRUGO);
+module_param(num_vfs, uint, S_IRUGO);
 MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
+MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize");
 
 static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
        { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
@@ -138,12 +141,19 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
+       /* MAC addr configuration will be done in hardware for VFs
+        * by their corresponding PFs. Just copy to netdev addr here
+        */
+       if (!be_physfn(adapter))
+               goto netdev_addr;
+
        status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id);
        if (status)
                return status;
 
        status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data,
                        adapter->if_handle, &adapter->pmac_id);
+netdev_addr:
        if (!status)
                memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 
@@ -386,26 +396,48 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
        AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
 }
 
+static void unmap_tx_frag(struct pci_dev *pdev, struct be_eth_wrb *wrb,
+               bool unmap_single)
+{
+       dma_addr_t dma;
+
+       be_dws_le_to_cpu(wrb, sizeof(*wrb));
+
+       dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo;
+       if (wrb->frag_len) {
+               if (unmap_single)
+                       pci_unmap_single(pdev, dma, wrb->frag_len,
+                               PCI_DMA_TODEVICE);
+               else
+                       pci_unmap_page(pdev, dma, wrb->frag_len,
+                               PCI_DMA_TODEVICE);
+       }
+}
 
 static int make_tx_wrbs(struct be_adapter *adapter,
                struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb)
 {
-       u64 busaddr;
-       u32 i, copied = 0;
+       dma_addr_t busaddr;
+       int i, copied = 0;
        struct pci_dev *pdev = adapter->pdev;
        struct sk_buff *first_skb = skb;
        struct be_queue_info *txq = &adapter->tx_obj.q;
        struct be_eth_wrb *wrb;
        struct be_eth_hdr_wrb *hdr;
+       bool map_single = false;
+       u16 map_head;
 
        hdr = queue_head_node(txq);
-       atomic_add(wrb_cnt, &txq->used);
        queue_head_inc(txq);
+       map_head = txq->head;
 
        if (skb->len > skb->data_len) {
-               int len = skb->len - skb->data_len;
+               int len = skb_headlen(skb);
                busaddr = pci_map_single(pdev, skb->data, len,
                                         PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, busaddr))
+                       goto dma_err;
+               map_single = true;
                wrb = queue_head_node(txq);
                wrb_fill(wrb, busaddr, len);
                be_dws_cpu_to_le(wrb, sizeof(*wrb));
@@ -419,6 +451,8 @@ static int make_tx_wrbs(struct be_adapter *adapter,
                busaddr = pci_map_page(pdev, frag->page,
                                       frag->page_offset,
                                       frag->size, PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(pdev, busaddr))
+                       goto dma_err;
                wrb = queue_head_node(txq);
                wrb_fill(wrb, busaddr, frag->size);
                be_dws_cpu_to_le(wrb, sizeof(*wrb));
@@ -438,6 +472,16 @@ static int make_tx_wrbs(struct be_adapter *adapter,
        be_dws_cpu_to_le(hdr, sizeof(*hdr));
 
        return copied;
+dma_err:
+       txq->head = map_head;
+       while (copied) {
+               wrb = queue_head_node(txq);
+               unmap_tx_frag(pdev, wrb, map_single);
+               map_single = false;
+               copied -= wrb->frag_len;
+               queue_head_inc(txq);
+       }
+       return 0;
 }
 
 static netdev_tx_t be_xmit(struct sk_buff *skb,
@@ -462,6 +506,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
                 * *BEFORE* ringing the tx doorbell, so that we serialze the
                 * tx compls of the current transmit which'll wake up the queue
                 */
+               atomic_add(wrb_cnt, &txq->used);
                if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >=
                                                                txq->len) {
                        netif_stop_queue(netdev);
@@ -541,6 +586,9 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
+       if (!be_physfn(adapter))
+               return;
+
        adapter->vlan_tag[vid] = 1;
        adapter->vlans_added++;
        if (adapter->vlans_added <= (adapter->max_vlans + 1))
@@ -551,6 +599,9 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
+       if (!be_physfn(adapter))
+               return;
+
        adapter->vlan_tag[vid] = 0;
        vlan_group_set_device(adapter->vlan_grp, vid, NULL);
        adapter->vlans_added--;
@@ -588,6 +639,28 @@ done:
        return;
 }
 
+static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       int status;
+
+       if (!adapter->sriov_enabled)
+               return -EPERM;
+
+       if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
+               return -EINVAL;
+
+       status = be_cmd_pmac_del(adapter, adapter->vf_if_handle[vf],
+                               adapter->vf_pmac_id[vf]);
+
+       status = be_cmd_pmac_add(adapter, mac, adapter->vf_if_handle[vf],
+                               &adapter->vf_pmac_id[vf]);
+       if (!status)
+               dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
+                               mac, vf);
+       return status;
+}
+
 static void be_rx_rate_update(struct be_adapter *adapter)
 {
        struct be_drvr_stats *stats = drvr_stats(adapter);
@@ -647,7 +720,7 @@ get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
        BUG_ON(!rx_page_info->page);
 
        if (rx_page_info->last_page_user) {
-               pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus),
+               pci_unmap_page(adapter->pdev, dma_unmap_addr(rx_page_info, bus),
                        adapter->big_page_size, PCI_DMA_FROMDEVICE);
                rx_page_info->last_page_user = false;
        }
@@ -757,7 +830,6 @@ static void skb_fill_rx_data(struct be_adapter *adapter,
 
 done:
        be_rx_stats_update(adapter, pktsize, num_rcvd);
-       return;
 }
 
 /* Process the RX completion indicated by rxcp when GRO is disabled */
@@ -791,7 +863,6 @@ static void be_rx_compl_process(struct be_adapter *adapter,
 
        skb->truesize = skb->len + sizeof(struct sk_buff);
        skb->protocol = eth_type_trans(skb, adapter->netdev);
-       skb->dev = adapter->netdev;
 
        vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
        vtm = AMAP_GET_BITS(struct amap_eth_rx_compl, vtm, rxcp);
@@ -812,8 +883,6 @@ static void be_rx_compl_process(struct be_adapter *adapter,
        } else {
                netif_receive_skb(skb);
        }
-
-       return;
 }
 
 /* Process the RX completion indicated by rxcp when GRO is enabled */
@@ -893,7 +962,6 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
        }
 
        be_rx_stats_update(adapter, pkt_size, num_rcvd);
-       return;
 }
 
 static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
@@ -959,7 +1027,7 @@ static void be_post_rx_frags(struct be_adapter *adapter)
                }
                page_offset = page_info->page_offset;
                page_info->page = pagep;
-               pci_unmap_addr_set(page_info, bus, page_dmaaddr);
+               dma_unmap_addr_set(page_info, bus, page_dmaaddr);
                frag_dmaaddr = page_dmaaddr + page_info->page_offset;
 
                rxd = queue_head_node(rxq);
@@ -987,8 +1055,6 @@ static void be_post_rx_frags(struct be_adapter *adapter)
                /* Let be_worker replenish when memory is available */
                adapter->rx_post_starved = true;
        }
-
-       return;
 }
 
 static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
@@ -1012,35 +1078,26 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
        struct be_eth_wrb *wrb;
        struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
        struct sk_buff *sent_skb;
-       u64 busaddr;
-       u16 cur_index, num_wrbs = 0;
+       u16 cur_index, num_wrbs = 1; /* account for hdr wrb */
+       bool unmap_skb_hdr = true;
 
-       cur_index = txq->tail;
-       sent_skb = sent_skbs[cur_index];
+       sent_skb = sent_skbs[txq->tail];
        BUG_ON(!sent_skb);
-       sent_skbs[cur_index] = NULL;
-       wrb = queue_tail_node(txq);
-       be_dws_le_to_cpu(wrb, sizeof(*wrb));
-       busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
-       if (busaddr != 0) {
-               pci_unmap_single(adapter->pdev, busaddr,
-                                wrb->frag_len, PCI_DMA_TODEVICE);
-       }
-       num_wrbs++;
+       sent_skbs[txq->tail] = NULL;
+
+       /* skip header wrb */
        queue_tail_inc(txq);
 
-       while (cur_index != last_index) {
+       do {
                cur_index = txq->tail;
                wrb = queue_tail_node(txq);
-               be_dws_le_to_cpu(wrb, sizeof(*wrb));
-               busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
-               if (busaddr != 0) {
-                       pci_unmap_page(adapter->pdev, busaddr,
-                                      wrb->frag_len, PCI_DMA_TODEVICE);
-               }
+               unmap_tx_frag(adapter->pdev, wrb, (unmap_skb_hdr &&
+                                       skb_headlen(sent_skb)));
+               unmap_skb_hdr = false;
+
                num_wrbs++;
                queue_tail_inc(txq);
-       }
+       } while (cur_index != last_index);
 
        atomic_sub(num_wrbs, &txq->used);
 
@@ -1255,6 +1312,8 @@ static int be_tx_queues_create(struct be_adapter *adapter)
        /* Ask BE to create Tx Event queue */
        if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd))
                goto tx_eq_free;
+       adapter->base_eq_id = adapter->tx_eq.q.id;
+
        /* Alloc TX eth compl queue */
        cq = &adapter->tx_obj.cq;
        if (be_queue_alloc(adapter, cq, TX_CQ_LEN,
@@ -1382,7 +1441,7 @@ rx_eq_free:
 /* There are 8 evt ids per func. Retruns the evt id's bit number */
 static inline int be_evt_bit_get(struct be_adapter *adapter, u32 eq_id)
 {
-       return eq_id % 8;
+       return eq_id - adapter->base_eq_id;
 }
 
 static irqreturn_t be_intx(int irq, void *dev)
@@ -1557,7 +1616,27 @@ static void be_msix_enable(struct be_adapter *adapter)
                BE_NUM_MSIX_VECTORS);
        if (status == 0)
                adapter->msix_enabled = true;
-       return;
+}
+
+static void be_sriov_enable(struct be_adapter *adapter)
+{
+#ifdef CONFIG_PCI_IOV
+       int status;
+       if (be_physfn(adapter) && num_vfs) {
+               status = pci_enable_sriov(adapter->pdev, num_vfs);
+               adapter->sriov_enabled = status ? false : true;
+       }
+#endif
+}
+
+static void be_sriov_disable(struct be_adapter *adapter)
+{
+#ifdef CONFIG_PCI_IOV
+       if (adapter->sriov_enabled) {
+               pci_disable_sriov(adapter->pdev);
+               adapter->sriov_enabled = false;
+       }
+#endif
 }
 
 static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
@@ -1617,6 +1696,9 @@ static int be_irq_register(struct be_adapter *adapter)
                status = be_msix_register(adapter);
                if (status == 0)
                        goto done;
+               /* INTx is not supported for VF */
+               if (!be_physfn(adapter))
+                       return status;
        }
 
        /* INTx */
@@ -1651,7 +1733,6 @@ static void be_irq_unregister(struct be_adapter *adapter)
        be_free_irq(adapter, &adapter->rx_eq);
 done:
        adapter->isr_registered = false;
-       return;
 }
 
 static int be_open(struct net_device *netdev)
@@ -1690,14 +1771,17 @@ static int be_open(struct net_device *netdev)
                goto ret_sts;
        be_link_status_update(adapter, link_up);
 
-       status = be_vid_config(adapter);
+       if (be_physfn(adapter))
+               status = be_vid_config(adapter);
        if (status)
                goto ret_sts;
 
-       status = be_cmd_set_flow_control(adapter,
-                                       adapter->tx_fc, adapter->rx_fc);
-       if (status)
-               goto ret_sts;
+       if (be_physfn(adapter)) {
+               status = be_cmd_set_flow_control(adapter,
+                               adapter->tx_fc, adapter->rx_fc);
+               if (status)
+                       goto ret_sts;
+       }
 
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
 ret_sts:
@@ -1723,7 +1807,7 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
                        PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK);
                if (status) {
                        dev_err(&adapter->pdev->dev,
-                               "Could not enable Wake-on-lan \n");
+                               "Could not enable Wake-on-lan\n");
                        pci_free_consistent(adapter->pdev, cmd.size, cmd.va,
                                        cmd.dma);
                        return status;
@@ -1745,22 +1829,48 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
 static int be_setup(struct be_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
-       u32 cap_flags, en_flags;
+       u32 cap_flags, en_flags, vf = 0;
        int status;
+       u8 mac[ETH_ALEN];
+
+       cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST;
 
-       cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                       BE_IF_FLAGS_MCAST_PROMISCUOUS |
-                       BE_IF_FLAGS_PROMISCUOUS |
-                       BE_IF_FLAGS_PASS_L3L4_ERRORS;
-       en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
-                       BE_IF_FLAGS_PASS_L3L4_ERRORS;
+       if (be_physfn(adapter)) {
+               cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS |
+                               BE_IF_FLAGS_PROMISCUOUS |
+                               BE_IF_FLAGS_PASS_L3L4_ERRORS;
+               en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
+       }
 
        status = be_cmd_if_create(adapter, cap_flags, en_flags,
                        netdev->dev_addr, false/* pmac_invalid */,
-                       &adapter->if_handle, &adapter->pmac_id);
+                       &adapter->if_handle, &adapter->pmac_id, 0);
        if (status != 0)
                goto do_none;
 
+       if (be_physfn(adapter)) {
+               while (vf < num_vfs) {
+                       cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED
+                                       | BE_IF_FLAGS_BROADCAST;
+                       status = be_cmd_if_create(adapter, cap_flags, en_flags,
+                                       mac, true, &adapter->vf_if_handle[vf],
+                                       NULL, vf+1);
+                       if (status) {
+                               dev_err(&adapter->pdev->dev,
+                               "Interface Create failed for VF %d\n", vf);
+                               goto if_destroy;
+                       }
+                       vf++;
+               } while (vf < num_vfs);
+       } else if (!be_physfn(adapter)) {
+               status = be_cmd_mac_addr_query(adapter, mac,
+                       MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle);
+               if (!status) {
+                       memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+                       memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+               }
+       }
+
        status = be_tx_queues_create(adapter);
        if (status != 0)
                goto if_destroy;
@@ -1782,6 +1892,9 @@ rx_qs_destroy:
 tx_qs_destroy:
        be_tx_queues_destroy(adapter);
 if_destroy:
+       for (vf = 0; vf < num_vfs; vf++)
+               if (adapter->vf_if_handle[vf])
+                       be_cmd_if_destroy(adapter, adapter->vf_if_handle[vf]);
        be_cmd_if_destroy(adapter, adapter->if_handle);
 do_none:
        return status;
@@ -2061,6 +2174,7 @@ static struct net_device_ops be_netdev_ops = {
        .ndo_vlan_rx_register   = be_vlan_register,
        .ndo_vlan_rx_add_vid    = be_vlan_add_vid,
        .ndo_vlan_rx_kill_vid   = be_vlan_rem_vid,
+       .ndo_set_vf_mac         = be_set_vf_mac
 };
 
 static void be_netdev_init(struct net_device *netdev)
@@ -2102,37 +2216,48 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
                iounmap(adapter->csr);
        if (adapter->db)
                iounmap(adapter->db);
-       if (adapter->pcicfg)
+       if (adapter->pcicfg && be_physfn(adapter))
                iounmap(adapter->pcicfg);
 }
 
 static int be_map_pci_bars(struct be_adapter *adapter)
 {
        u8 __iomem *addr;
-       int pcicfg_reg;
+       int pcicfg_reg, db_reg;
 
-       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
-                       pci_resource_len(adapter->pdev, 2));
-       if (addr == NULL)
-               return -ENOMEM;
-       adapter->csr = addr;
-
-       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4),
-                       128 * 1024);
-       if (addr == NULL)
-               goto pci_map_err;
-       adapter->db = addr;
+       if (be_physfn(adapter)) {
+               addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
+                               pci_resource_len(adapter->pdev, 2));
+               if (addr == NULL)
+                       return -ENOMEM;
+               adapter->csr = addr;
+       }
 
-       if (adapter->generation == BE_GEN2)
+       if (adapter->generation == BE_GEN2) {
                pcicfg_reg = 1;
-       else
+               db_reg = 4;
+       } else {
                pcicfg_reg = 0;
-
-       addr = ioremap_nocache(pci_resource_start(adapter->pdev, pcicfg_reg),
-                       pci_resource_len(adapter->pdev, pcicfg_reg));
+               if (be_physfn(adapter))
+                       db_reg = 4;
+               else
+                       db_reg = 0;
+       }
+       addr = ioremap_nocache(pci_resource_start(adapter->pdev, db_reg),
+                               pci_resource_len(adapter->pdev, db_reg));
        if (addr == NULL)
                goto pci_map_err;
-       adapter->pcicfg = addr;
+       adapter->db = addr;
+
+       if (be_physfn(adapter)) {
+               addr = ioremap_nocache(
+                               pci_resource_start(adapter->pdev, pcicfg_reg),
+                               pci_resource_len(adapter->pdev, pcicfg_reg));
+               if (addr == NULL)
+                       goto pci_map_err;
+               adapter->pcicfg = addr;
+       } else
+               adapter->pcicfg = adapter->db + SRIOV_VF_PCICFG_OFFSET;
 
        return 0;
 pci_map_err:
@@ -2246,6 +2371,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
 
        be_ctrl_cleanup(adapter);
 
+       be_sriov_disable(adapter);
+
        be_msix_disable(adapter);
 
        pci_set_drvdata(pdev, NULL);
@@ -2270,16 +2397,20 @@ static int be_get_config(struct be_adapter *adapter)
                return status;
 
        memset(mac, 0, ETH_ALEN);
-       status = be_cmd_mac_addr_query(adapter, mac,
+
+       if (be_physfn(adapter)) {
+               status = be_cmd_mac_addr_query(adapter, mac,
                        MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
-       if (status)
-               return status;
 
-       if (!is_valid_ether_addr(mac))
-               return -EADDRNOTAVAIL;
+               if (status)
+                       return status;
 
-       memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
-       memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+               if (!is_valid_ether_addr(mac))
+                       return -EADDRNOTAVAIL;
+
+               memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
+               memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+       }
 
        if (adapter->cap & 0x400)
                adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
@@ -2296,6 +2427,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
        struct be_adapter *adapter;
        struct net_device *netdev;
 
+
        status = pci_enable_device(pdev);
        if (status)
                goto do_none;
@@ -2344,24 +2476,28 @@ static int __devinit be_probe(struct pci_dev *pdev,
                }
        }
 
+       be_sriov_enable(adapter);
+
        status = be_ctrl_init(adapter);
        if (status)
                goto free_netdev;
 
        /* sync up with fw's ready state */
-       status = be_cmd_POST(adapter);
-       if (status)
-               goto ctrl_clean;
+       if (be_physfn(adapter)) {
+               status = be_cmd_POST(adapter);
+               if (status)
+                       goto ctrl_clean;
+
+               status = be_cmd_reset_function(adapter);
+               if (status)
+                       goto ctrl_clean;
+       }
 
        /* tell fw we're ready to fire cmds */
        status = be_cmd_fw_init(adapter);
        if (status)
                goto ctrl_clean;
 
-       status = be_cmd_reset_function(adapter);
-       if (status)
-               goto ctrl_clean;
-
        status = be_stats_init(adapter);
        if (status)
                goto ctrl_clean;
@@ -2391,6 +2527,7 @@ ctrl_clean:
        be_ctrl_cleanup(adapter);
 free_netdev:
        be_msix_disable(adapter);
+       be_sriov_disable(adapter);
        free_netdev(adapter->netdev);
        pci_set_drvdata(pdev, NULL);
 rel_reg:
@@ -2474,8 +2611,6 @@ static void be_shutdown(struct pci_dev *pdev)
                be_setup_wol(adapter, true);
 
        pci_disable_device(pdev);
-
-       return;
 }
 
 static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
@@ -2557,7 +2692,6 @@ static void be_eeh_resume(struct pci_dev *pdev)
        return;
 err:
        dev_err(&adapter->pdev->dev, "EEH resume failed\n");
-       return;
 }
 
 static struct pci_error_handlers be_eeh_handlers = {
@@ -2587,6 +2721,13 @@ static int __init be_init_module(void)
                rx_frag_size = 2048;
        }
 
+       if (num_vfs > 32) {
+               printk(KERN_WARNING DRV_NAME
+                       " : Module param num_vfs must not be greater than 32."
+                       "Using 32\n");
+               num_vfs = 32;
+       }
+
        return pci_register_driver(&be_driver);
 }
 module_init(be_init_module);
index 587f93cf03f6ce053d2d1f9481623b1c99d63ae7..39a54bad397f7212b22340187a73325f20b7ab9d 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/dma.h>
 #include <linux/dma-mapping.h>
 
+#include <asm/div64.h>
 #include <asm/dpmc.h>
 #include <asm/blackfin.h>
 #include <asm/cacheflush.h>
@@ -80,9 +81,6 @@ static u16 pin_req[] = P_RMII0;
 static u16 pin_req[] = P_MII0;
 #endif
 
-static void bfin_mac_disable(void);
-static void bfin_mac_enable(void);
-
 static void desc_list_free(void)
 {
        struct net_dma_desc_rx *r;
@@ -202,6 +200,11 @@ static int desc_list_init(void)
                        goto init_error;
                }
                skb_reserve(new_skb, NET_IP_ALIGN);
+               /* Invidate the data cache of skb->data range when it is write back
+                * cache. It will prevent overwritting the new data from DMA
+                */
+               blackfin_dcache_invalidate_range((unsigned long)new_skb->head,
+                                        (unsigned long)new_skb->end);
                r->skb = new_skb;
 
                /*
@@ -254,7 +257,7 @@ init_error:
  * MII operations
  */
 /* Wait until the previous MDC/MDIO transaction has completed */
-static void bfin_mdio_poll(void)
+static int bfin_mdio_poll(void)
 {
        int timeout_cnt = MAX_TIMEOUT_CNT;
 
@@ -264,22 +267,30 @@ static void bfin_mdio_poll(void)
                if (timeout_cnt-- < 0) {
                        printk(KERN_ERR DRV_NAME
                        ": wait MDC/MDIO transaction to complete timeout\n");
-                       break;
+                       return -ETIMEDOUT;
                }
        }
+
+       return 0;
 }
 
 /* Read an off-chip register in a PHY through the MDC/MDIO port */
 static int bfin_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 {
-       bfin_mdio_poll();
+       int ret;
+
+       ret = bfin_mdio_poll();
+       if (ret)
+               return ret;
 
        /* read mode */
        bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
                                SET_REGAD((u16) regnum) |
                                STABUSY);
 
-       bfin_mdio_poll();
+       ret = bfin_mdio_poll();
+       if (ret)
+               return ret;
 
        return (int) bfin_read_EMAC_STADAT();
 }
@@ -288,7 +299,11 @@ static int bfin_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
 static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
                              u16 value)
 {
-       bfin_mdio_poll();
+       int ret;
+
+       ret = bfin_mdio_poll();
+       if (ret)
+               return ret;
 
        bfin_write_EMAC_STADAT((u32) value);
 
@@ -298,9 +313,7 @@ static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
                                STAOP |
                                STABUSY);
 
-       bfin_mdio_poll();
-
-       return 0;
+       return bfin_mdio_poll();
 }
 
 static int bfin_mdiobus_reset(struct mii_bus *bus)
@@ -458,6 +471,14 @@ static int mii_probe(struct net_device *dev)
  * Ethtool support
  */
 
+/*
+ * interrupt routine for magic packet wakeup
+ */
+static irqreturn_t bfin_mac_wake_interrupt(int irq, void *dev_id)
+{
+       return IRQ_HANDLED;
+}
+
 static int
 bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
@@ -492,11 +513,57 @@ static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
        strcpy(info->bus_info, dev_name(&dev->dev));
 }
 
+static void bfin_mac_ethtool_getwol(struct net_device *dev,
+       struct ethtool_wolinfo *wolinfo)
+{
+       struct bfin_mac_local *lp = netdev_priv(dev);
+
+       wolinfo->supported = WAKE_MAGIC;
+       wolinfo->wolopts = lp->wol;
+}
+
+static int bfin_mac_ethtool_setwol(struct net_device *dev,
+       struct ethtool_wolinfo *wolinfo)
+{
+       struct bfin_mac_local *lp = netdev_priv(dev);
+       int rc;
+
+       if (wolinfo->wolopts & (WAKE_MAGICSECURE |
+                               WAKE_UCAST |
+                               WAKE_MCAST |
+                               WAKE_BCAST |
+                               WAKE_ARP))
+               return -EOPNOTSUPP;
+
+       lp->wol = wolinfo->wolopts;
+
+       if (lp->wol && !lp->irq_wake_requested) {
+               /* register wake irq handler */
+               rc = request_irq(IRQ_MAC_WAKEDET, bfin_mac_wake_interrupt,
+                                IRQF_DISABLED, "EMAC_WAKE", dev);
+               if (rc)
+                       return rc;
+               lp->irq_wake_requested = true;
+       }
+
+       if (!lp->wol && lp->irq_wake_requested) {
+               free_irq(IRQ_MAC_WAKEDET, dev);
+               lp->irq_wake_requested = false;
+       }
+
+       /* Make sure the PHY driver doesn't suspend */
+       device_init_wakeup(&dev->dev, lp->wol);
+
+       return 0;
+}
+
 static const struct ethtool_ops bfin_mac_ethtool_ops = {
        .get_settings = bfin_mac_ethtool_getsettings,
        .set_settings = bfin_mac_ethtool_setsettings,
        .get_link = ethtool_op_get_link,
        .get_drvinfo = bfin_mac_ethtool_getdrvinfo,
+       .get_wol = bfin_mac_ethtool_getwol,
+       .set_wol = bfin_mac_ethtool_setwol,
 };
 
 /**************************************************************************/
@@ -509,10 +576,11 @@ void setup_system_regs(struct net_device *dev)
         * Configure checksum support and rcve frame word alignment
         */
        sysctl = bfin_read_EMAC_SYSCTL();
+       sysctl |= RXDWA;
 #if defined(BFIN_MAC_CSUM_OFFLOAD)
-       sysctl |= RXDWA | RXCKS;
+       sysctl |= RXCKS;
 #else
-       sysctl |= RXDWA;
+       sysctl &= ~RXCKS;
 #endif
        bfin_write_EMAC_SYSCTL(sysctl);
 
@@ -551,6 +619,309 @@ static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
        return 0;
 }
 
+#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
+#define bfin_mac_hwtstamp_is_none(cfg) ((cfg) == HWTSTAMP_FILTER_NONE)
+
+static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
+               struct ifreq *ifr, int cmd)
+{
+       struct hwtstamp_config config;
+       struct bfin_mac_local *lp = netdev_priv(netdev);
+       u16 ptpctl;
+       u32 ptpfv1, ptpfv2, ptpfv3, ptpfoff;
+
+       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       pr_debug("%s config flag:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
+                       __func__, config.flags, config.tx_type, config.rx_filter);
+
+       /* reserved for future extensions */
+       if (config.flags)
+               return -EINVAL;
+
+       if ((config.tx_type != HWTSTAMP_TX_OFF) &&
+                       (config.tx_type != HWTSTAMP_TX_ON))
+               return -ERANGE;
+
+       ptpctl = bfin_read_EMAC_PTP_CTL();
+
+       switch (config.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               /*
+                * Dont allow any timestamping
+                */
+               ptpfv3 = 0xFFFFFFFF;
+               bfin_write_EMAC_PTP_FV3(ptpfv3);
+               break;
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+               /*
+                * Clear the five comparison mask bits (bits[12:8]) in EMAC_PTP_CTL)
+                * to enable all the field matches.
+                */
+               ptpctl &= ~0x1F00;
+               bfin_write_EMAC_PTP_CTL(ptpctl);
+               /*
+                * Keep the default values of the EMAC_PTP_FOFF register.
+                */
+               ptpfoff = 0x4A24170C;
+               bfin_write_EMAC_PTP_FOFF(ptpfoff);
+               /*
+                * Keep the default values of the EMAC_PTP_FV1 and EMAC_PTP_FV2
+                * registers.
+                */
+               ptpfv1 = 0x11040800;
+               bfin_write_EMAC_PTP_FV1(ptpfv1);
+               ptpfv2 = 0x0140013F;
+               bfin_write_EMAC_PTP_FV2(ptpfv2);
+               /*
+                * The default value (0xFFFC) allows the timestamping of both
+                * received Sync messages and Delay_Req messages.
+                */
+               ptpfv3 = 0xFFFFFFFC;
+               bfin_write_EMAC_PTP_FV3(ptpfv3);
+
+               config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               /* Clear all five comparison mask bits (bits[12:8]) in the
+                * EMAC_PTP_CTL register to enable all the field matches.
+                */
+               ptpctl &= ~0x1F00;
+               bfin_write_EMAC_PTP_CTL(ptpctl);
+               /*
+                * Keep the default values of the EMAC_PTP_FOFF register, except set
+                * the PTPCOF field to 0x2A.
+                */
+               ptpfoff = 0x2A24170C;
+               bfin_write_EMAC_PTP_FOFF(ptpfoff);
+               /*
+                * Keep the default values of the EMAC_PTP_FV1 and EMAC_PTP_FV2
+                * registers.
+                */
+               ptpfv1 = 0x11040800;
+               bfin_write_EMAC_PTP_FV1(ptpfv1);
+               ptpfv2 = 0x0140013F;
+               bfin_write_EMAC_PTP_FV2(ptpfv2);
+               /*
+                * To allow the timestamping of Pdelay_Req and Pdelay_Resp, set
+                * the value to 0xFFF0.
+                */
+               ptpfv3 = 0xFFFFFFF0;
+               bfin_write_EMAC_PTP_FV3(ptpfv3);
+
+               config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
+               break;
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+               /*
+                * Clear bits 8 and 12 of the EMAC_PTP_CTL register to enable only the
+                * EFTM and PTPCM field comparison.
+                */
+               ptpctl &= ~0x1100;
+               bfin_write_EMAC_PTP_CTL(ptpctl);
+               /*
+                * Keep the default values of all the fields of the EMAC_PTP_FOFF
+                * register, except set the PTPCOF field to 0x0E.
+                */
+               ptpfoff = 0x0E24170C;
+               bfin_write_EMAC_PTP_FOFF(ptpfoff);
+               /*
+                * Program bits [15:0] of the EMAC_PTP_FV1 register to 0x88F7, which
+                * corresponds to PTP messages on the MAC layer.
+                */
+               ptpfv1 = 0x110488F7;
+               bfin_write_EMAC_PTP_FV1(ptpfv1);
+               ptpfv2 = 0x0140013F;
+               bfin_write_EMAC_PTP_FV2(ptpfv2);
+               /*
+                * To allow the timestamping of Pdelay_Req and Pdelay_Resp
+                * messages, set the value to 0xFFF0.
+                */
+               ptpfv3 = 0xFFFFFFF0;
+               bfin_write_EMAC_PTP_FV3(ptpfv3);
+
+               config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       if (config.tx_type == HWTSTAMP_TX_OFF &&
+           bfin_mac_hwtstamp_is_none(config.rx_filter)) {
+               ptpctl &= ~PTP_EN;
+               bfin_write_EMAC_PTP_CTL(ptpctl);
+
+               SSYNC();
+       } else {
+               ptpctl |= PTP_EN;
+               bfin_write_EMAC_PTP_CTL(ptpctl);
+
+               /*
+                * clear any existing timestamp
+                */
+               bfin_read_EMAC_PTP_RXSNAPLO();
+               bfin_read_EMAC_PTP_RXSNAPHI();
+
+               bfin_read_EMAC_PTP_TXSNAPLO();
+               bfin_read_EMAC_PTP_TXSNAPHI();
+
+               /*
+                * Set registers so that rollover occurs soon to test this.
+                */
+               bfin_write_EMAC_PTP_TIMELO(0x00000000);
+               bfin_write_EMAC_PTP_TIMEHI(0xFF800000);
+
+               SSYNC();
+
+               lp->compare.last_update = 0;
+               timecounter_init(&lp->clock,
+                               &lp->cycles,
+                               ktime_to_ns(ktime_get_real()));
+               timecompare_update(&lp->compare, 0);
+       }
+
+       lp->stamp_cfg = config;
+       return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+               -EFAULT : 0;
+}
+
+static void bfin_dump_hwtamp(char *s, ktime_t *hw, ktime_t *ts, struct timecompare *cmp)
+{
+       ktime_t sys = ktime_get_real();
+
+       pr_debug("%s %s hardware:%d,%d transform system:%d,%d system:%d,%d, cmp:%lld, %lld\n",
+                       __func__, s, hw->tv.sec, hw->tv.nsec, ts->tv.sec, ts->tv.nsec, sys.tv.sec,
+                       sys.tv.nsec, cmp->offset, cmp->skew);
+}
+
+static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
+{
+       struct bfin_mac_local *lp = netdev_priv(netdev);
+       union skb_shared_tx *shtx = skb_tx(skb);
+
+       if (shtx->hardware) {
+               int timeout_cnt = MAX_TIMEOUT_CNT;
+
+               /* When doing time stamping, keep the connection to the socket
+                * a while longer
+                */
+               shtx->in_progress = 1;
+
+               /*
+                * The timestamping is done at the EMAC module's MII/RMII interface
+                * when the module sees the Start of Frame of an event message packet. This
+                * interface is the closest possible place to the physical Ethernet transmission
+                * medium, providing the best timing accuracy.
+                */
+               while ((!(bfin_read_EMAC_PTP_ISTAT() & TXTL)) && (--timeout_cnt))
+                       udelay(1);
+               if (timeout_cnt == 0)
+                       printk(KERN_ERR DRV_NAME
+                                       ": fails to timestamp the TX packet\n");
+               else {
+                       struct skb_shared_hwtstamps shhwtstamps;
+                       u64 ns;
+                       u64 regval;
+
+                       regval = bfin_read_EMAC_PTP_TXSNAPLO();
+                       regval |= (u64)bfin_read_EMAC_PTP_TXSNAPHI() << 32;
+                       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+                       ns = timecounter_cyc2time(&lp->clock,
+                                       regval);
+                       timecompare_update(&lp->compare, ns);
+                       shhwtstamps.hwtstamp = ns_to_ktime(ns);
+                       shhwtstamps.syststamp =
+                               timecompare_transform(&lp->compare, ns);
+                       skb_tstamp_tx(skb, &shhwtstamps);
+
+                       bfin_dump_hwtamp("TX", &shhwtstamps.hwtstamp, &shhwtstamps.syststamp, &lp->compare);
+               }
+       }
+}
+
+static void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
+{
+       struct bfin_mac_local *lp = netdev_priv(netdev);
+       u32 valid;
+       u64 regval, ns;
+       struct skb_shared_hwtstamps *shhwtstamps;
+
+       if (bfin_mac_hwtstamp_is_none(lp->stamp_cfg.rx_filter))
+               return;
+
+       valid = bfin_read_EMAC_PTP_ISTAT() & RXEL;
+       if (!valid)
+               return;
+
+       shhwtstamps = skb_hwtstamps(skb);
+
+       regval = bfin_read_EMAC_PTP_RXSNAPLO();
+       regval |= (u64)bfin_read_EMAC_PTP_RXSNAPHI() << 32;
+       ns = timecounter_cyc2time(&lp->clock, regval);
+       timecompare_update(&lp->compare, ns);
+       memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+       shhwtstamps->hwtstamp = ns_to_ktime(ns);
+       shhwtstamps->syststamp = timecompare_transform(&lp->compare, ns);
+
+       bfin_dump_hwtamp("RX", &shhwtstamps->hwtstamp, &shhwtstamps->syststamp, &lp->compare);
+}
+
+/*
+ * bfin_read_clock - read raw cycle counter (to be used by time counter)
+ */
+static cycle_t bfin_read_clock(const struct cyclecounter *tc)
+{
+       u64 stamp;
+
+       stamp =  bfin_read_EMAC_PTP_TIMELO();
+       stamp |= (u64)bfin_read_EMAC_PTP_TIMEHI() << 32ULL;
+
+       return stamp;
+}
+
+#define PTP_CLK 25000000
+
+static void bfin_mac_hwtstamp_init(struct net_device *netdev)
+{
+       struct bfin_mac_local *lp = netdev_priv(netdev);
+       u64 append;
+
+       /* Initialize hardware timer */
+       append = PTP_CLK * (1ULL << 32);
+       do_div(append, get_sclk());
+       bfin_write_EMAC_PTP_ADDEND((u32)append);
+
+       memset(&lp->cycles, 0, sizeof(lp->cycles));
+       lp->cycles.read = bfin_read_clock;
+       lp->cycles.mask = CLOCKSOURCE_MASK(64);
+       lp->cycles.mult = 1000000000 / PTP_CLK;
+       lp->cycles.shift = 0;
+
+       /* Synchronize our NIC clock against system wall clock */
+       memset(&lp->compare, 0, sizeof(lp->compare));
+       lp->compare.source = &lp->clock;
+       lp->compare.target = ktime_get_real;
+       lp->compare.num_samples = 10;
+
+       /* Initialize hwstamp config */
+       lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
+       lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
+}
+
+#else
+# define bfin_mac_hwtstamp_is_none(cfg) 0
+# define bfin_mac_hwtstamp_init(dev)
+# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP)
+# define bfin_rx_hwtstamp(dev, skb)
+# define bfin_tx_hwtstamp(dev, skb)
+#endif
+
 static void adjust_tx_list(void)
 {
        int timeout_cnt = MAX_TIMEOUT_CNT;
@@ -608,18 +979,32 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
 {
        u16 *data;
        u32 data_align = (unsigned long)(skb->data) & 0x3;
+       union skb_shared_tx *shtx = skb_tx(skb);
+
        current_tx_ptr->skb = skb;
 
        if (data_align == 0x2) {
                /* move skb->data to current_tx_ptr payload */
                data = (u16 *)(skb->data) - 1;
-                               *data = (u16)(skb->len);
+               *data = (u16)(skb->len);
+               /*
+                * When transmitting an Ethernet packet, the PTP_TSYNC module requires
+                * a DMA_Length_Word field associated with the packet. The lower 12 bits
+                * of this field are the length of the packet payload in bytes and the higher
+                * 4 bits are the timestamping enable field.
+                */
+               if (shtx->hardware)
+                       *data |= 0x1000;
+
                current_tx_ptr->desc_a.start_addr = (u32)data;
                /* this is important! */
                blackfin_dcache_flush_range((u32)data,
                                (u32)((u8 *)data + skb->len + 4));
        } else {
                *((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
+               /* enable timestamping for the sent packet */
+               if (shtx->hardware)
+                       *((u16 *)(current_tx_ptr->packet)) |= 0x1000;
                memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
                        skb->len);
                current_tx_ptr->desc_a.start_addr =
@@ -653,20 +1038,42 @@ static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
 
 out:
        adjust_tx_list();
+
+       bfin_tx_hwtstamp(dev, skb);
+
        current_tx_ptr = current_tx_ptr->next;
-       dev->trans_start = jiffies;
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += (skb->len);
        return NETDEV_TX_OK;
 }
 
+#define IP_HEADER_OFF  0
+#define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \
+       RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE)
+
 static void bfin_mac_rx(struct net_device *dev)
 {
        struct sk_buff *skb, *new_skb;
        unsigned short len;
+       struct bfin_mac_local *lp __maybe_unused = netdev_priv(dev);
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+       unsigned int i;
+       unsigned char fcs[ETH_FCS_LEN + 1];
+#endif
+
+       /* check if frame status word reports an error condition
+        * we which case we simply drop the packet
+        */
+       if (current_rx_ptr->status.status_word & RX_ERROR_MASK) {
+               printk(KERN_NOTICE DRV_NAME
+                      ": rx: receive error - packet dropped\n");
+               dev->stats.rx_dropped++;
+               goto out;
+       }
 
        /* allocate a new skb for next time receive */
        skb = current_rx_ptr->skb;
+
        new_skb = dev_alloc_skb(PKT_BUF_SZ + NET_IP_ALIGN);
        if (!new_skb) {
                printk(KERN_NOTICE DRV_NAME
@@ -676,34 +1083,59 @@ static void bfin_mac_rx(struct net_device *dev)
        }
        /* reserve 2 bytes for RXDWA padding */
        skb_reserve(new_skb, NET_IP_ALIGN);
-       current_rx_ptr->skb = new_skb;
-       current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
-
        /* Invidate the data cache of skb->data range when it is write back
         * cache. It will prevent overwritting the new data from DMA
         */
        blackfin_dcache_invalidate_range((unsigned long)new_skb->head,
                                         (unsigned long)new_skb->end);
 
+       current_rx_ptr->skb = new_skb;
+       current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
+
        len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
+       /* Deduce Ethernet FCS length from Ethernet payload length */
+       len -= ETH_FCS_LEN;
        skb_put(skb, len);
-       blackfin_dcache_invalidate_range((unsigned long)skb->head,
-                                        (unsigned long)skb->tail);
 
        skb->protocol = eth_type_trans(skb, dev);
+
+       bfin_rx_hwtstamp(dev, skb);
+
 #if defined(BFIN_MAC_CSUM_OFFLOAD)
-       skb->csum = current_rx_ptr->status.ip_payload_csum;
-       skb->ip_summed = CHECKSUM_COMPLETE;
+       /* Checksum offloading only works for IPv4 packets with the standard IP header
+        * length of 20 bytes, because the blackfin MAC checksum calculation is
+        * based on that assumption. We must NOT use the calculated checksum if our
+        * IP version or header break that assumption.
+        */
+       if (skb->data[IP_HEADER_OFF] == 0x45) {
+               skb->csum = current_rx_ptr->status.ip_payload_csum;
+               /*
+                * Deduce Ethernet FCS from hardware generated IP payload checksum.
+                * IP checksum is based on 16-bit one's complement algorithm.
+                * To deduce a value from checksum is equal to add its inversion.
+                * If the IP payload len is odd, the inversed FCS should also
+                * begin from odd address and leave first byte zero.
+                */
+               if (skb->len % 2) {
+                       fcs[0] = 0;
+                       for (i = 0; i < ETH_FCS_LEN; i++)
+                               fcs[i + 1] = ~skb->data[skb->len + i];
+                       skb->csum = csum_partial(fcs, ETH_FCS_LEN + 1, skb->csum);
+               } else {
+                       for (i = 0; i < ETH_FCS_LEN; i++)
+                               fcs[i] = ~skb->data[skb->len + i];
+                       skb->csum = csum_partial(fcs, ETH_FCS_LEN, skb->csum);
+               }
+               skb->ip_summed = CHECKSUM_COMPLETE;
+       }
 #endif
 
        netif_rx(skb);
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += len;
+out:
        current_rx_ptr->status.status_word = 0x00000000;
        current_rx_ptr = current_rx_ptr->next;
-
-out:
-       return;
 }
 
 /* interrupt routine to handle rx and error signal */
@@ -755,8 +1187,9 @@ static void bfin_mac_disable(void)
 /*
  * Enable Interrupts, Receive, and Transmit
  */
-static void bfin_mac_enable(void)
+static int bfin_mac_enable(void)
 {
+       int ret;
        u32 opmode;
 
        pr_debug("%s: %s\n", DRV_NAME, __func__);
@@ -766,7 +1199,9 @@ static void bfin_mac_enable(void)
        bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
 
        /* Wait MII done */
-       bfin_mdio_poll();
+       ret = bfin_mdio_poll();
+       if (ret)
+               return ret;
 
        /* We enable only RX here */
        /* ASTP   : Enable Automatic Pad Stripping
@@ -790,6 +1225,8 @@ static void bfin_mac_enable(void)
 #endif
        /* Turn on the EMAC rx */
        bfin_write_EMAC_OPMODE(opmode);
+
+       return 0;
 }
 
 /* Our watchdog timed out. Called by the networking layer */
@@ -805,21 +1242,21 @@ static void bfin_mac_timeout(struct net_device *dev)
        bfin_mac_enable();
 
        /* We can accept TX packets again */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
 static void bfin_mac_multicast_hash(struct net_device *dev)
 {
        u32 emac_hashhi, emac_hashlo;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        u32 crc;
 
        emac_hashhi = emac_hashlo = 0;
 
-       netdev_for_each_mc_addr(dmi, dev) {
-               addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrs = ha->addr;
 
                /* skip non-multicast addresses */
                if (!(*addrs & 1))
@@ -836,8 +1273,6 @@ static void bfin_mac_multicast_hash(struct net_device *dev)
 
        bfin_write_EMAC_HASHHI(emac_hashhi);
        bfin_write_EMAC_HASHLO(emac_hashlo);
-
-       return;
 }
 
 /*
@@ -853,7 +1288,7 @@ static void bfin_mac_set_multicast_list(struct net_device *dev)
        if (dev->flags & IFF_PROMISC) {
                printk(KERN_INFO "%s: set to promisc mode\n", dev->name);
                sysctl = bfin_read_EMAC_OPMODE();
-               sysctl |= RAF;
+               sysctl |= PR;
                bfin_write_EMAC_OPMODE(sysctl);
        } else if (dev->flags & IFF_ALLMULTI) {
                /* accept all multicast */
@@ -874,6 +1309,16 @@ static void bfin_mac_set_multicast_list(struct net_device *dev)
        }
 }
 
+static int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       case SIOCSHWTSTAMP:
+               return bfin_mac_hwtstamp_ioctl(netdev, ifr, cmd);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 /*
  * this puts the device in an inactive state
  */
@@ -894,7 +1339,7 @@ static void bfin_mac_shutdown(struct net_device *dev)
 static int bfin_mac_open(struct net_device *dev)
 {
        struct bfin_mac_local *lp = netdev_priv(dev);
-       int retval;
+       int ret;
        pr_debug("%s: %s\n", dev->name, __func__);
 
        /*
@@ -908,18 +1353,21 @@ static int bfin_mac_open(struct net_device *dev)
        }
 
        /* initial rx and tx list */
-       retval = desc_list_init();
-
-       if (retval)
-               return retval;
+       ret = desc_list_init();
+       if (ret)
+               return ret;
 
        phy_start(lp->phydev);
        phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
        setup_system_regs(dev);
        setup_mac_addr(dev->dev_addr);
+
        bfin_mac_disable();
-       bfin_mac_enable();
+       ret = bfin_mac_enable();
+       if (ret)
+               return ret;
        pr_debug("hardware init finished\n");
+
        netif_start_queue(dev);
        netif_carrier_on(dev);
 
@@ -958,6 +1406,7 @@ static const struct net_device_ops bfin_mac_netdev_ops = {
        .ndo_set_mac_address    = bfin_mac_set_mac_address,
        .ndo_tx_timeout         = bfin_mac_timeout,
        .ndo_set_multicast_list = bfin_mac_set_multicast_list,
+       .ndo_do_ioctl           = bfin_mac_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1017,6 +1466,11 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
        }
        pd = pdev->dev.platform_data;
        lp->mii_bus = platform_get_drvdata(pd);
+       if (!lp->mii_bus) {
+               dev_err(&pdev->dev, "Cannot get mii_bus!\n");
+               rc = -ENODEV;
+               goto out_err_mii_bus_probe;
+       }
        lp->mii_bus->priv = ndev;
 
        rc = mii_probe(ndev);
@@ -1049,6 +1503,8 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
                goto out_err_reg_ndev;
        }
 
+       bfin_mac_hwtstamp_init(ndev);
+
        /* now, print out the card info, in a short format.. */
        dev_info(&pdev->dev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
 
@@ -1060,6 +1516,7 @@ out_err_request_irq:
 out_err_mii_probe:
        mdiobus_unregister(lp->mii_bus);
        mdiobus_free(lp->mii_bus);
+out_err_mii_bus_probe:
        peripheral_free_list(pin_req);
 out_err_probe_mac:
        platform_set_drvdata(pdev, NULL);
@@ -1092,9 +1549,16 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
 static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
 {
        struct net_device *net_dev = platform_get_drvdata(pdev);
+       struct bfin_mac_local *lp = netdev_priv(net_dev);
 
-       if (netif_running(net_dev))
-               bfin_mac_close(net_dev);
+       if (lp->wol) {
+               bfin_write_EMAC_OPMODE((bfin_read_EMAC_OPMODE() & ~TE) | RE);
+               bfin_write_EMAC_WKUP_CTL(MPKE);
+               enable_irq_wake(IRQ_MAC_WAKEDET);
+       } else {
+               if (netif_running(net_dev))
+                       bfin_mac_close(net_dev);
+       }
 
        return 0;
 }
@@ -1102,9 +1566,16 @@ static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
 static int bfin_mac_resume(struct platform_device *pdev)
 {
        struct net_device *net_dev = platform_get_drvdata(pdev);
+       struct bfin_mac_local *lp = netdev_priv(net_dev);
 
-       if (netif_running(net_dev))
-               bfin_mac_open(net_dev);
+       if (lp->wol) {
+               bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
+               bfin_write_EMAC_WKUP_CTL(0);
+               disable_irq_wake(IRQ_MAC_WAKEDET);
+       } else {
+               if (netif_running(net_dev))
+                       bfin_mac_open(net_dev);
+       }
 
        return 0;
 }
index 052b5dce3e3c8a865c2d351d86450dc2976fd3c2..1ae7b82ceeee716b98c18f7f42d4cd6a6f8ccc74 100644 (file)
@@ -7,6 +7,12 @@
  *
  * Licensed under the GPL-2 or later.
  */
+#ifndef _BFIN_MAC_H_
+#define _BFIN_MAC_H_
+
+#include <linux/net_tstamp.h>
+#include <linux/clocksource.h>
+#include <linux/timecompare.h>
 
 #define BFIN_MAC_CSUM_OFFLOAD
 
@@ -60,6 +66,9 @@ struct bfin_mac_local {
        unsigned char Mac[6];   /* MAC address of the board */
        spinlock_t lock;
 
+       int wol;                /* Wake On Lan */
+       int irq_wake_requested;
+
        /* MII and PHY stuffs */
        int old_link;          /* used by bf537_adjust_link */
        int old_speed;
@@ -67,6 +76,15 @@ struct bfin_mac_local {
 
        struct phy_device *phydev;
        struct mii_bus *mii_bus;
+
+#if defined(CONFIG_BFIN_MAC_USE_HWSTAMP)
+       struct cyclecounter cycles;
+       struct timecounter clock;
+       struct timecompare compare;
+       struct hwtstamp_config stamp_cfg;
+#endif
 };
 
 extern void bfin_get_ether_addr(char *addr);
+
+#endif
index 598b007f1991dfac42c54bd0e263f2b1694176cc..39250b2ca886e9c7216ffcc956870c1320f85d0e 100644 (file)
@@ -167,7 +167,6 @@ static inline void
 dbdma_st32(volatile __u32 __iomem *a, unsigned long x)
 {
        __asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory");
-       return;
 }
 
 static inline unsigned long
@@ -382,8 +381,6 @@ bmac_init_registers(struct net_device *dev)
        bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets);
 
        bmwrite(dev, INTDISABLE, EnableNormal);
-
-       return;
 }
 
 #if 0
@@ -972,7 +969,7 @@ bmac_remove_multi(struct net_device *dev,
  */
 static void bmac_set_multicast(struct net_device *dev)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        struct bmac_data *bp = netdev_priv(dev);
        int num_addrs = netdev_mc_count(dev);
        unsigned short rx_cfg;
@@ -1001,8 +998,8 @@ static void bmac_set_multicast(struct net_device *dev)
                        rx_cfg = bmac_rx_on(dev, 0, 0);
                        XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg));
                } else {
-                       netdev_for_each_mc_addr(dmi, dev)
-                               bmac_addhash(bp, dmi->dmi_addr);
+                       netdev_for_each_mc_addr(ha, dev)
+                               bmac_addhash(bp, ha->addr);
                        bmac_update_hash_table_mask(dev, bp);
                        rx_cfg = bmac_rx_on(dev, 1, 0);
                        XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg));
@@ -1016,7 +1013,7 @@ static void bmac_set_multicast(struct net_device *dev)
 
 static void bmac_set_multicast(struct net_device *dev)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        int i;
        unsigned short rx_cfg;
@@ -1040,8 +1037,8 @@ static void bmac_set_multicast(struct net_device *dev)
 
                for(i = 0; i < 4; i++) hash_table[i] = 0;
 
-               netdev_for_each_mc_addr(dmi, dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       addrs = ha->addr;
 
                        if(!(*addrs & 1))
                                continue;
index ac90a3828f69fd3f56efd3443a785b15af0ffb1e..188e356c30a30e005a69eaf05997ea57fdae880e 100644 (file)
 #include "bnx2_fw.h"
 
 #define DRV_MODULE_NAME                "bnx2"
-#define DRV_MODULE_VERSION     "2.0.9"
-#define DRV_MODULE_RELDATE     "April 27, 2010"
+#define DRV_MODULE_VERSION     "2.0.15"
+#define DRV_MODULE_RELDATE     "May 4, 2010"
 #define FW_MIPS_FILE_06                "bnx2/bnx2-mips-06-5.0.0.j6.fw"
 #define FW_RV2P_FILE_06                "bnx2/bnx2-rv2p-06-5.0.0.j3.fw"
-#define FW_MIPS_FILE_09                "bnx2/bnx2-mips-09-5.0.0.j9.fw"
+#define FW_MIPS_FILE_09                "bnx2/bnx2-mips-09-5.0.0.j15.fw"
 #define FW_RV2P_FILE_09_Ax     "bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw"
 #define FW_RV2P_FILE_09                "bnx2/bnx2-rv2p-09-5.0.0.j10.fw"
 
@@ -656,19 +656,11 @@ bnx2_netif_stop(struct bnx2 *bp, bool stop_cnic)
        if (stop_cnic)
                bnx2_cnic_stop(bp);
        if (netif_running(bp->dev)) {
-               int i;
-
                bnx2_napi_disable(bp);
                netif_tx_disable(bp->dev);
-               /* prevent tx timeout */
-               for (i = 0; i <  bp->dev->num_tx_queues; i++) {
-                       struct netdev_queue *txq;
-
-                       txq = netdev_get_tx_queue(bp->dev, i);
-                       txq->trans_start = jiffies;
-               }
        }
        bnx2_disable_int_sync(bp);
+       netif_carrier_off(bp->dev);     /* prevent tx timeout */
 }
 
 static void
@@ -677,6 +669,10 @@ bnx2_netif_start(struct bnx2 *bp, bool start_cnic)
        if (atomic_dec_and_test(&bp->intr_sem)) {
                if (netif_running(bp->dev)) {
                        netif_tx_wake_all_queues(bp->dev);
+                       spin_lock_bh(&bp->phy_lock);
+                       if (bp->link_up)
+                               netif_carrier_on(bp->dev);
+                       spin_unlock_bh(&bp->phy_lock);
                        bnx2_napi_enable(bp);
                        bnx2_enable_int(bp);
                        if (start_cnic)
@@ -2672,7 +2668,7 @@ bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
        }
 
        rx_pg->page = page;
-       pci_unmap_addr_set(rx_pg, mapping, mapping);
+       dma_unmap_addr_set(rx_pg, mapping, mapping);
        rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
        rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
        return 0;
@@ -2687,7 +2683,7 @@ bnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
        if (!page)
                return;
 
-       pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE,
+       pci_unmap_page(bp->pdev, dma_unmap_addr(rx_pg, mapping), PAGE_SIZE,
                       PCI_DMA_FROMDEVICE);
 
        __free_page(page);
@@ -2719,7 +2715,8 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
        }
 
        rx_buf->skb = skb;
-       pci_unmap_addr_set(rx_buf, mapping, mapping);
+       rx_buf->desc = (struct l2_fhdr *) skb->data;
+       dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
        rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
@@ -2818,7 +2815,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                        }
                }
 
-               pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
+               pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
                        skb_headlen(skb), PCI_DMA_TODEVICE);
 
                tx_buf->skb = NULL;
@@ -2828,7 +2825,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                        sw_cons = NEXT_TX_BD(sw_cons);
 
                        pci_unmap_page(bp->pdev,
-                               pci_unmap_addr(
+                               dma_unmap_addr(
                                        &txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
                                        mapping),
                                skb_shinfo(skb)->frags[i].size,
@@ -2910,8 +2907,8 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
                if (prod != cons) {
                        prod_rx_pg->page = cons_rx_pg->page;
                        cons_rx_pg->page = NULL;
-                       pci_unmap_addr_set(prod_rx_pg, mapping,
-                               pci_unmap_addr(cons_rx_pg, mapping));
+                       dma_unmap_addr_set(prod_rx_pg, mapping,
+                               dma_unmap_addr(cons_rx_pg, mapping));
 
                        prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
                        prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
@@ -2935,18 +2932,19 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
        prod_rx_buf = &rxr->rx_buf_ring[prod];
 
        pci_dma_sync_single_for_device(bp->pdev,
-               pci_unmap_addr(cons_rx_buf, mapping),
+               dma_unmap_addr(cons_rx_buf, mapping),
                BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
 
        rxr->rx_prod_bseq += bp->rx_buf_use_size;
 
        prod_rx_buf->skb = skb;
+       prod_rx_buf->desc = (struct l2_fhdr *) skb->data;
 
        if (cons == prod)
                return;
 
-       pci_unmap_addr_set(prod_rx_buf, mapping,
-                       pci_unmap_addr(cons_rx_buf, mapping));
+       dma_unmap_addr_set(prod_rx_buf, mapping,
+                       dma_unmap_addr(cons_rx_buf, mapping));
 
        cons_bd = &rxr->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
        prod_bd = &rxr->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
@@ -3019,7 +3017,7 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
                        /* Don't unmap yet.  If we're unable to allocate a new
                         * page, we need to recycle the page and the DMA addr.
                         */
-                       mapping_old = pci_unmap_addr(rx_pg, mapping);
+                       mapping_old = dma_unmap_addr(rx_pg, mapping);
                        if (i == pages - 1)
                                frag_len -= 4;
 
@@ -3074,6 +3072,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
        u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
        struct l2_fhdr *rx_hdr;
        int rx_pkt = 0, pg_ring_used = 0;
+       struct pci_dev *pdev = bp->pdev;
 
        hw_cons = bnx2_get_hw_rx_cons(bnapi);
        sw_cons = rxr->rx_cons;
@@ -3086,7 +3085,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
        while (sw_cons != hw_cons) {
                unsigned int len, hdr_len;
                u32 status;
-               struct sw_bd *rx_buf;
+               struct sw_bd *rx_buf, *next_rx_buf;
                struct sk_buff *skb;
                dma_addr_t dma_addr;
                u16 vtag = 0;
@@ -3097,16 +3096,23 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 
                rx_buf = &rxr->rx_buf_ring[sw_ring_cons];
                skb = rx_buf->skb;
+               prefetchw(skb);
 
+               if (!get_dma_ops(&pdev->dev)->sync_single_for_cpu) {
+                       next_rx_buf =
+                               &rxr->rx_buf_ring[
+                                       RX_RING_IDX(NEXT_RX_BD(sw_cons))];
+                       prefetch(next_rx_buf->desc);
+               }
                rx_buf->skb = NULL;
 
-               dma_addr = pci_unmap_addr(rx_buf, mapping);
+               dma_addr = dma_unmap_addr(rx_buf, mapping);
 
                pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
                        BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH,
                        PCI_DMA_FROMDEVICE);
 
-               rx_hdr = (struct l2_fhdr *) skb->data;
+               rx_hdr = rx_buf->desc;
                len = rx_hdr->l2_fhdr_pkt_len;
                status = rx_hdr->l2_fhdr_status;
 
@@ -3207,10 +3213,10 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
 
 #ifdef BCM_VLAN
                if (hw_vlan)
-                       vlan_hwaccel_receive_skb(skb, bp->vlgrp, vtag);
+                       vlan_gro_receive(&bnapi->napi, bp->vlgrp, vtag, skb);
                else
 #endif
-                       netif_receive_skb(skb);
+                       napi_gro_receive(&bnapi->napi, skb);
 
                rx_pkt++;
 
@@ -3548,7 +3554,6 @@ bnx2_set_rx_mode(struct net_device *dev)
        }
        else {
                /* Accept one or more multicast(s). */
-               struct dev_mc_list *mclist;
                u32 mc_filter[NUM_MC_HASH_REGISTERS];
                u32 regidx;
                u32 bit;
@@ -3556,8 +3561,8 @@ bnx2_set_rx_mode(struct net_device *dev)
 
                memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
 
-               netdev_for_each_mc_addr(mclist, dev) {
-                       crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       crc = ether_crc_le(ETH_ALEN, ha->addr);
                        bit = crc & 0xff;
                        regidx = (bit & 0xe0) >> 5;
                        bit &= 0x1f;
@@ -5318,7 +5323,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
                        }
 
                        pci_unmap_single(bp->pdev,
-                                        pci_unmap_addr(tx_buf, mapping),
+                                        dma_unmap_addr(tx_buf, mapping),
                                         skb_headlen(skb),
                                         PCI_DMA_TODEVICE);
 
@@ -5329,7 +5334,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
                        for (k = 0; k < last; k++, j++) {
                                tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)];
                                pci_unmap_page(bp->pdev,
-                                       pci_unmap_addr(tx_buf, mapping),
+                                       dma_unmap_addr(tx_buf, mapping),
                                        skb_shinfo(skb)->frags[k].size,
                                        PCI_DMA_TODEVICE);
                        }
@@ -5359,7 +5364,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
                                continue;
 
                        pci_unmap_single(bp->pdev,
-                                        pci_unmap_addr(rx_buf, mapping),
+                                        dma_unmap_addr(rx_buf, mapping),
                                         bp->rx_buf_use_size,
                                         PCI_DMA_FROMDEVICE);
 
@@ -5765,11 +5770,11 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
        rx_buf = &rxr->rx_buf_ring[rx_start_idx];
        rx_skb = rx_buf->skb;
 
-       rx_hdr = (struct l2_fhdr *) rx_skb->data;
+       rx_hdr = rx_buf->desc;
        skb_reserve(rx_skb, BNX2_RX_OFFSET);
 
        pci_dma_sync_single_for_cpu(bp->pdev,
-               pci_unmap_addr(rx_buf, mapping),
+               dma_unmap_addr(rx_buf, mapping),
                bp->rx_buf_size, PCI_DMA_FROMDEVICE);
 
        if (rx_hdr->l2_fhdr_status &
@@ -6292,14 +6297,23 @@ static void
 bnx2_dump_state(struct bnx2 *bp)
 {
        struct net_device *dev = bp->dev;
+       u32 mcp_p0, mcp_p1;
 
        netdev_err(dev, "DEBUG: intr_sem[%x]\n", atomic_read(&bp->intr_sem));
-       netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] RPM_MGMT_PKT_CTRL[%08x]\n",
+       netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n",
                   REG_RD(bp, BNX2_EMAC_TX_STATUS),
+                  REG_RD(bp, BNX2_EMAC_RX_STATUS));
+       netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n",
                   REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL));
+       if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+               mcp_p0 = BNX2_MCP_STATE_P0;
+               mcp_p1 = BNX2_MCP_STATE_P1;
+       } else {
+               mcp_p0 = BNX2_MCP_STATE_P0_5708;
+               mcp_p1 = BNX2_MCP_STATE_P1_5708;
+       }
        netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n",
-                  bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0),
-                  bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1));
+                  bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1));
        netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n",
                   REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS));
        if (bp->flags & BNX2_FLAG_USING_MSIX)
@@ -6429,7 +6443,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        tx_buf = &txr->tx_buf_ring[ring_prod];
        tx_buf->skb = skb;
-       pci_unmap_addr_set(tx_buf, mapping, mapping);
+       dma_unmap_addr_set(tx_buf, mapping, mapping);
 
        txbd = &txr->tx_desc_ring[ring_prod];
 
@@ -6454,7 +6468,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        len, PCI_DMA_TODEVICE);
                if (pci_dma_mapping_error(bp->pdev, mapping))
                        goto dma_error;
-               pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
+               dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping,
                                   mapping);
 
                txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
@@ -6491,7 +6505,7 @@ dma_error:
        ring_prod = TX_RING_IDX(prod);
        tx_buf = &txr->tx_buf_ring[ring_prod];
        tx_buf->skb = NULL;
-       pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
+       pci_unmap_single(bp->pdev, dma_unmap_addr(tx_buf, mapping),
                         skb_headlen(skb), PCI_DMA_TODEVICE);
 
        /* unmap remaining mapped pages */
@@ -6499,7 +6513,7 @@ dma_error:
                prod = NEXT_TX_BD(prod);
                ring_prod = TX_RING_IDX(prod);
                tx_buf = &txr->tx_buf_ring[ring_prod];
-               pci_unmap_page(bp->pdev, pci_unmap_addr(tx_buf, mapping),
+               pci_unmap_page(bp->pdev, dma_unmap_addr(tx_buf, mapping),
                               skb_shinfo(skb)->frags[i].size,
                               PCI_DMA_TODEVICE);
        }
@@ -8297,7 +8311,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        memcpy(dev->dev_addr, bp->mac_addr, 6);
        memcpy(dev->perm_addr, bp->mac_addr, 6);
 
-       dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+       dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_GRO;
        vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
        if (CHIP_NUM(bp) == CHIP_NUM_5709) {
                dev->features |= NETIF_F_IPV6_CSUM;
index cd4b0e4637ab4aad478ca72304a42a36ecd29667..ddaa3fc99876bbc183a02a2d5769131a525eac64 100644 (file)
@@ -6347,6 +6347,8 @@ struct l2_fhdr {
 #define BNX2_MCP_SCRATCH                               0x00160000
 #define BNX2_MCP_STATE_P1                               0x0016f9c8
 #define BNX2_MCP_STATE_P0                               0x0016fdc8
+#define BNX2_MCP_STATE_P1_5708                          0x001699c8
+#define BNX2_MCP_STATE_P0_5708                          0x00169dc8
 
 #define BNX2_SHM_HDR_SIGNATURE                         BNX2_MCP_SCRATCH
 #define BNX2_SHM_HDR_SIGNATURE_SIG_MASK                         0xffff0000
@@ -6551,17 +6553,18 @@ struct l2_fhdr {
 
 struct sw_bd {
        struct sk_buff          *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       struct l2_fhdr          *desc;
+       DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
 struct sw_pg {
        struct page             *page;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
 struct sw_tx_bd {
        struct sk_buff          *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
        unsigned short          is_gso;
        unsigned short          nr_frags;
 };
index 3c48a7a683086fecf1b5b3eba52e0de89af7d016..8bd23687c530f2e244c7050091d14c05b8fa7901 100644 (file)
 #define BCM_VLAN                       1
 #endif
 
+#define BNX2X_MULTI_QUEUE
+
+#define BNX2X_NEW_NAPI
+
+
+
 #if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
 #define BCM_CNIC 1
 #include "cnic_if.h"
 #endif
 
-#define BNX2X_MULTI_QUEUE
-
-#define BNX2X_NEW_NAPI
-
 
+#ifdef BCM_CNIC
+#define BNX2X_MIN_MSIX_VEC_CNT 3
+#define BNX2X_MSIX_VEC_FP_START 2
+#else
+#define BNX2X_MIN_MSIX_VEC_CNT 2
+#define BNX2X_MSIX_VEC_FP_START 1
+#endif
 
 #include <linux/mdio.h>
 #include "bnx2x_reg.h"
@@ -83,7 +92,12 @@ do {                                                         \
               __func__, __LINE__,                              \
               bp->dev ? (bp->dev->name) : "?",                 \
               ##__args);                                       \
-} while (0)
+       } while (0)
+
+#define BNX2X_ERROR(__fmt, __args...) do { \
+       pr_err("[%s:%d]" __fmt, __func__, __LINE__, ##__args); \
+       } while (0)
+
 
 /* before we have a dev->name use dev_info() */
 #define BNX2X_DEV_INFO(__fmt, __args...)                        \
@@ -155,15 +169,21 @@ do {                                                               \
 #define SHMEM2_RD(bp, field)           REG_RD(bp, SHMEM2_ADDR(bp, field))
 #define SHMEM2_WR(bp, field, val)      REG_WR(bp, SHMEM2_ADDR(bp, field), val)
 
+#define MF_CFG_RD(bp, field)           SHMEM_RD(bp, mf_cfg.field)
+#define MF_CFG_WR(bp, field, val)      SHMEM_WR(bp, mf_cfg.field, val)
+
 #define EMAC_RD(bp, reg)               REG_RD(bp, emac_base + reg)
 #define EMAC_WR(bp, reg, val)          REG_WR(bp, emac_base + reg, val)
 
+#define AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR \
+       AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR
+
 
 /* fast path */
 
 struct sw_rx_bd {
        struct sk_buff  *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
 struct sw_tx_bd {
@@ -176,7 +196,7 @@ struct sw_tx_bd {
 
 struct sw_rx_page {
        struct page     *page;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
 union db_prod {
@@ -261,7 +281,7 @@ struct bnx2x_eth_q_stats {
        u32 hw_csum_err;
 };
 
-#define BNX2X_NUM_Q_STATS              11
+#define BNX2X_NUM_Q_STATS              13
 #define Q_STATS_OFFSET32(stat_name) \
                        (offsetof(struct bnx2x_eth_q_stats, stat_name) / 4)
 
@@ -767,7 +787,7 @@ struct bnx2x_eth_stats {
        u32 nig_timer_max;
 };
 
-#define BNX2X_NUM_STATS                        41
+#define BNX2X_NUM_STATS                        43
 #define STATS_OFFSET32(stat_name) \
                        (offsetof(struct bnx2x_eth_stats, stat_name) / 4)
 
@@ -818,6 +838,12 @@ struct attn_route {
        u32     sig[4];
 };
 
+typedef enum {
+       BNX2X_RECOVERY_DONE,
+       BNX2X_RECOVERY_INIT,
+       BNX2X_RECOVERY_WAIT,
+} bnx2x_recovery_state_t;
+
 struct bnx2x {
        /* Fields used in the tx and intr/napi performance paths
         * are grouped together in the beginning of the structure
@@ -835,6 +861,9 @@ struct bnx2x {
        struct pci_dev          *pdev;
 
        atomic_t                intr_sem;
+
+       bnx2x_recovery_state_t  recovery_state;
+       int                     is_leader;
 #ifdef BCM_CNIC
        struct msix_entry       msix_table[MAX_CONTEXT+2];
 #else
@@ -842,7 +871,6 @@ struct bnx2x {
 #endif
 #define INT_MODE_INTx                  1
 #define INT_MODE_MSI                   2
-#define INT_MODE_MSIX                  3
 
        int                     tx_ring_size;
 
@@ -924,8 +952,7 @@ struct bnx2x {
        int                     mrrs;
 
        struct delayed_work     sp_task;
-       struct work_struct      reset_task;
-
+       struct delayed_work     reset_task;
        struct timer_list       timer;
        int                     current_interval;
 
@@ -961,6 +988,8 @@ struct bnx2x {
        u16                     rx_quick_cons_trip;
        u16                     rx_ticks_int;
        u16                     rx_ticks;
+/* Maximal coalescing timeout in us */
+#define BNX2X_MAX_COALESCE_TOUT                (0xf0*12)
 
        u32                     lin_cnt;
 
@@ -1075,6 +1104,7 @@ struct bnx2x {
 #define INIT_CSEM_INT_TABLE_DATA(bp)   (bp->csem_int_table_data)
 #define INIT_CSEM_PRAM_DATA(bp)                (bp->csem_pram_data)
 
+       char                    fw_ver[32];
        const struct firmware   *firmware;
 };
 
@@ -1125,6 +1155,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define LOAD_DIAG                      2
 #define UNLOAD_NORMAL                  0
 #define UNLOAD_CLOSE                   1
+#define UNLOAD_RECOVERY                 2
 
 
 /* DMAE command defines */
@@ -1152,7 +1183,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define DMAE_CMD_E1HVN_SHIFT           DMAE_COMMAND_E1HVN_SHIFT
 
 #define DMAE_LEN32_RD_MAX              0x80
-#define DMAE_LEN32_WR_MAX              0x400
+#define DMAE_LEN32_WR_MAX(bp)          (CHIP_IS_E1(bp) ? 0x400 : 0x2000)
 
 #define DMAE_COMP_VAL                  0xe0d0d0ae
 
@@ -1294,8 +1325,12 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                                 AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR | \
                                 AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR)
 
+#define HW_PRTY_ASSERT_SET_3 (AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY | \
+               AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY | \
+               AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY | \
+               AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY)
 
-#define MULTI_FLAGS(bp) \
+#define RSS_FLAGS(bp) \
                (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \
                 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \
                 TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \
@@ -1333,6 +1368,9 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define PXP2_REG_PXP2_INT_STS          PXP2_REG_PXP2_INT_STS_0
 #endif
 
+#define BNX2X_VPD_LEN                  128
+#define VENDOR_ID_LEN                  4
+
 /* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */
 
 #endif /* bnx2x.h */
index 32e79c359e8945795ad4a909245223fbcff07ac3..ff70be898765d79b5ca45e83332fb4bd810de948 100644 (file)
@@ -1594,7 +1594,7 @@ static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
                                MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
                pause_result |= (lp_pause &
                                 MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
-               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n",
+               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
                   pause_result);
                bnx2x_pause_resolve(vars, pause_result);
                if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE &&
@@ -1616,7 +1616,7 @@ static u8 bnx2x_ext_phy_resolve_fc(struct link_params *params,
                                MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7;
 
                        bnx2x_pause_resolve(vars, pause_result);
-                       DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x \n",
+                       DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n",
                                 pause_result);
                }
        }
@@ -1974,7 +1974,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params,
                }
        }
 
-       DP(NETIF_MSG_LINK, "gp_status 0x%x  phy_link_up %x line_speed %x \n",
+       DP(NETIF_MSG_LINK, "gp_status 0x%x  phy_link_up %x line_speed %x\n",
                 gp_status, vars->phy_link_up, vars->line_speed);
        DP(NETIF_MSG_LINK, "duplex %x  flow_ctrl 0x%x"
                 " autoneg 0x%x\n",
@@ -3852,7 +3852,7 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                                    SPEED_AUTO_NEG) &&
                                   ((params->speed_cap_mask &
                                     PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
-                               DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+                               DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
                                bnx2x_cl45_write(bp, params->port, ext_phy_type,
                                               ext_phy_addr, MDIO_AN_DEVAD,
                                               MDIO_AN_REG_ADV, 0x20);
@@ -4234,14 +4234,14 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                                      ext_phy_addr,
                                      MDIO_PMA_DEVAD,
                                      MDIO_PMA_REG_10G_CTRL2, &tmp1);
-                               DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
+                               DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1);
 
                        } else if ((params->req_line_speed ==
                                    SPEED_AUTO_NEG) &&
                                   ((params->speed_cap_mask &
                                     PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
 
-                               DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+                               DP(NETIF_MSG_LINK, "Setting 1G clause37\n");
                                bnx2x_cl45_write(bp, params->port, ext_phy_type,
                                               ext_phy_addr, MDIO_AN_DEVAD,
                                               MDIO_PMA_REG_8727_MISC_CTRL, 0);
index 6c042a72d6ccb0ef460bf5ad0700e3aedf7ff7ed..57ff5b3bcce6fcd58edc438998ea1bf1ca08ee63 100644 (file)
@@ -57,8 +57,8 @@
 #include "bnx2x_init_ops.h"
 #include "bnx2x_dump.h"
 
-#define DRV_MODULE_VERSION     "1.52.1-7"
-#define DRV_MODULE_RELDATE     "2010/02/28"
+#define DRV_MODULE_VERSION     "1.52.53-1"
+#define DRV_MODULE_RELDATE     "2010/18/04"
 #define BNX2X_BC_VER           0x040200
 
 #include <linux/firmware.h>
@@ -102,7 +102,8 @@ MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 
 static int int_mode;
 module_param(int_mode, int, 0);
-MODULE_PARM_DESC(int_mode, " Force interrupt mode (1 INT#x; 2 MSI)");
+MODULE_PARM_DESC(int_mode, " Force interrupt mode other then MSI-X "
+                               "(1 INT#x; 2 MSI)");
 
 static int dropless_fc;
 module_param(dropless_fc, int, 0);
@@ -352,13 +353,14 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
 void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
                               u32 addr, u32 len)
 {
+       int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
        int offset = 0;
 
-       while (len > DMAE_LEN32_WR_MAX) {
+       while (len > dmae_wr_max) {
                bnx2x_write_dmae(bp, phys_addr + offset,
-                                addr + offset, DMAE_LEN32_WR_MAX);
-               offset += DMAE_LEN32_WR_MAX * 4;
-               len -= DMAE_LEN32_WR_MAX;
+                                addr + offset, dmae_wr_max);
+               offset += dmae_wr_max * 4;
+               len -= dmae_wr_max;
        }
 
        bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
@@ -508,26 +510,31 @@ static int bnx2x_mc_assert(struct bnx2x *bp)
 
 static void bnx2x_fw_dump(struct bnx2x *bp)
 {
+       u32 addr;
        u32 mark, offset;
        __be32 data[9];
        int word;
 
-       mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104);
-       mark = ((mark + 0x3) & ~0x3);
+       if (BP_NOMCP(bp)) {
+               BNX2X_ERR("NO MCP - can not dump\n");
+               return;
+       }
+
+       addr = bp->common.shmem_base - 0x0800 + 4;
+       mark = REG_RD(bp, addr);
+       mark = MCP_REG_MCPR_SCRATCH + ((mark + 0x3) & ~0x3) - 0x08000000;
        pr_err("begin fw dump (mark 0x%x)\n", mark);
 
        pr_err("");
-       for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) {
+       for (offset = mark; offset <= bp->common.shmem_base; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
-                       data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
-                                                 offset + 4*word));
+                       data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
                pr_cont("%s", (char *)data);
        }
-       for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) {
+       for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
                for (word = 0; word < 8; word++)
-                       data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH +
-                                                 offset + 4*word));
+                       data[word] = htonl(REG_RD(bp, offset + 4*word));
                data[8] = 0x0;
                pr_cont("%s", (char *)data);
        }
@@ -546,9 +553,9 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
 
        /* Indices */
        /* Common */
-       BNX2X_ERR("def_c_idx(%u)  def_u_idx(%u)  def_x_idx(%u)"
-                 "  def_t_idx(%u)  def_att_idx(%u)  attn_state(%u)"
-                 "  spq_prod_idx(%u)\n",
+       BNX2X_ERR("def_c_idx(0x%x)  def_u_idx(0x%x)  def_x_idx(0x%x)"
+                 "  def_t_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)"
+                 "  spq_prod_idx(0x%x)\n",
                  bp->def_c_idx, bp->def_u_idx, bp->def_x_idx, bp->def_t_idx,
                  bp->def_att_idx, bp->attn_state, bp->spq_prod_idx);
 
@@ -556,14 +563,14 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
-               BNX2X_ERR("fp%d: rx_bd_prod(%x)  rx_bd_cons(%x)"
-                         "  *rx_bd_cons_sb(%x)  rx_comp_prod(%x)"
-                         "  rx_comp_cons(%x)  *rx_cons_sb(%x)\n",
+               BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)"
+                         "  *rx_bd_cons_sb(0x%x)  rx_comp_prod(0x%x)"
+                         "  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
                          i, fp->rx_bd_prod, fp->rx_bd_cons,
                          le16_to_cpu(*fp->rx_bd_cons_sb), fp->rx_comp_prod,
                          fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
-               BNX2X_ERR("      rx_sge_prod(%x)  last_max_sge(%x)"
-                         "  fp_u_idx(%x) *sb_u_idx(%x)\n",
+               BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)"
+                         "  fp_u_idx(0x%x) *sb_u_idx(0x%x)\n",
                          fp->rx_sge_prod, fp->last_max_sge,
                          le16_to_cpu(fp->fp_u_idx),
                          fp->status_blk->u_status_block.status_block_index);
@@ -573,12 +580,13 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
-               BNX2X_ERR("fp%d: tx_pkt_prod(%x)  tx_pkt_cons(%x)"
-                         "  tx_bd_prod(%x)  tx_bd_cons(%x)  *tx_cons_sb(%x)\n",
+               BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)"
+                         "  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)"
+                         "  *tx_cons_sb(0x%x)\n",
                          i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
                          fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb));
-               BNX2X_ERR("      fp_c_idx(%x)  *sb_c_idx(%x)"
-                         "  tx_db_prod(%x)\n", le16_to_cpu(fp->fp_c_idx),
+               BNX2X_ERR("     fp_c_idx(0x%x)  *sb_c_idx(0x%x)"
+                         "  tx_db_prod(0x%x)\n", le16_to_cpu(fp->fp_c_idx),
                          fp->status_blk->c_status_block.status_block_index,
                          fp->tx_db.data.prod);
        }
@@ -764,6 +772,40 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
  * General service functions
  */
 
+/* Return true if succeeded to acquire the lock */
+static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
+{
+       u32 lock_status;
+       u32 resource_bit = (1 << resource);
+       int func = BP_FUNC(bp);
+       u32 hw_lock_control_reg;
+
+       DP(NETIF_MSG_HW, "Trying to take a lock on resource %d\n", resource);
+
+       /* Validating that the resource is within range */
+       if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
+               DP(NETIF_MSG_HW,
+                  "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
+                  resource, HW_LOCK_MAX_RESOURCE_VALUE);
+               return -EINVAL;
+       }
+
+       if (func <= 5)
+               hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
+       else
+               hw_lock_control_reg =
+                               (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
+
+       /* Try to acquire the lock */
+       REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
+       lock_status = REG_RD(bp, hw_lock_control_reg);
+       if (lock_status & resource_bit)
+               return true;
+
+       DP(NETIF_MSG_HW, "Failed to get a lock on resource %d\n", resource);
+       return false;
+}
+
 static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
                                u8 storm, u16 index, u8 op, u8 update)
 {
@@ -842,7 +884,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        /* unmap first bd */
        DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
        tx_start_bd = &fp->tx_desc_ring[bd_idx].start_bd;
-       pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_start_bd),
+       dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
                         BD_UNMAP_LEN(tx_start_bd), PCI_DMA_TODEVICE);
 
        nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
@@ -872,8 +914,8 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 
                DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
                tx_data_bd = &fp->tx_desc_ring[bd_idx].reg_bd;
-               pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_data_bd),
-                              BD_UNMAP_LEN(tx_data_bd), PCI_DMA_TODEVICE);
+               dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd),
+                              BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE);
                if (--nbd)
                        bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
        }
@@ -1023,7 +1065,8 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
 
                default:
                        BNX2X_ERR("unexpected MC reply (%d)  "
-                                 "fp->state is %x\n", command, fp->state);
+                                 "fp[%d] state is %x\n",
+                                 command, fp->index, fp->state);
                        break;
                }
                mb(); /* force bnx2x_wait_ramrod() to see the change */
@@ -1086,7 +1129,7 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
        if (!page)
                return;
 
-       pci_unmap_page(bp->pdev, pci_unmap_addr(sw_buf, mapping),
+       dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping),
                       SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
        __free_pages(page, PAGES_PER_SGE_SHIFT);
 
@@ -1115,15 +1158,15 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
        if (unlikely(page == NULL))
                return -ENOMEM;
 
-       mapping = pci_map_page(bp->pdev, page, 0, SGE_PAGE_SIZE*PAGES_PER_SGE,
-                              PCI_DMA_FROMDEVICE);
+       mapping = dma_map_page(&bp->pdev->dev, page, 0,
+                              SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                __free_pages(page, PAGES_PER_SGE_SHIFT);
                return -ENOMEM;
        }
 
        sw_buf->page = page;
-       pci_unmap_addr_set(sw_buf, mapping, mapping);
+       dma_unmap_addr_set(sw_buf, mapping, mapping);
 
        sge->addr_hi = cpu_to_le32(U64_HI(mapping));
        sge->addr_lo = cpu_to_le32(U64_LO(mapping));
@@ -1143,15 +1186,15 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
        if (unlikely(skb == NULL))
                return -ENOMEM;
 
-       mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_size,
-                                PCI_DMA_FROMDEVICE);
+       mapping = dma_map_single(&bp->pdev->dev, skb->data, bp->rx_buf_size,
+                                DMA_FROM_DEVICE);
        if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
                dev_kfree_skb(skb);
                return -ENOMEM;
        }
 
        rx_buf->skb = skb;
-       pci_unmap_addr_set(rx_buf, mapping, mapping);
+       dma_unmap_addr_set(rx_buf, mapping, mapping);
 
        rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
@@ -1173,13 +1216,13 @@ static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp,
        struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons];
        struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod];
 
-       pci_dma_sync_single_for_device(bp->pdev,
-                                      pci_unmap_addr(cons_rx_buf, mapping),
-                                      RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
+       dma_sync_single_for_device(&bp->pdev->dev,
+                                  dma_unmap_addr(cons_rx_buf, mapping),
+                                  RX_COPY_THRESH, DMA_FROM_DEVICE);
 
        prod_rx_buf->skb = cons_rx_buf->skb;
-       pci_unmap_addr_set(prod_rx_buf, mapping,
-                          pci_unmap_addr(cons_rx_buf, mapping));
+       dma_unmap_addr_set(prod_rx_buf, mapping,
+                          dma_unmap_addr(cons_rx_buf, mapping));
        *prod_bd = *cons_bd;
 }
 
@@ -1283,9 +1326,9 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
        /* move empty skb from pool to prod and map it */
        prod_rx_buf->skb = fp->tpa_pool[queue].skb;
-       mapping = pci_map_single(bp->pdev, fp->tpa_pool[queue].skb->data,
-                                bp->rx_buf_size, PCI_DMA_FROMDEVICE);
-       pci_unmap_addr_set(prod_rx_buf, mapping, mapping);
+       mapping = dma_map_single(&bp->pdev->dev, fp->tpa_pool[queue].skb->data,
+                                bp->rx_buf_size, DMA_FROM_DEVICE);
+       dma_unmap_addr_set(prod_rx_buf, mapping, mapping);
 
        /* move partial skb from cons to pool (don't unmap yet) */
        fp->tpa_pool[queue] = *cons_rx_buf;
@@ -1302,7 +1345,7 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
 
 #ifdef BNX2X_STOP_ON_ERROR
        fp->tpa_queue_used |= (1 << queue);
-#ifdef __powerpc64__
+#ifdef _ASM_GENERIC_INT_L64_H
        DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n",
 #else
        DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n",
@@ -1331,8 +1374,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                                               max(frag_size, (u32)len_on_bd));
 
 #ifdef BNX2X_STOP_ON_ERROR
-       if (pages >
-           min((u32)8, (u32)MAX_SKB_FRAGS) * SGE_PAGE_SIZE * PAGES_PER_SGE) {
+       if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) {
                BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
                          pages, cqe_idx);
                BNX2X_ERR("fp_cqe->pkt_len = %d  fp_cqe->len_on_bd = %d\n",
@@ -1361,8 +1403,9 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                }
 
                /* Unmap the page as we r going to pass it to the stack */
-               pci_unmap_page(bp->pdev, pci_unmap_addr(&old_rx_pg, mapping),
-                             SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+               dma_unmap_page(&bp->pdev->dev,
+                              dma_unmap_addr(&old_rx_pg, mapping),
+                              SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE);
 
                /* Add one frag and update the appropriate fields in the skb */
                skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
@@ -1389,8 +1432,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
        /* Unmap skb in the pool anyway, as we are going to change
           pool entry status to BNX2X_TPA_STOP even if new skb allocation
           fails. */
-       pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
-                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+       dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping),
+                        bp->rx_buf_size, DMA_FROM_DEVICE);
 
        if (likely(new_skb)) {
                /* fix ip xsum and give it to the stack */
@@ -1441,12 +1484,12 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 #ifdef BCM_VLAN
                        if ((bp->vlgrp != NULL) && is_vlan_cqe &&
                            (!is_not_hwaccel_vlan_cqe))
-                               vlan_hwaccel_receive_skb(skb, bp->vlgrp,
-                                               le16_to_cpu(cqe->fast_path_cqe.
-                                                           vlan_tag));
+                               vlan_gro_receive(&fp->napi, bp->vlgrp,
+                                                le16_to_cpu(cqe->fast_path_cqe.
+                                                            vlan_tag), skb);
                        else
 #endif
-                               netif_receive_skb(skb);
+                               napi_gro_receive(&fp->napi, skb);
                } else {
                        DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
                           " - dropping packet!\n");
@@ -1539,7 +1582,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                struct sw_rx_bd *rx_buf = NULL;
                struct sk_buff *skb;
                union eth_rx_cqe *cqe;
-               u8 cqe_fp_flags;
+               u8 cqe_fp_flags, cqe_fp_status_flags;
                u16 len, pad;
 
                comp_ring_cons = RCQ_BD(sw_comp_cons);
@@ -1555,6 +1598,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 
                cqe = &fp->rx_comp_ring[comp_ring_cons];
                cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+               cqe_fp_status_flags = cqe->fast_path_cqe.status_flags;
 
                DP(NETIF_MSG_RX_STATUS, "CQE type %x  err %x  status %x"
                   "  queue %x  vlan %x  len %u\n", CQE_TYPE(cqe_fp_flags),
@@ -1573,7 +1617,6 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                        rx_buf = &fp->rx_buf_ring[bd_cons];
                        skb = rx_buf->skb;
                        prefetch(skb);
-                       prefetch((u8 *)skb + 256);
                        len = le16_to_cpu(cqe->fast_path_cqe.pkt_len);
                        pad = cqe->fast_path_cqe.placement_offset;
 
@@ -1620,11 +1663,10 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                                }
                        }
 
-                       pci_dma_sync_single_for_device(bp->pdev,
-                                       pci_unmap_addr(rx_buf, mapping),
-                                                      pad + RX_COPY_THRESH,
-                                                      PCI_DMA_FROMDEVICE);
-                       prefetch(skb);
+                       dma_sync_single_for_device(&bp->pdev->dev,
+                                       dma_unmap_addr(rx_buf, mapping),
+                                                  pad + RX_COPY_THRESH,
+                                                  DMA_FROM_DEVICE);
                        prefetch(((char *)(skb)) + 128);
 
                        /* is this an error packet? */
@@ -1665,10 +1707,10 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
 
                        } else
                        if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) {
-                               pci_unmap_single(bp->pdev,
-                                       pci_unmap_addr(rx_buf, mapping),
+                               dma_unmap_single(&bp->pdev->dev,
+                                       dma_unmap_addr(rx_buf, mapping),
                                                 bp->rx_buf_size,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                                skb_reserve(skb, pad);
                                skb_put(skb, len);
 
@@ -1684,6 +1726,12 @@ reuse_rx:
 
                        skb->protocol = eth_type_trans(skb, bp->dev);
 
+                       if ((bp->dev->features & NETIF_F_RXHASH) &&
+                           (cqe_fp_status_flags &
+                            ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG))
+                               skb->rxhash = le32_to_cpu(
+                                   cqe->fast_path_cqe.rss_hash_result);
+
                        skb->ip_summed = CHECKSUM_NONE;
                        if (bp->rx_csum) {
                                if (likely(BNX2X_RX_CSUM_OK(cqe)))
@@ -1699,11 +1747,11 @@ reuse_rx:
                if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
                    (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
                     PARSING_FLAGS_VLAN))
-                       vlan_hwaccel_receive_skb(skb, bp->vlgrp,
-                               le16_to_cpu(cqe->fast_path_cqe.vlan_tag));
+                       vlan_gro_receive(&fp->napi, bp->vlgrp,
+                               le16_to_cpu(cqe->fast_path_cqe.vlan_tag), skb);
                else
 #endif
-                       netif_receive_skb(skb);
+                       napi_gro_receive(&fp->napi, skb);
 
 
 next_rx:
@@ -1831,8 +1879,8 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
                        return IRQ_HANDLED;
        }
 
-       if (status)
-               DP(NETIF_MSG_INTR, "got an unknown interrupt! (status %u)\n",
+       if (unlikely(status))
+               DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
                   status);
 
        return IRQ_HANDLED;
@@ -1900,6 +1948,8 @@ static int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
        int func = BP_FUNC(bp);
        u32 hw_lock_control_reg;
 
+       DP(NETIF_MSG_HW, "Releasing a lock on resource %d\n", resource);
+
        /* Validating that the resource is within range */
        if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
                DP(NETIF_MSG_HW,
@@ -2254,11 +2304,14 @@ static void bnx2x__link_reset(struct bnx2x *bp)
 
 static u8 bnx2x_link_test(struct bnx2x *bp)
 {
-       u8 rc;
+       u8 rc = 0;
 
-       bnx2x_acquire_phy_lock(bp);
-       rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
-       bnx2x_release_phy_lock(bp);
+       if (!BP_NOMCP(bp)) {
+               bnx2x_acquire_phy_lock(bp);
+               rc = bnx2x_test_link(&bp->link_params, &bp->link_vars);
+               bnx2x_release_phy_lock(bp);
+       } else
+               BNX2X_ERR("Bootcode is missing - can not test link\n");
 
        return rc;
 }
@@ -2387,10 +2440,10 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
                   T_FAIR_COEF / (8 * vn_weight_sum) will always be greater
                   than zero */
                m_fair_vn.vn_credit_delta =
-                       max((u32)(vn_min_rate * (T_FAIR_COEF /
-                                                (8 * bp->vn_weight_sum))),
-                           (u32)(bp->cmng.fair_vars.fair_threshold * 2));
-               DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta=%d\n",
+                       max_t(u32, (vn_min_rate * (T_FAIR_COEF /
+                                                  (8 * bp->vn_weight_sum))),
+                             (bp->cmng.fair_vars.fair_threshold * 2));
+               DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n",
                   m_fair_vn.vn_credit_delta);
        }
 
@@ -2410,6 +2463,7 @@ static void bnx2x_init_vn_minmax(struct bnx2x *bp, int func)
 /* This function is called upon link interrupt */
 static void bnx2x_link_attn(struct bnx2x *bp)
 {
+       u32 prev_link_status = bp->link_vars.link_status;
        /* Make sure that we are synced with the current statistics */
        bnx2x_stats_handle(bp, STATS_EVENT_STOP);
 
@@ -2442,8 +2496,9 @@ static void bnx2x_link_attn(struct bnx2x *bp)
                        bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
        }
 
-       /* indicate link status */
-       bnx2x_link_report(bp);
+       /* indicate link status only if link status actually changed */
+       if (prev_link_status != bp->link_vars.link_status)
+               bnx2x_link_report(bp);
 
        if (IS_E1HMF(bp)) {
                int port = BP_PORT(bp);
@@ -2560,7 +2615,6 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
        return rc;
 }
 
-static void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
 static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
 static void bnx2x_set_rx_mode(struct net_device *dev);
 
@@ -2696,12 +2750,6 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 {
        struct eth_spe *spe;
 
-       DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
-          "SPQE (%x:%x)  command %d  hw_cid %x  data (%x:%x)  left %x\n",
-          (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) +
-          (void *)bp->spq_prod_bd - (void *)bp->spq), command,
-          HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
-
 #ifdef BNX2X_STOP_ON_ERROR
        if (unlikely(bp->panic))
                return -EIO;
@@ -2720,8 +2768,8 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 
        /* CID needs port number to be encoded int it */
        spe->hdr.conn_and_cmd_data =
-                       cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) |
-                                    HW_CID(bp, cid)));
+                       cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
+                                   HW_CID(bp, cid));
        spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
        if (common)
                spe->hdr.type |=
@@ -2732,6 +2780,13 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 
        bp->spq_left--;
 
+       DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
+          "SPQE[%x] (%x:%x)  command %d  hw_cid %x  data (%x:%x)  left %x\n",
+          bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping),
+          (u32)(U64_LO(bp->spq_mapping) +
+          (void *)bp->spq_prod_bd - (void *)bp->spq), command,
+          HW_CID(bp, cid), data_hi, data_lo, bp->spq_left);
+
        bnx2x_sp_prod_update(bp);
        spin_unlock_bh(&bp->spq_lock);
        return 0;
@@ -2740,12 +2795,11 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
 /* acquire split MCP access lock register */
 static int bnx2x_acquire_alr(struct bnx2x *bp)
 {
-       u32 i, j, val;
+       u32 j, val;
        int rc = 0;
 
        might_sleep();
-       i = 100;
-       for (j = 0; j < i*10; j++) {
+       for (j = 0; j < 1000; j++) {
                val = (1UL << 31);
                REG_WR(bp, GRCBASE_MCP + 0x9c, val);
                val = REG_RD(bp, GRCBASE_MCP + 0x9c);
@@ -2765,9 +2819,7 @@ static int bnx2x_acquire_alr(struct bnx2x *bp)
 /* release split MCP access lock register */
 static void bnx2x_release_alr(struct bnx2x *bp)
 {
-       u32 val = 0;
-
-       REG_WR(bp, GRCBASE_MCP + 0x9c, val);
+       REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
 }
 
 static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
@@ -2823,7 +2875,7 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
 
        DP(NETIF_MSG_HW, "aeu_mask %x  newly asserted %x\n",
           aeu_mask, asserted);
-       aeu_mask &= ~(asserted & 0xff);
+       aeu_mask &= ~(asserted & 0x3ff);
        DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
 
        REG_WR(bp, aeu_addr, aeu_mask);
@@ -2910,8 +2962,9 @@ static inline void bnx2x_fan_failure(struct bnx2x *bp)
                 bp->link_params.ext_phy_config);
 
        /* log the failure */
-       netdev_err(bp->dev, "Fan Failure on Network Controller has caused the driver to shutdown the card to prevent permanent damage.\n"
-                  "Please contact Dell Support for assistance.\n");
+       netdev_err(bp->dev, "Fan Failure on Network Controller has caused"
+              " the driver to shutdown the card to prevent permanent"
+              " damage.  Please contact OEM Support for assistance\n");
 }
 
 static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -3104,10 +3157,311 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
        }
 }
 
-static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode);
+static int bnx2x_nic_load(struct bnx2x *bp, int load_mode);
+
+
+#define BNX2X_MISC_GEN_REG      MISC_REG_GENERIC_POR_1
+#define LOAD_COUNTER_BITS      16 /* Number of bits for load counter */
+#define LOAD_COUNTER_MASK      (((u32)0x1 << LOAD_COUNTER_BITS) - 1)
+#define RESET_DONE_FLAG_MASK   (~LOAD_COUNTER_MASK)
+#define RESET_DONE_FLAG_SHIFT  LOAD_COUNTER_BITS
+#define CHIP_PARITY_SUPPORTED(bp)   (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp))
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_set_reset_done(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       val &= ~(1 << RESET_DONE_FLAG_SHIFT);
+       REG_WR(bp, BNX2X_MISC_GEN_REG, val);
+       barrier();
+       mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_set_reset_in_progress(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       val |= (1 << 16);
+       REG_WR(bp, BNX2X_MISC_GEN_REG, val);
+       barrier();
+       mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline bool bnx2x_reset_is_done(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
+       return (val & RESET_DONE_FLAG_MASK) ? false : true;
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline void bnx2x_inc_load_cnt(struct bnx2x *bp)
+{
+       u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+
+       DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
+
+       val1 = ((val & LOAD_COUNTER_MASK) + 1) & LOAD_COUNTER_MASK;
+       REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
+       barrier();
+       mmiowb();
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline u32 bnx2x_dec_load_cnt(struct bnx2x *bp)
+{
+       u32 val1, val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+
+       DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val);
+
+       val1 = ((val & LOAD_COUNTER_MASK) - 1) & LOAD_COUNTER_MASK;
+       REG_WR(bp, BNX2X_MISC_GEN_REG, (val & RESET_DONE_FLAG_MASK) | val1);
+       barrier();
+       mmiowb();
+
+       return val1;
+}
+
+/*
+ * should be run under rtnl lock
+ */
+static inline u32 bnx2x_get_load_cnt(struct bnx2x *bp)
+{
+       return REG_RD(bp, BNX2X_MISC_GEN_REG) & LOAD_COUNTER_MASK;
+}
+
+static inline void bnx2x_clear_load_cnt(struct bnx2x *bp)
+{
+       u32 val = REG_RD(bp, BNX2X_MISC_GEN_REG);
+       REG_WR(bp, BNX2X_MISC_GEN_REG, val & (~LOAD_COUNTER_MASK));
+}
+
+static inline void _print_next_block(int idx, const char *blk)
+{
+       if (idx)
+               pr_cont(", ");
+       pr_cont("%s", blk);
+}
+
+static inline int bnx2x_print_blocks_with_parity0(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
+                               _print_next_block(par_num++, "BRB");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
+                               _print_next_block(par_num++, "PARSER");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "TSDM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
+                               _print_next_block(par_num++, "SEARCHER");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "TSEMI");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity1(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
+                               _print_next_block(par_num++, "PBCLIENT");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
+                               _print_next_block(par_num++, "QM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "XSDM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "XSEMI");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
+                               _print_next_block(par_num++, "DOORBELLQ");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
+                               _print_next_block(par_num++, "VAUX PCI CORE");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
+                               _print_next_block(par_num++, "DEBUG");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "USDM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "USEMI");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
+                               _print_next_block(par_num++, "UPB");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
+                               _print_next_block(par_num++, "CSDM");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity2(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
+                               _print_next_block(par_num++, "CSEMI");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
+                               _print_next_block(par_num++, "PXP");
+                               break;
+                       case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
+                               _print_next_block(par_num++,
+                                       "PXPPCICLOCKCLIENT");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
+                               _print_next_block(par_num++, "CFC");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
+                               _print_next_block(par_num++, "CDU");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
+                               _print_next_block(par_num++, "IGU");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
+                               _print_next_block(par_num++, "MISC");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline int bnx2x_print_blocks_with_parity3(u32 sig, int par_num)
+{
+       int i = 0;
+       u32 cur_bit = 0;
+       for (i = 0; sig; i++) {
+               cur_bit = ((u32)0x1 << i);
+               if (sig & cur_bit) {
+                       switch (cur_bit) {
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY:
+                               _print_next_block(par_num++, "MCP ROM");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY:
+                               _print_next_block(par_num++, "MCP UMP RX");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY:
+                               _print_next_block(par_num++, "MCP UMP TX");
+                               break;
+                       case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY:
+                               _print_next_block(par_num++, "MCP SCPAD");
+                               break;
+                       }
+
+                       /* Clear the bit */
+                       sig &= ~cur_bit;
+               }
+       }
+
+       return par_num;
+}
+
+static inline bool bnx2x_parity_attn(struct bnx2x *bp, u32 sig0, u32 sig1,
+                                    u32 sig2, u32 sig3)
+{
+       if ((sig0 & HW_PRTY_ASSERT_SET_0) || (sig1 & HW_PRTY_ASSERT_SET_1) ||
+           (sig2 & HW_PRTY_ASSERT_SET_2) || (sig3 & HW_PRTY_ASSERT_SET_3)) {
+               int par_num = 0;
+               DP(NETIF_MSG_HW, "Was parity error: HW block parity attention: "
+                       "[0]:0x%08x [1]:0x%08x "
+                       "[2]:0x%08x [3]:0x%08x\n",
+                         sig0 & HW_PRTY_ASSERT_SET_0,
+                         sig1 & HW_PRTY_ASSERT_SET_1,
+                         sig2 & HW_PRTY_ASSERT_SET_2,
+                         sig3 & HW_PRTY_ASSERT_SET_3);
+               printk(KERN_ERR"%s: Parity errors detected in blocks: ",
+                      bp->dev->name);
+               par_num = bnx2x_print_blocks_with_parity0(
+                       sig0 & HW_PRTY_ASSERT_SET_0, par_num);
+               par_num = bnx2x_print_blocks_with_parity1(
+                       sig1 & HW_PRTY_ASSERT_SET_1, par_num);
+               par_num = bnx2x_print_blocks_with_parity2(
+                       sig2 & HW_PRTY_ASSERT_SET_2, par_num);
+               par_num = bnx2x_print_blocks_with_parity3(
+                       sig3 & HW_PRTY_ASSERT_SET_3, par_num);
+               printk("\n");
+               return true;
+       } else
+               return false;
+}
+
+static bool bnx2x_chk_parity_attn(struct bnx2x *bp)
 {
        struct attn_route attn;
-       struct attn_route group_mask;
+       int port = BP_PORT(bp);
+
+       attn.sig[0] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 +
+                            port*4);
+       attn.sig[1] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 +
+                            port*4);
+       attn.sig[2] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 +
+                            port*4);
+       attn.sig[3] = REG_RD(bp,
+               MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 +
+                            port*4);
+
+       return bnx2x_parity_attn(bp, attn.sig[0], attn.sig[1], attn.sig[2],
+                                       attn.sig[3]);
+}
+
+static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
+{
+       struct attn_route attn, *group_mask;
        int port = BP_PORT(bp);
        int index;
        u32 reg_addr;
@@ -3118,6 +3472,19 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
           try to handle this event */
        bnx2x_acquire_alr(bp);
 
+       if (bnx2x_chk_parity_attn(bp)) {
+               bp->recovery_state = BNX2X_RECOVERY_INIT;
+               bnx2x_set_reset_in_progress(bp);
+               schedule_delayed_work(&bp->reset_task, 0);
+               /* Disable HW interrupts */
+               bnx2x_int_disable(bp);
+               bnx2x_release_alr(bp);
+               /* In case of parity errors don't handle attentions so that
+                * other function would "see" parity errors.
+                */
+               return;
+       }
+
        attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4);
        attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4);
        attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4);
@@ -3127,28 +3494,20 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
 
        for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) {
                if (deasserted & (1 << index)) {
-                       group_mask = bp->attn_group[index];
+                       group_mask = &bp->attn_group[index];
 
                        DP(NETIF_MSG_HW, "group[%d]: %08x %08x %08x %08x\n",
-                          index, group_mask.sig[0], group_mask.sig[1],
-                          group_mask.sig[2], group_mask.sig[3]);
+                          index, group_mask->sig[0], group_mask->sig[1],
+                          group_mask->sig[2], group_mask->sig[3]);
 
                        bnx2x_attn_int_deasserted3(bp,
-                                       attn.sig[3] & group_mask.sig[3]);
+                                       attn.sig[3] & group_mask->sig[3]);
                        bnx2x_attn_int_deasserted1(bp,
-                                       attn.sig[1] & group_mask.sig[1]);
+                                       attn.sig[1] & group_mask->sig[1]);
                        bnx2x_attn_int_deasserted2(bp,
-                                       attn.sig[2] & group_mask.sig[2]);
+                                       attn.sig[2] & group_mask->sig[2]);
                        bnx2x_attn_int_deasserted0(bp,
-                                       attn.sig[0] & group_mask.sig[0]);
-
-                       if ((attn.sig[0] & group_mask.sig[0] &
-                                               HW_PRTY_ASSERT_SET_0) ||
-                           (attn.sig[1] & group_mask.sig[1] &
-                                               HW_PRTY_ASSERT_SET_1) ||
-                           (attn.sig[2] & group_mask.sig[2] &
-                                               HW_PRTY_ASSERT_SET_2))
-                               BNX2X_ERR("FATAL HW block parity attention\n");
+                                       attn.sig[0] & group_mask->sig[0]);
                }
        }
 
@@ -3172,7 +3531,7 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
 
        DP(NETIF_MSG_HW, "aeu_mask %x  newly deasserted %x\n",
           aeu_mask, deasserted);
-       aeu_mask |= (deasserted & 0xff);
+       aeu_mask |= (deasserted & 0x3ff);
        DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask);
 
        REG_WR(bp, reg_addr, aeu_mask);
@@ -3216,7 +3575,6 @@ static void bnx2x_sp_task(struct work_struct *work)
        struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
        u16 status;
 
-
        /* Return here if interrupt is disabled */
        if (unlikely(atomic_read(&bp->intr_sem) != 0)) {
                DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n");
@@ -3227,11 +3585,23 @@ static void bnx2x_sp_task(struct work_struct *work)
 /*     if (status == 0)                                     */
 /*             BNX2X_ERR("spurious slowpath interrupt!\n"); */
 
-       DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status);
+       DP(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status);
 
        /* HW attentions */
-       if (status & 0x1)
+       if (status & 0x1) {
                bnx2x_attn_int(bp);
+               status &= ~0x1;
+       }
+
+       /* CStorm events: STAT_QUERY */
+       if (status & 0x2) {
+               DP(BNX2X_MSG_SP, "CStorm events: STAT_QUERY\n");
+               status &= ~0x2;
+       }
+
+       if (unlikely(status))
+               DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
+                  status);
 
        bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(bp->def_att_idx),
                     IGU_INT_NOP, 1);
@@ -3243,7 +3613,6 @@ static void bnx2x_sp_task(struct work_struct *work)
                     IGU_INT_NOP, 1);
        bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx),
                     IGU_INT_ENABLE, 1);
-
 }
 
 static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
@@ -3947,7 +4316,6 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
                u32 lo;
                u32 hi;
        } diff;
-       u32 nig_timer_max;
 
        if (bp->link_vars.mac_type == MAC_TYPE_BMAC)
                bnx2x_bmac_stats_update(bp);
@@ -3978,10 +4346,14 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
 
        pstats->host_port_stats_start = ++pstats->host_port_stats_end;
 
-       nig_timer_max = SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
-       if (nig_timer_max != estats->nig_timer_max) {
-               estats->nig_timer_max = nig_timer_max;
-               BNX2X_ERR("NIG timer max (%u)\n", estats->nig_timer_max);
+       if (!BP_NOMCP(bp)) {
+               u32 nig_timer_max =
+                       SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer);
+               if (nig_timer_max != estats->nig_timer_max) {
+                       estats->nig_timer_max = nig_timer_max;
+                       BNX2X_ERR("NIG timer max (%u)\n",
+                                 estats->nig_timer_max);
+               }
        }
 
        return 0;
@@ -4025,21 +4397,21 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
                if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) !=
                                                        bp->stats_counter) {
                        DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
-                          "  xstorm counter (%d) != stats_counter (%d)\n",
+                          "  xstorm counter (0x%x) != stats_counter (0x%x)\n",
                           i, xclient->stats_counter, bp->stats_counter);
                        return -1;
                }
                if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) !=
                                                        bp->stats_counter) {
                        DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
-                          "  tstorm counter (%d) != stats_counter (%d)\n",
+                          "  tstorm counter (0x%x) != stats_counter (0x%x)\n",
                           i, tclient->stats_counter, bp->stats_counter);
                        return -2;
                }
                if ((u16)(le16_to_cpu(uclient->stats_counter) + 1) !=
                                                        bp->stats_counter) {
                        DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
-                          "  ustorm counter (%d) != stats_counter (%d)\n",
+                          "  ustorm counter (0x%x) != stats_counter (0x%x)\n",
                           i, uclient->stats_counter, bp->stats_counter);
                        return -4;
                }
@@ -4059,6 +4431,21 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
                       qstats->total_bytes_received_lo,
                       le32_to_cpu(tclient->rcv_unicast_bytes.lo));
 
+               SUB_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(uclient->bcast_no_buff_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(uclient->bcast_no_buff_bytes.lo));
+
+               SUB_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(uclient->mcast_no_buff_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(uclient->mcast_no_buff_bytes.lo));
+
+               SUB_64(qstats->total_bytes_received_hi,
+                      le32_to_cpu(uclient->ucast_no_buff_bytes.hi),
+                      qstats->total_bytes_received_lo,
+                      le32_to_cpu(uclient->ucast_no_buff_bytes.lo));
+
                qstats->valid_bytes_received_hi =
                                        qstats->total_bytes_received_hi;
                qstats->valid_bytes_received_lo =
@@ -4307,47 +4694,43 @@ static void bnx2x_stats_update(struct bnx2x *bp)
        bnx2x_drv_stats_update(bp);
 
        if (netif_msg_timer(bp)) {
-               struct bnx2x_fastpath *fp0_rx = bp->fp;
-               struct bnx2x_fastpath *fp0_tx = bp->fp;
-               struct tstorm_per_client_stats *old_tclient =
-                                                       &bp->fp->old_tclient;
-               struct bnx2x_eth_q_stats *qstats = &bp->fp->eth_q_stats;
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
-               struct net_device_stats *nstats = &bp->dev->stats;
                int i;
 
-               netdev_printk(KERN_DEBUG, bp->dev, "\n");
-               printk(KERN_DEBUG "  tx avail (%4x)  tx hc idx (%x)"
-                                 "  tx pkt (%lx)\n",
-                      bnx2x_tx_avail(fp0_tx),
-                      le16_to_cpu(*fp0_tx->tx_cons_sb), nstats->tx_packets);
-               printk(KERN_DEBUG "  rx usage (%4x)  rx hc idx (%x)"
-                                 "  rx pkt (%lx)\n",
-                      (u16)(le16_to_cpu(*fp0_rx->rx_cons_sb) -
-                            fp0_rx->rx_comp_cons),
-                      le16_to_cpu(*fp0_rx->rx_cons_sb), nstats->rx_packets);
-               printk(KERN_DEBUG "  %s (Xoff events %u)  brb drops %u  "
-                                 "brb truncate %u\n",
-                      (netif_queue_stopped(bp->dev) ? "Xoff" : "Xon"),
-                      qstats->driver_xoff,
+               printk(KERN_DEBUG "%s: brb drops %u  brb truncate %u\n",
+                      bp->dev->name,
                       estats->brb_drop_lo, estats->brb_truncate_lo);
-               printk(KERN_DEBUG "tstats: checksum_discard %u  "
-                       "packets_too_big_discard %lu  no_buff_discard %lu  "
-                       "mac_discard %u  mac_filter_discard %u  "
-                       "xxovrflow_discard %u  brb_truncate_discard %u  "
-                       "ttl0_discard %u\n",
-                      le32_to_cpu(old_tclient->checksum_discard),
-                      bnx2x_hilo(&qstats->etherstatsoverrsizepkts_hi),
-                      bnx2x_hilo(&qstats->no_buff_discard_hi),
-                      estats->mac_discard, estats->mac_filter_discard,
-                      estats->xxoverflow_discard, estats->brb_truncate_discard,
-                      le32_to_cpu(old_tclient->ttl0_discard));
 
                for_each_queue(bp, i) {
-                       printk(KERN_DEBUG "[%d]: %lu\t%lu\t%lu\n", i,
-                              bnx2x_fp(bp, i, tx_pkt),
-                              bnx2x_fp(bp, i, rx_pkt),
-                              bnx2x_fp(bp, i, rx_calls));
+                       struct bnx2x_fastpath *fp = &bp->fp[i];
+                       struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+
+                       printk(KERN_DEBUG "%s: rx usage(%4u)  *rx_cons_sb(%u)"
+                                         "  rx pkt(%lu)  rx calls(%lu %lu)\n",
+                              fp->name, (le16_to_cpu(*fp->rx_cons_sb) -
+                              fp->rx_comp_cons),
+                              le16_to_cpu(*fp->rx_cons_sb),
+                              bnx2x_hilo(&qstats->
+                                         total_unicast_packets_received_hi),
+                              fp->rx_calls, fp->rx_pkt);
+               }
+
+               for_each_queue(bp, i) {
+                       struct bnx2x_fastpath *fp = &bp->fp[i];
+                       struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats;
+                       struct netdev_queue *txq =
+                               netdev_get_tx_queue(bp->dev, i);
+
+                       printk(KERN_DEBUG "%s: tx avail(%4u)  *tx_cons_sb(%u)"
+                                         "  tx pkt(%lu) tx calls (%lu)"
+                                         "  %s (Xoff events %u)\n",
+                              fp->name, bnx2x_tx_avail(fp),
+                              le16_to_cpu(*fp->tx_cons_sb),
+                              bnx2x_hilo(&qstats->
+                                         total_unicast_packets_transmitted_hi),
+                              fp->tx_pkt,
+                              (netif_tx_queue_stopped(txq) ? "Xoff" : "Xon"),
+                              qstats->driver_xoff);
                }
        }
 
@@ -4468,6 +4851,9 @@ static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
        enum bnx2x_stats_state state = bp->stats_state;
 
+       if (unlikely(bp->panic))
+               return;
+
        bnx2x_stats_stm[state][event].action(bp);
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
 
@@ -4940,9 +5326,9 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
                }
 
                if (fp->tpa_state[i] == BNX2X_TPA_START)
-                       pci_unmap_single(bp->pdev,
-                                        pci_unmap_addr(rx_buf, mapping),
-                                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+                       dma_unmap_single(&bp->pdev->dev,
+                                        dma_unmap_addr(rx_buf, mapping),
+                                        bp->rx_buf_size, DMA_FROM_DEVICE);
 
                dev_kfree_skb(skb);
                rx_buf->skb = NULL;
@@ -4978,7 +5364,7 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
                                        fp->disable_tpa = 1;
                                        break;
                                }
-                               pci_unmap_addr_set((struct sw_rx_bd *)
+                               dma_unmap_addr_set((struct sw_rx_bd *)
                                                        &bp->fp->tpa_pool[i],
                                                   mapping, 0);
                                fp->tpa_state[i] = BNX2X_TPA_STOP;
@@ -5072,8 +5458,8 @@ static void bnx2x_init_rx_rings(struct bnx2x *bp)
 
                fp->rx_bd_prod = ring_prod;
                /* must not have more available CQEs than BDs */
-               fp->rx_comp_prod = min((u16)(NUM_RCQ_RINGS*RCQ_DESC_CNT),
-                                      cqe_ring_prod);
+               fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
+                                        cqe_ring_prod);
                fp->rx_pkt = fp->rx_calls = 0;
 
                /* Warning!
@@ -5179,8 +5565,8 @@ static void bnx2x_init_context(struct bnx2x *bp)
                        context->ustorm_st_context.common.flags |=
                                USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_TPA;
                        context->ustorm_st_context.common.sge_buff_size =
-                               (u16)min((u32)SGE_PAGE_SIZE*PAGES_PER_SGE,
-                                        (u32)0xffff);
+                               (u16)min_t(u32, SGE_PAGE_SIZE*PAGES_PER_SGE,
+                                          0xffff);
                        context->ustorm_st_context.common.sge_page_base_hi =
                                                U64_HI(fp->rx_sge_mapping);
                        context->ustorm_st_context.common.sge_page_base_lo =
@@ -5369,10 +5755,10 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        u32 offset;
        u16 max_agg_size;
 
-       if (is_multi(bp)) {
-               tstorm_config.config_flags = MULTI_FLAGS(bp);
+       tstorm_config.config_flags = RSS_FLAGS(bp);
+
+       if (is_multi(bp))
                tstorm_config.rss_result_mask = MULTI_MASK;
-       }
 
        /* Enable TPA if needed */
        if (bp->flags & TPA_ENABLE_FLAG)
@@ -5477,10 +5863,8 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        }
 
        /* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */
-       max_agg_size =
-               min((u32)(min((u32)8, (u32)MAX_SKB_FRAGS) *
-                         SGE_PAGE_SIZE * PAGES_PER_SGE),
-                   (u32)0xffff);
+       max_agg_size = min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) *
+                                  SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff);
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
@@ -5566,7 +5950,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
        }
 
 
-       /* Store it to internal memory */
+       /* Store cmng structures to internal memory */
        if (bp->port.pmf)
                for (i = 0; i < sizeof(struct cmng_struct_per_port) / 4; i++)
                        REG_WR(bp, BAR_XSTRORM_INTMEM +
@@ -5658,8 +6042,8 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 
 static int bnx2x_gunzip_init(struct bnx2x *bp)
 {
-       bp->gunzip_buf = pci_alloc_consistent(bp->pdev, FW_BUF_SIZE,
-                                             &bp->gunzip_mapping);
+       bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE,
+                                           &bp->gunzip_mapping, GFP_KERNEL);
        if (bp->gunzip_buf  == NULL)
                goto gunzip_nomem1;
 
@@ -5679,12 +6063,13 @@ gunzip_nomem3:
        bp->strm = NULL;
 
 gunzip_nomem2:
-       pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf,
-                           bp->gunzip_mapping);
+       dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
+                         bp->gunzip_mapping);
        bp->gunzip_buf = NULL;
 
 gunzip_nomem1:
-       netdev_err(bp->dev, "Cannot allocate firmware buffer for un-compression\n");
+       netdev_err(bp->dev, "Cannot allocate firmware buffer for"
+              " un-compression\n");
        return -ENOMEM;
 }
 
@@ -5696,8 +6081,8 @@ static void bnx2x_gunzip_end(struct bnx2x *bp)
        bp->strm = NULL;
 
        if (bp->gunzip_buf) {
-               pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf,
-                                   bp->gunzip_mapping);
+               dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
+                                 bp->gunzip_mapping);
                bp->gunzip_buf = NULL;
        }
 }
@@ -5735,8 +6120,9 @@ static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len)
 
        bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out);
        if (bp->gunzip_outlen & 0x3)
-               netdev_err(bp->dev, "Firmware decompression error: gunzip_outlen (%d) not aligned\n",
-                          bp->gunzip_outlen);
+               netdev_err(bp->dev, "Firmware decompression error:"
+                                   " gunzip_outlen (%d) not aligned\n",
+                               bp->gunzip_outlen);
        bp->gunzip_outlen >>= 2;
 
        zlib_inflateEnd(bp->strm);
@@ -5962,6 +6348,50 @@ static void enable_blocks_attention(struct bnx2x *bp)
        REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18);         /* bit 3,4 masked */
 }
 
+static const struct {
+       u32 addr;
+       u32 mask;
+} bnx2x_parity_mask[] = {
+       {PXP_REG_PXP_PRTY_MASK, 0xffffffff},
+       {PXP2_REG_PXP2_PRTY_MASK_0, 0xffffffff},
+       {PXP2_REG_PXP2_PRTY_MASK_1, 0xffffffff},
+       {HC_REG_HC_PRTY_MASK, 0xffffffff},
+       {MISC_REG_MISC_PRTY_MASK, 0xffffffff},
+       {QM_REG_QM_PRTY_MASK, 0x0},
+       {DORQ_REG_DORQ_PRTY_MASK, 0x0},
+       {GRCBASE_UPB + PB_REG_PB_PRTY_MASK, 0x0},
+       {GRCBASE_XPB + PB_REG_PB_PRTY_MASK, 0x0},
+       {SRC_REG_SRC_PRTY_MASK, 0x4}, /* bit 2 */
+       {CDU_REG_CDU_PRTY_MASK, 0x0},
+       {CFC_REG_CFC_PRTY_MASK, 0x0},
+       {DBG_REG_DBG_PRTY_MASK, 0x0},
+       {DMAE_REG_DMAE_PRTY_MASK, 0x0},
+       {BRB1_REG_BRB1_PRTY_MASK, 0x0},
+       {PRS_REG_PRS_PRTY_MASK, (1<<6)},/* bit 6 */
+       {TSDM_REG_TSDM_PRTY_MASK, 0x18},/* bit 3,4 */
+       {CSDM_REG_CSDM_PRTY_MASK, 0x8}, /* bit 3 */
+       {USDM_REG_USDM_PRTY_MASK, 0x38},/* bit 3,4,5 */
+       {XSDM_REG_XSDM_PRTY_MASK, 0x8}, /* bit 3 */
+       {TSEM_REG_TSEM_PRTY_MASK_0, 0x0},
+       {TSEM_REG_TSEM_PRTY_MASK_1, 0x0},
+       {USEM_REG_USEM_PRTY_MASK_0, 0x0},
+       {USEM_REG_USEM_PRTY_MASK_1, 0x0},
+       {CSEM_REG_CSEM_PRTY_MASK_0, 0x0},
+       {CSEM_REG_CSEM_PRTY_MASK_1, 0x0},
+       {XSEM_REG_XSEM_PRTY_MASK_0, 0x0},
+       {XSEM_REG_XSEM_PRTY_MASK_1, 0x0}
+};
+
+static void enable_blocks_parity(struct bnx2x *bp)
+{
+       int i, mask_arr_len =
+               sizeof(bnx2x_parity_mask)/(sizeof(bnx2x_parity_mask[0]));
+
+       for (i = 0; i < mask_arr_len; i++)
+               REG_WR(bp, bnx2x_parity_mask[i].addr,
+                       bnx2x_parity_mask[i].mask);
+}
+
 
 static void bnx2x_reset_common(struct bnx2x *bp)
 {
@@ -5992,10 +6422,14 @@ static void bnx2x_init_pxp(struct bnx2x *bp)
 
 static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
 {
+       int is_required;
        u32 val;
-       u8 port;
-       u8 is_required = 0;
+       int port;
+
+       if (BP_NOMCP(bp))
+               return;
 
+       is_required = 0;
        val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
              SHARED_HW_CFG_FAN_FAILURE_MASK;
 
@@ -6034,7 +6468,7 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
        /* set to active low mode */
        val = REG_RD(bp, MISC_REG_SPIO_INT);
        val |= ((1 << MISC_REGISTERS_SPIO_5) <<
-                               MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+                                       MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
        REG_WR(bp, MISC_REG_SPIO_INT, val);
 
        /* enable interrupt to signal the IGU */
@@ -6200,10 +6634,8 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_init_block(bp, PBF_BLOCK, COMMON_STAGE);
 
        REG_WR(bp, SRC_REG_SOFT_RST, 1);
-       for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) {
-               REG_WR(bp, i, 0xc0cac01a);
-               /* TODO: replace with something meaningful */
-       }
+       for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4)
+               REG_WR(bp, i, random32());
        bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
 #ifdef BCM_CNIC
        REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
@@ -6221,7 +6653,8 @@ static int bnx2x_init_common(struct bnx2x *bp)
 
        if (sizeof(union cdu_context) != 1024)
                /* we currently assume that a context is 1024 bytes */
-               pr_alert("please adjust the size of cdu_context(%ld)\n",
+               dev_alert(&bp->pdev->dev, "please adjust the size "
+                                         "of cdu_context(%ld)\n",
                         (long)sizeof(union cdu_context));
 
        bnx2x_init_block(bp, CDU_BLOCK, COMMON_STAGE);
@@ -6305,6 +6738,8 @@ static int bnx2x_init_common(struct bnx2x *bp)
        REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
 
        enable_blocks_attention(bp);
+       if (CHIP_PARITY_SUPPORTED(bp))
+               enable_blocks_parity(bp);
 
        if (!BP_NOMCP(bp)) {
                bnx2x_acquire_phy_lock(bp);
@@ -6323,7 +6758,7 @@ static int bnx2x_init_port(struct bnx2x *bp)
        u32 low, high;
        u32 val;
 
-       DP(BNX2X_MSG_MCP, "starting port init  port %x\n", port);
+       DP(BNX2X_MSG_MCP, "starting port init  port %d\n", port);
 
        REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
 
@@ -6342,6 +6777,7 @@ static int bnx2x_init_port(struct bnx2x *bp)
        REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20);
        REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31);
 #endif
+
        bnx2x_init_block(bp, DQ_BLOCK, init_stage);
 
        bnx2x_init_block(bp, BRB1_BLOCK, init_stage);
@@ -6534,7 +6970,7 @@ static int bnx2x_init_func(struct bnx2x *bp)
        u32 addr, val;
        int i;
 
-       DP(BNX2X_MSG_MCP, "starting func init  func %x\n", func);
+       DP(BNX2X_MSG_MCP, "starting func init  func %d\n", func);
 
        /* set MSI reconfigure capability */
        addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0);
@@ -6692,7 +7128,7 @@ static void bnx2x_free_mem(struct bnx2x *bp)
 #define BNX2X_PCI_FREE(x, y, size) \
        do { \
                if (x) { \
-                       pci_free_consistent(bp->pdev, size, x, y); \
+                       dma_free_coherent(&bp->pdev->dev, size, x, y); \
                        x = NULL; \
                        y = 0; \
                } \
@@ -6773,7 +7209,7 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
 
 #define BNX2X_PCI_ALLOC(x, y, size) \
        do { \
-               x = pci_alloc_consistent(bp->pdev, size, y); \
+               x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
                if (x == NULL) \
                        goto alloc_mem_err; \
                memset(x, 0, size); \
@@ -6906,9 +7342,9 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp)
                        if (skb == NULL)
                                continue;
 
-                       pci_unmap_single(bp->pdev,
-                                        pci_unmap_addr(rx_buf, mapping),
-                                        bp->rx_buf_size, PCI_DMA_FROMDEVICE);
+                       dma_unmap_single(&bp->pdev->dev,
+                                        dma_unmap_addr(rx_buf, mapping),
+                                        bp->rx_buf_size, DMA_FROM_DEVICE);
 
                        rx_buf->skb = NULL;
                        dev_kfree_skb(skb);
@@ -6987,7 +7423,31 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
 
        rc = pci_enable_msix(bp->pdev, &bp->msix_table[0],
                             BNX2X_NUM_QUEUES(bp) + offset);
-       if (rc) {
+
+       /*
+        * reconfigure number of tx/rx queues according to available
+        * MSI-X vectors
+        */
+       if (rc >= BNX2X_MIN_MSIX_VEC_CNT) {
+               /* vectors available for FP */
+               int fp_vec = rc - BNX2X_MSIX_VEC_FP_START;
+
+               DP(NETIF_MSG_IFUP,
+                  "Trying to use less MSI-X vectors: %d\n", rc);
+
+               rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
+
+               if (rc) {
+                       DP(NETIF_MSG_IFUP,
+                          "MSI-X is not attainable  rc %d\n", rc);
+                       return rc;
+               }
+
+               bp->num_queues = min(bp->num_queues, fp_vec);
+
+               DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n",
+                                 bp->num_queues);
+       } else if (rc) {
                DP(NETIF_MSG_IFUP, "MSI-X is not attainable  rc %d\n", rc);
                return rc;
        }
@@ -7028,10 +7488,11 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
        }
 
        i = BNX2X_NUM_QUEUES(bp);
-       netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d ... fp[%d] %d\n",
-                   bp->msix_table[0].vector,
-                   0, bp->msix_table[offset].vector,
-                   i - 1, bp->msix_table[offset + i - 1].vector);
+       netdev_info(bp->dev, "using MSI-X  IRQs: sp %d  fp[%d] %d"
+              " ... fp[%d] %d\n",
+              bp->msix_table[0].vector,
+              0, bp->msix_table[offset].vector,
+              i - 1, bp->msix_table[offset + i - 1].vector);
 
        return 0;
 }
@@ -7409,8 +7870,6 @@ static int bnx2x_set_num_queues(struct bnx2x *bp)
                bp->num_queues = 1;
                DP(NETIF_MSG_IFUP, "set number of queues to 1\n");
                break;
-
-       case INT_MODE_MSIX:
        default:
                /* Set number of queues according to bp->multi_mode value */
                bnx2x_set_num_queues_msix(bp);
@@ -7656,6 +8115,7 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        if (bp->state == BNX2X_STATE_OPEN)
                bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
 #endif
+       bnx2x_inc_load_cnt(bp);
 
        return 0;
 
@@ -7843,33 +8303,12 @@ static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code)
        }
 }
 
-/* must be called with rtnl_lock */
-static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
+static void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode)
 {
        int port = BP_PORT(bp);
        u32 reset_code = 0;
        int i, cnt, rc;
 
-#ifdef BCM_CNIC
-       bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
-#endif
-       bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
-
-       /* Set "drop all" */
-       bp->rx_mode = BNX2X_RX_MODE_NONE;
-       bnx2x_set_storm_rx_mode(bp);
-
-       /* Disable HW interrupts, NAPI and Tx */
-       bnx2x_netif_stop(bp, 1);
-
-       del_timer_sync(&bp->timer);
-       SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
-                (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
-       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
-
-       /* Release IRQs */
-       bnx2x_free_irq(bp, false);
-
        /* Wait until tx fastpath tasks complete */
        for_each_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
@@ -8010,31 +8449,524 @@ unload_error:
        if (!BP_NOMCP(bp))
                bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE);
 
-       bp->port.pmf = 0;
+}
 
-       /* Free SKBs, SGEs, TPA pool and driver internals */
-       bnx2x_free_skbs(bp);
-       for_each_queue(bp, i)
-               bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
-       for_each_queue(bp, i)
+static inline void bnx2x_disable_close_the_gate(struct bnx2x *bp)
+{
+       u32 val;
+
+       DP(NETIF_MSG_HW, "Disabling \"close the gates\"\n");
+
+       if (CHIP_IS_E1(bp)) {
+               int port = BP_PORT(bp);
+               u32 addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 :
+                       MISC_REG_AEU_MASK_ATTN_FUNC_0;
+
+               val = REG_RD(bp, addr);
+               val &= ~(0x300);
+               REG_WR(bp, addr, val);
+       } else if (CHIP_IS_E1H(bp)) {
+               val = REG_RD(bp, MISC_REG_AEU_GENERAL_MASK);
+               val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK |
+                        MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK);
+               REG_WR(bp, MISC_REG_AEU_GENERAL_MASK, val);
+       }
+}
+
+/* must be called with rtnl_lock */
+static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
+{
+       int i;
+
+       if (bp->state == BNX2X_STATE_CLOSED) {
+               /* Interface has been removed - nothing to recover */
+               bp->recovery_state = BNX2X_RECOVERY_DONE;
+               bp->is_leader = 0;
+               bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+               smp_wmb();
+
+               return -EINVAL;
+       }
+
+#ifdef BCM_CNIC
+       bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
+#endif
+       bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
+
+       /* Set "drop all" */
+       bp->rx_mode = BNX2X_RX_MODE_NONE;
+       bnx2x_set_storm_rx_mode(bp);
+
+       /* Disable HW interrupts, NAPI and Tx */
+       bnx2x_netif_stop(bp, 1);
+       netif_carrier_off(bp->dev);
+
+       del_timer_sync(&bp->timer);
+       SHMEM_WR(bp, func_mb[BP_FUNC(bp)].drv_pulse_mb,
+                (DRV_PULSE_ALWAYS_ALIVE | bp->fw_drv_pulse_wr_seq));
+       bnx2x_stats_handle(bp, STATS_EVENT_STOP);
+
+       /* Release IRQs */
+       bnx2x_free_irq(bp, false);
+
+       /* Cleanup the chip if needed */
+       if (unload_mode != UNLOAD_RECOVERY)
+               bnx2x_chip_cleanup(bp, unload_mode);
+
+       bp->port.pmf = 0;
+
+       /* Free SKBs, SGEs, TPA pool and driver internals */
+       bnx2x_free_skbs(bp);
+       for_each_queue(bp, i)
+               bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
+       for_each_queue(bp, i)
                netif_napi_del(&bnx2x_fp(bp, i, napi));
        bnx2x_free_mem(bp);
 
        bp->state = BNX2X_STATE_CLOSED;
 
-       netif_carrier_off(bp->dev);
+       /* The last driver must disable a "close the gate" if there is no
+        * parity attention or "process kill" pending.
+        */
+       if ((!bnx2x_dec_load_cnt(bp)) && (!bnx2x_chk_parity_attn(bp)) &&
+           bnx2x_reset_is_done(bp))
+               bnx2x_disable_close_the_gate(bp);
+
+       /* Reset MCP mail box sequence if there is on going recovery */
+       if (unload_mode == UNLOAD_RECOVERY)
+               bp->fw_seq = 0;
+
+       return 0;
+}
+
+/* Close gates #2, #3 and #4: */
+static void bnx2x_set_234_gates(struct bnx2x *bp, bool close)
+{
+       u32 val, addr;
+
+       /* Gates #2 and #4a are closed/opened for "not E1" only */
+       if (!CHIP_IS_E1(bp)) {
+               /* #4 */
+               val = REG_RD(bp, PXP_REG_HST_DISCARD_DOORBELLS);
+               REG_WR(bp, PXP_REG_HST_DISCARD_DOORBELLS,
+                      close ? (val | 0x1) : (val & (~(u32)1)));
+               /* #2 */
+               val = REG_RD(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES);
+               REG_WR(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES,
+                      close ? (val | 0x1) : (val & (~(u32)1)));
+       }
+
+       /* #3 */
+       addr = BP_PORT(bp) ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
+       val = REG_RD(bp, addr);
+       REG_WR(bp, addr, (!close) ? (val | 0x1) : (val & (~(u32)1)));
+
+       DP(NETIF_MSG_HW, "%s gates #2, #3 and #4\n",
+               close ? "closing" : "opening");
+       mmiowb();
+}
+
+#define SHARED_MF_CLP_MAGIC  0x80000000 /* `magic' bit */
+
+static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val)
+{
+       /* Do some magic... */
+       u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
+       *magic_val = val & SHARED_MF_CLP_MAGIC;
+       MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC);
+}
+
+/* Restore the value of the `magic' bit.
+ *
+ * @param pdev Device handle.
+ * @param magic_val Old value of the `magic' bit.
+ */
+static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
+{
+       /* Restore the `magic' bit value... */
+       /* u32 val = SHMEM_RD(bp, mf_cfg.shared_mf_config.clp_mb);
+       SHMEM_WR(bp, mf_cfg.shared_mf_config.clp_mb,
+               (val & (~SHARED_MF_CLP_MAGIC)) | magic_val); */
+       u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb);
+       MF_CFG_WR(bp, shared_mf_config.clp_mb,
+               (val & (~SHARED_MF_CLP_MAGIC)) | magic_val);
+}
+
+/* Prepares for MCP reset: takes care of CLP configurations.
+ *
+ * @param bp
+ * @param magic_val Old value of 'magic' bit.
+ */
+static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
+{
+       u32 shmem;
+       u32 validity_offset;
+
+       DP(NETIF_MSG_HW, "Starting\n");
+
+       /* Set `magic' bit in order to save MF config */
+       if (!CHIP_IS_E1(bp))
+               bnx2x_clp_reset_prep(bp, magic_val);
+
+       /* Get shmem offset */
+       shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+       validity_offset = offsetof(struct shmem_region, validity_map[0]);
+
+       /* Clear validity map flags */
+       if (shmem > 0)
+               REG_WR(bp, shmem + validity_offset, 0);
+}
+
+#define MCP_TIMEOUT      5000   /* 5 seconds (in ms) */
+#define MCP_ONE_TIMEOUT  100    /* 100 ms */
+
+/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10,
+ * depending on the HW type.
+ *
+ * @param bp
+ */
+static inline void bnx2x_mcp_wait_one(struct bnx2x *bp)
+{
+       /* special handling for emulation and FPGA,
+          wait 10 times longer */
+       if (CHIP_REV_IS_SLOW(bp))
+               msleep(MCP_ONE_TIMEOUT*10);
+       else
+               msleep(MCP_ONE_TIMEOUT);
+}
+
+static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val)
+{
+       u32 shmem, cnt, validity_offset, val;
+       int rc = 0;
+
+       msleep(100);
+
+       /* Get shmem offset */
+       shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+       if (shmem == 0) {
+               BNX2X_ERR("Shmem 0 return failure\n");
+               rc = -ENOTTY;
+               goto exit_lbl;
+       }
+
+       validity_offset = offsetof(struct shmem_region, validity_map[0]);
+
+       /* Wait for MCP to come up */
+       for (cnt = 0; cnt < (MCP_TIMEOUT / MCP_ONE_TIMEOUT); cnt++) {
+               /* TBD: its best to check validity map of last port.
+                * currently checks on port 0.
+                */
+               val = REG_RD(bp, shmem + validity_offset);
+               DP(NETIF_MSG_HW, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem,
+                  shmem + validity_offset, val);
+
+               /* check that shared memory is valid. */
+               if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+                   == (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
+                       break;
+
+               bnx2x_mcp_wait_one(bp);
+       }
+
+       DP(NETIF_MSG_HW, "Cnt=%d Shmem validity map 0x%x\n", cnt, val);
+
+       /* Check that shared memory is valid. This indicates that MCP is up. */
+       if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) !=
+           (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) {
+               BNX2X_ERR("Shmem signature not present. MCP is not up !!\n");
+               rc = -ENOTTY;
+               goto exit_lbl;
+       }
+
+exit_lbl:
+       /* Restore the `magic' bit value */
+       if (!CHIP_IS_E1(bp))
+               bnx2x_clp_reset_done(bp, magic_val);
+
+       return rc;
+}
+
+static void bnx2x_pxp_prep(struct bnx2x *bp)
+{
+       if (!CHIP_IS_E1(bp)) {
+               REG_WR(bp, PXP2_REG_RD_START_INIT, 0);
+               REG_WR(bp, PXP2_REG_RQ_RBC_DONE, 0);
+               REG_WR(bp, PXP2_REG_RQ_CFG_DONE, 0);
+               mmiowb();
+       }
+}
+
+/*
+ * Reset the whole chip except for:
+ *      - PCIE core
+ *      - PCI Glue, PSWHST, PXP/PXP2 RF (all controlled by
+ *              one reset bit)
+ *      - IGU
+ *      - MISC (including AEU)
+ *      - GRC
+ *      - RBCN, RBCP
+ */
+static void bnx2x_process_kill_chip_reset(struct bnx2x *bp)
+{
+       u32 not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2;
+
+       not_reset_mask1 =
+               MISC_REGISTERS_RESET_REG_1_RST_HC |
+               MISC_REGISTERS_RESET_REG_1_RST_PXPV |
+               MISC_REGISTERS_RESET_REG_1_RST_PXP;
+
+       not_reset_mask2 =
+               MISC_REGISTERS_RESET_REG_2_RST_MDIO |
+               MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_RBCN |
+               MISC_REGISTERS_RESET_REG_2_RST_GRC  |
+               MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE |
+               MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B;
+
+       reset_mask1 = 0xffffffff;
+
+       if (CHIP_IS_E1(bp))
+               reset_mask2 = 0xffff;
+       else
+               reset_mask2 = 0x1ffff;
+
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR,
+              reset_mask1 & (~not_reset_mask1));
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
+              reset_mask2 & (~not_reset_mask2));
+
+       barrier();
+       mmiowb();
+
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1);
+       REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, reset_mask2);
+       mmiowb();
+}
+
+static int bnx2x_process_kill(struct bnx2x *bp)
+{
+       int cnt = 1000;
+       u32 val = 0;
+       u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2;
+
+
+       /* Empty the Tetris buffer, wait for 1s */
+       do {
+               sr_cnt  = REG_RD(bp, PXP2_REG_RD_SR_CNT);
+               blk_cnt = REG_RD(bp, PXP2_REG_RD_BLK_CNT);
+               port_is_idle_0 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_0);
+               port_is_idle_1 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_1);
+               pgl_exp_rom2 = REG_RD(bp, PXP2_REG_PGL_EXP_ROM2);
+               if ((sr_cnt == 0x7e) && (blk_cnt == 0xa0) &&
+                   ((port_is_idle_0 & 0x1) == 0x1) &&
+                   ((port_is_idle_1 & 0x1) == 0x1) &&
+                   (pgl_exp_rom2 == 0xffffffff))
+                       break;
+               msleep(1);
+       } while (cnt-- > 0);
+
+       if (cnt <= 0) {
+               DP(NETIF_MSG_HW, "Tetris buffer didn't get empty or there"
+                         " are still"
+                         " outstanding read requests after 1s!\n");
+               DP(NETIF_MSG_HW, "sr_cnt=0x%08x, blk_cnt=0x%08x,"
+                         " port_is_idle_0=0x%08x,"
+                         " port_is_idle_1=0x%08x, pgl_exp_rom2=0x%08x\n",
+                         sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1,
+                         pgl_exp_rom2);
+               return -EAGAIN;
+       }
+
+       barrier();
+
+       /* Close gates #2, #3 and #4 */
+       bnx2x_set_234_gates(bp, true);
+
+       /* TBD: Indicate that "process kill" is in progress to MCP */
+
+       /* Clear "unprepared" bit */
+       REG_WR(bp, MISC_REG_UNPREPARED, 0);
+       barrier();
+
+       /* Make sure all is written to the chip before the reset */
+       mmiowb();
+
+       /* Wait for 1ms to empty GLUE and PCI-E core queues,
+        * PSWHST, GRC and PSWRD Tetris buffer.
+        */
+       msleep(1);
+
+       /* Prepare to chip reset: */
+       /* MCP */
+       bnx2x_reset_mcp_prep(bp, &val);
+
+       /* PXP */
+       bnx2x_pxp_prep(bp);
+       barrier();
+
+       /* reset the chip */
+       bnx2x_process_kill_chip_reset(bp);
+       barrier();
+
+       /* Recover after reset: */
+       /* MCP */
+       if (bnx2x_reset_mcp_comp(bp, val))
+               return -EAGAIN;
+
+       /* PXP */
+       bnx2x_pxp_prep(bp);
+
+       /* Open the gates #2, #3 and #4 */
+       bnx2x_set_234_gates(bp, false);
+
+       /* TBD: IGU/AEU preparation bring back the AEU/IGU to a
+        * reset state, re-enable attentions. */
 
        return 0;
 }
 
+static int bnx2x_leader_reset(struct bnx2x *bp)
+{
+       int rc = 0;
+       /* Try to recover after the failure */
+       if (bnx2x_process_kill(bp)) {
+               printk(KERN_ERR "%s: Something bad had happen! Aii!\n",
+                      bp->dev->name);
+               rc = -EAGAIN;
+               goto exit_leader_reset;
+       }
+
+       /* Clear "reset is in progress" bit and update the driver state */
+       bnx2x_set_reset_done(bp);
+       bp->recovery_state = BNX2X_RECOVERY_DONE;
+
+exit_leader_reset:
+       bp->is_leader = 0;
+       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESERVED_08);
+       smp_wmb();
+       return rc;
+}
+
+static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
+
+/* Assumption: runs under rtnl lock. This together with the fact
+ * that it's called only from bnx2x_reset_task() ensure that it
+ * will never be called when netif_running(bp->dev) is false.
+ */
+static void bnx2x_parity_recover(struct bnx2x *bp)
+{
+       DP(NETIF_MSG_HW, "Handling parity\n");
+       while (1) {
+               switch (bp->recovery_state) {
+               case BNX2X_RECOVERY_INIT:
+                       DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_INIT\n");
+                       /* Try to get a LEADER_LOCK HW lock */
+                       if (bnx2x_trylock_hw_lock(bp,
+                               HW_LOCK_RESOURCE_RESERVED_08))
+                               bp->is_leader = 1;
+
+                       /* Stop the driver */
+                       /* If interface has been removed - break */
+                       if (bnx2x_nic_unload(bp, UNLOAD_RECOVERY))
+                               return;
+
+                       bp->recovery_state = BNX2X_RECOVERY_WAIT;
+                       /* Ensure "is_leader" and "recovery_state"
+                        *  update values are seen on other CPUs
+                        */
+                       smp_wmb();
+                       break;
+
+               case BNX2X_RECOVERY_WAIT:
+                       DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_WAIT\n");
+                       if (bp->is_leader) {
+                               u32 load_counter = bnx2x_get_load_cnt(bp);
+                               if (load_counter) {
+                                       /* Wait until all other functions get
+                                        * down.
+                                        */
+                                       schedule_delayed_work(&bp->reset_task,
+                                                               HZ/10);
+                                       return;
+                               } else {
+                                       /* If all other functions got down -
+                                        * try to bring the chip back to
+                                        * normal. In any case it's an exit
+                                        * point for a leader.
+                                        */
+                                       if (bnx2x_leader_reset(bp) ||
+                                       bnx2x_nic_load(bp, LOAD_NORMAL)) {
+                                               printk(KERN_ERR"%s: Recovery "
+                                               "has failed. Power cycle is "
+                                               "needed.\n", bp->dev->name);
+                                               /* Disconnect this device */
+                                               netif_device_detach(bp->dev);
+                                               /* Block ifup for all function
+                                                * of this ASIC until
+                                                * "process kill" or power
+                                                * cycle.
+                                                */
+                                               bnx2x_set_reset_in_progress(bp);
+                                               /* Shut down the power */
+                                               bnx2x_set_power_state(bp,
+                                                               PCI_D3hot);
+                                               return;
+                                       }
+
+                                       return;
+                               }
+                       } else { /* non-leader */
+                               if (!bnx2x_reset_is_done(bp)) {
+                                       /* Try to get a LEADER_LOCK HW lock as
+                                        * long as a former leader may have
+                                        * been unloaded by the user or
+                                        * released a leadership by another
+                                        * reason.
+                                        */
+                                       if (bnx2x_trylock_hw_lock(bp,
+                                           HW_LOCK_RESOURCE_RESERVED_08)) {
+                                               /* I'm a leader now! Restart a
+                                                * switch case.
+                                                */
+                                               bp->is_leader = 1;
+                                               break;
+                                       }
+
+                                       schedule_delayed_work(&bp->reset_task,
+                                                               HZ/10);
+                                       return;
+
+                               } else { /* A leader has completed
+                                         * the "process kill". It's an exit
+                                         * point for a non-leader.
+                                         */
+                                       bnx2x_nic_load(bp, LOAD_NORMAL);
+                                       bp->recovery_state =
+                                               BNX2X_RECOVERY_DONE;
+                                       smp_wmb();
+                                       return;
+                               }
+                       }
+               default:
+                       return;
+               }
+       }
+}
+
+/* bnx2x_nic_unload() flushes the bnx2x_wq, thus reset task is
+ * scheduled on a general queue in order to prevent a dead lock.
+ */
 static void bnx2x_reset_task(struct work_struct *work)
 {
-       struct bnx2x *bp = container_of(work, struct bnx2x, reset_task);
+       struct bnx2x *bp = container_of(work, struct bnx2x, reset_task.work);
 
 #ifdef BNX2X_STOP_ON_ERROR
        BNX2X_ERR("reset task called but STOP_ON_ERROR defined"
                  " so reset not done to allow debug dump,\n"
-                 " you will need to reboot when done\n");
+        KERN_ERR " you will need to reboot when done\n");
        return;
 #endif
 
@@ -8043,8 +8975,12 @@ static void bnx2x_reset_task(struct work_struct *work)
        if (!netif_running(bp->dev))
                goto reset_task_exit;
 
-       bnx2x_nic_unload(bp, UNLOAD_NORMAL);
-       bnx2x_nic_load(bp, LOAD_NORMAL);
+       if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE))
+               bnx2x_parity_recover(bp);
+       else {
+               bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+               bnx2x_nic_load(bp, LOAD_NORMAL);
+       }
 
 reset_task_exit:
        rtnl_unlock();
@@ -8264,7 +9200,7 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
        if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
                != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
-               BNX2X_ERR("BAD MCP validity signature\n");
+               BNX2X_ERROR("BAD MCP validity signature\n");
 
        bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
        BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config);
@@ -8288,8 +9224,8 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        if (val < BNX2X_BC_VER) {
                /* for now only warn
                 * later we might need to enforce this */
-               BNX2X_ERR("This driver needs bc_ver %X but found %X,"
-                         please upgrade BC\n", BNX2X_BC_VER, val);
+               BNX2X_ERROR("This driver needs bc_ver %X but found %X, "
+                           "please upgrade BC\n", BNX2X_BC_VER, val);
        }
        bp->link_params.feature_config_flags |=
                (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
@@ -8310,7 +9246,8 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
        val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]);
        val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]);
 
-       pr_info("part number %X-%X-%X-%X\n", val, val2, val3, val4);
+       dev_info(&bp->pdev->dev, "part number %X-%X-%X-%X\n",
+                val, val2, val3, val4);
 }
 
 static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
@@ -8588,11 +9525,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_10baseT_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8604,11 +9541,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_10baseT_Half |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8619,11 +9556,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_100baseT_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8635,11 +9572,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_100baseT_Half |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8650,11 +9587,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_1000baseT_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8665,11 +9602,11 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_2500baseX_Full |
                                                ADVERTISED_TP);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
@@ -8682,19 +9619,19 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
                        bp->port.advertising = (ADVERTISED_10000baseT_Full |
                                                ADVERTISED_FIBRE);
                } else {
-                       BNX2X_ERR("NVRAM config error. "
-                                 "Invalid link_config 0x%x"
-                                 "  speed_cap_mask 0x%x\n",
-                                 bp->port.link_config,
-                                 bp->link_params.speed_cap_mask);
+                       BNX2X_ERROR("NVRAM config error. "
+                                   "Invalid link_config 0x%x"
+                                   "  speed_cap_mask 0x%x\n",
+                                   bp->port.link_config,
+                                   bp->link_params.speed_cap_mask);
                        return;
                }
                break;
 
        default:
-               BNX2X_ERR("NVRAM config error. "
-                         "BAD link speed link_config 0x%x\n",
-                         bp->port.link_config);
+               BNX2X_ERROR("NVRAM config error. "
+                           "BAD link speed link_config 0x%x\n",
+                           bp->port.link_config);
                bp->link_params.req_line_speed = SPEED_AUTO_NEG;
                bp->port.advertising = bp->port.supported;
                break;
@@ -8823,7 +9760,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
 
        bp->e1hov = 0;
        bp->e1hmf = 0;
-       if (CHIP_IS_E1H(bp)) {
+       if (CHIP_IS_E1H(bp) && !BP_NOMCP(bp)) {
                bp->mf_config =
                        SHMEM_RD(bp, mf_cfg.func_mf_config[func].config);
 
@@ -8844,14 +9781,14 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
                                               "(0x%04x)\n",
                                               func, bp->e1hov, bp->e1hov);
                        } else {
-                               BNX2X_ERR("!!!  No valid E1HOV for func %d,"
-                                         "  aborting\n", func);
+                               BNX2X_ERROR("No valid E1HOV for func %d,"
+                                           "  aborting\n", func);
                                rc = -EPERM;
                        }
                } else {
                        if (BP_E1HVN(bp)) {
-                               BNX2X_ERR("!!!  VN %d in single function mode,"
-                                         "  aborting\n", BP_E1HVN(bp));
+                               BNX2X_ERROR("VN %d in single function mode,"
+                                           "  aborting\n", BP_E1HVN(bp));
                                rc = -EPERM;
                        }
                }
@@ -8887,7 +9824,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
 
        if (BP_NOMCP(bp)) {
                /* only supposed to happen on emulation/FPGA */
-               BNX2X_ERR("warning random MAC workaround active\n");
+               BNX2X_ERROR("warning: random MAC workaround active\n");
                random_ether_addr(bp->dev->dev_addr);
                memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
        }
@@ -8895,6 +9832,70 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
        return rc;
 }
 
+static void __devinit bnx2x_read_fwinfo(struct bnx2x *bp)
+{
+       int cnt, i, block_end, rodi;
+       char vpd_data[BNX2X_VPD_LEN+1];
+       char str_id_reg[VENDOR_ID_LEN+1];
+       char str_id_cap[VENDOR_ID_LEN+1];
+       u8 len;
+
+       cnt = pci_read_vpd(bp->pdev, 0, BNX2X_VPD_LEN, vpd_data);
+       memset(bp->fw_ver, 0, sizeof(bp->fw_ver));
+
+       if (cnt < BNX2X_VPD_LEN)
+               goto out_not_found;
+
+       i = pci_vpd_find_tag(vpd_data, 0, BNX2X_VPD_LEN,
+                            PCI_VPD_LRDT_RO_DATA);
+       if (i < 0)
+               goto out_not_found;
+
+
+       block_end = i + PCI_VPD_LRDT_TAG_SIZE +
+                   pci_vpd_lrdt_size(&vpd_data[i]);
+
+       i += PCI_VPD_LRDT_TAG_SIZE;
+
+       if (block_end > BNX2X_VPD_LEN)
+               goto out_not_found;
+
+       rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
+                                  PCI_VPD_RO_KEYWORD_MFR_ID);
+       if (rodi < 0)
+               goto out_not_found;
+
+       len = pci_vpd_info_field_size(&vpd_data[rodi]);
+
+       if (len != VENDOR_ID_LEN)
+               goto out_not_found;
+
+       rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
+
+       /* vendor specific info */
+       snprintf(str_id_reg, VENDOR_ID_LEN + 1, "%04x", PCI_VENDOR_ID_DELL);
+       snprintf(str_id_cap, VENDOR_ID_LEN + 1, "%04X", PCI_VENDOR_ID_DELL);
+       if (!strncmp(str_id_reg, &vpd_data[rodi], VENDOR_ID_LEN) ||
+           !strncmp(str_id_cap, &vpd_data[rodi], VENDOR_ID_LEN)) {
+
+               rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end,
+                                               PCI_VPD_RO_KEYWORD_VENDOR0);
+               if (rodi >= 0) {
+                       len = pci_vpd_info_field_size(&vpd_data[rodi]);
+
+                       rodi += PCI_VPD_INFO_FLD_HDR_SIZE;
+
+                       if (len < 32 && (len + rodi) <= BNX2X_VPD_LEN) {
+                               memcpy(bp->fw_ver, &vpd_data[rodi], len);
+                               bp->fw_ver[len] = ' ';
+                       }
+               }
+               return;
+       }
+out_not_found:
+       return;
+}
+
 static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 {
        int func = BP_FUNC(bp);
@@ -8912,29 +9913,34 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
 #endif
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
-       INIT_WORK(&bp->reset_task, bnx2x_reset_task);
+       INIT_DELAYED_WORK(&bp->reset_task, bnx2x_reset_task);
 
        rc = bnx2x_get_hwinfo(bp);
 
+       bnx2x_read_fwinfo(bp);
        /* need to reset chip if undi was active */
        if (!BP_NOMCP(bp))
                bnx2x_undi_unload(bp);
 
        if (CHIP_REV_IS_FPGA(bp))
-               pr_err("FPGA detected\n");
+               dev_err(&bp->pdev->dev, "FPGA detected\n");
 
        if (BP_NOMCP(bp) && (func == 0))
-               pr_err("MCP disabled, must load devices in order!\n");
+               dev_err(&bp->pdev->dev, "MCP disabled, "
+                                       "must load devices in order!\n");
 
        /* Set multi queue mode */
        if ((multi_mode != ETH_RSS_MODE_DISABLED) &&
            ((int_mode == INT_MODE_INTx) || (int_mode == INT_MODE_MSI))) {
-               pr_err("Multi disabled since int_mode requested is not MSI-X\n");
+               dev_err(&bp->pdev->dev, "Multi disabled since int_mode "
+                                       "requested is not MSI-X\n");
                multi_mode = ETH_RSS_MODE_DISABLED;
        }
        bp->multi_mode = multi_mode;
 
 
+       bp->dev->features |= NETIF_F_GRO;
+
        /* Set TPA flags */
        if (disable_tpa) {
                bp->flags &= ~TPA_ENABLE_FLAG;
@@ -9304,11 +10310,13 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
                bnx2x_release_phy_lock(bp);
        }
 
-       snprintf(info->fw_version, 32, "BC:%d.%d.%d%s%s",
+       strncpy(info->fw_version, bp->fw_ver, 32);
+       snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver),
+                "bc %d.%d.%d%s%s",
                 (bp->common.bc_ver & 0xff0000) >> 16,
                 (bp->common.bc_ver & 0xff00) >> 8,
                 (bp->common.bc_ver & 0xff),
-                ((phy_fw_ver[0] != '\0') ? " PHY:" : ""), phy_fw_ver);
+                ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
        strcpy(info->bus_info, pci_name(bp->pdev));
        info->n_stats = BNX2X_NUM_STATS;
        info->testinfo_len = BNX2X_NUM_TESTS;
@@ -9842,19 +10850,18 @@ static int bnx2x_get_coalesce(struct net_device *dev,
        return 0;
 }
 
-#define BNX2X_MAX_COALES_TOUT  (0xf0*12) /* Maximal coalescing timeout in us */
 static int bnx2x_set_coalesce(struct net_device *dev,
                              struct ethtool_coalesce *coal)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
-       bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
-       if (bp->rx_ticks > BNX2X_MAX_COALES_TOUT)
-               bp->rx_ticks = BNX2X_MAX_COALES_TOUT;
+       bp->rx_ticks = (u16)coal->rx_coalesce_usecs;
+       if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT)
+               bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT;
 
-       bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
-       if (bp->tx_ticks > BNX2X_MAX_COALES_TOUT)
-               bp->tx_ticks = BNX2X_MAX_COALES_TOUT;
+       bp->tx_ticks = (u16)coal->tx_coalesce_usecs;
+       if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT)
+               bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT;
 
        if (netif_running(dev))
                bnx2x_update_coalesce(bp);
@@ -9885,6 +10892,11 @@ static int bnx2x_set_ringparam(struct net_device *dev,
        struct bnx2x *bp = netdev_priv(dev);
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        if ((ering->rx_pending > MAX_RX_AVAIL) ||
            (ering->tx_pending > MAX_TX_AVAIL) ||
            (ering->tx_pending <= MAX_SKB_FRAGS + 4))
@@ -9970,6 +10982,11 @@ static int bnx2x_set_flags(struct net_device *dev, u32 data)
        int changed = 0;
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        /* TPA requires Rx CSUM offloading */
        if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
                if (!disable_tpa) {
@@ -9986,6 +11003,11 @@ static int bnx2x_set_flags(struct net_device *dev, u32 data)
                changed = 1;
        }
 
+       if (data & ETH_FLAG_RXHASH)
+               dev->features |= NETIF_F_RXHASH;
+       else
+               dev->features &= ~NETIF_F_RXHASH;
+
        if (changed && netif_running(dev)) {
                bnx2x_nic_unload(bp, UNLOAD_NORMAL);
                rc = bnx2x_nic_load(bp, LOAD_NORMAL);
@@ -10006,6 +11028,11 @@ static int bnx2x_set_rx_csum(struct net_device *dev, u32 data)
        struct bnx2x *bp = netdev_priv(dev);
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        bp->rx_csum = data;
 
        /* Disable TPA, when Rx CSUM is disabled. Otherwise all
@@ -10050,9 +11077,9 @@ static int bnx2x_test_registers(struct bnx2x *bp)
        u32 wr_val = 0;
        int port = BP_PORT(bp);
        static const struct {
-               u32  offset0;
-               u32  offset1;
-               u32  mask;
+               u32 offset0;
+               u32 offset1;
+               u32 mask;
        } reg_tbl[] = {
 /* 0 */                { BRB1_REG_PAUSE_LOW_THRESHOLD_0,      4, 0x000003ff },
                { DORQ_REG_DB_ADDR0,                   4, 0xffffffff },
@@ -10119,15 +11146,19 @@ static int bnx2x_test_registers(struct bnx2x *bp)
 
                        save_val = REG_RD(bp, offset);
 
-                       REG_WR(bp, offset, wr_val);
+                       REG_WR(bp, offset, (wr_val & mask));
                        val = REG_RD(bp, offset);
 
                        /* Restore the original register's value */
                        REG_WR(bp, offset, save_val);
 
-                       /* verify that value is as expected value */
-                       if ((val & mask) != (wr_val & mask))
+                       /* verify value is as expected */
+                       if ((val & mask) != (wr_val & mask)) {
+                               DP(NETIF_MSG_PROBE,
+                                  "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n",
+                                  offset, val, wr_val, mask);
                                goto test_reg_exit;
+                       }
                }
        }
 
@@ -10267,8 +11298,8 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
 
        bd_prod = TX_BD(fp_tx->tx_bd_prod);
        tx_start_bd = &fp_tx->tx_desc_ring[bd_prod].start_bd;
-       mapping = pci_map_single(bp->pdev, skb->data,
-                                skb_headlen(skb), PCI_DMA_TODEVICE);
+       mapping = dma_map_single(&bp->pdev->dev, skb->data,
+                                skb_headlen(skb), DMA_TO_DEVICE);
        tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
        tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */
@@ -10344,6 +11375,9 @@ static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
 {
        int rc = 0, res;
 
+       if (BP_NOMCP(bp))
+               return rc;
+
        if (!netif_running(bp->dev))
                return BNX2X_LOOPBACK_FAILED;
 
@@ -10391,6 +11425,9 @@ static int bnx2x_test_nvram(struct bnx2x *bp)
        int i, rc;
        u32 magic, crc;
 
+       if (BP_NOMCP(bp))
+               return 0;
+
        rc = bnx2x_nvram_read(bp, 0, data, 4);
        if (rc) {
                DP(NETIF_MSG_PROBE, "magic value read (rc %d)\n", rc);
@@ -10468,6 +11505,12 @@ static void bnx2x_self_test(struct net_device *dev,
 {
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               etest->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
+
        memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS);
 
        if (!netif_running(dev))
@@ -10556,7 +11599,11 @@ static const struct {
 
 /* 10 */{ Q_STATS_OFFSET32(total_bytes_transmitted_hi),        8, "[%d]: tx_bytes" },
        { Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi),
-                                                       8, "[%d]: tx_packets" }
+                                               8, "[%d]: tx_ucast_packets" },
+       { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+                                               8, "[%d]: tx_mcast_packets" },
+       { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+                                               8, "[%d]: tx_bcast_packets" }
 };
 
 static const struct {
@@ -10618,16 +11665,20 @@ static const struct {
        { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi),
                                8, STATS_FLAGS_PORT, "tx_error_bytes" },
        { STATS_OFFSET32(total_unicast_packets_transmitted_hi),
-                               8, STATS_FLAGS_BOTH, "tx_packets" },
+                               8, STATS_FLAGS_BOTH, "tx_ucast_packets" },
+       { STATS_OFFSET32(total_multicast_packets_transmitted_hi),
+                               8, STATS_FLAGS_BOTH, "tx_mcast_packets" },
+       { STATS_OFFSET32(total_broadcast_packets_transmitted_hi),
+                               8, STATS_FLAGS_BOTH, "tx_bcast_packets" },
        { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi),
                                8, STATS_FLAGS_PORT, "tx_mac_errors" },
        { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi),
                                8, STATS_FLAGS_PORT, "tx_carrier_errors" },
-       { STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
+/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi),
                                8, STATS_FLAGS_PORT, "tx_single_collisions" },
        { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi),
                                8, STATS_FLAGS_PORT, "tx_multi_collisions" },
-/* 30 */{ STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
+       { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi),
                                8, STATS_FLAGS_PORT, "tx_deferred" },
        { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi),
                                8, STATS_FLAGS_PORT, "tx_excess_collisions" },
@@ -10643,11 +11694,11 @@ static const struct {
                        8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" },
        { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi),
                        8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" },
-       { STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
+/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi),
                        8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" },
        { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi),
                        8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" },
-/* 40 */{ STATS_OFFSET32(etherstatspktsover1522octets_hi),
+       { STATS_OFFSET32(etherstatspktsover1522octets_hi),
                        8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" },
        { STATS_OFFSET32(pause_frames_sent_hi),
                                8, STATS_FLAGS_PORT, "tx_pause_frames" }
@@ -10664,7 +11715,7 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
        struct bnx2x *bp = netdev_priv(dev);
        int i, num_stats;
 
-       switch(stringset) {
+       switch (stringset) {
        case ETH_SS_STATS:
                if (is_multi(bp)) {
                        num_stats = BNX2X_NUM_Q_STATS * bp->num_queues;
@@ -10893,6 +11944,14 @@ static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
                break;
 
        case PCI_D3hot:
+               /* If there are other clients above don't
+                  shut down the power */
+               if (atomic_read(&bp->pdev->enable_cnt) != 1)
+                       return 0;
+               /* Don't shut down the power for emulation and FPGA */
+               if (CHIP_REV_IS_SLOW(bp))
+                       return 0;
+
                pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
                pmcsr |= 3;
 
@@ -11182,6 +12241,8 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int i;
        u8 hlen = 0;
        __le16 pkt_size = 0;
+       struct ethhdr *eth;
+       u8 mac_type = UNICAST_ADDRESS;
 
 #ifdef BNX2X_STOP_ON_ERROR
        if (unlikely(bp->panic))
@@ -11205,6 +12266,16 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
           skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr,
           ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type);
 
+       eth = (struct ethhdr *)skb->data;
+
+       /* set flag according to packet type (UNICAST_ADDRESS is default)*/
+       if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
+               if (is_broadcast_ether_addr(eth->h_dest))
+                       mac_type = BROADCAST_ADDRESS;
+               else
+                       mac_type = MULTICAST_ADDRESS;
+       }
+
 #if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
        /* First, check if we need to linearize the skb (due to FW
           restrictions). No need to check fragmentation if page size > 8K
@@ -11238,8 +12309,8 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_start_bd = &fp->tx_desc_ring[bd_prod].start_bd;
 
        tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
-       tx_start_bd->general_data = (UNICAST_ADDRESS <<
-                                    ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
+       tx_start_bd->general_data =  (mac_type <<
+                                       ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
        /* header nbd */
        tx_start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
 
@@ -11314,8 +12385,8 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       mapping = pci_map_single(bp->pdev, skb->data,
-                                skb_headlen(skb), PCI_DMA_TODEVICE);
+       mapping = dma_map_single(&bp->pdev->dev, skb->data,
+                                skb_headlen(skb), DMA_TO_DEVICE);
 
        tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
        tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
@@ -11372,8 +12443,9 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                if (total_pkt_bd == NULL)
                        total_pkt_bd = &fp->tx_desc_ring[bd_prod].reg_bd;
 
-               mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
-                                      frag->size, PCI_DMA_TODEVICE);
+               mapping = dma_map_page(&bp->pdev->dev, frag->page,
+                                      frag->page_offset,
+                                      frag->size, DMA_TO_DEVICE);
 
                tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping));
                tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping));
@@ -11452,6 +12524,40 @@ static int bnx2x_open(struct net_device *dev)
 
        bnx2x_set_power_state(bp, PCI_D0);
 
+       if (!bnx2x_reset_is_done(bp)) {
+               do {
+                       /* Reset MCP mail box sequence if there is on going
+                        * recovery
+                        */
+                       bp->fw_seq = 0;
+
+                       /* If it's the first function to load and reset done
+                        * is still not cleared it may mean that. We don't
+                        * check the attention state here because it may have
+                        * already been cleared by a "common" reset but we
+                        * shell proceed with "process kill" anyway.
+                        */
+                       if ((bnx2x_get_load_cnt(bp) == 0) &&
+                               bnx2x_trylock_hw_lock(bp,
+                               HW_LOCK_RESOURCE_RESERVED_08) &&
+                               (!bnx2x_leader_reset(bp))) {
+                               DP(NETIF_MSG_HW, "Recovered in open\n");
+                               break;
+                       }
+
+                       bnx2x_set_power_state(bp, PCI_D3hot);
+
+                       printk(KERN_ERR"%s: Recovery flow hasn't been properly"
+                       " completed yet. Try again later. If u still see this"
+                       " message after a few retries then power cycle is"
+                       " required.\n", bp->dev->name);
+
+                       return -EAGAIN;
+               } while (0);
+       }
+
+       bp->recovery_state = BNX2X_RECOVERY_DONE;
+
        return bnx2x_nic_load(bp, LOAD_OPEN);
 }
 
@@ -11462,9 +12568,7 @@ static int bnx2x_close(struct net_device *dev)
 
        /* Unload the driver, release IRQs */
        bnx2x_nic_unload(bp, UNLOAD_CLOSE);
-       if (atomic_read(&bp->pdev->enable_cnt) == 1)
-               if (!CHIP_REV_IS_SLOW(bp))
-                       bnx2x_set_power_state(bp, PCI_D3hot);
+       bnx2x_set_power_state(bp, PCI_D3hot);
 
        return 0;
 }
@@ -11494,21 +12598,21 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
        else { /* some multicasts */
                if (CHIP_IS_E1(bp)) {
                        int i, old, offset;
-                       struct dev_mc_list *mclist;
+                       struct netdev_hw_addr *ha;
                        struct mac_configuration_cmd *config =
                                                bnx2x_sp(bp, mcast_config);
 
                        i = 0;
-                       netdev_for_each_mc_addr(mclist, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                config->config_table[i].
                                        cam_entry.msb_mac_addr =
-                                       swab16(*(u16 *)&mclist->dmi_addr[0]);
+                                       swab16(*(u16 *)&ha->addr[0]);
                                config->config_table[i].
                                        cam_entry.middle_mac_addr =
-                                       swab16(*(u16 *)&mclist->dmi_addr[2]);
+                                       swab16(*(u16 *)&ha->addr[2]);
                                config->config_table[i].
                                        cam_entry.lsb_mac_addr =
-                                       swab16(*(u16 *)&mclist->dmi_addr[4]);
+                                       swab16(*(u16 *)&ha->addr[4]);
                                config->config_table[i].cam_entry.flags =
                                                        cpu_to_le16(port);
                                config->config_table[i].
@@ -11562,18 +12666,18 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
                                      0);
                } else { /* E1H */
                        /* Accept one or more multicasts */
-                       struct dev_mc_list *mclist;
+                       struct netdev_hw_addr *ha;
                        u32 mc_filter[MC_HASH_SIZE];
                        u32 crc, bit, regidx;
                        int i;
 
                        memset(mc_filter, 0, 4 * MC_HASH_SIZE);
 
-                       netdev_for_each_mc_addr(mclist, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
-                                  mclist->dmi_addr);
+                                  ha->addr);
 
-                               crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN);
+                               crc = crc32c_le(0, ha->addr, ETH_ALEN);
                                bit = (crc >> 24) & 0xff;
                                regidx = bit >> 5;
                                bit &= 0x1f;
@@ -11690,6 +12794,11 @@ static int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
        struct bnx2x *bp = netdev_priv(dev);
        int rc = 0;
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) ||
            ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE))
                return -EINVAL;
@@ -11717,7 +12826,7 @@ static void bnx2x_tx_timeout(struct net_device *dev)
                bnx2x_panic();
 #endif
        /* This allows the netif to be shutdown gracefully before resetting */
-       schedule_work(&bp->reset_task);
+       schedule_delayed_work(&bp->reset_task, 0);
 }
 
 #ifdef BCM_VLAN
@@ -11789,18 +12898,21 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 
        rc = pci_enable_device(pdev);
        if (rc) {
-               pr_err("Cannot enable PCI device, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot enable PCI device, aborting\n");
                goto err_out;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               pr_err("Cannot find PCI device base address, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot find PCI device base address, aborting\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
 
        if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
-               pr_err("Cannot find second PCI device base address, aborting\n");
+               dev_err(&bp->pdev->dev, "Cannot find second PCI device"
+                      " base address, aborting\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
@@ -11808,7 +12920,8 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        if (atomic_read(&pdev->enable_cnt) == 1) {
                rc = pci_request_regions(pdev, DRV_MODULE_NAME);
                if (rc) {
-                       pr_err("Cannot obtain PCI resources, aborting\n");
+                       dev_err(&bp->pdev->dev,
+                               "Cannot obtain PCI resources, aborting\n");
                        goto err_out_disable;
                }
 
@@ -11818,28 +12931,32 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 
        bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
        if (bp->pm_cap == 0) {
-               pr_err("Cannot find power management capability, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot find power management capability, aborting\n");
                rc = -EIO;
                goto err_out_release;
        }
 
        bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
        if (bp->pcie_cap == 0) {
-               pr_err("Cannot find PCI Express capability, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot find PCI Express capability, aborting\n");
                rc = -EIO;
                goto err_out_release;
        }
 
-       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+       if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) == 0) {
                bp->flags |= USING_DAC_FLAG;
-               if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
-                       pr_err("pci_set_consistent_dma_mask failed, aborting\n");
+               if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)) != 0) {
+                       dev_err(&bp->pdev->dev, "dma_set_coherent_mask"
+                              " failed, aborting\n");
                        rc = -EIO;
                        goto err_out_release;
                }
 
-       } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
-               pr_err("System does not support DMA, aborting\n");
+       } else if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)) != 0) {
+               dev_err(&bp->pdev->dev,
+                       "System does not support DMA, aborting\n");
                rc = -EIO;
                goto err_out_release;
        }
@@ -11852,7 +12969,8 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
 
        bp->regview = pci_ioremap_bar(pdev, 0);
        if (!bp->regview) {
-               pr_err("Cannot map register space, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot map register space, aborting\n");
                rc = -ENOMEM;
                goto err_out_release;
        }
@@ -11861,7 +12979,8 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
                                        min_t(u64, BNX2X_DB_SIZE,
                                              pci_resource_len(pdev, 2)));
        if (!bp->doorbells) {
-               pr_err("Cannot map doorbell space, aborting\n");
+               dev_err(&bp->pdev->dev,
+                       "Cannot map doorbell space, aborting\n");
                rc = -ENOMEM;
                goto err_out_unmap;
        }
@@ -11876,6 +12995,9 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0);
        REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0);
 
+       /* Reset the load counter */
+       bnx2x_clear_load_cnt(bp);
+
        dev->watchdog_timeo = TX_TIMEOUT;
 
        dev->netdev_ops = &bnx2x_netdev_ops;
@@ -11963,7 +13085,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
                offset = be32_to_cpu(sections[i].offset);
                len = be32_to_cpu(sections[i].len);
                if (offset + len > firmware->size) {
-                       pr_err("Section %d length is out of bounds\n", i);
+                       dev_err(&bp->pdev->dev,
+                               "Section %d length is out of bounds\n", i);
                        return -EINVAL;
                }
        }
@@ -11975,7 +13098,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
 
        for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) {
                if (be16_to_cpu(ops_offsets[i]) > num_ops) {
-                       pr_err("Section offset %d is out of bounds\n", i);
+                       dev_err(&bp->pdev->dev,
+                               "Section offset %d is out of bounds\n", i);
                        return -EINVAL;
                }
        }
@@ -11987,7 +13111,8 @@ static int __devinit bnx2x_check_firmware(struct bnx2x *bp)
            (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) ||
            (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) ||
            (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) {
-               pr_err("Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n",
+               dev_err(&bp->pdev->dev,
+                       "Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n",
                       fw_ver[0], fw_ver[1], fw_ver[2],
                       fw_ver[3], BCM_5710_FW_MAJOR_VERSION,
                       BCM_5710_FW_MINOR_VERSION,
@@ -12022,8 +13147,8 @@ static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n)
        for (i = 0, j = 0; i < n/8; i++, j += 2) {
                tmp = be32_to_cpu(source[j]);
                target[i].op = (tmp >> 24) & 0xff;
-               target[i].offset =  tmp & 0xffffff;
-               target[i].raw_data = be32_to_cpu(source[j+1]);
+               target[i].offset = tmp & 0xffffff;
+               target[i].raw_data = be32_to_cpu(source[j + 1]);
        }
 }
 
@@ -12057,20 +13182,24 @@ static int __devinit bnx2x_init_firmware(struct bnx2x *bp, struct device *dev)
 
        if (CHIP_IS_E1(bp))
                fw_file_name = FW_FILE_NAME_E1;
-       else
+       else if (CHIP_IS_E1H(bp))
                fw_file_name = FW_FILE_NAME_E1H;
+       else {
+               dev_err(dev, "Unsupported chip revision\n");
+               return -EINVAL;
+       }
 
-       pr_info("Loading %s\n", fw_file_name);
+       dev_info(dev, "Loading %s\n", fw_file_name);
 
        rc = request_firmware(&bp->firmware, fw_file_name, dev);
        if (rc) {
-               pr_err("Can't load firmware file %s\n", fw_file_name);
+               dev_err(dev, "Can't load firmware file %s\n", fw_file_name);
                goto request_firmware_exit;
        }
 
        rc = bnx2x_check_firmware(bp);
        if (rc) {
-               pr_err("Corrupt firmware file %s\n", fw_file_name);
+               dev_err(dev, "Corrupt firmware file %s\n", fw_file_name);
                goto request_firmware_exit;
        }
 
@@ -12129,7 +13258,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        /* dev zeroed in init_etherdev */
        dev = alloc_etherdev_mq(sizeof(*bp), MAX_CONTEXT);
        if (!dev) {
-               pr_err("Cannot allocate net device\n");
+               dev_err(&pdev->dev, "Cannot allocate net device\n");
                return -ENOMEM;
        }
 
@@ -12151,7 +13280,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        /* Set init arrays */
        rc = bnx2x_init_firmware(bp, &pdev->dev);
        if (rc) {
-               pr_err("Error loading firmware\n");
+               dev_err(&pdev->dev, "Error loading firmware\n");
                goto init_one_exit;
        }
 
@@ -12162,11 +13291,12 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
        }
 
        bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
-       netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
-                   board_info[ent->driver_data].name,
-                   (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
-                   pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
-                   dev->base_addr, bp->pdev->irq, dev->dev_addr);
+       netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx,"
+              " IRQ %d, ", board_info[ent->driver_data].name,
+              (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
+              pcie_width, (pcie_speed == 2) ? "5GHz (Gen2)" : "2.5GHz",
+              dev->base_addr, bp->pdev->irq);
+       pr_cont("node addr %pM\n", dev->dev_addr);
 
        return 0;
 
@@ -12194,13 +13324,16 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
        struct bnx2x *bp;
 
        if (!dev) {
-               pr_err("BAD net device from bnx2x_init_one\n");
+               dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
                return;
        }
        bp = netdev_priv(dev);
 
        unregister_netdev(dev);
 
+       /* Make sure RESET task is not scheduled before continuing */
+       cancel_delayed_work_sync(&bp->reset_task);
+
        kfree(bp->init_ops_offsets);
        kfree(bp->init_ops);
        kfree(bp->init_data);
@@ -12227,7 +13360,7 @@ static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
        struct bnx2x *bp;
 
        if (!dev) {
-               pr_err("BAD net device from bnx2x_init_one\n");
+               dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
                return -ENODEV;
        }
        bp = netdev_priv(dev);
@@ -12259,11 +13392,16 @@ static int bnx2x_resume(struct pci_dev *pdev)
        int rc;
 
        if (!dev) {
-               pr_err("BAD net device from bnx2x_init_one\n");
+               dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
                return -ENODEV;
        }
        bp = netdev_priv(dev);
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return -EAGAIN;
+       }
+
        rtnl_lock();
 
        pci_restore_state(pdev);
@@ -12292,6 +13430,7 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
        bp->rx_mode = BNX2X_RX_MODE_NONE;
 
        bnx2x_netif_stop(bp, 0);
+       netif_carrier_off(bp->dev);
 
        del_timer_sync(&bp->timer);
        bp->stats_state = STATS_STATE_DISABLED;
@@ -12318,8 +13457,6 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
 
        bp->state = BNX2X_STATE_CLOSED;
 
-       netif_carrier_off(bp->dev);
-
        return 0;
 }
 
@@ -12430,6 +13567,11 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct bnx2x *bp = netdev_priv(dev);
 
+       if (bp->recovery_state != BNX2X_RECOVERY_DONE) {
+               printk(KERN_ERR "Handling parity error recovery. Try again later\n");
+               return;
+       }
+
        rtnl_lock();
 
        bnx2x_eeh_recover(bp);
index 944964e78c8140e09802e19dfb2977bc6771335c..a1f3bf0cd630d2de15be155830ca7f038de904f7 100644 (file)
 #define MCP_REG_MCPR_NVM_SW_ARB                                 0x86420
 #define MCP_REG_MCPR_NVM_WRITE                                  0x86408
 #define MCP_REG_MCPR_SCRATCH                                    0xa0000
+#define MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK            (0x1<<1)
+#define MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK            (0x1<<0)
 /* [R 32] read first 32 bit after inversion of function 0. mapped as
    follows: [0] NIG attention for function0; [1] NIG attention for
    function1; [2] GPIO1 mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp;
 #define MISC_REG_E1HMF_MODE                                     0xa5f8
 /* [RW 32] Debug only: spare RW register reset by core reset */
 #define MISC_REG_GENERIC_CR_0                                   0xa460
+/* [RW 32] Debug only: spare RW register reset by por reset */
+#define MISC_REG_GENERIC_POR_1                                  0xa474
 /* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of
    these bits is written as a '1'; the corresponding SPIO bit will turn off
    it's drivers and become an input. This is the reset state of all GPIO
    (~misc_registers_sw_timer_cfg_4.sw_timer_cfg_4[1] ) is set */
 #define MISC_REG_SW_TIMER_RELOAD_VAL_4                          0xa2fc
 /* [RW 32] the value of the counter for sw timers1-8. there are 8 addresses
-   in this register. addres 0 - timer 1; address - timer 2�address 7 -
+   in this register. addres 0 - timer 1; address 1 - timer 2, ...  address 7 -
    timer 8 */
 #define MISC_REG_SW_TIMER_VAL                                   0xa5c0
 /* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
 /* [R 8] debug only: A bit mask for all PSWHST arbiter clients. '1' means
    this client is waiting for the arbiter. */
 #define PXP_REG_HST_CLIENTS_WAITING_TO_ARB                      0x103008
+/* [RW 1] When 1; doorbells are discarded and not passed to doorbell queue
+   block. Should be used for close the gates. */
+#define PXP_REG_HST_DISCARD_DOORBELLS                           0x1030a4
 /* [R 1] debug only: '1' means this PSWHST is discarding doorbells. This bit
    should update accoring to 'hst_discard_doorbells' register when the state
    machine is idle */
 #define PXP_REG_HST_DISCARD_DOORBELLS_STATUS                    0x1030a0
+/* [RW 1] When 1; new internal writes arriving to the block are discarded.
+   Should be used for close the gates. */
+#define PXP_REG_HST_DISCARD_INTERNAL_WRITES                     0x1030a8
 /* [R 6] debug only: A bit mask for all PSWHST internal write clients. '1'
    means this PSWHST is discarding inputs from this client. Each bit should
    update accoring to 'hst_discard_internal_writes' register when the state
 #define MISC_REGISTERS_GPIO_PORT_SHIFT                          4
 #define MISC_REGISTERS_GPIO_SET_POS                             8
 #define MISC_REGISTERS_RESET_REG_1_CLEAR                        0x588
+#define MISC_REGISTERS_RESET_REG_1_RST_HC                       (0x1<<29)
 #define MISC_REGISTERS_RESET_REG_1_RST_NIG                      (0x1<<7)
+#define MISC_REGISTERS_RESET_REG_1_RST_PXP                      (0x1<<26)
+#define MISC_REGISTERS_RESET_REG_1_RST_PXPV                     (0x1<<27)
 #define MISC_REGISTERS_RESET_REG_1_SET                          0x584
 #define MISC_REGISTERS_RESET_REG_2_CLEAR                        0x598
 #define MISC_REGISTERS_RESET_REG_2_RST_BMAC0                    (0x1<<0)
 #define MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE          (0x1<<14)
+#define MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE          (0x1<<15)
+#define MISC_REGISTERS_RESET_REG_2_RST_GRC                      (0x1<<4)
+#define MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B    (0x1<<6)
+#define MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE (0x1<<5)
+#define MISC_REGISTERS_RESET_REG_2_RST_MDIO                     (0x1<<13)
+#define MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE                (0x1<<11)
+#define MISC_REGISTERS_RESET_REG_2_RST_RBCN                     (0x1<<9)
 #define MISC_REGISTERS_RESET_REG_2_SET                          0x594
 #define MISC_REGISTERS_RESET_REG_3_CLEAR                        0x5a8
 #define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ    (0x1<<1)
 #define HW_LOCK_RESOURCE_GPIO                                   1
 #define HW_LOCK_RESOURCE_MDIO                                   0
 #define HW_LOCK_RESOURCE_PORT0_ATT_MASK                         3
+#define HW_LOCK_RESOURCE_RESERVED_08                            8
 #define HW_LOCK_RESOURCE_SPIO                                   2
 #define HW_LOCK_RESOURCE_UNDI                                   5
 #define PRS_FLAG_OVERETH_IPV4                                   1
 #define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0                (1<<5)
 #define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1                (1<<9)
 #define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR                (1<<12)
+#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY          (1<<28)
+#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY        (1<<31)
+#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY       (1<<29)
+#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY       (1<<30)
 #define AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT               (1<<15)
 #define AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR               (1<<14)
 #define AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR             (1<<20)
index 6dd64cf3cb76889d3f5be1ffdd0db84d6b395196..969ffed86b9f4e217581f61aa67a5cda815c21f9 100644 (file)
@@ -37,7 +37,6 @@
 static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
 {
        struct inet6_dev *idev;
-       struct inet6_ifaddr *ifa;
 
        if (!dev)
                return;
@@ -47,10 +46,12 @@ static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
                return;
 
        read_lock_bh(&idev->lock);
-       ifa = idev->addr_list;
-       if (ifa)
+       if (!list_empty(&idev->addr_list)) {
+               struct inet6_ifaddr *ifa
+                       = list_first_entry(&idev->addr_list,
+                                          struct inet6_ifaddr, if_list);
                ipv6_addr_copy(addr, &ifa->addr);
-       else
+       else
                ipv6_addr_set(addr, 0, 0, 0, 0);
 
        read_unlock_bh(&idev->lock);
index 0075514bf32fc1d78e15bab0a717c91f945227d6..5e12462a9d5ed7965a56c3178244bc8fd646c290 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/uaccess.h>
 #include <linux/errno.h>
 #include <linux/netdevice.h>
+#include <linux/netpoll.h>
 #include <linux/inetdevice.h>
 #include <linux/igmp.h>
 #include <linux/etherdevice.h>
@@ -430,7 +431,18 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
        }
 
        skb->priority = 1;
-       dev_queue_xmit(skb);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       if (unlikely(bond->dev->priv_flags & IFF_IN_NETPOLL)) {
+               struct netpoll *np = bond->dev->npinfo->netpoll;
+               slave_dev->npinfo = bond->dev->npinfo;
+               np->real_dev = np->dev = skb->dev;
+               slave_dev->priv_flags |= IFF_IN_NETPOLL;
+               netpoll_send_skb(np, skb);
+               slave_dev->priv_flags &= ~IFF_IN_NETPOLL;
+               np->dev = bond->dev;
+       } else
+#endif
+               dev_queue_xmit(skb);
 
        return 0;
 }
@@ -761,32 +773,6 @@ static int bond_check_dev_link(struct bonding *bond,
 
 /*----------------------------- Multicast list ------------------------------*/
 
-/*
- * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise
- */
-static inline int bond_is_dmi_same(const struct dev_mc_list *dmi1,
-                                  const struct dev_mc_list *dmi2)
-{
-       return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 &&
-                       dmi1->dmi_addrlen == dmi2->dmi_addrlen;
-}
-
-/*
- * returns dmi entry if found, NULL otherwise
- */
-static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi,
-                                                struct dev_mc_list *mc_list)
-{
-       struct dev_mc_list *idmi;
-
-       for (idmi = mc_list; idmi; idmi = idmi->next) {
-               if (bond_is_dmi_same(dmi, idmi))
-                       return idmi;
-       }
-
-       return NULL;
-}
-
 /*
  * Push the promiscuity flag down to appropriate slaves
  */
@@ -839,18 +825,18 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
  * Add a Multicast address to slaves
  * according to mode
  */
-static void bond_mc_add(struct bonding *bond, void *addr, int alen)
+static void bond_mc_add(struct bonding *bond, void *addr)
 {
        if (USES_PRIMARY(bond->params.mode)) {
                /* write lock already acquired */
                if (bond->curr_active_slave)
-                       dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0);
+                       dev_mc_add(bond->curr_active_slave->dev, addr);
        } else {
                struct slave *slave;
                int i;
 
                bond_for_each_slave(bond, slave, i)
-                       dev_mc_add(slave->dev, addr, alen, 0);
+                       dev_mc_add(slave->dev, addr);
        }
 }
 
@@ -858,18 +844,17 @@ static void bond_mc_add(struct bonding *bond, void *addr, int alen)
  * Remove a multicast address from slave
  * according to mode
  */
-static void bond_mc_delete(struct bonding *bond, void *addr, int alen)
+static void bond_mc_del(struct bonding *bond, void *addr)
 {
        if (USES_PRIMARY(bond->params.mode)) {
                /* write lock already acquired */
                if (bond->curr_active_slave)
-                       dev_mc_delete(bond->curr_active_slave->dev, addr,
-                                     alen, 0);
+                       dev_mc_del(bond->curr_active_slave->dev, addr);
        } else {
                struct slave *slave;
                int i;
                bond_for_each_slave(bond, slave, i) {
-                       dev_mc_delete(slave->dev, addr, alen, 0);
+                       dev_mc_del(slave->dev, addr);
                }
        }
 }
@@ -895,50 +880,6 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
        rcu_read_unlock();
 }
 
-/*
- * Totally destroys the mc_list in bond
- */
-static void bond_mc_list_destroy(struct bonding *bond)
-{
-       struct dev_mc_list *dmi;
-
-       dmi = bond->mc_list;
-       while (dmi) {
-               bond->mc_list = dmi->next;
-               kfree(dmi);
-               dmi = bond->mc_list;
-       }
-
-       bond->mc_list = NULL;
-}
-
-/*
- * Copy all the Multicast addresses from src to the bonding device dst
- */
-static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond,
-                            gfp_t gfp_flag)
-{
-       struct dev_mc_list *dmi, *new_dmi;
-
-       for (dmi = mc_list; dmi; dmi = dmi->next) {
-               new_dmi = kmalloc(sizeof(struct dev_mc_list), gfp_flag);
-
-               if (!new_dmi) {
-                       /* FIXME: Potential memory leak !!! */
-                       return -ENOMEM;
-               }
-
-               new_dmi->next = bond->mc_list;
-               bond->mc_list = new_dmi;
-               new_dmi->dmi_addrlen = dmi->dmi_addrlen;
-               memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen);
-               new_dmi->dmi_users = dmi->dmi_users;
-               new_dmi->dmi_gusers = dmi->dmi_gusers;
-       }
-
-       return 0;
-}
-
 /*
  * flush all members of flush->mc_list from device dev->mc_list
  */
@@ -946,16 +887,16 @@ static void bond_mc_list_flush(struct net_device *bond_dev,
                               struct net_device *slave_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
-       for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next)
-               dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+       netdev_for_each_mc_addr(ha, bond_dev)
+               dev_mc_del(slave_dev, ha->addr);
 
        if (bond->params.mode == BOND_MODE_8023AD) {
                /* del lacpdu mc addr from mc list */
                u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
-               dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0);
+               dev_mc_del(slave_dev, lacpdu_multicast);
        }
 }
 
@@ -969,7 +910,7 @@ static void bond_mc_list_flush(struct net_device *bond_dev,
 static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
                         struct slave *old_active)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
        if (!USES_PRIMARY(bond->params.mode))
                /* nothing to do -  mc list is already up-to-date on
@@ -984,9 +925,8 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
                if (bond->dev->flags & IFF_ALLMULTI)
                        dev_set_allmulti(old_active->dev, -1);
 
-               for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next)
-                       dev_mc_delete(old_active->dev, dmi->dmi_addr,
-                                     dmi->dmi_addrlen, 0);
+               netdev_for_each_mc_addr(ha, bond->dev)
+                       dev_mc_del(old_active->dev, ha->addr);
        }
 
        if (new_active) {
@@ -997,9 +937,8 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
                if (bond->dev->flags & IFF_ALLMULTI)
                        dev_set_allmulti(new_active->dev, 1);
 
-               for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next)
-                       dev_mc_add(new_active->dev, dmi->dmi_addr,
-                                  dmi->dmi_addrlen, 0);
+               netdev_for_each_mc_addr(ha, bond->dev)
+                       dev_mc_add(new_active->dev, ha->addr);
                bond_resend_igmp_join_requests(bond);
        }
 }
@@ -1329,6 +1268,61 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave)
        bond->slave_cnt--;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * You must hold read lock on bond->lock before calling this.
+ */
+static bool slaves_support_netpoll(struct net_device *bond_dev)
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       struct slave *slave;
+       int i = 0;
+       bool ret = true;
+
+       bond_for_each_slave(bond, slave, i) {
+               if ((slave->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
+                   !slave->dev->netdev_ops->ndo_poll_controller)
+                       ret = false;
+       }
+       return i != 0 && ret;
+}
+
+static void bond_poll_controller(struct net_device *bond_dev)
+{
+       struct net_device *dev = bond_dev->npinfo->netpoll->real_dev;
+       if (dev != bond_dev)
+               netpoll_poll_dev(dev);
+}
+
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       struct slave *slave;
+       const struct net_device_ops *ops;
+       int i;
+
+       read_lock(&bond->lock);
+       bond_dev->npinfo = NULL;
+       bond_for_each_slave(bond, slave, i) {
+               if (slave->dev) {
+                       ops = slave->dev->netdev_ops;
+                       if (ops->ndo_netpoll_cleanup)
+                               ops->ndo_netpoll_cleanup(slave->dev);
+                       else
+                               slave->dev->npinfo = NULL;
+               }
+       }
+       read_unlock(&bond->lock);
+}
+
+#else
+
+static void bond_netpoll_cleanup(struct net_device *bond_dev)
+{
+}
+
+#endif
+
 /*---------------------------------- IOCTL ----------------------------------*/
 
 static int bond_sethwaddr(struct net_device *bond_dev,
@@ -1411,7 +1405,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        struct bonding *bond = netdev_priv(bond_dev);
        const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
        struct slave *new_slave = NULL;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        struct sockaddr addr;
        int link_reporting;
        int old_features = bond_dev->features;
@@ -1485,14 +1479,27 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                 bond_dev->name,
                                 bond_dev->type, slave_dev->type);
 
-                       netdev_bonding_change(bond_dev, NETDEV_BONDING_OLDTYPE);
+                       res = netdev_bonding_change(bond_dev,
+                                                   NETDEV_PRE_TYPE_CHANGE);
+                       res = notifier_to_errno(res);
+                       if (res) {
+                               pr_err("%s: refused to change device type\n",
+                                      bond_dev->name);
+                               res = -EBUSY;
+                               goto err_undo_flags;
+                       }
+
+                       /* Flush unicast and multicast addresses */
+                       dev_uc_flush(bond_dev);
+                       dev_mc_flush(bond_dev);
 
                        if (slave_dev->type != ARPHRD_ETHER)
                                bond_setup_by_slave(bond_dev, slave_dev);
                        else
                                ether_setup(bond_dev);
 
-                       netdev_bonding_change(bond_dev, NETDEV_BONDING_NEWTYPE);
+                       netdev_bonding_change(bond_dev,
+                                             NETDEV_POST_TYPE_CHANGE);
                }
        } else if (bond_dev->type != slave_dev->type) {
                pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it.\n",
@@ -1593,9 +1600,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
                netif_addr_lock_bh(bond_dev);
                /* upload master's mc_list to new slave */
-               for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next)
-                       dev_mc_add(slave_dev, dmi->dmi_addr,
-                                  dmi->dmi_addrlen, 0);
+               netdev_for_each_mc_addr(ha, bond_dev)
+                       dev_mc_add(slave_dev, ha->addr);
                netif_addr_unlock_bh(bond_dev);
        }
 
@@ -1603,7 +1609,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                /* add lacpdu mc addr to mc list */
                u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
 
-               dev_mc_add(slave_dev, lacpdu_multicast, ETH_ALEN, 0);
+               dev_mc_add(slave_dev, lacpdu_multicast);
        }
 
        bond_add_vlans_on_slave(bond, slave_dev);
@@ -1735,6 +1741,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        bond_set_carrier(bond);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       if (slaves_support_netpoll(bond_dev)) {
+               bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+               if (bond_dev->npinfo)
+                       slave_dev->npinfo = bond_dev->npinfo;
+       } else if (!(bond_dev->priv_flags & IFF_DISABLE_NETPOLL)) {
+               bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
+               pr_info("New slave device %s does not support netpoll\n",
+                       slave_dev->name);
+               pr_info("Disabling netpoll support for %s\n", bond_dev->name);
+       }
+#endif
        read_unlock(&bond->lock);
 
        res = bond_create_slave_symlinks(bond_dev, slave_dev);
@@ -1801,6 +1819,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
                return -EINVAL;
        }
 
+       netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE);
        write_lock_bh(&bond->lock);
 
        slave = bond_get_slave_by_dev(bond, slave_dev);
@@ -1929,6 +1948,17 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 
        netdev_set_master(slave_dev, NULL);
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       read_lock_bh(&bond->lock);
+       if (slaves_support_netpoll(bond_dev))
+               bond_dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+       read_unlock_bh(&bond->lock);
+       if (slave_dev->netdev_ops->ndo_netpoll_cleanup)
+               slave_dev->netdev_ops->ndo_netpoll_cleanup(slave_dev);
+       else
+               slave_dev->npinfo = NULL;
+#endif
+
        /* close slave before restoring its mac address */
        dev_close(slave_dev);
 
@@ -3905,10 +3935,24 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
        return res;
 }
 
+static bool bond_addr_in_mc_list(unsigned char *addr,
+                                struct netdev_hw_addr_list *list,
+                                int addrlen)
+{
+       struct netdev_hw_addr *ha;
+
+       netdev_hw_addr_list_for_each(ha, list)
+               if (!memcmp(ha->addr, addr, addrlen))
+                       return true;
+
+       return false;
+}
+
 static void bond_set_multicast_list(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
+       bool found;
 
        /*
         * Do promisc before checking multicast_mode
@@ -3943,20 +3987,25 @@ static void bond_set_multicast_list(struct net_device *bond_dev)
        bond->flags = bond_dev->flags;
 
        /* looking for addresses to add to slaves' mc list */
-       for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {
-               if (!bond_mc_list_find_dmi(dmi, bond->mc_list))
-                       bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen);
+       netdev_for_each_mc_addr(ha, bond_dev) {
+               found = bond_addr_in_mc_list(ha->addr, &bond->mc_list,
+                                            bond_dev->addr_len);
+               if (!found)
+                       bond_mc_add(bond, ha->addr);
        }
 
        /* looking for addresses to delete from slaves' list */
-       for (dmi = bond->mc_list; dmi; dmi = dmi->next) {
-               if (!bond_mc_list_find_dmi(dmi, bond_dev->mc_list))
-                       bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen);
+       netdev_hw_addr_list_for_each(ha, &bond->mc_list) {
+               found = bond_addr_in_mc_list(ha->addr, &bond_dev->mc,
+                                            bond_dev->addr_len);
+               if (!found)
+                       bond_mc_del(bond, ha->addr);
        }
 
        /* save master's multicast list */
-       bond_mc_list_destroy(bond);
-       bond_mc_list_copy(bond_dev->mc_list, bond, GFP_ATOMIC);
+       __hw_addr_flush(&bond->mc_list);
+       __hw_addr_add_multiple(&bond->mc_list, &bond_dev->mc,
+                              bond_dev->addr_len, NETDEV_HW_ADDR_T_MULTICAST);
 
        read_unlock(&bond->lock);
 }
@@ -4448,6 +4497,10 @@ static const struct net_device_ops bond_netdev_ops = {
        .ndo_vlan_rx_register   = bond_vlan_rx_register,
        .ndo_vlan_rx_add_vid    = bond_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = bond_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_netpoll_cleanup    = bond_netpoll_cleanup,
+       .ndo_poll_controller    = bond_poll_controller,
+#endif
 };
 
 static void bond_destructor(struct net_device *bond_dev)
@@ -4541,6 +4594,8 @@ static void bond_uninit(struct net_device *bond_dev)
 {
        struct bonding *bond = netdev_priv(bond_dev);
 
+       bond_netpoll_cleanup(bond_dev);
+
        /* Release the bonded slaves */
        bond_release_all(bond_dev);
 
@@ -4550,9 +4605,7 @@ static void bond_uninit(struct net_device *bond_dev)
 
        bond_remove_proc_entry(bond);
 
-       netif_addr_lock_bh(bond_dev);
-       bond_mc_list_destroy(bond);
-       netif_addr_unlock_bh(bond_dev);
+       __hw_addr_flush(&bond->mc_list);
 }
 
 /*------------------------- Module initialization ---------------------------*/
@@ -4683,13 +4736,13 @@ static int bond_check_params(struct bond_params *params)
        }
 
        if (num_grat_arp < 0 || num_grat_arp > 255) {
-               pr_warning("Warning: num_grat_arp (%d) not in range 0-255 so it was reset to 1 \n",
+               pr_warning("Warning: num_grat_arp (%d) not in range 0-255 so it was reset to 1\n",
                           num_grat_arp);
                num_grat_arp = 1;
        }
 
        if (num_unsol_na < 0 || num_unsol_na > 255) {
-               pr_warning("Warning: num_unsol_na (%d) not in range 0-255 so it was reset to 1 \n",
+               pr_warning("Warning: num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
                           num_unsol_na);
                num_unsol_na = 1;
        }
@@ -4924,6 +4977,8 @@ static int bond_init(struct net_device *bond_dev)
        list_add_tail(&bond->bond_list, &bn->dev_list);
 
        bond_prepare_sysfs_group(bond);
+
+       __hw_addr_init(&bond->mc_list);
        return 0;
 }
 
index 257a7a4dfce98b93f7d04130d21e98f3173c1ab2..2aa336720591066734e9ce2ed036c81049fb1caa 100644 (file)
@@ -202,7 +202,7 @@ struct bonding {
        char     proc_file_name[IFNAMSIZ];
 #endif /* CONFIG_PROC_FS */
        struct   list_head bond_list;
-       struct   dev_mc_list *mc_list;
+       struct   netdev_hw_addr_list mc_list;
        int      (*xmit_hash_policy)(struct sk_buff *, int);
        __be32   master_ip;
        u16      flags;
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
new file mode 100644 (file)
index 0000000..0b28e01
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# CAIF physical drivers
+#
+
+if CAIF
+
+comment "CAIF transport drivers"
+
+config CAIF_TTY
+       tristate "CAIF TTY transport driver"
+       default n
+       ---help---
+       The CAIF TTY transport driver is a Line Discipline (ldisc)
+       identified as N_CAIF. When this ldisc is opened from user space
+       it will redirect the TTY's traffic into the CAIF stack.
+
+endif # CAIF
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
new file mode 100644 (file)
index 0000000..52b6d1f
--- /dev/null
@@ -0,0 +1,12 @@
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_DBG_FLAGS := -DDEBUG
+endif
+
+KBUILD_EXTRA_SYMBOLS=net/caif/Module.symvers
+
+ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
+clean-dirs:= .tmp_versions
+clean-files:= Module.symvers modules.order *.cmd *~ \
+
+# Serial interface
+obj-$(CONFIG_CAIF_TTY) += caif_serial.o
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
new file mode 100644 (file)
index 0000000..09257ca
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland / sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/tty.h>
+#include <linux/file.h>
+#include <linux/if_arp.h>
+#include <net/caif/caif_device.h>
+#include <net/caif/cfcnfg.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sjur Brendeland<sjur.brandeland@stericsson.com>");
+MODULE_DESCRIPTION("CAIF serial device TTY line discipline");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_CAIF);
+
+#define SEND_QUEUE_LOW 10
+#define SEND_QUEUE_HIGH 100
+#define CAIF_SENDING           1 /* Bit 1 = 0x02*/
+#define CAIF_FLOW_OFF_SENT     4 /* Bit 4 = 0x10 */
+#define MAX_WRITE_CHUNK             4096
+#define ON 1
+#define OFF 0
+#define CAIF_MAX_MTU 4096
+
+/*This list is protected by the rtnl lock. */
+static LIST_HEAD(ser_list);
+
+static int ser_loop;
+module_param(ser_loop, bool, S_IRUGO);
+MODULE_PARM_DESC(ser_loop, "Run in simulated loopback mode.");
+
+static int ser_use_stx = 1;
+module_param(ser_use_stx, bool, S_IRUGO);
+MODULE_PARM_DESC(ser_use_stx, "STX enabled or not.");
+
+static int ser_use_fcs = 1;
+
+module_param(ser_use_fcs, bool, S_IRUGO);
+MODULE_PARM_DESC(ser_use_fcs, "FCS enabled or not.");
+
+static int ser_write_chunk = MAX_WRITE_CHUNK;
+module_param(ser_write_chunk, int, S_IRUGO);
+
+MODULE_PARM_DESC(ser_write_chunk, "Maximum size of data written to UART.");
+
+static struct dentry *debugfsdir;
+
+static int caif_net_open(struct net_device *dev);
+static int caif_net_close(struct net_device *dev);
+
+struct ser_device {
+       struct caif_dev_common common;
+       struct list_head node;
+       struct net_device *dev;
+       struct sk_buff_head head;
+       struct tty_struct *tty;
+       bool tx_started;
+       unsigned long state;
+       char *tty_name;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_tty_dir;
+       struct debugfs_blob_wrapper tx_blob;
+       struct debugfs_blob_wrapper rx_blob;
+       u8 rx_data[128];
+       u8 tx_data[128];
+       u8 tty_status;
+
+#endif
+};
+
+static void caifdev_setup(struct net_device *dev);
+static void ldisc_tx_wakeup(struct tty_struct *tty);
+#ifdef CONFIG_DEBUG_FS
+static inline void update_tty_status(struct ser_device *ser)
+{
+       ser->tty_status =
+               ser->tty->stopped << 5 |
+               ser->tty->hw_stopped << 4 |
+               ser->tty->flow_stopped << 3 |
+               ser->tty->packet << 2 |
+               ser->tty->low_latency << 1 |
+               ser->tty->warned;
+}
+static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
+{
+       ser->debugfs_tty_dir =
+                       debugfs_create_dir(tty->name, debugfsdir);
+       if (!IS_ERR(ser->debugfs_tty_dir)) {
+               debugfs_create_blob("last_tx_msg", S_IRUSR,
+                               ser->debugfs_tty_dir,
+                               &ser->tx_blob);
+
+               debugfs_create_blob("last_rx_msg", S_IRUSR,
+                               ser->debugfs_tty_dir,
+                               &ser->rx_blob);
+
+               debugfs_create_x32("ser_state", S_IRUSR,
+                               ser->debugfs_tty_dir,
+                               (u32 *)&ser->state);
+
+               debugfs_create_x8("tty_status", S_IRUSR,
+                               ser->debugfs_tty_dir,
+                               &ser->tty_status);
+
+       }
+       ser->tx_blob.data = ser->tx_data;
+       ser->tx_blob.size = 0;
+       ser->rx_blob.data = ser->rx_data;
+       ser->rx_blob.size = 0;
+}
+
+static inline void debugfs_deinit(struct ser_device *ser)
+{
+       debugfs_remove_recursive(ser->debugfs_tty_dir);
+}
+
+static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size)
+{
+       if (size > sizeof(ser->rx_data))
+               size = sizeof(ser->rx_data);
+       memcpy(ser->rx_data, data, size);
+       ser->rx_blob.data = ser->rx_data;
+       ser->rx_blob.size = size;
+}
+
+static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
+{
+       if (size > sizeof(ser->tx_data))
+               size = sizeof(ser->tx_data);
+       memcpy(ser->tx_data, data, size);
+       ser->tx_blob.data = ser->tx_data;
+       ser->tx_blob.size = size;
+}
+#else
+static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
+{
+}
+
+static inline void debugfs_deinit(struct ser_device *ser)
+{
+}
+
+static inline void update_tty_status(struct ser_device *ser)
+{
+}
+
+static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size)
+{
+}
+
+static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
+{
+}
+
+#endif
+
+static void ldisc_receive(struct tty_struct *tty, const u8 *data,
+                       char *flags, int count)
+{
+       struct sk_buff *skb = NULL;
+       struct ser_device *ser;
+       int ret;
+       u8 *p;
+       ser = tty->disc_data;
+
+       /*
+        * NOTE: flags may contain information about break or overrun.
+        * This is not yet handled.
+        */
+
+
+       /*
+        * Workaround for garbage at start of transmission,
+        * only enable if STX handling is not enabled.
+        */
+       if (!ser->common.use_stx && !ser->tx_started) {
+               dev_info(&ser->dev->dev,
+                       "Bytes received before initial transmission -"
+                       "bytes discarded.\n");
+               return;
+       }
+
+       BUG_ON(ser->dev == NULL);
+
+       /* Get a suitable caif packet and copy in data. */
+       skb = netdev_alloc_skb(ser->dev, count+1);
+       if (skb == NULL)
+               return;
+       p = skb_put(skb, count);
+       memcpy(p, data, count);
+
+       skb->protocol = htons(ETH_P_CAIF);
+       skb_reset_mac_header(skb);
+       skb->dev = ser->dev;
+       debugfs_rx(ser, data, count);
+       /* Push received packet up the stack. */
+       ret = netif_rx_ni(skb);
+       if (!ret) {
+               ser->dev->stats.rx_packets++;
+               ser->dev->stats.rx_bytes += count;
+       } else
+               ++ser->dev->stats.rx_dropped;
+       update_tty_status(ser);
+}
+
+static int handle_tx(struct ser_device *ser)
+{
+       struct tty_struct *tty;
+       struct sk_buff *skb;
+       int tty_wr, len, room;
+       tty = ser->tty;
+       ser->tx_started = true;
+
+       /* Enter critical section */
+       if (test_and_set_bit(CAIF_SENDING, &ser->state))
+               return 0;
+
+       /* skb_peek is safe because handle_tx is called after skb_queue_tail */
+       while ((skb = skb_peek(&ser->head)) != NULL) {
+
+               /* Make sure you don't write too much */
+               len = skb->len;
+               room = tty_write_room(tty);
+               if (!room)
+                       break;
+               if (room > ser_write_chunk)
+                       room = ser_write_chunk;
+               if (len > room)
+                       len = room;
+
+               /* Write to tty or loopback */
+               if (!ser_loop) {
+                       tty_wr = tty->ops->write(tty, skb->data, len);
+                       update_tty_status(ser);
+               } else {
+                       tty_wr = len;
+                       ldisc_receive(tty, skb->data, NULL, len);
+               }
+               ser->dev->stats.tx_packets++;
+               ser->dev->stats.tx_bytes += tty_wr;
+
+               /* Error on TTY ?! */
+               if (tty_wr < 0)
+                       goto error;
+               /* Reduce buffer written, and discard if empty */
+               skb_pull(skb, tty_wr);
+               if (skb->len == 0) {
+                       struct sk_buff *tmp = skb_dequeue(&ser->head);
+                       BUG_ON(tmp != skb);
+                       if (in_interrupt())
+                               dev_kfree_skb_irq(skb);
+                       else
+                               kfree_skb(skb);
+               }
+       }
+       /* Send flow off if queue is empty */
+       if (ser->head.qlen <= SEND_QUEUE_LOW &&
+               test_and_clear_bit(CAIF_FLOW_OFF_SENT, &ser->state) &&
+               ser->common.flowctrl != NULL)
+                               ser->common.flowctrl(ser->dev, ON);
+       clear_bit(CAIF_SENDING, &ser->state);
+       return 0;
+error:
+       clear_bit(CAIF_SENDING, &ser->state);
+       return tty_wr;
+}
+
+static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ser_device *ser;
+       BUG_ON(dev == NULL);
+       ser = netdev_priv(dev);
+
+       /* Send flow off once, on high water mark */
+       if (ser->head.qlen > SEND_QUEUE_HIGH &&
+               !test_and_set_bit(CAIF_FLOW_OFF_SENT, &ser->state) &&
+               ser->common.flowctrl != NULL)
+
+               ser->common.flowctrl(ser->dev, OFF);
+
+       skb_queue_tail(&ser->head, skb);
+       return handle_tx(ser);
+}
+
+
+static void ldisc_tx_wakeup(struct tty_struct *tty)
+{
+       struct ser_device *ser;
+       ser = tty->disc_data;
+       BUG_ON(ser == NULL);
+       BUG_ON(ser->tty != tty);
+       handle_tx(ser);
+}
+
+
+static int ldisc_open(struct tty_struct *tty)
+{
+       struct ser_device *ser;
+       struct net_device *dev;
+       char name[64];
+       int result;
+
+       /* No write no play */
+       if (tty->ops->write == NULL)
+               return -EOPNOTSUPP;
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_TTY_CONFIG))
+               return -EPERM;
+
+       sprintf(name, "cf%s", tty->name);
+       dev = alloc_netdev(sizeof(*ser), name, caifdev_setup);
+       ser = netdev_priv(dev);
+       ser->tty = tty_kref_get(tty);
+       ser->dev = dev;
+       debugfs_init(ser, tty);
+       tty->receive_room = N_TTY_BUF_SIZE;
+       tty->disc_data = ser;
+       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       rtnl_lock();
+       result = register_netdevice(dev);
+       if (result) {
+               rtnl_unlock();
+               free_netdev(dev);
+               return -ENODEV;
+       }
+
+       list_add(&ser->node, &ser_list);
+       rtnl_unlock();
+       netif_stop_queue(dev);
+       update_tty_status(ser);
+       return 0;
+}
+
+static void ldisc_close(struct tty_struct *tty)
+{
+       struct ser_device *ser = tty->disc_data;
+       /* Remove may be called inside or outside of rtnl_lock */
+       int islocked = rtnl_is_locked();
+       if (!islocked)
+               rtnl_lock();
+       /* device is freed automagically by net-sysfs */
+       dev_close(ser->dev);
+       unregister_netdevice(ser->dev);
+       list_del(&ser->node);
+       debugfs_deinit(ser);
+       tty_kref_put(ser->tty);
+       if (!islocked)
+               rtnl_unlock();
+}
+
+/* The line discipline structure. */
+static struct tty_ldisc_ops caif_ldisc = {
+       .owner =        THIS_MODULE,
+       .magic =        TTY_LDISC_MAGIC,
+       .name =         "n_caif",
+       .open =         ldisc_open,
+       .close =        ldisc_close,
+       .receive_buf =  ldisc_receive,
+       .write_wakeup = ldisc_tx_wakeup
+};
+
+static int register_ldisc(void)
+{
+       int result;
+       result = tty_register_ldisc(N_CAIF, &caif_ldisc);
+       if (result < 0) {
+               pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF,
+                       result);
+               return result;
+       }
+       return result;
+}
+static const struct net_device_ops netdev_ops = {
+       .ndo_open = caif_net_open,
+       .ndo_stop = caif_net_close,
+       .ndo_start_xmit = caif_xmit
+};
+
+static void caifdev_setup(struct net_device *dev)
+{
+       struct ser_device *serdev = netdev_priv(dev);
+       dev->features = 0;
+       dev->netdev_ops = &netdev_ops;
+       dev->type = ARPHRD_CAIF;
+       dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+       dev->mtu = CAIF_MAX_MTU;
+       dev->hard_header_len = CAIF_NEEDED_HEADROOM;
+       dev->tx_queue_len = 0;
+       dev->destructor = free_netdev;
+       skb_queue_head_init(&serdev->head);
+       serdev->common.link_select = CAIF_LINK_LOW_LATENCY;
+       serdev->common.use_frag = true;
+       serdev->common.use_stx = ser_use_stx;
+       serdev->common.use_fcs = ser_use_fcs;
+       serdev->dev = dev;
+}
+
+
+static int caif_net_open(struct net_device *dev)
+{
+       struct ser_device *ser;
+       ser = netdev_priv(dev);
+       netif_wake_queue(dev);
+       return 0;
+}
+
+static int caif_net_close(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+       return 0;
+}
+
+static int __init caif_ser_init(void)
+{
+       int ret;
+       ret = register_ldisc();
+       debugfsdir = debugfs_create_dir("caif_serial", NULL);
+       return ret;
+}
+
+static void __exit caif_ser_exit(void)
+{
+       struct ser_device *ser = NULL;
+       struct list_head *node;
+       struct list_head *_tmp;
+       list_for_each_safe(node, _tmp, &ser_list) {
+               ser = list_entry(node, struct ser_device, node);
+               dev_close(ser->dev);
+               unregister_netdevice(ser->dev);
+               list_del(node);
+       }
+       tty_unregister_ldisc(N_CAIF);
+       debugfs_remove_recursive(debugfsdir);
+}
+
+module_init(caif_ser_init);
+module_exit(caif_ser_exit);
index a2f29a38798a4de2fe9ae631749afa81279ce449..2d8bd86bc5e2072bf66d4966d5042869044fb0b9 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/string.h>
 #include <linux/types.h>
 
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
@@ -376,7 +375,6 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
        at91_write(priv, AT91_MCR(mb), reg_mcr);
 
        stats->tx_bytes += cf->can_dlc;
-       dev->trans_start = jiffies;
 
        /* _NOTE_: substract AT91_MB_TX_FIRST offset from mb! */
        can_put_echo_skb(skb, dev, mb - AT91_MB_TX_FIRST);
@@ -662,7 +660,6 @@ static int at91_poll_err(struct net_device *dev, int quota, u32 reg_sr)
        at91_poll_err_frame(dev, cf, reg_sr);
        netif_receive_skb(skb);
 
-       dev->last_rx = jiffies;
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
 
@@ -899,7 +896,6 @@ static void at91_irq_err(struct net_device *dev)
        at91_irq_err_state(dev, cf, new_state);
        netif_rx(skb);
 
-       dev->last_rx = jiffies;
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += cf->can_dlc;
 
index 03489864376df7ca060927c3afd3d058b41e088b..b6e890d28366c68bf2ae078b4a73f688dfe75962 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/skbuff.h>
 #include <linux/platform_device.h>
 
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
@@ -270,8 +269,6 @@ static int bfin_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* fill data length code */
        bfin_write16(&reg->chl[TRANSMIT_CHL].dlc, dlc);
 
-       dev->trans_start = jiffies;
-
        can_put_echo_skb(skb, dev, 0);
 
        /* set transmit request */
index b39b108318b48cfa584d25a124babe936af1a9ec..b11a0cb5ed81eb9ffabaa067dcdc544edabadc22 100644 (file)
@@ -58,7 +58,6 @@
  *
  */
 
-#include <linux/can.h>
 #include <linux/can/core.h>
 #include <linux/can/dev.h>
 #include <linux/can/platform/mcp251x.h>
@@ -476,7 +475,6 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
 
        netif_stop_queue(net);
        priv->tx_skb = skb;
-       net->trans_start = jiffies;
        queue_work(priv->wq, &priv->tx_work);
 
        return NETDEV_TX_OK;
@@ -923,12 +921,16 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
        struct net_device *net;
        struct mcp251x_priv *priv;
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
+       int model = spi_get_device_id(spi)->driver_data;
        int ret = -ENODEV;
 
        if (!pdata)
                /* Platform data is required for osc freq */
                goto error_out;
 
+       if (model)
+               pdata->model = model;
+
        /* Allocate can/net device */
        net = alloc_candev(sizeof(struct mcp251x_priv), TX_ECHO_SKB_MAX);
        if (!net) {
@@ -1118,6 +1120,15 @@ static int mcp251x_can_resume(struct spi_device *spi)
 #define mcp251x_can_resume NULL
 #endif
 
+static struct spi_device_id mcp251x_id_table[] = {
+       { "mcp251x",    0 /* Use pdata.model */ },
+       { "mcp2510",    CAN_MCP251X_MCP2510 },
+       { "mcp2515",    CAN_MCP251X_MCP2515 },
+       { },
+};
+
+MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
+
 static struct spi_driver mcp251x_can_driver = {
        .driver = {
                .name = DEVICE_NAME,
@@ -1125,6 +1136,7 @@ static struct spi_driver mcp251x_can_driver = {
                .owner = THIS_MODULE,
        },
 
+       .id_table = mcp251x_id_table,
        .probe = mcp251x_can_probe,
        .remove = __devexit_p(mcp251x_can_remove),
        .suspend = mcp251x_can_suspend,
index 03e7c48465a212bd8b5ca17f248ff27e2f58051f..225fd147774aa1f8c37ea452f46d1e558a317316 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
index 6b7dd578d417b55c65e5eeb47439b5c604e76500..64c378cd0c34125471f6cb3fcae10482ae1e0656 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/list.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 #include <linux/io.h>
index 9e277d64a3183e1232b5ce604b80d7bdde635a79..ae3505afd682ccf58a9bd09dc6112ae83eaf96c4 100644 (file)
@@ -53,7 +53,9 @@ config CAN_PLX_PCI
          Driver supports now:
           - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/)
           - Adlink PCI-7841/cPCI-7841 SE card
+          - esd CAN-PCI/CPCI/PCI104/200 (http://www.esd.eu/)
+          - esd CAN-PCI/PMC/266
+          - esd CAN-PCIe/2000
           - Marathon CAN-bus-PCI card (http://www.marathon.ru/)
           - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/)
-
 endif
index 5f53da0bc40ceddc2ce58c8949b536f789b1b15d..36f4f9780c300c3952e5889e960de3ddb75e8b45 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/io.h>
 
index 441e776a7f59f51cedb91671e83f80e66436bde9..ed004cebd31f0dc46b79f34c41893d279d5e41a2 100644 (file)
@@ -36,7 +36,6 @@
 #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>
 
index 4aff4070db96236a90229380cebcf1e2e7f1e53c..437b5c716a2426aeac6157808b0539976db0515a 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/io.h>
 
@@ -41,7 +40,10 @@ MODULE_DESCRIPTION("Socket-CAN driver for PLX90xx PCI-bridge cards with "
 MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, "
                        "Adlink PCI-7841/cPCI-7841 SE, "
                        "Marathon CAN-bus-PCI, "
-                       "TEWS TECHNOLOGIES TPMC810");
+                       "TEWS TECHNOLOGIES TPMC810, "
+                       "esd CAN-PCI/CPCI/PCI104/200, "
+                       "esd CAN-PCI/PMC/266, "
+                       "esd CAN-PCIe/2000")
 MODULE_LICENSE("GPL v2");
 
 #define PLX_PCI_MAX_CHAN 2
@@ -50,11 +52,14 @@ struct plx_pci_card {
        int channels;                   /* detected channels count */
        struct net_device *net_dev[PLX_PCI_MAX_CHAN];
        void __iomem *conf_addr;
+
+       /* Pointer to device-dependent reset function */
+       void (*reset_func)(struct pci_dev *pdev);
 };
 
 #define PLX_PCI_CAN_CLOCK (16000000 / 2)
 
-/* PLX90xx registers */
+/* PLX9030/9050/9052 registers */
 #define PLX_INTCSR     0x4c            /* Interrupt Control/Status */
 #define PLX_CNTRL      0x50            /* User I/O, Direct Slave Response,
                                         * Serial EEPROM, and Initialization
@@ -66,6 +71,14 @@ struct plx_pci_card {
 #define PLX_PCI_INT_EN (1 << 6)        /* PCI Interrupt Enable */
 #define PLX_PCI_RESET  (1 << 30)       /* PCI Adapter Software Reset */
 
+/* PLX9056 registers */
+#define PLX9056_INTCSR 0x68            /* Interrupt Control/Status */
+#define PLX9056_CNTRL  0x6c            /* Control / Software Reset */
+
+#define PLX9056_LINTI  (1 << 11)
+#define PLX9056_PCI_INT_EN (1 << 8)
+#define PLX9056_PCI_RCR        (1 << 29)       /* Read Configuration Registers */
+
 /*
  * The board configuration is probably following:
  * RX1 is connected to ground.
@@ -101,6 +114,13 @@ struct plx_pci_card {
 #define ADLINK_PCI_VENDOR_ID           0x144A
 #define ADLINK_PCI_DEVICE_ID           0x7841
 
+#define ESD_PCI_SUB_SYS_ID_PCI200      0x0004
+#define ESD_PCI_SUB_SYS_ID_PCI266      0x0009
+#define ESD_PCI_SUB_SYS_ID_PMC266      0x000e
+#define ESD_PCI_SUB_SYS_ID_CPCI200     0x010b
+#define ESD_PCI_SUB_SYS_ID_PCIE2000    0x0200
+#define ESD_PCI_SUB_SYS_ID_PCI104200   0x0501
+
 #define MARATHON_PCI_DEVICE_ID         0x2715
 
 #define TEWS_PCI_VENDOR_ID             0x1498
@@ -108,6 +128,7 @@ struct plx_pci_card {
 
 static void plx_pci_reset_common(struct pci_dev *pdev);
 static void plx_pci_reset_marathon(struct pci_dev *pdev);
+static void plx9056_pci_reset_common(struct pci_dev *pdev);
 
 struct plx_pci_channel_map {
        u32 bar;
@@ -148,6 +169,30 @@ static struct plx_pci_card_info plx_pci_card_info_adlink_se __devinitdata = {
        /* based on PLX9052 */
 };
 
+static struct plx_pci_card_info plx_pci_card_info_esd200 __devinitdata = {
+       "esd CAN-PCI/CPCI/PCI104/200", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} },
+       &plx_pci_reset_common
+       /* based on PLX9030/9050 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_esd266 __devinitdata = {
+       "esd CAN-PCI/PMC/266", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} },
+       &plx9056_pci_reset_common
+       /* based on PLX9056 */
+};
+
+static struct plx_pci_card_info plx_pci_card_info_esd2000 __devinitdata = {
+       "esd CAN-PCIe/2000", 2,
+       PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR,
+       {0, 0x00, 0x00}, { {2, 0x00, 0x80}, {2, 0x100, 0x80} },
+       &plx9056_pci_reset_common
+       /* based on PEX8311 */
+};
+
 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,
@@ -179,6 +224,48 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = {
                PCI_CLASS_COMMUNICATION_OTHER << 8, ~0,
                (kernel_ulong_t)&plx_pci_card_info_adlink_se
        },
+       {
+               /* esd CAN-PCI/200 */
+               PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+               PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI200,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_esd200
+       },
+       {
+               /* esd CAN-CPCI/200 */
+               PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_CPCI200,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_esd200
+       },
+       {
+               /* esd CAN-PCI104/200 */
+               PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+               PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI104200,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_esd200
+       },
+       {
+               /* esd CAN-PCI/266 */
+               PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056,
+               PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCI266,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_esd266
+       },
+       {
+               /* esd CAN-PMC/266 */
+               PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056,
+               PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PMC266,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_esd266
+       },
+       {
+               /* esd CAN-PCIE/2000 */
+               PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9056,
+               PCI_VENDOR_ID_ESDGMBH, ESD_PCI_SUB_SYS_ID_PCIE2000,
+               0, 0,
+               (kernel_ulong_t)&plx_pci_card_info_esd2000
+       },
        {
                /* Marathon CAN-bus-PCI card */
                PCI_VENDOR_ID_PLX, MARATHON_PCI_DEVICE_ID,
@@ -242,7 +329,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
 }
 
 /*
- * PLX90xx software reset
+ * PLX9030/50/52 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.
  */
@@ -259,6 +346,38 @@ static void plx_pci_reset_common(struct pci_dev *pdev)
        iowrite32(cntrl, card->conf_addr + PLX_CNTRL);
 };
 
+/*
+ * PLX9056 software reset
+ * Assert LRESET# and reset device(s) on the Local Bus (if wired).
+ */
+static void plx9056_pci_reset_common(struct pci_dev *pdev)
+{
+       struct plx_pci_card *card = pci_get_drvdata(pdev);
+       u32 cntrl;
+
+       /* issue a local bus reset */
+       cntrl = ioread32(card->conf_addr + PLX9056_CNTRL);
+       cntrl |= PLX_PCI_RESET;
+       iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL);
+       udelay(100);
+       cntrl ^= PLX_PCI_RESET;
+       iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL);
+
+       /* reload local configuration from EEPROM */
+       cntrl |= PLX9056_PCI_RCR;
+       iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL);
+
+       /*
+        * There is no safe way to poll for the end
+        * of reconfiguration process. Waiting for 10ms
+        * is safe.
+        */
+       mdelay(10);
+
+       cntrl ^= PLX9056_PCI_RCR;
+       iowrite32(cntrl, card->conf_addr + PLX9056_CNTRL);
+};
+
 /* Special reset function for Marathon card */
 static void plx_pci_reset_marathon(struct pci_dev *pdev)
 {
@@ -302,13 +421,16 @@ static void plx_pci_del_card(struct pci_dev *pdev)
                free_sja1000dev(dev);
        }
 
-       plx_pci_reset_common(pdev);
+       card->reset_func(pdev);
 
        /*
-        * Disable interrupts from PCI-card (PLX90xx) and disable Local_1,
-        * Local_2 interrupts
+        * Disable interrupts from PCI-card and disable local
+        * interrupts
         */
-       iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+       if (pdev->device != PCI_DEVICE_ID_PLX_9056)
+               iowrite32(0x0, card->conf_addr + PLX_INTCSR);
+       else
+               iowrite32(0x0, card->conf_addr + PLX9056_INTCSR);
 
        if (card->conf_addr)
                pci_iounmap(pdev, card->conf_addr);
@@ -367,6 +489,7 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
        card->conf_addr = addr + ci->conf_map.offset;
 
        ci->reset_func(pdev);
+       card->reset_func = ci->reset_func;
 
        /* Detect available channels */
        for (i = 0; i < ci->channel_count; i++) {
@@ -438,10 +561,17 @@ static int __devinit plx_pci_add_card(struct pci_dev *pdev,
         * 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);
-
+       if (pdev->device != PCI_DEVICE_ID_PLX_9056) {
+               val = ioread32(card->conf_addr + PLX_INTCSR);
+               if (pdev->subsystem_vendor == PCI_VENDOR_ID_ESDGMBH)
+                       val |= PLX_LINT1_EN | PLX_PCI_INT_EN;
+               else
+                       val |= PLX_LINT1_EN | PLX_LINT2_EN | PLX_PCI_INT_EN;
+               iowrite32(val, card->conf_addr + PLX_INTCSR);
+       } else {
+               iowrite32(PLX9056_LINTI | PLX9056_PCI_INT_EN,
+                         card->conf_addr + PLX9056_INTCSR);
+       }
        return 0;
 
 failure_cleanup:
index 145b1a731a53aa99f9c8c902df96bf8453c59796..85f7cbfe8e5fbfe4ec54e6290a78372f0b576533 100644 (file)
@@ -60,7 +60,6 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>
 
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 
@@ -84,6 +83,20 @@ static struct can_bittiming_const sja1000_bittiming_const = {
        .brp_inc = 1,
 };
 
+static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
+{
+       unsigned long flags;
+
+       /*
+        * The command register needs some locking and time to settle
+        * the write_reg() operation - especially on SMP systems.
+        */
+       spin_lock_irqsave(&priv->cmdreg_lock, flags);
+       priv->write_reg(priv, REG_CMR, val);
+       priv->read_reg(priv, REG_SR);
+       spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
+}
+
 static int sja1000_probe_chip(struct net_device *dev)
 {
        struct sja1000_priv *priv = netdev_priv(dev);
@@ -293,11 +306,9 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
        for (i = 0; i < dlc; i++)
                priv->write_reg(priv, dreg++, cf->data[i]);
 
-       dev->trans_start = jiffies;
-
        can_put_echo_skb(skb, dev, 0);
 
-       priv->write_reg(priv, REG_CMR, CMD_TR);
+       sja1000_write_cmdreg(priv, CMD_TR);
 
        return NETDEV_TX_OK;
 }
@@ -346,7 +357,7 @@ static void sja1000_rx(struct net_device *dev)
        cf->can_id = id;
 
        /* release receive buffer */
-       priv->write_reg(priv, REG_CMR, CMD_RRB);
+       sja1000_write_cmdreg(priv, CMD_RRB);
 
        netif_rx(skb);
 
@@ -374,7 +385,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                stats->rx_over_errors++;
                stats->rx_errors++;
-               priv->write_reg(priv, REG_CMR, CMD_CDO);        /* clear bit */
+               sja1000_write_cmdreg(priv, CMD_CDO);    /* clear bit */
        }
 
        if (isrc & IRQ_EI) {
index 97a622b9302f22116d02de429f2877dfe4474ba7..de8e778f6832de6c1040a15b6e6807dbaf67cce6 100644 (file)
@@ -167,6 +167,7 @@ struct sja1000_priv {
 
        void __iomem *reg_base;  /* ioremap'ed address to registers */
        unsigned long irq_flags; /* for request_irq() */
+       spinlock_t cmdreg_lock;  /* lock for concurrent cmd register writes */
 
        u16 flags;              /* custom mode flags */
        u8 ocr;                 /* output control register */
index a6a51f1559628db67181dea7c1bc0cba2355b50d..496223e9e2fc469d14dffee5bd584951239cabe1 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/platform/sja1000.h>
 
index 9dd076a626a5b329b1ff368f3682daabe516acd9..34e79efbd2fca7413924a8e47abde8b47baa82bb 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/delay.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 
 #include <linux/of_platform.h>
index 628374c2a05f728b7d05f25d016e12ba7312e8c3..d9fadc489b32dc75f09c0d55d63b9e85b90f143c 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/platform/sja1000.h>
 #include <linux/io.h>
@@ -37,16 +36,36 @@ MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
 MODULE_LICENSE("GPL v2");
 
-static u8 sp_read_reg(const struct sja1000_priv *priv, int reg)
+static u8 sp_read_reg8(const struct sja1000_priv *priv, int reg)
 {
        return ioread8(priv->reg_base + reg);
 }
 
-static void sp_write_reg(const struct sja1000_priv *priv, int reg, u8 val)
+static void sp_write_reg8(const struct sja1000_priv *priv, int reg, u8 val)
 {
        iowrite8(val, priv->reg_base + reg);
 }
 
+static u8 sp_read_reg16(const struct sja1000_priv *priv, int reg)
+{
+       return ioread8(priv->reg_base + reg * 2);
+}
+
+static void sp_write_reg16(const struct sja1000_priv *priv, int reg, u8 val)
+{
+       iowrite8(val, priv->reg_base + reg * 2);
+}
+
+static u8 sp_read_reg32(const struct sja1000_priv *priv, int reg)
+{
+       return ioread8(priv->reg_base + reg * 4);
+}
+
+static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
+{
+       iowrite8(val, priv->reg_base + reg * 4);
+}
+
 static int sp_probe(struct platform_device *pdev)
 {
        int err;
@@ -90,14 +109,29 @@ static int sp_probe(struct platform_device *pdev)
        priv = netdev_priv(dev);
 
        dev->irq = res_irq->start;
-       priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+       priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED);
        priv->reg_base = addr;
-       priv->read_reg = sp_read_reg;
-       priv->write_reg = sp_write_reg;
-       priv->can.clock.freq = pdata->clock;
+       /* The CAN clock frequency is half the oscillator clock frequency */
+       priv->can.clock.freq = pdata->osc_freq / 2;
        priv->ocr = pdata->ocr;
        priv->cdr = pdata->cdr;
 
+       switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+       case IORESOURCE_MEM_32BIT:
+               priv->read_reg = sp_read_reg32;
+               priv->write_reg = sp_write_reg32;
+               break;
+       case IORESOURCE_MEM_16BIT:
+               priv->read_reg = sp_read_reg16;
+               priv->write_reg = sp_write_reg16;
+               break;
+       case IORESOURCE_MEM_8BIT:
+       default:
+               priv->read_reg = sp_read_reg8;
+               priv->write_reg = sp_write_reg8;
+               break;
+       }
+
        dev_set_drvdata(&pdev->dev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
index 0c3d2ba0d1789cf665f590868dd0ab8af8dc7e99..4d07f1ee7168acd8e736b08b63c4a455e0e56bc8 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 
-#include <linux/can.h>
 #include <linux/can/dev.h>
 #include <linux/can/error.h>
 #include <linux/can/platform/ti_hecc.h>
index d800b598ae3d008cfb13149ac098d19c6e0ae25c..df0a6369d2f2e22584528e0522cffec1f99da479 100644 (file)
@@ -300,8 +300,6 @@ static void ems_usb_read_interrupt_callback(struct urb *urb)
        else if (err)
                dev_err(netdev->dev.parent,
                        "failed resubmitting intr urb: %d\n", err);
-
-       return;
 }
 
 static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg)
@@ -497,8 +495,6 @@ resubmit_urb:
        else if (retval)
                dev_err(netdev->dev.parent,
                        "failed resubmitting read bulk urb: %d\n", retval);
-
-       return;
 }
 
 /*
index 9bd155e4111c6ef5e771319c38066ad3f9a1c7f0..04a03f7003a0d9e0e0d2bf0d852c90f253fcaa56 100644 (file)
@@ -2889,7 +2889,6 @@ static netdev_tx_t cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb))
                return NETDEV_TX_BUSY;
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
@@ -2957,20 +2956,20 @@ static void cas_process_mc_list(struct cas *cp)
 {
        u16 hash_table[16];
        u32 crc;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int i = 1;
 
        memset(hash_table, 0, sizeof(hash_table));
-       netdev_for_each_mc_addr(dmi, cp->dev) {
+       netdev_for_each_mc_addr(ha, cp->dev) {
                if (i <= CAS_MC_EXACT_MATCH_SIZE) {
                        /* use the alternate mac address registers for the
                         * first 15 multicast addresses
                         */
-                       writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
+                       writel((ha->addr[4] << 8) | ha->addr[5],
                               cp->regs + REG_MAC_ADDRN(i*3 + 0));
-                       writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
+                       writel((ha->addr[2] << 8) | ha->addr[3],
                               cp->regs + REG_MAC_ADDRN(i*3 + 1));
-                       writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
+                       writel((ha->addr[0] << 8) | ha->addr[1],
                               cp->regs + REG_MAC_ADDRN(i*3 + 2));
                        i++;
                }
@@ -2978,7 +2977,7 @@ static void cas_process_mc_list(struct cas *cp)
                        /* use hw hash table for the next series of
                         * multicast addresses
                         */
-                       crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
+                       crc = ether_crc_le(ETH_ALEN, ha->addr);
                        crc >>= 24;
                        hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
                }
@@ -4825,7 +4824,7 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                break;
        default:
                break;
-       };
+       }
 
        mutex_unlock(&cp->pm_mutex);
        return rc;
index 9e631b9d3948cb9d04e6461c66b23db4f2afe893..7dbb16d36fffffa775f8cf214f8767da72870b54 100644 (file)
@@ -377,12 +377,13 @@ static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm)
                rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN;
        } else if (t1_rx_mode_mc_cnt(rm)) {
                /* Accept one or more multicast(s). */
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                int bit;
                u16 mc_filter[4] = { 0, };
 
-               netdev_for_each_mc_addr(dmi, t1_get_netdev(rm)) {
-                       bit = (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 23) & 0x3f; /* bit[23:28] */
+               netdev_for_each_mc_addr(ha, t1_get_netdev(rm)) {
+                       /* bit[23:28] */
+                       bit = (ether_crc(ETH_ALEN, ha->addr) >> 23) & 0x3f;
                        mc_filter[bit >> 4] |= 1 << (bit & 0xf);
                }
                pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]);
index df3a1410696eeb6f53e36a5ed0609f466d27cedf..f01cfdb995deaef8a04d74b5d997a8fb1e74b6dd 100644 (file)
@@ -162,14 +162,14 @@ struct respQ_e {
  */
 struct cmdQ_ce {
        struct sk_buff *skb;
-       DECLARE_PCI_UNMAP_ADDR(dma_addr);
-       DECLARE_PCI_UNMAP_LEN(dma_len);
+       DEFINE_DMA_UNMAP_ADDR(dma_addr);
+       DEFINE_DMA_UNMAP_LEN(dma_len);
 };
 
 struct freelQ_ce {
        struct sk_buff *skb;
-       DECLARE_PCI_UNMAP_ADDR(dma_addr);
-       DECLARE_PCI_UNMAP_LEN(dma_len);
+       DEFINE_DMA_UNMAP_ADDR(dma_addr);
+       DEFINE_DMA_UNMAP_LEN(dma_len);
 };
 
 /*
@@ -460,7 +460,7 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
 
 again:
        for (i = 0; i < MAX_NPORTS; i++) {
-               s->port = ++s->port & (MAX_NPORTS - 1);
+               s->port = (s->port + 1) & (MAX_NPORTS - 1);
                skbq = &s->p[s->port].skbq;
 
                skb = skb_peek(skbq);
@@ -518,8 +518,8 @@ static void free_freelQ_buffers(struct pci_dev *pdev, struct freelQ *q)
        while (q->credits--) {
                struct freelQ_ce *ce = &q->centries[cidx];
 
-               pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
-                                pci_unmap_len(ce, dma_len),
+               pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr),
+                                dma_unmap_len(ce, dma_len),
                                 PCI_DMA_FROMDEVICE);
                dev_kfree_skb(ce->skb);
                ce->skb = NULL;
@@ -633,9 +633,9 @@ static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n)
        q->in_use -= n;
        ce = &q->centries[cidx];
        while (n--) {
-               if (likely(pci_unmap_len(ce, dma_len))) {
-                       pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
-                                        pci_unmap_len(ce, dma_len),
+               if (likely(dma_unmap_len(ce, dma_len))) {
+                       pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr),
+                                        dma_unmap_len(ce, dma_len),
                                         PCI_DMA_TODEVICE);
                        if (q->sop)
                                q->sop = 0;
@@ -851,8 +851,8 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
                skb_reserve(skb, sge->rx_pkt_pad);
 
                ce->skb = skb;
-               pci_unmap_addr_set(ce, dma_addr, mapping);
-               pci_unmap_len_set(ce, dma_len, dma_len);
+               dma_unmap_addr_set(ce, dma_addr, mapping);
+               dma_unmap_len_set(ce, dma_len, dma_len);
                e->addr_lo = (u32)mapping;
                e->addr_hi = (u64)mapping >> 32;
                e->len_gen = V_CMD_LEN(dma_len) | V_CMD_GEN1(q->genbit);
@@ -1059,13 +1059,13 @@ static inline struct sk_buff *get_packet(struct pci_dev *pdev,
                skb_reserve(skb, 2);    /* align IP header */
                skb_put(skb, len);
                pci_dma_sync_single_for_cpu(pdev,
-                                           pci_unmap_addr(ce, dma_addr),
-                                           pci_unmap_len(ce, dma_len),
+                                           dma_unmap_addr(ce, dma_addr),
+                                           dma_unmap_len(ce, dma_len),
                                            PCI_DMA_FROMDEVICE);
                skb_copy_from_linear_data(ce->skb, skb->data, len);
                pci_dma_sync_single_for_device(pdev,
-                                              pci_unmap_addr(ce, dma_addr),
-                                              pci_unmap_len(ce, dma_len),
+                                              dma_unmap_addr(ce, dma_addr),
+                                              dma_unmap_len(ce, dma_len),
                                               PCI_DMA_FROMDEVICE);
                recycle_fl_buf(fl, fl->cidx);
                return skb;
@@ -1077,8 +1077,8 @@ use_orig_buf:
                return NULL;
        }
 
-       pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
-                        pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
+       pci_unmap_single(pdev, dma_unmap_addr(ce, dma_addr),
+                        dma_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
        skb = ce->skb;
        prefetch(skb->data);
 
@@ -1100,8 +1100,8 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
        struct freelQ_ce *ce = &fl->centries[fl->cidx];
        struct sk_buff *skb = ce->skb;
 
-       pci_dma_sync_single_for_cpu(adapter->pdev, pci_unmap_addr(ce, dma_addr),
-                           pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
+       pci_dma_sync_single_for_cpu(adapter->pdev, dma_unmap_addr(ce, dma_addr),
+                           dma_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
        pr_err("%s: unexpected offload packet, cmd %u\n",
               adapter->name, *skb->data);
        recycle_fl_buf(fl, fl->cidx);
@@ -1123,7 +1123,7 @@ static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
 
        if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) {
                unsigned int nfrags = skb_shinfo(skb)->nr_frags;
-               unsigned int i, len = skb->len - skb->data_len;
+               unsigned int i, len = skb_headlen(skb);
                while (len > SGE_TX_DESC_MAX_PLEN) {
                        count++;
                        len -= SGE_TX_DESC_MAX_PLEN;
@@ -1182,7 +1182,7 @@ static inline unsigned int write_large_page_tx_descs(unsigned int pidx,
                        write_tx_desc(e1, *desc_mapping, SGE_TX_DESC_MAX_PLEN,
                                      *gen, nfrags == 0 && *desc_len == 0);
                        ce1->skb = NULL;
-                       pci_unmap_len_set(ce1, dma_len, 0);
+                       dma_unmap_len_set(ce1, dma_len, 0);
                        *desc_mapping += SGE_TX_DESC_MAX_PLEN;
                        if (*desc_len) {
                                ce1++;
@@ -1219,10 +1219,10 @@ static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
        ce = &q->centries[pidx];
 
        mapping = pci_map_single(adapter->pdev, skb->data,
-                               skb->len - skb->data_len, PCI_DMA_TODEVICE);
+                                skb_headlen(skb), PCI_DMA_TODEVICE);
 
        desc_mapping = mapping;
-       desc_len = skb->len - skb->data_len;
+       desc_len = skb_headlen(skb);
 
        flags = F_CMD_DATAVALID | F_CMD_SOP |
            V_CMD_EOP(nfrags == 0 && desc_len <= SGE_TX_DESC_MAX_PLEN) |
@@ -1233,7 +1233,7 @@ static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
        e->addr_hi = (u64)desc_mapping >> 32;
        e->len_gen = V_CMD_LEN(first_desc_len) | V_CMD_GEN1(gen);
        ce->skb = NULL;
-       pci_unmap_len_set(ce, dma_len, 0);
+       dma_unmap_len_set(ce, dma_len, 0);
 
        if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN &&
            desc_len > SGE_TX_DESC_MAX_PLEN) {
@@ -1257,8 +1257,8 @@ static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
        }
 
        ce->skb = NULL;
-       pci_unmap_addr_set(ce, dma_addr, mapping);
-       pci_unmap_len_set(ce, dma_len, skb->len - skb->data_len);
+       dma_unmap_addr_set(ce, dma_addr, mapping);
+       dma_unmap_len_set(ce, dma_len, skb_headlen(skb));
 
        for (i = 0; nfrags--; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -1284,8 +1284,8 @@ static inline void write_tx_descs(struct adapter *adapter, struct sk_buff *skb,
                        write_tx_desc(e1, desc_mapping, desc_len, gen,
                                      nfrags == 0);
                ce->skb = NULL;
-               pci_unmap_addr_set(ce, dma_addr, mapping);
-               pci_unmap_len_set(ce, dma_len, frag->size);
+               dma_unmap_addr_set(ce, dma_addr, mapping);
+               dma_unmap_len_set(ce, dma_len, frag->size);
        }
        ce->skb = skb;
        wmb();
index 4b451a7c03e9191ea7e06ebb46245b87a35ce3ea..be90d3598bcab522889767495506490cf409a35e 100644 (file)
@@ -1143,12 +1143,12 @@ static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
 
        spin_lock_bh(&cp->cnic_ulp_lock);
        if (num_wqes > cnic_kwq_avail(cp) &&
-           !(cp->cnic_local_flags & CNIC_LCL_FL_KWQ_INIT)) {
+           !test_bit(CNIC_LCL_FL_KWQ_INIT, &cp->cnic_local_flags)) {
                spin_unlock_bh(&cp->cnic_ulp_lock);
                return -EAGAIN;
        }
 
-       cp->cnic_local_flags &= ~CNIC_LCL_FL_KWQ_INIT;
+       clear_bit(CNIC_LCL_FL_KWQ_INIT, &cp->cnic_local_flags);
 
        prod = cp->kwq_prod_idx;
        sw_prod = prod & MAX_KWQ_IDX;
@@ -2092,7 +2092,6 @@ end:
                i += j;
                j = 1;
        }
-       return;
 }
 
 static u16 cnic_bnx2_next_idx(u16 idx)
@@ -2146,17 +2145,56 @@ static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
        return last_cnt;
 }
 
+static int cnic_l2_completion(struct cnic_local *cp)
+{
+       u16 hw_cons, sw_cons;
+       union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
+                                       (cp->l2_ring + (2 * BCM_PAGE_SIZE));
+       u32 cmd;
+       int comp = 0;
+
+       if (!test_bit(CNIC_F_BNX2X_CLASS, &cp->dev->flags))
+               return 0;
+
+       hw_cons = *cp->rx_cons_ptr;
+       if ((hw_cons & BNX2X_MAX_RCQ_DESC_CNT) == BNX2X_MAX_RCQ_DESC_CNT)
+               hw_cons++;
+
+       sw_cons = cp->rx_cons;
+       while (sw_cons != hw_cons) {
+               u8 cqe_fp_flags;
+
+               cqe = &cqe_ring[sw_cons & BNX2X_MAX_RCQ_DESC_CNT];
+               cqe_fp_flags = cqe->fast_path_cqe.type_error_flags;
+               if (cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE) {
+                       cmd = le32_to_cpu(cqe->ramrod_cqe.conn_and_cmd_data);
+                       cmd >>= COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT;
+                       if (cmd == RAMROD_CMD_ID_ETH_CLIENT_SETUP ||
+                           cmd == RAMROD_CMD_ID_ETH_HALT)
+                               comp++;
+               }
+               sw_cons = BNX2X_NEXT_RCQE(sw_cons);
+       }
+       return comp;
+}
+
 static void cnic_chk_pkt_rings(struct cnic_local *cp)
 {
        u16 rx_cons = *cp->rx_cons_ptr;
        u16 tx_cons = *cp->tx_cons_ptr;
+       int comp = 0;
 
        if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
+               if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
+                       comp = cnic_l2_completion(cp);
+
                cp->tx_cons = tx_cons;
                cp->rx_cons = rx_cons;
 
                uio_event_notify(cp->cnic_uinfo);
        }
+       if (comp)
+               clear_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
 }
 
 static int cnic_service_bnx2(void *data, void *status_blk)
@@ -2325,7 +2363,6 @@ done:
                           status_idx, IGU_INT_ENABLE, 1);
 
        cp->kcq_prod_idx = sw_prod;
-       return;
 }
 
 static int cnic_service_bnx2x(void *data, void *status_blk)
@@ -3692,7 +3729,7 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
        cp->max_kwq_idx = MAX_KWQ_IDX;
        cp->kwq_prod_idx = 0;
        cp->kwq_con_idx = 0;
-       cp->cnic_local_flags |= CNIC_LCL_FL_KWQ_INIT;
+       set_bit(CNIC_LCL_FL_KWQ_INIT, &cp->cnic_local_flags);
 
        if (CHIP_NUM(cp) == CHIP_NUM_5706 || CHIP_NUM(cp) == CHIP_NUM_5708)
                cp->kwq_con_idx_ptr = &sblk->status_rx_quick_consumer_index15;
@@ -4170,6 +4207,8 @@ static void cnic_init_rings(struct cnic_dev *dev)
                for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++)
                        CNIC_WR(dev, off + i * 4, ((u32 *) &rx_prods)[i]);
 
+               set_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
+
                cnic_init_bnx2x_tx_ring(dev);
                cnic_init_bnx2x_rx_ring(dev);
 
@@ -4177,6 +4216,15 @@ static void cnic_init_rings(struct cnic_dev *dev)
                l5_data.phy_address.hi = 0;
                cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CLIENT_SETUP,
                        BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data);
+               i = 0;
+               while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
+                      ++i < 10)
+                       msleep(1);
+
+               if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
+                       netdev_err(dev->netdev,
+                               "iSCSI CLIENT_SETUP did not complete\n");
+               cnic_kwq_completion(dev, 1);
                cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1);
        }
 }
@@ -4189,14 +4237,25 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
                struct cnic_local *cp = dev->cnic_priv;
                u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
                union l5cm_specific_data l5_data;
+               int i;
 
                cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0);
 
+               set_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags);
+
                l5_data.phy_address.lo = cli;
                l5_data.phy_address.hi = 0;
                cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_HALT,
                        BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data);
-               msleep(10);
+               i = 0;
+               while (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags) &&
+                      ++i < 10)
+                       msleep(1);
+
+               if (test_bit(CNIC_LCL_FL_L2_WAIT, &cp->cnic_local_flags))
+                       netdev_err(dev->netdev,
+                               "iSCSI CLIENT_HALT did not complete\n");
+               cnic_kwq_completion(dev, 1);
 
                memset(&l5_data, 0, sizeof(l5_data));
                cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL,
@@ -4317,7 +4376,15 @@ static void cnic_stop_hw(struct cnic_dev *dev)
 {
        if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
                struct cnic_local *cp = dev->cnic_priv;
+               int i = 0;
 
+               /* Need to wait for the ring shutdown event to complete
+                * before clearing the CNIC_UP flag.
+                */
+               while (cp->uio_dev != -1 && i < 15) {
+                       msleep(100);
+                       i++;
+               }
                clear_bit(CNIC_F_CNIC_UP, &dev->flags);
                rcu_assign_pointer(cp->ulp_ops[CNIC_ULP_L4], NULL);
                synchronize_rcu();
@@ -4628,7 +4695,6 @@ static void __exit cnic_exit(void)
 {
        unregister_netdevice_notifier(&cnic_netdev_notifier);
        cnic_release();
-       return;
 }
 
 module_init(cnic_init);
index a0d853dff983a31ab9a8a1fb235c18cae3f05169..08b1235d987db09492df534521a2fd9d89c0e8d5 100644 (file)
@@ -179,9 +179,9 @@ struct cnic_local {
 #define ULP_F_CALL_PENDING     2
        struct cnic_ulp_ops *ulp_ops[MAX_CNIC_ULP_TYPE];
 
-       /* protected by ulp_lock */
-       u32 cnic_local_flags;
-#define        CNIC_LCL_FL_KWQ_INIT    0x00000001
+       unsigned long cnic_local_flags;
+#define        CNIC_LCL_FL_KWQ_INIT            0x0
+#define        CNIC_LCL_FL_L2_WAIT             0x1
 
        struct cnic_dev *dev;
 
@@ -349,6 +349,10 @@ struct bnx2x_bd_chain_next {
 #define BNX2X_RCQ_DESC_CNT             (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe))
 #define BNX2X_MAX_RCQ_DESC_CNT         (BNX2X_RCQ_DESC_CNT - 1)
 
+#define BNX2X_NEXT_RCQE(x) (((x) & BNX2X_MAX_RCQ_DESC_CNT) ==          \
+               (BNX2X_MAX_RCQ_DESC_CNT - 1)) ?                         \
+               ((x) + 2) : ((x) + 1)
+
 #define BNX2X_DEF_SB_ID                        16
 
 #define BNX2X_ISCSI_RX_SB_INDEX_NUM                                    \
index 60777fd90b330ce8cc09b57caa2ed9b972f38e10..3c58db5952852ad5319741c7135e452e2ad086a0 100644 (file)
@@ -328,7 +328,7 @@ static int cpmac_config(struct net_device *dev, struct ifmap *map)
 
 static void cpmac_set_multicast_list(struct net_device *dev)
 {
-       struct dev_mc_list *iter;
+       struct netdev_hw_addr *ha;
        u8 tmp;
        u32 mbp, bit, hash[2] = { 0, };
        struct cpmac_priv *priv = netdev_priv(dev);
@@ -348,19 +348,19 @@ static void cpmac_set_multicast_list(struct net_device *dev)
                         * cpmac uses some strange mac address hashing
                         * (not crc32)
                         */
-                       netdev_for_each_mc_addr(iter, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                bit = 0;
-                               tmp = iter->dmi_addr[0];
+                               tmp = ha->addr[0];
                                bit  ^= (tmp >> 2) ^ (tmp << 4);
-                               tmp = iter->dmi_addr[1];
+                               tmp = ha->addr[1];
                                bit  ^= (tmp >> 4) ^ (tmp << 2);
-                               tmp = iter->dmi_addr[2];
+                               tmp = ha->addr[2];
                                bit  ^= (tmp >> 6) ^ tmp;
-                               tmp = iter->dmi_addr[3];
+                               tmp = ha->addr[3];
                                bit  ^= (tmp >> 2) ^ (tmp << 4);
-                               tmp = iter->dmi_addr[4];
+                               tmp = ha->addr[4];
                                bit  ^= (tmp >> 4) ^ (tmp << 2);
-                               tmp = iter->dmi_addr[5];
+                               tmp = ha->addr[5];
                                bit  ^= (tmp >> 6) ^ tmp;
                                bit &= 0x3f;
                                hash[bit / 32] |= 1 << (bit % 32);
@@ -579,7 +579,6 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        spin_lock(&priv->lock);
-       dev->trans_start = jiffies;
        spin_unlock(&priv->lock);
        desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN;
        desc->skb = skb;
index 61a33914e96f87b4550404247748cf9248305666..7e00027b9f8e8fbaf395f18f30d1ee059a87234f 100644 (file)
@@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        myNextTxDesc->skb = skb;
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
 
        e100_hardware_send_packet(np, buf, skb->len);
 
@@ -1595,16 +1595,16 @@ set_multicast_list(struct net_device *dev)
        } else {
                /* MC mode, receive normal and MC packets */
                char hash_ix;
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                char *baddr;
 
                lo_bits = 0x00000000ul;
                hi_bits = 0x00000000ul;
-               netdev_for_each_mc_addr(dmi, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        /* Calculate the hash index for the GA registers */
 
                        hash_ix = 0;
-                       baddr = dmi->dmi_addr;
+                       baddr = ha->addr;
                        hash_ix ^= (*baddr) & 0x3f;
                        hash_ix ^= ((*baddr) >> 6) & 0x03;
                        ++baddr;
index 4c38491b8efb02584e9e543a650494641bbd2692..2ccb9f12805b5f75c0f61c1c1550c573084650fc 100644 (file)
@@ -902,7 +902,6 @@ get_dma_channel(struct net_device *dev)
                        return;
                }
        }
-       return;
 }
 
 static void
@@ -1554,7 +1553,6 @@ static netdev_tx_t net_send_packet(struct sk_buff *skb,struct net_device *dev)
        writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1);
        spin_unlock_irqrestore(&lp->lock, flags);
        lp->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
 
        /*
@@ -1673,7 +1671,6 @@ count_rx_errors(int status, struct net_local *lp)
                /* per str 172 */
                lp->stats.rx_crc_errors++;
        if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++;
-       return;
 }
 
 /* We have a good packet(s), get it/them out of the buffers. */
index 2f3ee721c3e11c7075e327f74e1b4cdde1be1024..f452c400325312d8b864c7d4df182e3d9def85ba 100644 (file)
@@ -207,7 +207,6 @@ again:
                 */
                neigh_event_send(e->neigh, NULL);
        }
-       return;
 }
 
 EXPORT_SYMBOL(t3_l2t_send_event);
index 07d7e7fab3f5683e4189f349973940d9e9a99d9a..5962b911b5bd34e9d1433bc6ab99976c066838f5 100644 (file)
@@ -118,7 +118,7 @@ struct rx_sw_desc {                /* SW state per Rx descriptor */
                struct sk_buff *skb;
                struct fl_pg_chunk pg_chunk;
        };
-       DECLARE_PCI_UNMAP_ADDR(dma_addr);
+       DEFINE_DMA_UNMAP_ADDR(dma_addr);
 };
 
 struct rsp_desc {              /* response queue descriptor */
@@ -208,7 +208,7 @@ static inline int need_skb_unmap(void)
         * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
         */
        struct dummy {
-               DECLARE_PCI_UNMAP_ADDR(addr);
+               DEFINE_DMA_UNMAP_ADDR(addr);
        };
 
        return sizeof(struct dummy) != 0;
@@ -363,7 +363,7 @@ static void clear_rx_desc(struct pci_dev *pdev, const struct sge_fl *q,
                put_page(d->pg_chunk.page);
                d->pg_chunk.page = NULL;
        } else {
-               pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
+               pci_unmap_single(pdev, dma_unmap_addr(d, dma_addr),
                                 q->buf_size, PCI_DMA_FROMDEVICE);
                kfree_skb(d->skb);
                d->skb = NULL;
@@ -419,7 +419,7 @@ static inline int add_one_rx_buf(void *va, unsigned int len,
        if (unlikely(pci_dma_mapping_error(pdev, mapping)))
                return -ENOMEM;
 
-       pci_unmap_addr_set(sd, dma_addr, mapping);
+       dma_unmap_addr_set(sd, dma_addr, mapping);
 
        d->addr_lo = cpu_to_be32(mapping);
        d->addr_hi = cpu_to_be32((u64) mapping >> 32);
@@ -515,7 +515,7 @@ nomem:                              q->alloc_failed++;
                                break;
                        }
                        mapping = sd->pg_chunk.mapping + sd->pg_chunk.offset;
-                       pci_unmap_addr_set(sd, dma_addr, mapping);
+                       dma_unmap_addr_set(sd, dma_addr, mapping);
 
                        add_one_rx_chunk(mapping, d, q->gen);
                        pci_dma_sync_single_for_device(adap->pdev, mapping,
@@ -791,11 +791,11 @@ static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
                if (likely(skb != NULL)) {
                        __skb_put(skb, len);
                        pci_dma_sync_single_for_cpu(adap->pdev,
-                                           pci_unmap_addr(sd, dma_addr), len,
+                                           dma_unmap_addr(sd, dma_addr), len,
                                            PCI_DMA_FROMDEVICE);
                        memcpy(skb->data, sd->skb->data, len);
                        pci_dma_sync_single_for_device(adap->pdev,
-                                           pci_unmap_addr(sd, dma_addr), len,
+                                           dma_unmap_addr(sd, dma_addr), len,
                                            PCI_DMA_FROMDEVICE);
                } else if (!drop_thres)
                        goto use_orig_buf;
@@ -810,7 +810,7 @@ recycle:
                goto recycle;
 
 use_orig_buf:
-       pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+       pci_unmap_single(adap->pdev, dma_unmap_addr(sd, dma_addr),
                         fl->buf_size, PCI_DMA_FROMDEVICE);
        skb = sd->skb;
        skb_put(skb, len);
@@ -843,7 +843,7 @@ static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl,
        struct sk_buff *newskb, *skb;
        struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
 
-       dma_addr_t dma_addr = pci_unmap_addr(sd, dma_addr);
+       dma_addr_t dma_addr = dma_unmap_addr(sd, dma_addr);
 
        newskb = skb = q->pg_skb;
        if (!skb && (len <= SGE_RX_COPY_THRES)) {
@@ -2097,7 +2097,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
        fl->credits--;
 
        pci_dma_sync_single_for_cpu(adap->pdev,
-                                   pci_unmap_addr(sd, dma_addr),
+                                   dma_unmap_addr(sd, dma_addr),
                                    fl->buf_size - SGE_PG_RSVD,
                                    PCI_DMA_FROMDEVICE);
 
index c142a2132e9f5de783f4dc93bcf1ca2e1668a6fa..3af19a55037245827c7d4f5713391678185e1231 100644 (file)
@@ -311,16 +311,16 @@ int t3_mac_set_rx_mode(struct cmac *mac, struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI)
                hash_lo = hash_hi = 0xffffffff;
        else {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                int exact_addr_idx = mac->nucast;
 
                hash_lo = hash_hi = 0;
-               netdev_for_each_mc_addr(dmi, dev)
+               netdev_for_each_mc_addr(ha, dev)
                        if (exact_addr_idx < EXACT_ADDR_FILTERS)
                                set_addr_filter(mac, exact_addr_idx++,
-                                               dmi->dmi_addr);
+                                               ha->addr);
                        else {
-                               int hash = hash_hw_addr(dmi->dmi_addr);
+                               int hash = hash_hw_addr(ha->addr);
 
                                if (hash < 32)
                                        hash_lo |= (1 << hash);
index 3d8ff4889b563dd80b2b827318da3802f146e610..dd1770e075e68c8bbe4b95828c903f5dae0eaa6b 100644 (file)
@@ -53,7 +53,7 @@
 
 enum {
        MAX_NPORTS = 4,     /* max # of ports */
-       SERNUM_LEN = 16,    /* Serial # length */
+       SERNUM_LEN = 24,    /* Serial # length */
        EC_LEN     = 16,    /* E/C length */
        ID_LEN     = 16,    /* ID length */
 };
@@ -477,7 +477,6 @@ struct adapter {
        struct pci_dev *pdev;
        struct device *pdev_dev;
        unsigned long registered_device_map;
-       unsigned long open_device_map;
        unsigned long flags;
 
        const char *name;
@@ -651,14 +650,11 @@ int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
                  struct link_config *lc);
 int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port);
 int t4_seeprom_wp(struct adapter *adapter, bool enable);
-int t4_read_flash(struct adapter *adapter, unsigned int addr,
-                 unsigned int nwords, u32 *data, int byte_oriented);
 int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
 int t4_check_fw_version(struct adapter *adapter);
 int t4_prep_adapter(struct adapter *adapter);
 int t4_port_init(struct adapter *adap, int mbox, int pf, int vf);
 void t4_fatal_err(struct adapter *adapter);
-void t4_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
 int t4_set_trace_filter(struct adapter *adapter, const struct trace_params *tp,
                        int filter_index, int enable);
 void t4_get_trace_filter(struct adapter *adapter, struct trace_params *tp,
@@ -709,7 +705,8 @@ int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
 int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
               unsigned int vf, unsigned int viid);
 int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
-               int mtu, int promisc, int all_multi, int bcast, bool sleep_ok);
+               int mtu, int promisc, int all_multi, int bcast, int vlanex,
+               bool sleep_ok);
 int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
                      unsigned int viid, bool free, unsigned int naddr,
                      const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok);
index a7e30a23d322412c12b9e214f6d8f25fcfe29d64..58045b00cf40729ac54745bba13fdedc2cb11741 100644 (file)
@@ -240,9 +240,9 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
        u16 filt_idx[7];
        const u8 *addr[7];
        int ret, naddr = 0;
-       const struct dev_addr_list *d;
        const struct netdev_hw_addr *ha;
        int uc_cnt = netdev_uc_count(dev);
+       int mc_cnt = netdev_mc_count(dev);
        const struct port_info *pi = netdev_priv(dev);
 
        /* first do the secondary unicast addresses */
@@ -260,9 +260,9 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
        }
 
        /* next set up the multicast addresses */
-       netdev_for_each_mc_addr(d, dev) {
-               addr[naddr++] = d->dmi_addr;
-               if (naddr >= ARRAY_SIZE(addr) || d->next == NULL) {
+       netdev_for_each_mc_addr(ha, dev) {
+               addr[naddr++] = ha->addr;
+               if (--mc_cnt == 0 || naddr >= ARRAY_SIZE(addr)) {
                        ret = t4_alloc_mac_filt(pi->adapter, 0, pi->viid, free,
                                        naddr, addr, filt_idx, &mhash, sleep);
                        if (ret < 0)
@@ -290,7 +290,7 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
        if (ret == 0)
                ret = t4_set_rxmode(pi->adapter, 0, pi->viid, mtu,
                                    (dev->flags & IFF_PROMISC) ? 1 : 0,
-                                   (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1,
+                                   (dev->flags & IFF_ALLMULTI) ? 1 : 0, 1, -1,
                                    sleep_ok);
        return ret;
 }
@@ -311,11 +311,11 @@ static int link_start(struct net_device *dev)
         * that step explicitly.
         */
        ret = t4_set_rxmode(pi->adapter, 0, pi->viid, dev->mtu, -1, -1, -1,
-                           true);
+                           pi->vlan_grp != NULL, true);
        if (ret == 0) {
                ret = t4_change_mac(pi->adapter, 0, pi->viid,
                                    pi->xact_addr_filt, dev->dev_addr, true,
-                                   false);
+                                   true);
                if (ret >= 0) {
                        pi->xact_addr_filt = ret;
                        ret = 0;
@@ -859,6 +859,8 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
        "RxCsumGood         ",
        "VLANextractions    ",
        "VLANinsertions     ",
+       "GROpackets         ",
+       "GROmerged          ",
 };
 
 static int get_sset_count(struct net_device *dev, int sset)
@@ -922,6 +924,8 @@ struct queue_port_stats {
        u64 rx_csum;
        u64 vlan_ex;
        u64 vlan_ins;
+       u64 gro_pkts;
+       u64 gro_merged;
 };
 
 static void collect_sge_port_stats(const struct adapter *adap,
@@ -938,6 +942,8 @@ static void collect_sge_port_stats(const struct adapter *adap,
                s->rx_csum += rx->stats.rx_cso;
                s->vlan_ex += rx->stats.vlan_ex;
                s->vlan_ins += tx->vlan_ins;
+               s->gro_pkts += rx->stats.lro_pkts;
+               s->gro_merged += rx->stats.lro_merged;
        }
 }
 
@@ -1711,6 +1717,18 @@ static int set_tso(struct net_device *dev, u32 value)
        return 0;
 }
 
+static int set_flags(struct net_device *dev, u32 flags)
+{
+       if (flags & ~ETH_FLAG_RXHASH)
+               return -EOPNOTSUPP;
+
+       if (flags & ETH_FLAG_RXHASH)
+               dev->features |= NETIF_F_RXHASH;
+       else
+               dev->features &= ~NETIF_F_RXHASH;
+       return 0;
+}
+
 static struct ethtool_ops cxgb_ethtool_ops = {
        .get_settings      = get_settings,
        .set_settings      = set_settings,
@@ -1741,6 +1759,7 @@ static struct ethtool_ops cxgb_ethtool_ops = {
        .get_wol           = get_wol,
        .set_wol           = set_wol,
        .set_tso           = set_tso,
+       .set_flags         = set_flags,
        .flash_device      = set_flash,
 };
 
@@ -2308,6 +2327,9 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
                register_netevent_notifier(&cxgb4_netevent_nb);
                netevent_registered = true;
        }
+
+       if (adap->flags & FULL_INIT_DONE)
+               ulds[uld].state_change(handle, CXGB4_STATE_UP);
 }
 
 static void attach_ulds(struct adapter *adap)
@@ -2414,23 +2436,17 @@ EXPORT_SYMBOL(cxgb4_unregister_uld);
  */
 static int cxgb_up(struct adapter *adap)
 {
-       int err = 0;
+       int err;
 
-       if (!(adap->flags & FULL_INIT_DONE)) {
-               err = setup_sge_queues(adap);
-               if (err)
-                       goto out;
-               err = setup_rss(adap);
-               if (err) {
-                       t4_free_sge_resources(adap);
-                       goto out;
-               }
-               if (adap->flags & USING_MSIX)
-                       name_msix_vecs(adap);
-               adap->flags |= FULL_INIT_DONE;
-       }
+       err = setup_sge_queues(adap);
+       if (err)
+               goto out;
+       err = setup_rss(adap);
+       if (err)
+               goto freeq;
 
        if (adap->flags & USING_MSIX) {
+               name_msix_vecs(adap);
                err = request_irq(adap->msix_info[0].vec, t4_nondata_intr, 0,
                                  adap->msix_info[0].desc, adap);
                if (err)
@@ -2451,11 +2467,14 @@ static int cxgb_up(struct adapter *adap)
        enable_rx(adap);
        t4_sge_start(adap);
        t4_intr_enable(adap);
+       adap->flags |= FULL_INIT_DONE;
        notify_ulds(adap, CXGB4_STATE_UP);
  out:
        return err;
  irq_err:
        dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err);
+ freeq:
+       t4_free_sge_resources(adap);
        goto out;
 }
 
@@ -2471,6 +2490,9 @@ static void cxgb_down(struct adapter *adapter)
        } else
                free_irq(adapter->pdev->irq, adapter);
        quiesce_rx(adapter);
+       t4_sge_stop(adapter);
+       t4_free_sge_resources(adapter);
+       adapter->flags &= ~FULL_INIT_DONE;
 }
 
 /*
@@ -2482,11 +2504,13 @@ static int cxgb_open(struct net_device *dev)
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
 
-       if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
-               return err;
+       if (!(adapter->flags & FULL_INIT_DONE)) {
+               err = cxgb_up(adapter);
+               if (err < 0)
+                       return err;
+       }
 
        dev->real_num_tx_queues = pi->nqsets;
-       set_bit(pi->tx_chan, &adapter->open_device_map);
        link_start(dev);
        netif_tx_start_all_queues(dev);
        return 0;
@@ -2494,19 +2518,12 @@ static int cxgb_open(struct net_device *dev)
 
 static int cxgb_close(struct net_device *dev)
 {
-       int ret;
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
 
        netif_tx_stop_all_queues(dev);
        netif_carrier_off(dev);
-       ret = t4_enable_vi(adapter, 0, pi->viid, false, false);
-
-       clear_bit(pi->tx_chan, &adapter->open_device_map);
-
-       if (!adapter->open_device_map)
-               cxgb_down(adapter);
-       return 0;
+       return t4_enable_vi(adapter, 0, pi->viid, false, false);
 }
 
 static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
@@ -2601,7 +2618,7 @@ static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
 
        if (new_mtu < 81 || new_mtu > MAX_MTU)         /* accommodate SACK */
                return -EINVAL;
-       ret = t4_set_rxmode(pi->adapter, 0, pi->viid, new_mtu, -1, -1, -1,
+       ret = t4_set_rxmode(pi->adapter, 0, pi->viid, new_mtu, -1, -1, -1, -1,
                            true);
        if (!ret)
                dev->mtu = new_mtu;
@@ -2632,7 +2649,8 @@ static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
        struct port_info *pi = netdev_priv(dev);
 
        pi->vlan_grp = grp;
-       t4_set_vlan_accel(pi->adapter, 1 << pi->tx_chan, grp != NULL);
+       t4_set_rxmode(pi->adapter, 0, pi->viid, -1, -1, -1, -1, grp != NULL,
+                     true);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3066,6 +3084,12 @@ static void __devinit print_port_info(struct adapter *adap)
 
        int i;
        char buf[80];
+       const char *spd = "";
+
+       if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_2_5GB)
+               spd = " 2.5 GT/s";
+       else if (adap->params.pci.speed == PCI_EXP_LNKSTA_CLS_5_0GB)
+               spd = " 5 GT/s";
 
        for_each_port(adap, i) {
                struct net_device *dev = adap->port[i];
@@ -3085,10 +3109,10 @@ static void __devinit print_port_info(struct adapter *adap)
                        --bufp;
                sprintf(bufp, "BASE-%s", base[pi->port_type]);
 
-               netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s\n",
+               netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
                            adap->params.vpd.id, adap->params.rev,
                            buf, is_offload(adap) ? "R" : "",
-                           adap->params.pci.width,
+                           adap->params.pci.width, spd,
                            (adap->flags & USING_MSIX) ? " MSI-X" :
                            (adap->flags & USING_MSI) ? " MSI" : "");
                if (adap->name == dev->name)
@@ -3203,7 +3227,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
                netdev->features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6;
                netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-               netdev->features |= NETIF_F_GRO | highdma;
+               netdev->features |= NETIF_F_GRO | NETIF_F_RXHASH | highdma;
                netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
                netdev->vlan_features = netdev->features & VLAN_FEAT;
 
@@ -3334,8 +3358,8 @@ static void __devexit remove_one(struct pci_dev *pdev)
                if (adapter->debugfs_root)
                        debugfs_remove_recursive(adapter->debugfs_root);
 
-               t4_sge_stop(adapter);
-               t4_free_sge_resources(adapter);
+               if (adapter->flags & FULL_INIT_DONE)
+                       cxgb_down(adapter);
                t4_free_mem(adapter->l2t);
                t4_free_mem(adapter->tids.tid_tab);
                disable_msi(adapter);
index 14adc58e71c3be122679e078cca325a0cbed4431..d1f8f225e45a7799dd6e028a5980c39357907e5d 100644 (file)
@@ -1471,7 +1471,7 @@ EXPORT_SYMBOL(cxgb4_pktgl_to_skb);
  *     Releases the pages of a packet gather list.  We do not own the last
  *     page on the list and do not free it.
  */
-void t4_pktgl_free(const struct pkt_gl *gl)
+static void t4_pktgl_free(const struct pkt_gl *gl)
 {
        int n;
        const skb_frag_t *p;
@@ -1524,6 +1524,8 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
        skb->truesize += skb->data_len;
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb_record_rx_queue(skb, rxq->rspq.idx);
+       if (rxq->rspq.netdev->features & NETIF_F_RXHASH)
+               skb->rxhash = (__force u32)pkt->rsshdr.hash_val;
 
        if (unlikely(pkt->vlan_ex)) {
                struct port_info *pi = netdev_priv(rxq->rspq.netdev);
@@ -1565,7 +1567,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
        if (unlikely(*(u8 *)rsp == CPL_TRACE_PKT))
                return handle_trace_pkt(q->adap, si);
 
-       pkt = (void *)&rsp[1];
+       pkt = (const struct cpl_rx_pkt *)rsp;
        csum_ok = pkt->csum_calc && !pkt->err_vec;
        if ((pkt->l2info & htonl(RXF_TCP)) &&
            (q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) {
@@ -1583,6 +1585,9 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
        __skb_pull(skb, RX_PKT_PAD);      /* remove ethernet header padding */
        skb->protocol = eth_type_trans(skb, q->netdev);
        skb_record_rx_queue(skb, q->idx);
+       if (skb->dev->features & NETIF_F_RXHASH)
+               skb->rxhash = (__force u32)pkt->rsshdr.hash_val;
+
        pi = netdev_priv(skb->dev);
        rxq->stats.pkts++;
 
@@ -2047,7 +2052,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
        adap->sge.ingr_map[iq->cntxt_id] = iq;
 
        if (fl) {
-               fl->cntxt_id = htons(c.fl0id);
+               fl->cntxt_id = ntohs(c.fl0id);
                fl->avail = fl->pend_cred = 0;
                fl->pidx = fl->cidx = 0;
                fl->alloc_failed = fl->large_alloc_failed = fl->starving = 0;
index a814a3afe12354f5d1a266610e4787a75b80b479..da272a98fdbc3b6d5b3181ecc68769fdbbff7b69 100644 (file)
@@ -53,8 +53,8 @@
  *     at the time it indicated completion is stored there.  Returns 0 if the
  *     operation completes and -EAGAIN otherwise.
  */
-int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
-                       int polarity, int attempts, int delay, u32 *valp)
+static int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+                              int polarity, int attempts, int delay, u32 *valp)
 {
        while (1) {
                u32 val = t4_read_reg(adapter, reg);
@@ -109,9 +109,9 @@ void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
  *     Reads registers that are accessed indirectly through an address/data
  *     register pair.
  */
-void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
-                     unsigned int data_reg, u32 *vals, unsigned int nregs,
-                     unsigned int start_idx)
+static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
+                            unsigned int data_reg, u32 *vals,
+                            unsigned int nregs, unsigned int start_idx)
 {
        while (nregs--) {
                t4_write_reg(adap, addr_reg, start_idx);
@@ -120,6 +120,7 @@ void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
        }
 }
 
+#if 0
 /**
  *     t4_write_indirect - write indirectly addressed registers
  *     @adap: the adapter
@@ -132,15 +133,16 @@ void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
  *     Writes a sequential block of registers that are accessed indirectly
  *     through an address/data register pair.
  */
-void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
-                      unsigned int data_reg, const u32 *vals,
-                      unsigned int nregs, unsigned int start_idx)
+static void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
+                             unsigned int data_reg, const u32 *vals,
+                             unsigned int nregs, unsigned int start_idx)
 {
        while (nregs--) {
                t4_write_reg(adap, addr_reg, start_idx++);
                t4_write_reg(adap, data_reg, *vals++);
        }
 }
+#endif
 
 /*
  * Get the reply to a mailbox command and store it in @rpl in big-endian order.
@@ -345,33 +347,21 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
        return 0;
 }
 
-#define VPD_ENTRY(name, len) \
-       u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
-
 /*
  * Partial EEPROM Vital Product Data structure.  Includes only the ID and
- * VPD-R sections.
+ * VPD-R header.
  */
-struct t4_vpd {
+struct t4_vpd_hdr {
        u8  id_tag;
        u8  id_len[2];
        u8  id_data[ID_LEN];
        u8  vpdr_tag;
        u8  vpdr_len[2];
-       VPD_ENTRY(pn, 16);                     /* part number */
-       VPD_ENTRY(ec, EC_LEN);                 /* EC level */
-       VPD_ENTRY(sn, SERNUM_LEN);             /* serial number */
-       VPD_ENTRY(na, 12);                     /* MAC address base */
-       VPD_ENTRY(port_type, 8);               /* port types */
-       VPD_ENTRY(gpio, 14);                   /* GPIO usage */
-       VPD_ENTRY(cclk, 6);                    /* core clock */
-       VPD_ENTRY(port_addr, 8);               /* port MDIO addresses */
-       VPD_ENTRY(rv, 1);                      /* csum */
-       u32 pad;                  /* for multiple-of-4 sizing and alignment */
 };
 
 #define EEPROM_STAT_ADDR   0x7bfc
 #define VPD_BASE           0
+#define VPD_LEN            512
 
 /**
  *     t4_seeprom_wp - enable/disable EEPROM write protection
@@ -396,16 +386,36 @@ int t4_seeprom_wp(struct adapter *adapter, bool enable)
  */
 static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 {
-       int ret;
-       struct t4_vpd vpd;
-       u8 *q = (u8 *)&vpd, csum;
+       int i, ret;
+       int ec, sn, v2;
+       u8 vpd[VPD_LEN], csum;
+       unsigned int vpdr_len;
+       const struct t4_vpd_hdr *v;
 
-       ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), &vpd);
+       ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd);
        if (ret < 0)
                return ret;
 
-       for (csum = 0; q <= vpd.rv_data; q++)
-               csum += *q;
+       v = (const struct t4_vpd_hdr *)vpd;
+       vpdr_len = pci_vpd_lrdt_size(&v->vpdr_tag);
+       if (vpdr_len + sizeof(struct t4_vpd_hdr) > VPD_LEN) {
+               dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len);
+               return -EINVAL;
+       }
+
+#define FIND_VPD_KW(var, name) do { \
+       var = pci_vpd_find_info_keyword(&v->id_tag, sizeof(struct t4_vpd_hdr), \
+                                       vpdr_len, name); \
+       if (var < 0) { \
+               dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \
+               return -EINVAL; \
+       } \
+       var += PCI_VPD_INFO_FLD_HDR_SIZE; \
+} while (0)
+
+       FIND_VPD_KW(i, "RV");
+       for (csum = 0; i >= 0; i--)
+               csum += vpd[i];
 
        if (csum) {
                dev_err(adapter->pdev_dev,
@@ -413,12 +423,18 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
                return -EINVAL;
        }
 
-       p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
-       memcpy(p->id, vpd.id_data, sizeof(vpd.id_data));
+       FIND_VPD_KW(ec, "EC");
+       FIND_VPD_KW(sn, "SN");
+       FIND_VPD_KW(v2, "V2");
+#undef FIND_VPD_KW
+
+       p->cclk = simple_strtoul(vpd + v2, NULL, 10);
+       memcpy(p->id, v->id_data, ID_LEN);
        strim(p->id);
-       memcpy(p->ec, vpd.ec_data, sizeof(vpd.ec_data));
+       memcpy(p->ec, vpd + ec, EC_LEN);
        strim(p->ec);
-       memcpy(p->sn, vpd.sn_data, sizeof(vpd.sn_data));
+       i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
+       memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
        strim(p->sn);
        return 0;
 }
@@ -537,8 +553,8 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
  *     (i.e., big-endian), otherwise as 32-bit words in the platform's
  *     natural endianess.
  */
-int t4_read_flash(struct adapter *adapter, unsigned int addr,
-                 unsigned int nwords, u32 *data, int byte_oriented)
+static int t4_read_flash(struct adapter *adapter, unsigned int addr,
+                        unsigned int nwords, u32 *data, int byte_oriented)
 {
        int ret;
 
@@ -870,22 +886,6 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
 
-/**
- *     t4_set_vlan_accel - configure HW VLAN extraction
- *     @adap: the adapter
- *     @ports: bitmap of adapter ports to operate on
- *     @on: enable (1) or disable (0) HW VLAN extraction
- *
- *     Enables or disables HW extraction of VLAN tags for the ports specified
- *     by @ports.  @ports is a bitmap with the ith bit designating the port
- *     associated with the ith adapter channel.
- */
-void t4_set_vlan_accel(struct adapter *adap, unsigned int ports, int on)
-{
-       ports <<= VLANEXTENABLE_SHIFT;
-       t4_set_reg_field(adap, TP_OUT_CONFIG, ports, on ? ports : 0);
-}
-
 struct intr_info {
        unsigned int mask;       /* bits to check in interrupt status */
        const char *msg;         /* message to print or NULL */
@@ -2608,12 +2608,14 @@ int t4_free_vi(struct adapter *adap, unsigned int mbox, unsigned int pf,
  *     @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
  *     @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
  *     @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
+ *     @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change
  *     @sleep_ok: if true we may sleep while awaiting command completion
  *
  *     Sets Rx properties of a virtual interface.
  */
 int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
-                 int mtu, int promisc, int all_multi, int bcast, bool sleep_ok)
+                 int mtu, int promisc, int all_multi, int bcast, int vlanex,
+                 bool sleep_ok)
 {
        struct fw_vi_rxmode_cmd c;
 
@@ -2626,15 +2628,18 @@ int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
                all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK;
        if (bcast < 0)
                bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK;
+       if (vlanex < 0)
+               vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
 
        memset(&c, 0, sizeof(c));
        c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST |
                             FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid));
        c.retval_len16 = htonl(FW_LEN16(c));
-       c.mtu_to_broadcasten = htonl(FW_VI_RXMODE_CMD_MTU(mtu) |
-                                    FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
-                                    FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
-                                    FW_VI_RXMODE_CMD_BROADCASTEN(bcast));
+       c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU(mtu) |
+                                 FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
+                                 FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
+                                 FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
+                                 FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
        return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
 }
 
index fdb117443144969090c46207bced8848c88bd117..7a981b81afafe88a9c3be939e27fb24879e39d50 100644 (file)
@@ -503,6 +503,7 @@ struct cpl_rx_data_ack {
 };
 
 struct cpl_rx_pkt {
+       struct rss_header rsshdr;
        u8 opcode;
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        u8 iff:4;
index 3393d05a388a0a18ac9b0d48bea479f7ec7c2f7d..63991d68950e2efdc2d0d04e22fb86e840875358 100644 (file)
@@ -876,7 +876,7 @@ struct fw_vi_mac_cmd {
 struct fw_vi_rxmode_cmd {
        __be32 op_to_viid;
        __be32 retval_len16;
-       __be32 mtu_to_broadcasten;
+       __be32 mtu_to_vlanexen;
        __be32 r4_lo;
 };
 
@@ -888,6 +888,8 @@ struct fw_vi_rxmode_cmd {
 #define FW_VI_RXMODE_CMD_ALLMULTIEN(x) ((x) << 12)
 #define FW_VI_RXMODE_CMD_BROADCASTEN_MASK 0x3
 #define FW_VI_RXMODE_CMD_BROADCASTEN(x) ((x) << 10)
+#define FW_VI_RXMODE_CMD_VLANEXEN_MASK 0x3
+#define FW_VI_RXMODE_CMD_VLANEXEN(x) ((x) << 8)
 
 struct fw_vi_enable_cmd {
        __be32 op_to_viid;
index 2b8edd2efbf608994946f1a1cb9ae40f71938ae7..08e82b1a0b336219279738984c8511c0fbe50c4e 100644 (file)
@@ -952,13 +952,14 @@ static void emac_dev_mcast_set(struct net_device *ndev)
                        emac_add_mcast(priv, EMAC_ALL_MULTI_SET, NULL);
                }
                if (!netdev_mc_empty(ndev)) {
-                       struct dev_mc_list *mc_ptr;
+                       struct netdev_hw_addr *ha;
+
                        mbp_enable = (mbp_enable | EMAC_MBP_RXMCAST);
                        emac_add_mcast(priv, EMAC_ALL_MULTI_CLR, NULL);
                        /* program multicast address list into EMAC hardware */
-                       netdev_for_each_mc_addr(mc_ptr, ndev) {
+                       netdev_for_each_mc_addr(ha, ndev) {
                                emac_add_mcast(priv, EMAC_MULTICAST_ADD,
-                                              (u8 *) mc_ptr->dmi_addr);
+                                              (u8 *) ha->addr);
                        }
                } else {
                        mbp_enable = (mbp_enable & ~EMAC_MBP_RXMCAST);
@@ -1467,7 +1468,6 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev)
        tx_buf.length = skb->len;
        tx_buf.buf_token = (void *)skb;
        tx_buf.data_ptr = skb->data;
-       ndev->trans_start = jiffies;
        ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH);
        if (unlikely(ret_code != 0)) {
                if (ret_code == EMAC_ERR_TX_OUT_OF_BD) {
index 6b13f4fd2e9635b29327222f4083482aae05dc07..23a65398d0115d5c879da96fe59c56bfa7339046 100644 (file)
@@ -166,8 +166,8 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
        int     i;
 
        if (free_tx_pages <= 0) {       /* Do timeouts, to avoid hangs. */
-               tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < 5)
+               tickssofar = jiffies - dev_trans_start(dev);
+               if (tickssofar < HZ/20)
                        return NETDEV_TX_BUSY;
                /* else */
                printk(KERN_WARNING "%s: transmit timed out (%d), %s?\n", dev->name, tickssofar, "network cable problem");
index a0a6830b5e6de3a486106689bdf2995d99fe03cb..f3650fd096f4fd9e62b84966adee3a9615c723c3 100644 (file)
@@ -535,7 +535,6 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        de620_write_block(dev, buffer, skb->len, len-skb->len);
 
-       dev->trans_start = jiffies;
        if(!(using_txbuf == (TXBF0 | TXBF1)))
                netif_wake_queue(dev);
 
index 8cf3cc6f20e29894792bdb1f63a13b4bedd2186f..1d973db27c32752241eb4ed8355163406e9e9fb7 100644 (file)
@@ -874,7 +874,7 @@ static inline int lance_reset(struct net_device *dev)
 
        lance_init_ring(dev);
        load_csrs(lp);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        status = init_restart_lance(lp);
        return status;
 }
@@ -930,7 +930,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       dev->trans_start = jiffies;
        dev_kfree_skb(skb);
 
        return NETDEV_TX_OK;
@@ -940,7 +939,7 @@ static void lance_load_multicast(struct net_device *dev)
 {
        struct lance_private *lp = netdev_priv(dev);
        volatile u16 *ib = (volatile u16 *)dev->mem_start;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        u32 crc;
 
@@ -959,8 +958,8 @@ static void lance_load_multicast(struct net_device *dev)
        *lib_ptr(ib, filter[3], lp->type) = 0;
 
        /* Add addresses */
-       netdev_for_each_mc_addr(dmi, dev) {
-               addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrs = ha->addr;
 
                /* multicast address? */
                if (!(*addrs & 1))
@@ -970,7 +969,6 @@ static void lance_load_multicast(struct net_device *dev)
                crc = crc >> 26;
                *lib_ptr(ib, filter[crc >> 4], lp->type) |= 1 << (crc & 0xf);
        }
-       return;
 }
 
 static void lance_set_multicast(struct net_device *dev)
index ed53a8d45f4e5e8c43240b66ac0804e1cf461950..e5667c55844e17ac23bbf228fe4d890c995d59cc 100644 (file)
@@ -2195,7 +2195,7 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
 {
        DFX_board_t *bp = netdev_priv(dev);
        int                                     i;                      /* used as index in for loop */
-       struct dev_mc_list      *dmi;           /* ptr to multicast addr entry */
+       struct netdev_hw_addr *ha;
 
        /* Enable LLC frame promiscuous mode, if necessary */
 
@@ -2241,9 +2241,9 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
                /* Copy addresses to multicast address table, then update adapter CAM */
 
                i = 0;
-               netdev_for_each_mc_addr(dmi, dev)
+               netdev_for_each_mc_addr(ha, dev)
                        memcpy(&bp->mc_table[i++ * FDDI_K_ALEN],
-                              dmi->dmi_addr, FDDI_K_ALEN);
+                              ha->addr, FDDI_K_ALEN);
 
                if (dfx_ctl_update_cam(bp) != DFX_K_SUCCESS)
                        {
index 744c1928dfcaf9f79e034d68b62b565cf9391eed..bf66e9b3b19ed1c461ceb124d81f24b110171e54 100644 (file)
@@ -921,7 +921,7 @@ static void depca_tx_timeout(struct net_device *dev)
        STOP_DEPCA;
        depca_init_ring(dev);
        LoadCSRs(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
        InitRestartDepca(dev);
 }
@@ -954,7 +954,6 @@ static netdev_tx_t depca_start_xmit(struct sk_buff *skb,
                        outw(CSR0, DEPCA_ADDR);
                        outw(INEA | TDMD, DEPCA_DATA);
 
-                       dev->trans_start = jiffies;
                        dev_kfree_skb(skb);
                }
                if (TX_BUFFS_AVAIL)
@@ -1204,8 +1203,6 @@ static void LoadCSRs(struct net_device *dev)
        outw(ACON, DEPCA_DATA);
 
        outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
-
-       return;
 }
 
 static int InitRestartDepca(struct net_device *dev)
@@ -1272,7 +1269,7 @@ static void set_multicast_list(struct net_device *dev)
 static void SetMulticastFilter(struct net_device *dev)
 {
        struct depca_private *lp = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        int i, j, bit, byte;
        u16 hashcode;
@@ -1287,8 +1284,8 @@ static void SetMulticastFilter(struct net_device *dev)
                        lp->init_block.mcast_table[i] = 0;
                }
                /* Add multicast addresses */
-               netdev_for_each_mc_addr(dmi, dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       addrs = ha->addr;
                        if ((*addrs & 0x01) == 1) {     /* multicast address? */
                                crc = ether_crc(ETH_ALEN, addrs);
                                hashcode = (crc & 1);   /* hashcode is 6 LSb of CRC ... */
@@ -1303,8 +1300,6 @@ static void SetMulticastFilter(struct net_device *dev)
                        }
                }
        }
-
-       return;
 }
 
 static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
@@ -1909,8 +1904,6 @@ static void depca_dbg_open(struct net_device *dev)
                outw(CSR3, DEPCA_ADDR);
                printk("CSR3: 0x%4.4x\n", inw(DEPCA_DATA));
        }
-
-       return;
 }
 
 /*
index b05bad8298273cb6abf87f8f097dbfa1773519d7..a2f238d20caab0cfa80f196890ea6b96f47df363 100644 (file)
@@ -596,8 +596,6 @@ alloc_list (struct net_device *dev)
        /* Set RFDListPtr */
        writel (np->rx_ring_dma, dev->base_addr + RFDListPtr0);
        writel (0, dev->base_addr + RFDListPtr1);
-
-       return;
 }
 
 static netdev_tx_t
@@ -1132,14 +1130,14 @@ set_multicast (struct net_device *dev)
                /* Receive broadcast and multicast frames */
                rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
        } else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                /* Receive broadcast frames and multicast frames filtering
                   by Hashtable */
                rx_mode =
                    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        int bit, index = 0;
-                       int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+                       int crc = ether_crc_le(ETH_ALEN, ha->addr);
                        /* The inverted high significant 6 bits of CRC are
                           used as an index to hashtable */
                        for (bit = 0; bit < 6; bit++)
index 7f9960f718e35972dabedc30fb3f8faa3f7a3155..abcc838e18af1ca6d57f5256a94828a85b9a8c4c 100644 (file)
@@ -476,17 +476,13 @@ static uint32_t dm9000_get_rx_csum(struct net_device *dev)
        return dm->rx_csum;
 }
 
-static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
+static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data)
 {
        board_info_t *dm = to_dm9000_board(dev);
-       unsigned long flags;
 
        if (dm->can_csum) {
                dm->rx_csum = data;
-
-               spin_lock_irqsave(&dm->lock, flags);
                iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
-               spin_unlock_irqrestore(&dm->lock, flags);
 
                return 0;
        }
@@ -494,6 +490,19 @@ static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
        return -EOPNOTSUPP;
 }
 
+static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+       board_info_t *dm = to_dm9000_board(dev);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&dm->lock, flags);
+       ret = dm9000_set_rx_csum_unlocked(dev, data);
+       spin_unlock_irqrestore(&dm->lock, flags);
+
+       return ret;
+}
+
 static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
 {
        board_info_t *dm = to_dm9000_board(dev);
@@ -722,20 +731,17 @@ static unsigned char dm9000_type_to_char(enum dm9000_type type)
  *  Set DM9000 multicast address
  */
 static void
-dm9000_hash_table(struct net_device *dev)
+dm9000_hash_table_unlocked(struct net_device *dev)
 {
        board_info_t *db = netdev_priv(dev);
-       struct dev_mc_list *mcptr;
+       struct netdev_hw_addr *ha;
        int i, oft;
        u32 hash_val;
        u16 hash_table[4];
        u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;
-       unsigned long flags;
 
        dm9000_dbg(db, 1, "entering %s\n", __func__);
 
-       spin_lock_irqsave(&db->lock, flags);
-
        for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
                iow(db, oft, dev->dev_addr[i]);
 
@@ -753,8 +759,8 @@ dm9000_hash_table(struct net_device *dev)
                rcr |= RCR_ALL;
 
        /* the multicast address in Hash Table : 64 bits */
-       netdev_for_each_mc_addr(mcptr, dev) {
-               hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f;
+       netdev_for_each_mc_addr(ha, dev) {
+               hash_val = ether_crc_le(6, ha->addr) & 0x3f;
                hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
        }
 
@@ -765,11 +771,21 @@ dm9000_hash_table(struct net_device *dev)
        }
 
        iow(db, DM9000_RCR, rcr);
+}
+
+static void
+dm9000_hash_table(struct net_device *dev)
+{
+       board_info_t *db = netdev_priv(dev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&db->lock, flags);
+       dm9000_hash_table_unlocked(dev);
        spin_unlock_irqrestore(&db->lock, flags);
 }
 
 /*
- * Initilize dm9000 board
+ * Initialize dm9000 board
  */
 static void
 dm9000_init_dm9000(struct net_device *dev)
@@ -784,7 +800,7 @@ dm9000_init_dm9000(struct net_device *dev)
        db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
 
        /* Checksum mode */
-       dm9000_set_rx_csum(dev, db->rx_csum);
+       dm9000_set_rx_csum_unlocked(dev, db->rx_csum);
 
        /* GPIO0 on pre-activate PHY */
        iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
@@ -811,7 +827,7 @@ dm9000_init_dm9000(struct net_device *dev)
        iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */
 
        /* Set address filter table */
-       dm9000_hash_table(dev);
+       dm9000_hash_table_unlocked(dev);
 
        imr = IMR_PAR | IMR_PTM | IMR_PRM;
        if (db->type != TYPE_DM9000E)
@@ -825,7 +841,7 @@ dm9000_init_dm9000(struct net_device *dev)
        /* Init Driver variable */
        db->tx_pkt_cnt = 0;
        db->queue_pkt_len = 0;
-       dev->trans_start = 0;
+       dev->trans_start = jiffies;
 }
 
 /* Our watchdog timed out. Called by the networking layer */
@@ -843,7 +859,7 @@ static void dm9000_timeout(struct net_device *dev)
        dm9000_reset(db);
        dm9000_init_dm9000(dev);
        /* We can accept TX packets again */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 
        /* Restore previous register address */
index 234685213f1a2e194c3b68d8faab8664d023f514..8b0f50bbf3e5cd13bfa4b240387071b3d2a939c9 100644 (file)
@@ -594,8 +594,6 @@ static netdev_tx_t dnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&bp->lock, flags);
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -918,7 +916,7 @@ static int __devinit dnet_probe(struct platform_device *pdev)
 
        dev_info(&pdev->dev, "Dave DNET at 0x%p (0x%08x) irq %d %pM\n",
               bp->regs, mem_base, dev->irq, dev->dev_addr);
-       dev_info(&pdev->dev, "has %smdio, %sirq, %sgigabit, %sdma \n",
+       dev_info(&pdev->dev, "has %smdio, %sirq, %sgigabit, %sdma\n",
               (bp->capabilities & DNET_HAS_MDIO) ? "" : "no ",
               (bp->capabilities & DNET_HAS_IRQ) ? "" : "no ",
               (bp->capabilities & DNET_HAS_GIGABIT) ? "" : "no ",
index 791080303db100cf7f5f53d961253846e6e3049e..b194bad29ace251c2f33bfe5d9845ca571af352a 100644 (file)
  *      - add clean lowlevel I/O emulation for cards with MII-lacking PHYs
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #define DRV_VERSION            "3.5.24-k2"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT          "Copyright(c) 1999-2006 Intel Corporation"
-#define PFX                    DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD   (2 * HZ)
 #define E100_NAPI_WEIGHT       16
@@ -201,10 +202,6 @@ module_param(use_io, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
 MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
-#define DPRINTK(nlevel, klevel, fmt, args...) \
-       (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
-       printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
-               __func__ , ## args))
 
 #define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
        PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
@@ -690,12 +687,13 @@ static int e100_self_test(struct nic *nic)
 
        /* Check results of self-test */
        if (nic->mem->selftest.result != 0) {
-               DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n",
-                       nic->mem->selftest.result);
+               netif_err(nic, hw, nic->netdev,
+                         "Self-test failed: result=0x%08X\n",
+                         nic->mem->selftest.result);
                return -ETIMEDOUT;
        }
        if (nic->mem->selftest.signature == 0) {
-               DPRINTK(HW, ERR, "Self-test failed: timed out\n");
+               netif_err(nic, hw, nic->netdev, "Self-test failed: timed out\n");
                return -ETIMEDOUT;
        }
 
@@ -798,7 +796,7 @@ static int e100_eeprom_load(struct nic *nic)
        /* The checksum, stored in the last word, is calculated such that
         * the sum of words should be 0xBABA */
        if (cpu_to_le16(0xBABA - checksum) != nic->eeprom[nic->eeprom_wc - 1]) {
-               DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
+               netif_err(nic, probe, nic->netdev, "EEPROM corrupted\n");
                if (!eeprom_bad_csum_allow)
                        return -EAGAIN;
        }
@@ -954,8 +952,7 @@ static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
                udelay(20);
        }
        if (unlikely(!i)) {
-               printk("e100.mdio_ctrl(%s) won't go Ready\n",
-                       nic->netdev->name );
+               netdev_err(nic->netdev, "e100.mdio_ctrl won't go Ready\n");
                spin_unlock_irqrestore(&nic->mdio_lock, flags);
                return 0;               /* No way to indicate timeout error */
        }
@@ -967,9 +964,10 @@ static u16 mdio_ctrl_hw(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
                        break;
        }
        spin_unlock_irqrestore(&nic->mdio_lock, flags);
-       DPRINTK(HW, DEBUG,
-               "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
-               dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                    "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
+                    dir == mdi_read ? "READ" : "WRITE",
+                    addr, reg, data, data_out);
        return (u16)data_out;
 }
 
@@ -1029,17 +1027,19 @@ static u16 mdio_ctrl_phy_mii_emulated(struct nic *nic,
                        return  ADVERTISE_10HALF |
                                ADVERTISE_10FULL;
                default:
-                       DPRINTK(HW, DEBUG,
-               "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
-               dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
+                       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                                    "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
+                                    dir == mdi_read ? "READ" : "WRITE",
+                                    addr, reg, data);
                        return 0xFFFF;
                }
        } else {
                switch (reg) {
                default:
-                       DPRINTK(HW, DEBUG,
-               "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
-               dir == mdi_read ? "READ" : "WRITE", addr, reg, data);
+                       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                                    "%s:addr=%d, reg=%d, data=0x%04X: unimplemented emulation!\n",
+                                    dir == mdi_read ? "READ" : "WRITE",
+                                    addr, reg, data);
                        return 0xFFFF;
                }
        }
@@ -1156,12 +1156,15 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
                }
        }
 
-       DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-               c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
-       DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-               c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
-       DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-               c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                    "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+                    c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                    "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+                    c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                    "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+                    c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
 }
 
 /*************************************************************************
@@ -1254,16 +1257,18 @@ static const struct firmware *e100_request_firmware(struct nic *nic)
                err = request_firmware(&fw, fw_name, &nic->pdev->dev);
 
        if (err) {
-               DPRINTK(PROBE, ERR, "Failed to load firmware \"%s\": %d\n",
-                       fw_name, err);
+               netif_err(nic, probe, nic->netdev,
+                         "Failed to load firmware \"%s\": %d\n",
+                         fw_name, err);
                return ERR_PTR(err);
        }
 
        /* Firmware should be precisely UCODE_SIZE (words) plus three bytes
           indicating the offsets for BUNDLESMALL, BUNDLEMAX, INTDELAY */
        if (fw->size != UCODE_SIZE * 4 + 3) {
-               DPRINTK(PROBE, ERR, "Firmware \"%s\" has wrong size %zu\n",
-                       fw_name, fw->size);
+               netif_err(nic, probe, nic->netdev,
+                         "Firmware \"%s\" has wrong size %zu\n",
+                         fw_name, fw->size);
                release_firmware(fw);
                return ERR_PTR(-EINVAL);
        }
@@ -1275,9 +1280,9 @@ static const struct firmware *e100_request_firmware(struct nic *nic)
 
        if (timer >= UCODE_SIZE || bundle >= UCODE_SIZE ||
            min_size >= UCODE_SIZE) {
-               DPRINTK(PROBE, ERR,
-                       "\"%s\" has bogus offset values (0x%x,0x%x,0x%x)\n",
-                       fw_name, timer, bundle, min_size);
+               netif_err(nic, probe, nic->netdev,
+                         "\"%s\" has bogus offset values (0x%x,0x%x,0x%x)\n",
+                         fw_name, timer, bundle, min_size);
                release_firmware(fw);
                return ERR_PTR(-EINVAL);
        }
@@ -1329,7 +1334,8 @@ static inline int e100_load_ucode_wait(struct nic *nic)
                return PTR_ERR(fw);
 
        if ((err = e100_exec_cb(nic, (void *)fw, e100_setup_ucode)))
-               DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err);
+               netif_err(nic, probe, nic->netdev,
+                         "ucode cmd failed with error %d\n", err);
 
        /* must restart cuc */
        nic->cuc_cmd = cuc_start;
@@ -1349,7 +1355,7 @@ static inline int e100_load_ucode_wait(struct nic *nic)
 
        /* if the command failed, or is not OK, notify and return */
        if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
-               DPRINTK(PROBE,ERR, "ucode load failed\n");
+               netif_err(nic, probe, nic->netdev, "ucode load failed\n");
                err = -EPERM;
        }
 
@@ -1387,8 +1393,8 @@ static int e100_phy_check_without_mii(struct nic *nic)
                 * media is sensed automatically based on how the link partner
                 * is configured.  This is, in essence, manual configuration.
                 */
-               DPRINTK(PROBE, INFO,
-                        "found MII-less i82503 or 80c24 or other PHY\n");
+               netif_info(nic, probe, nic->netdev,
+                          "found MII-less i82503 or 80c24 or other PHY\n");
 
                nic->mdio_ctrl = mdio_ctrl_phy_mii_emulated;
                nic->mii.phy_id = 0; /* is this ok for an MII-less PHY? */
@@ -1435,18 +1441,20 @@ static int e100_phy_init(struct nic *nic)
                        return 0; /* simply return and hope for the best */
                else {
                        /* for unknown cases log a fatal error */
-                       DPRINTK(HW, ERR,
-                               "Failed to locate any known PHY, aborting.\n");
+                       netif_err(nic, hw, nic->netdev,
+                                 "Failed to locate any known PHY, aborting\n");
                        return -EAGAIN;
                }
        } else
-               DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
+               netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                            "phy_addr = %d\n", nic->mii.phy_id);
 
        /* Get phy ID */
        id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
        id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2);
        nic->phy = (u32)id_hi << 16 | (u32)id_lo;
-       DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                    "phy ID = 0x%08X\n", nic->phy);
 
        /* Select the phy and isolate the rest */
        for (addr = 0; addr < 32; addr++) {
@@ -1508,7 +1516,7 @@ static int e100_hw_init(struct nic *nic)
 
        e100_hw_reset(nic);
 
-       DPRINTK(HW, ERR, "e100_hw_init\n");
+       netif_err(nic, hw, nic->netdev, "e100_hw_init\n");
        if (!in_interrupt() && (err = e100_self_test(nic)))
                return err;
 
@@ -1538,16 +1546,16 @@ static int e100_hw_init(struct nic *nic)
 static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
 {
        struct net_device *netdev = nic->netdev;
-       struct dev_mc_list *list;
+       struct netdev_hw_addr *ha;
        u16 i, count = min(netdev_mc_count(netdev), E100_MAX_MULTICAST_ADDRS);
 
        cb->command = cpu_to_le16(cb_multi);
        cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);
        i = 0;
-       netdev_for_each_mc_addr(list, netdev) {
+       netdev_for_each_mc_addr(ha, netdev) {
                if (i == count)
                        break;
-               memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &list->dmi_addr,
+               memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &ha->addr,
                        ETH_ALEN);
        }
 }
@@ -1556,8 +1564,9 @@ static void e100_set_multicast_list(struct net_device *netdev)
 {
        struct nic *nic = netdev_priv(netdev);
 
-       DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
-               netdev_mc_count(netdev), netdev->flags);
+       netif_printk(nic, hw, KERN_DEBUG, nic->netdev,
+                    "mc_count=%d, flags=0x%04X\n",
+                    netdev_mc_count(netdev), netdev->flags);
 
        if (netdev->flags & IFF_PROMISC)
                nic->flags |= promiscuous;
@@ -1630,7 +1639,8 @@ static void e100_update_stats(struct nic *nic)
 
 
        if (e100_exec_cmd(nic, cuc_dump_reset, 0))
-               DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
+               netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+                            "exec cuc_dump_reset failed\n");
 }
 
 static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
@@ -1660,20 +1670,19 @@ static void e100_watchdog(unsigned long data)
        struct nic *nic = (struct nic *)data;
        struct ethtool_cmd cmd;
 
-       DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies);
+       netif_printk(nic, timer, KERN_DEBUG, nic->netdev,
+                    "right now = %ld\n", jiffies);
 
        /* mii library handles link maintenance tasks */
 
        mii_ethtool_gset(&nic->mii, &cmd);
 
        if (mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
-               printk(KERN_INFO "e100: %s NIC Link is Up %s Mbps %s Duplex\n",
-                      nic->netdev->name,
-                      cmd.speed == SPEED_100 ? "100" : "10",
-                      cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
+               netdev_info(nic->netdev, "NIC Link is Up %u Mbps %s Duplex\n",
+                           cmd.speed == SPEED_100 ? 100 : 10,
+                           cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
        } else if (!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
-               printk(KERN_INFO "e100: %s NIC Link is Down\n",
-                      nic->netdev->name);
+               netdev_info(nic->netdev, "NIC Link is Down\n");
        }
 
        mii_check_link(&nic->mii);
@@ -1733,7 +1742,8 @@ static netdev_tx_t e100_xmit_frame(struct sk_buff *skb,
                   Issue a NOP command followed by a 1us delay before
                   issuing the Tx command. */
                if (e100_exec_cmd(nic, cuc_nop, 0))
-                       DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
+                       netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+                                    "exec cuc_nop failed\n");
                udelay(1);
        }
 
@@ -1742,17 +1752,18 @@ static netdev_tx_t e100_xmit_frame(struct sk_buff *skb,
        switch (err) {
        case -ENOSPC:
                /* We queued the skb, but now we're out of space. */
-               DPRINTK(TX_ERR, DEBUG, "No space for CB\n");
+               netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+                            "No space for CB\n");
                netif_stop_queue(netdev);
                break;
        case -ENOMEM:
                /* This is a hard error - log it. */
-               DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n");
+               netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+                            "Out of Tx resources, returning skb\n");
                netif_stop_queue(netdev);
                return NETDEV_TX_BUSY;
        }
 
-       netdev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
@@ -1768,9 +1779,10 @@ static int e100_tx_clean(struct nic *nic)
        for (cb = nic->cb_to_clean;
            cb->status & cpu_to_le16(cb_complete);
            cb = nic->cb_to_clean = cb->next) {
-               DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
-                       (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
-                       cb->status);
+               netif_printk(nic, tx_done, KERN_DEBUG, nic->netdev,
+                            "cb[%d]->status = 0x%04X\n",
+                            (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
+                            cb->status);
 
                if (likely(cb->skb != NULL)) {
                        dev->stats.tx_packets++;
@@ -1913,7 +1925,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
                sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL);
        rfd_status = le16_to_cpu(rfd->status);
 
-       DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
+       netif_printk(nic, rx_status, KERN_DEBUG, nic->netdev,
+                    "status=0x%04X\n", rfd_status);
 
        /* If data isn't ready, nothing to indicate */
        if (unlikely(!(rfd_status & cb_complete))) {
@@ -2124,7 +2137,8 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
        struct nic *nic = netdev_priv(netdev);
        u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
 
-       DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
+       netif_printk(nic, intr, KERN_DEBUG, nic->netdev,
+                    "stat_ack = 0x%02X\n", stat_ack);
 
        if (stat_ack == stat_ack_not_ours ||    /* Not our interrupt */
           stat_ack == stat_ack_not_present)    /* Hardware is ejected */
@@ -2264,8 +2278,8 @@ static void e100_tx_timeout_task(struct work_struct *work)
        struct nic *nic = container_of(work, struct nic, tx_timeout_task);
        struct net_device *netdev = nic->netdev;
 
-       DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
-               ioread8(&nic->csr->scb.status));
+       netif_printk(nic, tx_err, KERN_DEBUG, nic->netdev,
+                    "scb.status=0x%02X\n", ioread8(&nic->csr->scb.status));
 
        rtnl_lock();
        if (netif_running(netdev)) {
@@ -2532,8 +2546,8 @@ static int e100_set_ringparam(struct net_device *netdev,
        rfds->count = min(rfds->count, rfds->max);
        cbs->count = max(ring->tx_pending, cbs->min);
        cbs->count = min(cbs->count, cbs->max);
-       DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n",
-               rfds->count, cbs->count);
+       netif_info(nic, drv, nic->netdev, "Ring Param settings: rx: %d, tx %d\n",
+                  rfds->count, cbs->count);
        if (netif_running(netdev))
                e100_up(nic);
 
@@ -2710,7 +2724,7 @@ static int e100_open(struct net_device *netdev)
 
        netif_carrier_off(netdev);
        if ((err = e100_up(nic)))
-               DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");
+               netif_err(nic, ifup, nic->netdev, "Cannot open interface, aborting\n");
        return err;
 }
 
@@ -2744,7 +2758,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 
        if (!(netdev = alloc_etherdev(sizeof(struct nic)))) {
                if (((1 << debug) - 1) & NETIF_MSG_PROBE)
-                       printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n");
+                       pr_err("Etherdev alloc failed, aborting\n");
                return -ENOMEM;
        }
 
@@ -2762,35 +2776,34 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        pci_set_drvdata(pdev, netdev);
 
        if ((err = pci_enable_device(pdev))) {
-               DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "Cannot enable PCI device, aborting\n");
                goto err_out_free_dev;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               DPRINTK(PROBE, ERR, "Cannot find proper PCI device "
-                       "base address, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "Cannot find proper PCI device base address, aborting\n");
                err = -ENODEV;
                goto err_out_disable_pdev;
        }
 
        if ((err = pci_request_regions(pdev, DRV_NAME))) {
-               DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "Cannot obtain PCI resources, aborting\n");
                goto err_out_disable_pdev;
        }
 
        if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) {
-               DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "No usable DMA configuration, aborting\n");
                goto err_out_free_res;
        }
 
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
        if (use_io)
-               DPRINTK(PROBE, INFO, "using i/o access mode\n");
+               netif_info(nic, probe, nic->netdev, "using i/o access mode\n");
 
        nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
        if (!nic->csr) {
-               DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "Cannot map device registers, aborting\n");
                err = -ENOMEM;
                goto err_out_free_res;
        }
@@ -2824,7 +2837,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
 
        if ((err = e100_alloc(nic))) {
-               DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "Cannot alloc driver memory, aborting\n");
                goto err_out_iounmap;
        }
 
@@ -2837,13 +2850,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
        memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
        if (!is_valid_ether_addr(netdev->perm_addr)) {
                if (!eeprom_bad_csum_allow) {
-                       DPRINTK(PROBE, ERR, "Invalid MAC address from "
-                               "EEPROM, aborting.\n");
+                       netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, aborting\n");
                        err = -EAGAIN;
                        goto err_out_free;
                } else {
-                       DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
-                               "you MUST configure one.\n");
+                       netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, you MUST configure one.\n");
                }
        }
 
@@ -2859,7 +2870,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
 
        strcpy(netdev->name, "eth%d");
        if ((err = register_netdev(netdev))) {
-               DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
+               netif_err(nic, probe, nic->netdev, "Cannot register net device, aborting\n");
                goto err_out_free;
        }
        nic->cbs_pool = pci_pool_create(netdev->name,
@@ -2867,9 +2878,10 @@ static int __devinit e100_probe(struct pci_dev *pdev,
                           nic->params.cbs.max * sizeof(struct cb),
                           sizeof(u32),
                           0);
-       DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
-               (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
-               pdev->irq, netdev->dev_addr);
+       netif_info(nic, probe, nic->netdev,
+                  "addr 0x%llx, irq %d, MAC addr %pM\n",
+                  (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
+                  pdev->irq, netdev->dev_addr);
 
        return 0;
 
@@ -3027,7 +3039,7 @@ static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev)
        struct nic *nic = netdev_priv(netdev);
 
        if (pci_enable_device(pdev)) {
-               printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n");
+               pr_err("Cannot re-enable PCI device after reset\n");
                return PCI_ERS_RESULT_DISCONNECT;
        }
        pci_set_master(pdev);
@@ -3086,8 +3098,8 @@ static struct pci_driver e100_driver = {
 static int __init e100_init_module(void)
 {
        if (((1 << debug) - 1) & NETIF_MSG_DRV) {
-               printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
-               printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
+               pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+               pr_info("%s\n", DRV_COPYRIGHT);
        }
        return pci_register_driver(&e100_driver);
 }
index 2f29c213185113c4d36eb095cc88b1190bef6603..40b62b406b08327ace3f83626613120be8399b54 100644 (file)
@@ -81,23 +81,6 @@ struct e1000_adapter;
 
 #include "e1000_hw.h"
 
-#ifdef DBG
-#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
-#else
-#define E1000_DBG(args...)
-#endif
-
-#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
-
-#define PFX "e1000: "
-
-#define DPRINTK(nlevel, klevel, fmt, args...)                          \
-do {                                                                   \
-       if (NETIF_MSG_##nlevel & adapter->msg_enable)                   \
-               printk(KERN_##klevel PFX "%s: %s: " fmt,                \
-                      adapter->netdev->name, __func__, ##args);        \
-} while (0)
-
 #define E1000_MAX_INTR 10
 
 /* TX/RX descriptor defines */
@@ -335,6 +318,25 @@ enum e1000_state_t {
        __E1000_DOWN
 };
 
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+extern struct net_device *e1000_get_hw_dev(struct e1000_hw *hw);
+#define e_dbg(format, arg...) \
+       netdev_dbg(e1000_get_hw_dev(hw), format, ## arg)
+#define e_err(format, arg...) \
+       netdev_err(adapter->netdev, format, ## arg)
+#define e_info(format, arg...) \
+       netdev_info(adapter->netdev, format, ## arg)
+#define e_warn(format, arg...) \
+       netdev_warn(adapter->netdev, format, ## arg)
+#define e_notice(format, arg...) \
+       netdev_notice(adapter->netdev, format, ## arg)
+#define e_dev_info(format, arg...) \
+       dev_info(&adapter->pdev->dev, format, ## arg)
+#define e_dev_warn(format, arg...) \
+       dev_warn(&adapter->pdev->dev, format, ## arg)
+
 extern char e1000_driver_name[];
 extern const char e1000_driver_version[];
 
@@ -352,5 +354,6 @@ extern bool e1000_has_link(struct e1000_adapter *adapter);
 extern void e1000_power_up_phy(struct e1000_adapter *);
 extern void e1000_set_ethtool_ops(struct net_device *netdev);
 extern void e1000_check_options(struct e1000_adapter *adapter);
+extern char *e1000_get_hw_dev_name(struct e1000_hw *hw);
 
 #endif /* _E1000_H_ */
index c67e93117271bb7478aac4d0c7d82cbbc19e64f6..d5ff029aa7b226f6ab60c4d96e46c231f19b9c16 100644 (file)
@@ -346,7 +346,7 @@ static int e1000_set_tso(struct net_device *netdev, u32 data)
 
        netdev->features &= ~NETIF_F_TSO6;
 
-       DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");
+       e_info("TSO is %s\n", data ? "Enabled" : "Disabled");
        adapter->tso_force = true;
        return 0;
 }
@@ -714,9 +714,9 @@ static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, int reg,
                writel(write & test[i], address);
                read = readl(address);
                if (read != (write & test[i] & mask)) {
-                       DPRINTK(DRV, ERR, "pattern test reg %04X failed: "
-                               "got 0x%08X expected 0x%08X\n",
-                               reg, read, (write & test[i] & mask));
+                       e_info("pattern test reg %04X failed: "
+                              "got 0x%08X expected 0x%08X\n",
+                              reg, read, (write & test[i] & mask));
                        *data = reg;
                        return true;
                }
@@ -734,9 +734,9 @@ static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, int reg,
        writel(write & mask, address);
        read = readl(address);
        if ((read & mask) != (write & mask)) {
-               DPRINTK(DRV, ERR, "set/check reg %04X test failed: "
-                       "got 0x%08X expected 0x%08X\n",
-                       reg, (read & mask), (write & mask));
+               e_err("set/check reg %04X test failed: "
+                     "got 0x%08X expected 0x%08X\n",
+                     reg, (read & mask), (write & mask));
                *data = reg;
                return true;
        }
@@ -779,8 +779,8 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
        ew32(STATUS, toggle);
        after = er32(STATUS) & toggle;
        if (value != after) {
-               DPRINTK(DRV, ERR, "failed STATUS register test got: "
-                       "0x%08X expected: 0x%08X\n", after, value);
+               e_err("failed STATUS register test got: "
+                     "0x%08X expected: 0x%08X\n", after, value);
                *data = 1;
                return 1;
        }
@@ -894,8 +894,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
                *data = 1;
                return -1;
        }
-       DPRINTK(HW, INFO, "testing %s interrupt\n",
-               (shared_int ? "shared" : "unshared"));
+       e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
 
        /* Disable all the interrupts */
        ew32(IMC, 0xFFFFFFFF);
@@ -980,9 +979,10 @@ static void e1000_free_desc_rings(struct e1000_adapter *adapter)
        if (txdr->desc && txdr->buffer_info) {
                for (i = 0; i < txdr->count; i++) {
                        if (txdr->buffer_info[i].dma)
-                               pci_unmap_single(pdev, txdr->buffer_info[i].dma,
+                               dma_unmap_single(&pdev->dev,
+                                                txdr->buffer_info[i].dma,
                                                 txdr->buffer_info[i].length,
-                                                PCI_DMA_TODEVICE);
+                                                DMA_TO_DEVICE);
                        if (txdr->buffer_info[i].skb)
                                dev_kfree_skb(txdr->buffer_info[i].skb);
                }
@@ -991,20 +991,23 @@ static void e1000_free_desc_rings(struct e1000_adapter *adapter)
        if (rxdr->desc && rxdr->buffer_info) {
                for (i = 0; i < rxdr->count; i++) {
                        if (rxdr->buffer_info[i].dma)
-                               pci_unmap_single(pdev, rxdr->buffer_info[i].dma,
+                               dma_unmap_single(&pdev->dev,
+                                                rxdr->buffer_info[i].dma,
                                                 rxdr->buffer_info[i].length,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        if (rxdr->buffer_info[i].skb)
                                dev_kfree_skb(rxdr->buffer_info[i].skb);
                }
        }
 
        if (txdr->desc) {
-               pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma);
+               dma_free_coherent(&pdev->dev, txdr->size, txdr->desc,
+                                 txdr->dma);
                txdr->desc = NULL;
        }
        if (rxdr->desc) {
-               pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);
+               dma_free_coherent(&pdev->dev, rxdr->size, rxdr->desc,
+                                 rxdr->dma);
                rxdr->desc = NULL;
        }
 
@@ -1012,8 +1015,6 @@ static void e1000_free_desc_rings(struct e1000_adapter *adapter)
        txdr->buffer_info = NULL;
        kfree(rxdr->buffer_info);
        rxdr->buffer_info = NULL;
-
-       return;
 }
 
 static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
@@ -1039,7 +1040,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
 
        txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
        txdr->size = ALIGN(txdr->size, 4096);
-       txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+       txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma,
+                                       GFP_KERNEL);
        if (!txdr->desc) {
                ret_val = 2;
                goto err_nomem;
@@ -1070,8 +1072,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
                txdr->buffer_info[i].skb = skb;
                txdr->buffer_info[i].length = skb->len;
                txdr->buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, skb->len,
-                                      PCI_DMA_TODEVICE);
+                       dma_map_single(&pdev->dev, skb->data, skb->len,
+                                      DMA_TO_DEVICE);
                tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);
                tx_desc->lower.data = cpu_to_le32(skb->len);
                tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
@@ -1093,7 +1095,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
        }
 
        rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
-       rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+       rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,
+                                       GFP_KERNEL);
        if (!rxdr->desc) {
                ret_val = 5;
                goto err_nomem;
@@ -1126,8 +1129,8 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
                rxdr->buffer_info[i].skb = skb;
                rxdr->buffer_info[i].length = E1000_RXBUFFER_2048;
                rxdr->buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, E1000_RXBUFFER_2048,
-                                      PCI_DMA_FROMDEVICE);
+                       dma_map_single(&pdev->dev, skb->data,
+                                      E1000_RXBUFFER_2048, DMA_FROM_DEVICE);
                rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);
                memset(skb->data, 0x00, skb->len);
        }
@@ -1444,10 +1447,10 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                for (i = 0; i < 64; i++) { /* send the packets */
                        e1000_create_lbtest_frame(txdr->buffer_info[i].skb,
                                        1024);
-                       pci_dma_sync_single_for_device(pdev,
-                                       txdr->buffer_info[k].dma,
-                                       txdr->buffer_info[k].length,
-                                       PCI_DMA_TODEVICE);
+                       dma_sync_single_for_device(&pdev->dev,
+                                                  txdr->buffer_info[k].dma,
+                                                  txdr->buffer_info[k].length,
+                                                  DMA_TO_DEVICE);
                        if (unlikely(++k == txdr->count)) k = 0;
                }
                ew32(TDT, k);
@@ -1455,10 +1458,10 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                time = jiffies; /* set the start time for the receive */
                good_cnt = 0;
                do { /* receive the sent packets */
-                       pci_dma_sync_single_for_cpu(pdev,
-                                       rxdr->buffer_info[l].dma,
-                                       rxdr->buffer_info[l].length,
-                                       PCI_DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(&pdev->dev,
+                                               rxdr->buffer_info[l].dma,
+                                               rxdr->buffer_info[l].length,
+                                               DMA_FROM_DEVICE);
 
                        ret_val = e1000_check_lbtest_frame(
                                        rxdr->buffer_info[l].skb,
@@ -1558,7 +1561,7 @@ static void e1000_diag_test(struct net_device *netdev,
                u8 forced_speed_duplex = hw->forced_speed_duplex;
                u8 autoneg = hw->autoneg;
 
-               DPRINTK(HW, INFO, "offline testing starting\n");
+               e_info("offline testing starting\n");
 
                /* Link test performed before hardware reset so autoneg doesn't
                 * interfere with test result */
@@ -1598,7 +1601,7 @@ static void e1000_diag_test(struct net_device *netdev,
                if (if_running)
                        dev_open(netdev);
        } else {
-               DPRINTK(HW, INFO, "online testing starting\n");
+               e_info("online testing starting\n");
                /* Online tests */
                if (e1000_link_test(adapter, &data[4]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1691,7 +1694,7 @@ static void e1000_get_wol(struct net_device *netdev,
                wol->supported &= ~WAKE_UCAST;
 
                if (adapter->wol & E1000_WUFC_EX)
-                       DPRINTK(DRV, ERR, "Interface does not support "
+                       e_err("Interface does not support "
                        "directed (unicast) frame wake-up packets\n");
                break;
        default:
@@ -1706,8 +1709,6 @@ static void e1000_get_wol(struct net_device *netdev,
                wol->wolopts |= WAKE_BCAST;
        if (adapter->wol & E1000_WUFC_MAG)
                wol->wolopts |= WAKE_MAGIC;
-
-       return;
 }
 
 static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
@@ -1725,8 +1726,8 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        switch (hw->device_id) {
        case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
                if (wol->wolopts & WAKE_UCAST) {
-                       DPRINTK(DRV, ERR, "Interface does not support "
-                       "directed (unicast) frame wake-up packets\n");
+                       e_err("Interface does not support "
+                             "directed (unicast) frame wake-up packets\n");
                        return -EOPNOTSUPP;
                }
                break;
@@ -1803,7 +1804,7 @@ static int e1000_get_coalesce(struct net_device *netdev,
        if (adapter->hw.mac_type < e1000_82545)
                return -EOPNOTSUPP;
 
-       if (adapter->itr_setting <= 3)
+       if (adapter->itr_setting <= 4)
                ec->rx_coalesce_usecs = adapter->itr_setting;
        else
                ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
@@ -1821,12 +1822,14 @@ static int e1000_set_coalesce(struct net_device *netdev,
                return -EOPNOTSUPP;
 
        if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
-           ((ec->rx_coalesce_usecs > 3) &&
+           ((ec->rx_coalesce_usecs > 4) &&
             (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
            (ec->rx_coalesce_usecs == 2))
                return -EINVAL;
 
-       if (ec->rx_coalesce_usecs <= 3) {
+       if (ec->rx_coalesce_usecs == 4) {
+               adapter->itr = adapter->itr_setting = 4;
+       } else if (ec->rx_coalesce_usecs <= 3) {
                adapter->itr = 20000;
                adapter->itr_setting = ec->rx_coalesce_usecs;
        } else {
index 8d7d87f128275e2d7ba1baf8f100933acad6feb3..c7e242b69a18096953fbb620b9e596bbdb3dbf3a 100644 (file)
@@ -30,7 +30,7 @@
  * Shared functions for accessing and configuring the MAC
  */
 
-#include "e1000_hw.h"
+#include "e1000.h"
 
 static s32 e1000_check_downshift(struct e1000_hw *hw);
 static s32 e1000_check_polarity(struct e1000_hw *hw,
@@ -114,7 +114,7 @@ static DEFINE_SPINLOCK(e1000_eeprom_lock);
  */
 static s32 e1000_set_phy_type(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_set_phy_type");
+       e_dbg("e1000_set_phy_type");
 
        if (hw->mac_type == e1000_undefined)
                return -E1000_ERR_PHY_TYPE;
@@ -152,7 +152,7 @@ static void e1000_phy_init_script(struct e1000_hw *hw)
        u32 ret_val;
        u16 phy_saved_data;
 
-       DEBUGFUNC("e1000_phy_init_script");
+       e_dbg("e1000_phy_init_script");
 
        if (hw->phy_init_script) {
                msleep(20);
@@ -245,7 +245,7 @@ static void e1000_phy_init_script(struct e1000_hw *hw)
  */
 s32 e1000_set_mac_type(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_set_mac_type");
+       e_dbg("e1000_set_mac_type");
 
        switch (hw->device_id) {
        case E1000_DEV_ID_82542:
@@ -354,7 +354,7 @@ void e1000_set_media_type(struct e1000_hw *hw)
 {
        u32 status;
 
-       DEBUGFUNC("e1000_set_media_type");
+       e_dbg("e1000_set_media_type");
 
        if (hw->mac_type != e1000_82543) {
                /* tbi_compatibility is only valid on 82543 */
@@ -401,16 +401,16 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
        u32 led_ctrl;
        s32 ret_val;
 
-       DEBUGFUNC("e1000_reset_hw");
+       e_dbg("e1000_reset_hw");
 
        /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
        if (hw->mac_type == e1000_82542_rev2_0) {
-               DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+               e_dbg("Disabling MWI on 82542 rev 2.0\n");
                e1000_pci_clear_mwi(hw);
        }
 
        /* Clear interrupt mask to stop board from generating interrupts */
-       DEBUGOUT("Masking off all interrupts\n");
+       e_dbg("Masking off all interrupts\n");
        ew32(IMC, 0xffffffff);
 
        /* Disable the Transmit and Receive units.  Then delay to allow
@@ -442,7 +442,7 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
         * the current PCI configuration.  The global reset bit is self-
         * clearing, and should clear within a microsecond.
         */
-       DEBUGOUT("Issuing a global reset to MAC\n");
+       e_dbg("Issuing a global reset to MAC\n");
 
        switch (hw->mac_type) {
        case e1000_82544:
@@ -516,7 +516,7 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
        }
 
        /* Clear interrupt mask to stop board from generating interrupts */
-       DEBUGOUT("Masking off all interrupts\n");
+       e_dbg("Masking off all interrupts\n");
        ew32(IMC, 0xffffffff);
 
        /* Clear any pending interrupt events. */
@@ -549,12 +549,12 @@ s32 e1000_init_hw(struct e1000_hw *hw)
        u32 mta_size;
        u32 ctrl_ext;
 
-       DEBUGFUNC("e1000_init_hw");
+       e_dbg("e1000_init_hw");
 
        /* Initialize Identification LED */
        ret_val = e1000_id_led_init(hw);
        if (ret_val) {
-               DEBUGOUT("Error Initializing Identification LED\n");
+               e_dbg("Error Initializing Identification LED\n");
                return ret_val;
        }
 
@@ -562,14 +562,14 @@ s32 e1000_init_hw(struct e1000_hw *hw)
        e1000_set_media_type(hw);
 
        /* Disabling VLAN filtering. */
-       DEBUGOUT("Initializing the IEEE VLAN\n");
+       e_dbg("Initializing the IEEE VLAN\n");
        if (hw->mac_type < e1000_82545_rev_3)
                ew32(VET, 0);
        e1000_clear_vfta(hw);
 
        /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
        if (hw->mac_type == e1000_82542_rev2_0) {
-               DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+               e_dbg("Disabling MWI on 82542 rev 2.0\n");
                e1000_pci_clear_mwi(hw);
                ew32(RCTL, E1000_RCTL_RST);
                E1000_WRITE_FLUSH();
@@ -591,7 +591,7 @@ s32 e1000_init_hw(struct e1000_hw *hw)
        }
 
        /* Zero out the Multicast HASH table */
-       DEBUGOUT("Zeroing the MTA\n");
+       e_dbg("Zeroing the MTA\n");
        mta_size = E1000_MC_TBL_SIZE;
        for (i = 0; i < mta_size; i++) {
                E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
@@ -662,7 +662,7 @@ static s32 e1000_adjust_serdes_amplitude(struct e1000_hw *hw)
        u16 eeprom_data;
        s32 ret_val;
 
-       DEBUGFUNC("e1000_adjust_serdes_amplitude");
+       e_dbg("e1000_adjust_serdes_amplitude");
 
        if (hw->media_type != e1000_media_type_internal_serdes)
                return E1000_SUCCESS;
@@ -709,7 +709,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
        s32 ret_val;
        u16 eeprom_data;
 
-       DEBUGFUNC("e1000_setup_link");
+       e_dbg("e1000_setup_link");
 
        /* Read and store word 0x0F of the EEPROM. This word contains bits
         * that determine the hardware's default PAUSE (flow control) mode,
@@ -723,7 +723,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
                ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
                                            1, &eeprom_data);
                if (ret_val) {
-                       DEBUGOUT("EEPROM Read Error\n");
+                       e_dbg("EEPROM Read Error\n");
                        return -E1000_ERR_EEPROM;
                }
                if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
@@ -747,7 +747,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
 
        hw->original_fc = hw->fc;
 
-       DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+       e_dbg("After fix-ups FlowControl is now = %x\n", hw->fc);
 
        /* Take the 4 bits from EEPROM word 0x0F that determine the initial
         * polarity value for the SW controlled pins, and setup the
@@ -760,7 +760,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
                ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
                                            1, &eeprom_data);
                if (ret_val) {
-                       DEBUGOUT("EEPROM Read Error\n");
+                       e_dbg("EEPROM Read Error\n");
                        return -E1000_ERR_EEPROM;
                }
                ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
@@ -777,8 +777,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
         * control is disabled, because it does not hurt anything to
         * initialize these registers.
         */
-       DEBUGOUT
-           ("Initializing the Flow Control address, type and timer regs\n");
+       e_dbg("Initializing the Flow Control address, type and timer regs\n");
 
        ew32(FCT, FLOW_CONTROL_TYPE);
        ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
@@ -827,7 +826,7 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
        u32 signal = 0;
        s32 ret_val;
 
-       DEBUGFUNC("e1000_setup_fiber_serdes_link");
+       e_dbg("e1000_setup_fiber_serdes_link");
 
        /* On adapters with a MAC newer than 82544, SWDP 1 will be
         * set when the optics detect a signal. On older adapters, it will be
@@ -893,7 +892,7 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
                txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
                break;
        default:
-               DEBUGOUT("Flow control param set incorrectly\n");
+               e_dbg("Flow control param set incorrectly\n");
                return -E1000_ERR_CONFIG;
                break;
        }
@@ -904,7 +903,7 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
         * link-up status bit will be set and the flow control enable bits (RFCE
         * and TFCE) will be set according to their negotiated value.
         */
-       DEBUGOUT("Auto-negotiation enabled\n");
+       e_dbg("Auto-negotiation enabled\n");
 
        ew32(TXCW, txcw);
        ew32(CTRL, ctrl);
@@ -921,7 +920,7 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
         */
        if (hw->media_type == e1000_media_type_internal_serdes ||
            (er32(CTRL) & E1000_CTRL_SWDPIN1) == signal) {
-               DEBUGOUT("Looking for Link\n");
+               e_dbg("Looking for Link\n");
                for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
                        msleep(10);
                        status = er32(STATUS);
@@ -929,7 +928,7 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
                                break;
                }
                if (i == (LINK_UP_TIMEOUT / 10)) {
-                       DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+                       e_dbg("Never got a valid link from auto-neg!!!\n");
                        hw->autoneg_failed = 1;
                        /* AutoNeg failed to achieve a link, so we'll call
                         * e1000_check_for_link. This routine will force the link up if
@@ -938,16 +937,16 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
                         */
                        ret_val = e1000_check_for_link(hw);
                        if (ret_val) {
-                               DEBUGOUT("Error while checking for link\n");
+                               e_dbg("Error while checking for link\n");
                                return ret_val;
                        }
                        hw->autoneg_failed = 0;
                } else {
                        hw->autoneg_failed = 0;
-                       DEBUGOUT("Valid Link Found\n");
+                       e_dbg("Valid Link Found\n");
                }
        } else {
-               DEBUGOUT("No Signal Detected\n");
+               e_dbg("No Signal Detected\n");
        }
        return E1000_SUCCESS;
 }
@@ -964,7 +963,7 @@ static s32 e1000_copper_link_preconfig(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_copper_link_preconfig");
+       e_dbg("e1000_copper_link_preconfig");
 
        ctrl = er32(CTRL);
        /* With 82543, we need to force speed and duplex on the MAC equal to what
@@ -987,10 +986,10 @@ static s32 e1000_copper_link_preconfig(struct e1000_hw *hw)
        /* Make sure we have a valid PHY */
        ret_val = e1000_detect_gig_phy(hw);
        if (ret_val) {
-               DEBUGOUT("Error, did not detect valid phy.\n");
+               e_dbg("Error, did not detect valid phy.\n");
                return ret_val;
        }
-       DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+       e_dbg("Phy ID = %x\n", hw->phy_id);
 
        /* Set PHY to class A mode (if necessary) */
        ret_val = e1000_set_phy_mode(hw);
@@ -1025,14 +1024,14 @@ static s32 e1000_copper_link_igp_setup(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_copper_link_igp_setup");
+       e_dbg("e1000_copper_link_igp_setup");
 
        if (hw->phy_reset_disable)
                return E1000_SUCCESS;
 
        ret_val = e1000_phy_reset(hw);
        if (ret_val) {
-               DEBUGOUT("Error Resetting the PHY\n");
+               e_dbg("Error Resetting the PHY\n");
                return ret_val;
        }
 
@@ -1049,7 +1048,7 @@ static s32 e1000_copper_link_igp_setup(struct e1000_hw *hw)
                /* disable lplu d3 during driver init */
                ret_val = e1000_set_d3_lplu_state(hw, false);
                if (ret_val) {
-                       DEBUGOUT("Error Disabling LPLU D3\n");
+                       e_dbg("Error Disabling LPLU D3\n");
                        return ret_val;
                }
        }
@@ -1166,7 +1165,7 @@ static s32 e1000_copper_link_mgp_setup(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_copper_link_mgp_setup");
+       e_dbg("e1000_copper_link_mgp_setup");
 
        if (hw->phy_reset_disable)
                return E1000_SUCCESS;
@@ -1255,7 +1254,7 @@ static s32 e1000_copper_link_mgp_setup(struct e1000_hw *hw)
        /* SW Reset the PHY so all changes take effect */
        ret_val = e1000_phy_reset(hw);
        if (ret_val) {
-               DEBUGOUT("Error Resetting the PHY\n");
+               e_dbg("Error Resetting the PHY\n");
                return ret_val;
        }
 
@@ -1274,7 +1273,7 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_copper_link_autoneg");
+       e_dbg("e1000_copper_link_autoneg");
 
        /* Perform some bounds checking on the hw->autoneg_advertised
         * parameter.  If this variable is zero, then set it to the default.
@@ -1287,13 +1286,13 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
        if (hw->autoneg_advertised == 0)
                hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
-       DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+       e_dbg("Reconfiguring auto-neg advertisement params\n");
        ret_val = e1000_phy_setup_autoneg(hw);
        if (ret_val) {
-               DEBUGOUT("Error Setting up Auto-Negotiation\n");
+               e_dbg("Error Setting up Auto-Negotiation\n");
                return ret_val;
        }
-       DEBUGOUT("Restarting Auto-Neg\n");
+       e_dbg("Restarting Auto-Neg\n");
 
        /* Restart auto-negotiation by setting the Auto Neg Enable bit and
         * the Auto Neg Restart bit in the PHY control register.
@@ -1313,7 +1312,7 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
        if (hw->wait_autoneg_complete) {
                ret_val = e1000_wait_autoneg(hw);
                if (ret_val) {
-                       DEBUGOUT
+                       e_dbg
                            ("Error while waiting for autoneg to complete\n");
                        return ret_val;
                }
@@ -1340,20 +1339,20 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
 static s32 e1000_copper_link_postconfig(struct e1000_hw *hw)
 {
        s32 ret_val;
-       DEBUGFUNC("e1000_copper_link_postconfig");
+       e_dbg("e1000_copper_link_postconfig");
 
        if (hw->mac_type >= e1000_82544) {
                e1000_config_collision_dist(hw);
        } else {
                ret_val = e1000_config_mac_to_phy(hw);
                if (ret_val) {
-                       DEBUGOUT("Error configuring MAC to PHY settings\n");
+                       e_dbg("Error configuring MAC to PHY settings\n");
                        return ret_val;
                }
        }
        ret_val = e1000_config_fc_after_link_up(hw);
        if (ret_val) {
-               DEBUGOUT("Error Configuring Flow Control\n");
+               e_dbg("Error Configuring Flow Control\n");
                return ret_val;
        }
 
@@ -1361,7 +1360,7 @@ static s32 e1000_copper_link_postconfig(struct e1000_hw *hw)
        if (hw->phy_type == e1000_phy_igp) {
                ret_val = e1000_config_dsp_after_link_change(hw, true);
                if (ret_val) {
-                       DEBUGOUT("Error Configuring DSP after link up\n");
+                       e_dbg("Error Configuring DSP after link up\n");
                        return ret_val;
                }
        }
@@ -1381,7 +1380,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
        u16 i;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_setup_copper_link");
+       e_dbg("e1000_setup_copper_link");
 
        /* Check if it is a valid PHY and set PHY mode if necessary. */
        ret_val = e1000_copper_link_preconfig(hw);
@@ -1407,10 +1406,10 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
        } else {
                /* PHY will be set to 10H, 10F, 100H,or 100F
                 * depending on value from forced_speed_duplex. */
-               DEBUGOUT("Forcing speed and duplex\n");
+               e_dbg("Forcing speed and duplex\n");
                ret_val = e1000_phy_force_speed_duplex(hw);
                if (ret_val) {
-                       DEBUGOUT("Error Forcing Speed and Duplex\n");
+                       e_dbg("Error Forcing Speed and Duplex\n");
                        return ret_val;
                }
        }
@@ -1432,13 +1431,13 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
                        if (ret_val)
                                return ret_val;
 
-                       DEBUGOUT("Valid link established!!!\n");
+                       e_dbg("Valid link established!!!\n");
                        return E1000_SUCCESS;
                }
                udelay(10);
        }
 
-       DEBUGOUT("Unable to establish link!!!\n");
+       e_dbg("Unable to establish link!!!\n");
        return E1000_SUCCESS;
 }
 
@@ -1454,7 +1453,7 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
        u16 mii_autoneg_adv_reg;
        u16 mii_1000t_ctrl_reg;
 
-       DEBUGFUNC("e1000_phy_setup_autoneg");
+       e_dbg("e1000_phy_setup_autoneg");
 
        /* Read the MII Auto-Neg Advertisement Register (Address 4). */
        ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
@@ -1481,41 +1480,41 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
        mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
        mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
 
-       DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+       e_dbg("autoneg_advertised %x\n", hw->autoneg_advertised);
 
        /* Do we want to advertise 10 Mb Half Duplex? */
        if (hw->autoneg_advertised & ADVERTISE_10_HALF) {
-               DEBUGOUT("Advertise 10mb Half duplex\n");
+               e_dbg("Advertise 10mb Half duplex\n");
                mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
        }
 
        /* Do we want to advertise 10 Mb Full Duplex? */
        if (hw->autoneg_advertised & ADVERTISE_10_FULL) {
-               DEBUGOUT("Advertise 10mb Full duplex\n");
+               e_dbg("Advertise 10mb Full duplex\n");
                mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
        }
 
        /* Do we want to advertise 100 Mb Half Duplex? */
        if (hw->autoneg_advertised & ADVERTISE_100_HALF) {
-               DEBUGOUT("Advertise 100mb Half duplex\n");
+               e_dbg("Advertise 100mb Half duplex\n");
                mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
        }
 
        /* Do we want to advertise 100 Mb Full Duplex? */
        if (hw->autoneg_advertised & ADVERTISE_100_FULL) {
-               DEBUGOUT("Advertise 100mb Full duplex\n");
+               e_dbg("Advertise 100mb Full duplex\n");
                mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
        }
 
        /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
        if (hw->autoneg_advertised & ADVERTISE_1000_HALF) {
-               DEBUGOUT
+               e_dbg
                    ("Advertise 1000mb Half duplex requested, request denied!\n");
        }
 
        /* Do we want to advertise 1000 Mb Full Duplex? */
        if (hw->autoneg_advertised & ADVERTISE_1000_FULL) {
-               DEBUGOUT("Advertise 1000mb Full duplex\n");
+               e_dbg("Advertise 1000mb Full duplex\n");
                mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
        }
 
@@ -1568,7 +1567,7 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
                mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
                break;
        default:
-               DEBUGOUT("Flow control param set incorrectly\n");
+               e_dbg("Flow control param set incorrectly\n");
                return -E1000_ERR_CONFIG;
        }
 
@@ -1576,7 +1575,7 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
        if (ret_val)
                return ret_val;
 
-       DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+       e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
        ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
        if (ret_val)
@@ -1600,12 +1599,12 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
        u16 phy_data;
        u16 i;
 
-       DEBUGFUNC("e1000_phy_force_speed_duplex");
+       e_dbg("e1000_phy_force_speed_duplex");
 
        /* Turn off Flow control if we are forcing speed and duplex. */
        hw->fc = E1000_FC_NONE;
 
-       DEBUGOUT1("hw->fc = %d\n", hw->fc);
+       e_dbg("hw->fc = %d\n", hw->fc);
 
        /* Read the Device Control Register. */
        ctrl = er32(CTRL);
@@ -1634,14 +1633,14 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
                 */
                ctrl |= E1000_CTRL_FD;
                mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
-               DEBUGOUT("Full Duplex\n");
+               e_dbg("Full Duplex\n");
        } else {
                /* We want to force half duplex so we CLEAR the full duplex bits in
                 * the Device and MII Control Registers.
                 */
                ctrl &= ~E1000_CTRL_FD;
                mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
-               DEBUGOUT("Half Duplex\n");
+               e_dbg("Half Duplex\n");
        }
 
        /* Are we forcing 100Mbps??? */
@@ -1651,13 +1650,13 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
                ctrl |= E1000_CTRL_SPD_100;
                mii_ctrl_reg |= MII_CR_SPEED_100;
                mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-               DEBUGOUT("Forcing 100mb ");
+               e_dbg("Forcing 100mb ");
        } else {
                /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
                ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
                mii_ctrl_reg |= MII_CR_SPEED_10;
                mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-               DEBUGOUT("Forcing 10mb ");
+               e_dbg("Forcing 10mb ");
        }
 
        e1000_config_collision_dist(hw);
@@ -1680,7 +1679,7 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
                if (ret_val)
                        return ret_val;
 
-               DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+               e_dbg("M88E1000 PSCR: %x\n", phy_data);
 
                /* Need to reset the PHY or these changes will be ignored */
                mii_ctrl_reg |= MII_CR_RESET;
@@ -1720,7 +1719,7 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
         */
        if (hw->wait_autoneg_complete) {
                /* We will wait for autoneg to complete. */
-               DEBUGOUT("Waiting for forced speed/duplex link.\n");
+               e_dbg("Waiting for forced speed/duplex link.\n");
                mii_status_reg = 0;
 
                /* We will wait for autoneg to complete or 4.5 seconds to expire. */
@@ -1746,7 +1745,7 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
                        /* We didn't get link.  Reset the DSP and wait again for link. */
                        ret_val = e1000_phy_reset_dsp(hw);
                        if (ret_val) {
-                               DEBUGOUT("Error Resetting PHY DSP\n");
+                               e_dbg("Error Resetting PHY DSP\n");
                                return ret_val;
                        }
                }
@@ -1826,7 +1825,7 @@ void e1000_config_collision_dist(struct e1000_hw *hw)
 {
        u32 tctl, coll_dist;
 
-       DEBUGFUNC("e1000_config_collision_dist");
+       e_dbg("e1000_config_collision_dist");
 
        if (hw->mac_type < e1000_82543)
                coll_dist = E1000_COLLISION_DISTANCE_82542;
@@ -1857,7 +1856,7 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_config_mac_to_phy");
+       e_dbg("e1000_config_mac_to_phy");
 
        /* 82544 or newer MAC, Auto Speed Detection takes care of
         * MAC speed/duplex configuration.*/
@@ -1913,7 +1912,7 @@ s32 e1000_force_mac_fc(struct e1000_hw *hw)
 {
        u32 ctrl;
 
-       DEBUGFUNC("e1000_force_mac_fc");
+       e_dbg("e1000_force_mac_fc");
 
        /* Get the current configuration of the Device Control Register */
        ctrl = er32(CTRL);
@@ -1952,7 +1951,7 @@ s32 e1000_force_mac_fc(struct e1000_hw *hw)
                ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
                break;
        default:
-               DEBUGOUT("Flow control param set incorrectly\n");
+               e_dbg("Flow control param set incorrectly\n");
                return -E1000_ERR_CONFIG;
        }
 
@@ -1984,7 +1983,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
        u16 speed;
        u16 duplex;
 
-       DEBUGFUNC("e1000_config_fc_after_link_up");
+       e_dbg("e1000_config_fc_after_link_up");
 
        /* Check for the case where we have fiber media and auto-neg failed
         * so we had to force link.  In this case, we need to force the
@@ -1997,7 +1996,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                && (!hw->autoneg))) {
                ret_val = e1000_force_mac_fc(hw);
                if (ret_val) {
-                       DEBUGOUT("Error forcing flow control settings\n");
+                       e_dbg("Error forcing flow control settings\n");
                        return ret_val;
                }
        }
@@ -2079,10 +2078,10 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                                 */
                                if (hw->original_fc == E1000_FC_FULL) {
                                        hw->fc = E1000_FC_FULL;
-                                       DEBUGOUT("Flow Control = FULL.\n");
+                                       e_dbg("Flow Control = FULL.\n");
                                } else {
                                        hw->fc = E1000_FC_RX_PAUSE;
-                                       DEBUGOUT
+                                       e_dbg
                                            ("Flow Control = RX PAUSE frames only.\n");
                                }
                        }
@@ -2100,7 +2099,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                                 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
                        {
                                hw->fc = E1000_FC_TX_PAUSE;
-                               DEBUGOUT
+                               e_dbg
                                    ("Flow Control = TX PAUSE frames only.\n");
                        }
                        /* For transmitting PAUSE frames ONLY.
@@ -2117,7 +2116,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                                 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR))
                        {
                                hw->fc = E1000_FC_RX_PAUSE;
-                               DEBUGOUT
+                               e_dbg
                                    ("Flow Control = RX PAUSE frames only.\n");
                        }
                        /* Per the IEEE spec, at this point flow control should be
@@ -2144,10 +2143,10 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                                  hw->original_fc == E1000_FC_TX_PAUSE) ||
                                 hw->fc_strict_ieee) {
                                hw->fc = E1000_FC_NONE;
-                               DEBUGOUT("Flow Control = NONE.\n");
+                               e_dbg("Flow Control = NONE.\n");
                        } else {
                                hw->fc = E1000_FC_RX_PAUSE;
-                               DEBUGOUT
+                               e_dbg
                                    ("Flow Control = RX PAUSE frames only.\n");
                        }
 
@@ -2158,7 +2157,7 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                        ret_val =
                            e1000_get_speed_and_duplex(hw, &speed, &duplex);
                        if (ret_val) {
-                               DEBUGOUT
+                               e_dbg
                                    ("Error getting link speed and duplex\n");
                                return ret_val;
                        }
@@ -2171,12 +2170,12 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
                         */
                        ret_val = e1000_force_mac_fc(hw);
                        if (ret_val) {
-                               DEBUGOUT
+                               e_dbg
                                    ("Error forcing flow control settings\n");
                                return ret_val;
                        }
                } else {
-                       DEBUGOUT
+                       e_dbg
                            ("Copper PHY and Auto Neg has not completed.\n");
                }
        }
@@ -2197,7 +2196,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
        u32 status;
        s32 ret_val = E1000_SUCCESS;
 
-       DEBUGFUNC("e1000_check_for_serdes_link_generic");
+       e_dbg("e1000_check_for_serdes_link_generic");
 
        ctrl = er32(CTRL);
        status = er32(STATUS);
@@ -2216,7 +2215,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
                        hw->autoneg_failed = 1;
                        goto out;
                }
-               DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n");
+               e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n");
 
                /* Disable auto-negotiation in the TXCW register */
                ew32(TXCW, (hw->txcw & ~E1000_TXCW_ANE));
@@ -2229,7 +2228,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
                /* Configure Flow Control after forcing link up. */
                ret_val = e1000_config_fc_after_link_up(hw);
                if (ret_val) {
-                       DEBUGOUT("Error configuring flow control\n");
+                       e_dbg("Error configuring flow control\n");
                        goto out;
                }
        } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
@@ -2239,7 +2238,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
                 * and disable forced link in the Device Control register
                 * in an attempt to auto-negotiate with our link partner.
                 */
-               DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
+               e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n");
                ew32(TXCW, hw->txcw);
                ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
 
@@ -2256,11 +2255,11 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
                if (rxcw & E1000_RXCW_SYNCH) {
                        if (!(rxcw & E1000_RXCW_IV)) {
                                hw->serdes_has_link = true;
-                               DEBUGOUT("SERDES: Link up - forced.\n");
+                               e_dbg("SERDES: Link up - forced.\n");
                        }
                } else {
                        hw->serdes_has_link = false;
-                       DEBUGOUT("SERDES: Link down - force failed.\n");
+                       e_dbg("SERDES: Link down - force failed.\n");
                }
        }
 
@@ -2273,20 +2272,20 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
                        if (rxcw & E1000_RXCW_SYNCH) {
                                if (!(rxcw & E1000_RXCW_IV)) {
                                        hw->serdes_has_link = true;
-                                       DEBUGOUT("SERDES: Link up - autoneg "
+                                       e_dbg("SERDES: Link up - autoneg "
                                                 "completed successfully.\n");
                                } else {
                                        hw->serdes_has_link = false;
-                                       DEBUGOUT("SERDES: Link down - invalid"
+                                       e_dbg("SERDES: Link down - invalid"
                                                 "codewords detected in autoneg.\n");
                                }
                        } else {
                                hw->serdes_has_link = false;
-                               DEBUGOUT("SERDES: Link down - no sync.\n");
+                               e_dbg("SERDES: Link down - no sync.\n");
                        }
                } else {
                        hw->serdes_has_link = false;
-                       DEBUGOUT("SERDES: Link down - autoneg failed\n");
+                       e_dbg("SERDES: Link down - autoneg failed\n");
                }
        }
 
@@ -2312,7 +2311,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_check_for_link");
+       e_dbg("e1000_check_for_link");
 
        ctrl = er32(CTRL);
        status = er32(STATUS);
@@ -2407,7 +2406,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
                else {
                        ret_val = e1000_config_mac_to_phy(hw);
                        if (ret_val) {
-                               DEBUGOUT
+                               e_dbg
                                    ("Error configuring MAC to PHY settings\n");
                                return ret_val;
                        }
@@ -2419,7 +2418,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
                 */
                ret_val = e1000_config_fc_after_link_up(hw);
                if (ret_val) {
-                       DEBUGOUT("Error configuring flow control\n");
+                       e_dbg("Error configuring flow control\n");
                        return ret_val;
                }
 
@@ -2435,7 +2434,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
                        ret_val =
                            e1000_get_speed_and_duplex(hw, &speed, &duplex);
                        if (ret_val) {
-                               DEBUGOUT
+                               e_dbg
                                    ("Error getting link speed and duplex\n");
                                return ret_val;
                        }
@@ -2487,30 +2486,30 @@ s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_get_speed_and_duplex");
+       e_dbg("e1000_get_speed_and_duplex");
 
        if (hw->mac_type >= e1000_82543) {
                status = er32(STATUS);
                if (status & E1000_STATUS_SPEED_1000) {
                        *speed = SPEED_1000;
-                       DEBUGOUT("1000 Mbs, ");
+                       e_dbg("1000 Mbs, ");
                } else if (status & E1000_STATUS_SPEED_100) {
                        *speed = SPEED_100;
-                       DEBUGOUT("100 Mbs, ");
+                       e_dbg("100 Mbs, ");
                } else {
                        *speed = SPEED_10;
-                       DEBUGOUT("10 Mbs, ");
+                       e_dbg("10 Mbs, ");
                }
 
                if (status & E1000_STATUS_FD) {
                        *duplex = FULL_DUPLEX;
-                       DEBUGOUT("Full Duplex\n");
+                       e_dbg("Full Duplex\n");
                } else {
                        *duplex = HALF_DUPLEX;
-                       DEBUGOUT(" Half Duplex\n");
+                       e_dbg(" Half Duplex\n");
                }
        } else {
-               DEBUGOUT("1000 Mbs, Full Duplex\n");
+               e_dbg("1000 Mbs, Full Duplex\n");
                *speed = SPEED_1000;
                *duplex = FULL_DUPLEX;
        }
@@ -2554,8 +2553,8 @@ static s32 e1000_wait_autoneg(struct e1000_hw *hw)
        u16 i;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_wait_autoneg");
-       DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+       e_dbg("e1000_wait_autoneg");
+       e_dbg("Waiting for Auto-Neg to complete.\n");
 
        /* We will wait for autoneg to complete or 4.5 seconds to expire. */
        for (i = PHY_AUTO_NEG_TIME; i > 0; i--) {
@@ -2718,7 +2717,7 @@ s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 reg_addr, u16 *phy_data)
 {
        u32 ret_val;
 
-       DEBUGFUNC("e1000_read_phy_reg");
+       e_dbg("e1000_read_phy_reg");
 
        if ((hw->phy_type == e1000_phy_igp) &&
            (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
@@ -2741,10 +2740,10 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
        u32 mdic = 0;
        const u32 phy_addr = 1;
 
-       DEBUGFUNC("e1000_read_phy_reg_ex");
+       e_dbg("e1000_read_phy_reg_ex");
 
        if (reg_addr > MAX_PHY_REG_ADDRESS) {
-               DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+               e_dbg("PHY Address %d is out of range\n", reg_addr);
                return -E1000_ERR_PARAM;
        }
 
@@ -2767,11 +2766,11 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
                                break;
                }
                if (!(mdic & E1000_MDIC_READY)) {
-                       DEBUGOUT("MDI Read did not complete\n");
+                       e_dbg("MDI Read did not complete\n");
                        return -E1000_ERR_PHY;
                }
                if (mdic & E1000_MDIC_ERROR) {
-                       DEBUGOUT("MDI Error\n");
+                       e_dbg("MDI Error\n");
                        return -E1000_ERR_PHY;
                }
                *phy_data = (u16) mdic;
@@ -2820,7 +2819,7 @@ s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 reg_addr, u16 phy_data)
 {
        u32 ret_val;
 
-       DEBUGFUNC("e1000_write_phy_reg");
+       e_dbg("e1000_write_phy_reg");
 
        if ((hw->phy_type == e1000_phy_igp) &&
            (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
@@ -2843,10 +2842,10 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
        u32 mdic = 0;
        const u32 phy_addr = 1;
 
-       DEBUGFUNC("e1000_write_phy_reg_ex");
+       e_dbg("e1000_write_phy_reg_ex");
 
        if (reg_addr > MAX_PHY_REG_ADDRESS) {
-               DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+               e_dbg("PHY Address %d is out of range\n", reg_addr);
                return -E1000_ERR_PARAM;
        }
 
@@ -2870,7 +2869,7 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
                                break;
                }
                if (!(mdic & E1000_MDIC_READY)) {
-                       DEBUGOUT("MDI Write did not complete\n");
+                       e_dbg("MDI Write did not complete\n");
                        return -E1000_ERR_PHY;
                }
        } else {
@@ -2910,9 +2909,9 @@ s32 e1000_phy_hw_reset(struct e1000_hw *hw)
        u32 led_ctrl;
        s32 ret_val;
 
-       DEBUGFUNC("e1000_phy_hw_reset");
+       e_dbg("e1000_phy_hw_reset");
 
-       DEBUGOUT("Resetting Phy...\n");
+       e_dbg("Resetting Phy...\n");
 
        if (hw->mac_type > e1000_82543) {
                /* Read the device control register and assert the E1000_CTRL_PHY_RST
@@ -2973,7 +2972,7 @@ s32 e1000_phy_reset(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_phy_reset");
+       e_dbg("e1000_phy_reset");
 
        switch (hw->phy_type) {
        case e1000_phy_igp:
@@ -3013,7 +3012,7 @@ static s32 e1000_detect_gig_phy(struct e1000_hw *hw)
        u16 phy_id_high, phy_id_low;
        bool match = false;
 
-       DEBUGFUNC("e1000_detect_gig_phy");
+       e_dbg("e1000_detect_gig_phy");
 
        if (hw->phy_id != 0)
                return E1000_SUCCESS;
@@ -3057,16 +3056,16 @@ static s32 e1000_detect_gig_phy(struct e1000_hw *hw)
                        match = true;
                break;
        default:
-               DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+               e_dbg("Invalid MAC type %d\n", hw->mac_type);
                return -E1000_ERR_CONFIG;
        }
        phy_init_status = e1000_set_phy_type(hw);
 
        if ((match) && (phy_init_status == E1000_SUCCESS)) {
-               DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+               e_dbg("PHY ID 0x%X detected\n", hw->phy_id);
                return E1000_SUCCESS;
        }
-       DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+       e_dbg("Invalid PHY ID 0x%X\n", hw->phy_id);
        return -E1000_ERR_PHY;
 }
 
@@ -3079,7 +3078,7 @@ static s32 e1000_detect_gig_phy(struct e1000_hw *hw)
 static s32 e1000_phy_reset_dsp(struct e1000_hw *hw)
 {
        s32 ret_val;
-       DEBUGFUNC("e1000_phy_reset_dsp");
+       e_dbg("e1000_phy_reset_dsp");
 
        do {
                ret_val = e1000_write_phy_reg(hw, 29, 0x001d);
@@ -3111,7 +3110,7 @@ static s32 e1000_phy_igp_get_info(struct e1000_hw *hw,
        u16 phy_data, min_length, max_length, average;
        e1000_rev_polarity polarity;
 
-       DEBUGFUNC("e1000_phy_igp_get_info");
+       e_dbg("e1000_phy_igp_get_info");
 
        /* The downshift status is checked only once, after link is established,
         * and it stored in the hw->speed_downgraded parameter. */
@@ -3189,7 +3188,7 @@ static s32 e1000_phy_m88_get_info(struct e1000_hw *hw,
        u16 phy_data;
        e1000_rev_polarity polarity;
 
-       DEBUGFUNC("e1000_phy_m88_get_info");
+       e_dbg("e1000_phy_m88_get_info");
 
        /* The downshift status is checked only once, after link is established,
         * and it stored in the hw->speed_downgraded parameter. */
@@ -3261,7 +3260,7 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_phy_get_info");
+       e_dbg("e1000_phy_get_info");
 
        phy_info->cable_length = e1000_cable_length_undefined;
        phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
@@ -3273,7 +3272,7 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
        phy_info->remote_rx = e1000_1000t_rx_status_undefined;
 
        if (hw->media_type != e1000_media_type_copper) {
-               DEBUGOUT("PHY info is only valid for copper media\n");
+               e_dbg("PHY info is only valid for copper media\n");
                return -E1000_ERR_CONFIG;
        }
 
@@ -3286,7 +3285,7 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
                return ret_val;
 
        if ((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
-               DEBUGOUT("PHY info is only valid if link is up\n");
+               e_dbg("PHY info is only valid if link is up\n");
                return -E1000_ERR_CONFIG;
        }
 
@@ -3298,10 +3297,10 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
 
 s32 e1000_validate_mdi_setting(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_validate_mdi_settings");
+       e_dbg("e1000_validate_mdi_settings");
 
        if (!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
-               DEBUGOUT("Invalid MDI setting detected\n");
+               e_dbg("Invalid MDI setting detected\n");
                hw->mdix = 1;
                return -E1000_ERR_CONFIG;
        }
@@ -3322,7 +3321,7 @@ s32 e1000_init_eeprom_params(struct e1000_hw *hw)
        s32 ret_val = E1000_SUCCESS;
        u16 eeprom_size;
 
-       DEBUGFUNC("e1000_init_eeprom_params");
+       e_dbg("e1000_init_eeprom_params");
 
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
@@ -3539,7 +3538,7 @@ static s32 e1000_acquire_eeprom(struct e1000_hw *hw)
        struct e1000_eeprom_info *eeprom = &hw->eeprom;
        u32 eecd, i = 0;
 
-       DEBUGFUNC("e1000_acquire_eeprom");
+       e_dbg("e1000_acquire_eeprom");
 
        eecd = er32(EECD);
 
@@ -3557,7 +3556,7 @@ static s32 e1000_acquire_eeprom(struct e1000_hw *hw)
                if (!(eecd & E1000_EECD_GNT)) {
                        eecd &= ~E1000_EECD_REQ;
                        ew32(EECD, eecd);
-                       DEBUGOUT("Could not acquire EEPROM grant\n");
+                       e_dbg("Could not acquire EEPROM grant\n");
                        return -E1000_ERR_EEPROM;
                }
        }
@@ -3639,7 +3638,7 @@ static void e1000_release_eeprom(struct e1000_hw *hw)
 {
        u32 eecd;
 
-       DEBUGFUNC("e1000_release_eeprom");
+       e_dbg("e1000_release_eeprom");
 
        eecd = er32(EECD);
 
@@ -3687,7 +3686,7 @@ static s32 e1000_spi_eeprom_ready(struct e1000_hw *hw)
        u16 retry_count = 0;
        u8 spi_stat_reg;
 
-       DEBUGFUNC("e1000_spi_eeprom_ready");
+       e_dbg("e1000_spi_eeprom_ready");
 
        /* Read "Status Register" repeatedly until the LSB is cleared.  The
         * EEPROM will signal that the command has been completed by clearing
@@ -3712,7 +3711,7 @@ static s32 e1000_spi_eeprom_ready(struct e1000_hw *hw)
         * only 0-5mSec on 5V devices)
         */
        if (retry_count >= EEPROM_MAX_RETRY_SPI) {
-               DEBUGOUT("SPI EEPROM Status error\n");
+               e_dbg("SPI EEPROM Status error\n");
                return -E1000_ERR_EEPROM;
        }
 
@@ -3741,7 +3740,7 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
        struct e1000_eeprom_info *eeprom = &hw->eeprom;
        u32 i = 0;
 
-       DEBUGFUNC("e1000_read_eeprom");
+       e_dbg("e1000_read_eeprom");
 
        /* If eeprom is not yet detected, do so now */
        if (eeprom->word_size == 0)
@@ -3752,9 +3751,8 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
         */
        if ((offset >= eeprom->word_size)
            || (words > eeprom->word_size - offset) || (words == 0)) {
-               DEBUGOUT2
-                   ("\"words\" parameter out of bounds. Words = %d, size = %d\n",
-                    offset, eeprom->word_size);
+               e_dbg("\"words\" parameter out of bounds. Words = %d,"
+                     "size = %d\n", offset, eeprom->word_size);
                return -E1000_ERR_EEPROM;
        }
 
@@ -3832,11 +3830,11 @@ s32 e1000_validate_eeprom_checksum(struct e1000_hw *hw)
        u16 checksum = 0;
        u16 i, eeprom_data;
 
-       DEBUGFUNC("e1000_validate_eeprom_checksum");
+       e_dbg("e1000_validate_eeprom_checksum");
 
        for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
                if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
-                       DEBUGOUT("EEPROM Read Error\n");
+                       e_dbg("EEPROM Read Error\n");
                        return -E1000_ERR_EEPROM;
                }
                checksum += eeprom_data;
@@ -3845,7 +3843,7 @@ s32 e1000_validate_eeprom_checksum(struct e1000_hw *hw)
        if (checksum == (u16) EEPROM_SUM)
                return E1000_SUCCESS;
        else {
-               DEBUGOUT("EEPROM Checksum Invalid\n");
+               e_dbg("EEPROM Checksum Invalid\n");
                return -E1000_ERR_EEPROM;
        }
 }
@@ -3862,18 +3860,18 @@ s32 e1000_update_eeprom_checksum(struct e1000_hw *hw)
        u16 checksum = 0;
        u16 i, eeprom_data;
 
-       DEBUGFUNC("e1000_update_eeprom_checksum");
+       e_dbg("e1000_update_eeprom_checksum");
 
        for (i = 0; i < EEPROM_CHECKSUM_REG; i++) {
                if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
-                       DEBUGOUT("EEPROM Read Error\n");
+                       e_dbg("EEPROM Read Error\n");
                        return -E1000_ERR_EEPROM;
                }
                checksum += eeprom_data;
        }
        checksum = (u16) EEPROM_SUM - checksum;
        if (e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
-               DEBUGOUT("EEPROM Write Error\n");
+               e_dbg("EEPROM Write Error\n");
                return -E1000_ERR_EEPROM;
        }
        return E1000_SUCCESS;
@@ -3904,7 +3902,7 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
        struct e1000_eeprom_info *eeprom = &hw->eeprom;
        s32 status = 0;
 
-       DEBUGFUNC("e1000_write_eeprom");
+       e_dbg("e1000_write_eeprom");
 
        /* If eeprom is not yet detected, do so now */
        if (eeprom->word_size == 0)
@@ -3915,7 +3913,7 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
         */
        if ((offset >= eeprom->word_size)
            || (words > eeprom->word_size - offset) || (words == 0)) {
-               DEBUGOUT("\"words\" parameter out of bounds\n");
+               e_dbg("\"words\" parameter out of bounds\n");
                return -E1000_ERR_EEPROM;
        }
 
@@ -3949,7 +3947,7 @@ static s32 e1000_write_eeprom_spi(struct e1000_hw *hw, u16 offset, u16 words,
        struct e1000_eeprom_info *eeprom = &hw->eeprom;
        u16 widx = 0;
 
-       DEBUGFUNC("e1000_write_eeprom_spi");
+       e_dbg("e1000_write_eeprom_spi");
 
        while (widx < words) {
                u8 write_opcode = EEPROM_WRITE_OPCODE_SPI;
@@ -4013,7 +4011,7 @@ static s32 e1000_write_eeprom_microwire(struct e1000_hw *hw, u16 offset,
        u16 words_written = 0;
        u16 i = 0;
 
-       DEBUGFUNC("e1000_write_eeprom_microwire");
+       e_dbg("e1000_write_eeprom_microwire");
 
        /* Send the write enable command to the EEPROM (3-bit opcode plus
         * 6/8-bit dummy address beginning with 11).  It's less work to include
@@ -4056,7 +4054,7 @@ static s32 e1000_write_eeprom_microwire(struct e1000_hw *hw, u16 offset,
                        udelay(50);
                }
                if (i == 200) {
-                       DEBUGOUT("EEPROM Write did not complete\n");
+                       e_dbg("EEPROM Write did not complete\n");
                        return -E1000_ERR_EEPROM;
                }
 
@@ -4092,12 +4090,12 @@ s32 e1000_read_mac_addr(struct e1000_hw *hw)
        u16 offset;
        u16 eeprom_data, i;
 
-       DEBUGFUNC("e1000_read_mac_addr");
+       e_dbg("e1000_read_mac_addr");
 
        for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
                offset = i >> 1;
                if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
-                       DEBUGOUT("EEPROM Read Error\n");
+                       e_dbg("EEPROM Read Error\n");
                        return -E1000_ERR_EEPROM;
                }
                hw->perm_mac_addr[i] = (u8) (eeprom_data & 0x00FF);
@@ -4132,17 +4130,17 @@ static void e1000_init_rx_addrs(struct e1000_hw *hw)
        u32 i;
        u32 rar_num;
 
-       DEBUGFUNC("e1000_init_rx_addrs");
+       e_dbg("e1000_init_rx_addrs");
 
        /* Setup the receive address. */
-       DEBUGOUT("Programming MAC Address into RAR[0]\n");
+       e_dbg("Programming MAC Address into RAR[0]\n");
 
        e1000_rar_set(hw, hw->mac_addr, 0);
 
        rar_num = E1000_RAR_ENTRIES;
 
        /* Zero out the other 15 receive addresses. */
-       DEBUGOUT("Clearing RAR[1-15]\n");
+       e_dbg("Clearing RAR[1-15]\n");
        for (i = 1; i < rar_num; i++) {
                E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
                E1000_WRITE_FLUSH();
@@ -4290,7 +4288,7 @@ static s32 e1000_id_led_init(struct e1000_hw *hw)
        u16 eeprom_data, i, temp;
        const u16 led_mask = 0x0F;
 
-       DEBUGFUNC("e1000_id_led_init");
+       e_dbg("e1000_id_led_init");
 
        if (hw->mac_type < e1000_82540) {
                /* Nothing to do */
@@ -4303,7 +4301,7 @@ static s32 e1000_id_led_init(struct e1000_hw *hw)
        hw->ledctl_mode2 = hw->ledctl_default;
 
        if (e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
-               DEBUGOUT("EEPROM Read Error\n");
+               e_dbg("EEPROM Read Error\n");
                return -E1000_ERR_EEPROM;
        }
 
@@ -4363,7 +4361,7 @@ s32 e1000_setup_led(struct e1000_hw *hw)
        u32 ledctl;
        s32 ret_val = E1000_SUCCESS;
 
-       DEBUGFUNC("e1000_setup_led");
+       e_dbg("e1000_setup_led");
 
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
@@ -4415,7 +4413,7 @@ s32 e1000_cleanup_led(struct e1000_hw *hw)
 {
        s32 ret_val = E1000_SUCCESS;
 
-       DEBUGFUNC("e1000_cleanup_led");
+       e_dbg("e1000_cleanup_led");
 
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
@@ -4451,7 +4449,7 @@ s32 e1000_led_on(struct e1000_hw *hw)
 {
        u32 ctrl = er32(CTRL);
 
-       DEBUGFUNC("e1000_led_on");
+       e_dbg("e1000_led_on");
 
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
@@ -4497,7 +4495,7 @@ s32 e1000_led_off(struct e1000_hw *hw)
 {
        u32 ctrl = er32(CTRL);
 
-       DEBUGFUNC("e1000_led_off");
+       e_dbg("e1000_led_off");
 
        switch (hw->mac_type) {
        case e1000_82542_rev2_0:
@@ -4626,7 +4624,7 @@ static void e1000_clear_hw_cntrs(struct e1000_hw *hw)
  */
 void e1000_reset_adaptive(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_reset_adaptive");
+       e_dbg("e1000_reset_adaptive");
 
        if (hw->adaptive_ifs) {
                if (!hw->ifs_params_forced) {
@@ -4639,7 +4637,7 @@ void e1000_reset_adaptive(struct e1000_hw *hw)
                hw->in_ifs_mode = false;
                ew32(AIT, 0);
        } else {
-               DEBUGOUT("Not in Adaptive IFS mode!\n");
+               e_dbg("Not in Adaptive IFS mode!\n");
        }
 }
 
@@ -4654,7 +4652,7 @@ void e1000_reset_adaptive(struct e1000_hw *hw)
  */
 void e1000_update_adaptive(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_update_adaptive");
+       e_dbg("e1000_update_adaptive");
 
        if (hw->adaptive_ifs) {
                if ((hw->collision_delta *hw->ifs_ratio) > hw->tx_packet_delta) {
@@ -4679,7 +4677,7 @@ void e1000_update_adaptive(struct e1000_hw *hw)
                        }
                }
        } else {
-               DEBUGOUT("Not in Adaptive IFS mode!\n");
+               e_dbg("Not in Adaptive IFS mode!\n");
        }
 }
 
@@ -4851,7 +4849,7 @@ static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length,
        u16 i, phy_data;
        u16 cable_length;
 
-       DEBUGFUNC("e1000_get_cable_length");
+       e_dbg("e1000_get_cable_length");
 
        *min_length = *max_length = 0;
 
@@ -4968,7 +4966,7 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_check_polarity");
+       e_dbg("e1000_check_polarity");
 
        if (hw->phy_type == e1000_phy_m88) {
                /* return the Polarity bit in the Status register. */
@@ -5034,7 +5032,7 @@ static s32 e1000_check_downshift(struct e1000_hw *hw)
        s32 ret_val;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_check_downshift");
+       e_dbg("e1000_check_downshift");
 
        if (hw->phy_type == e1000_phy_igp) {
                ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
@@ -5081,7 +5079,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
        };
        u16 min_length, max_length;
 
-       DEBUGFUNC("e1000_config_dsp_after_link_change");
+       e_dbg("e1000_config_dsp_after_link_change");
 
        if (hw->phy_type != e1000_phy_igp)
                return E1000_SUCCESS;
@@ -5089,7 +5087,7 @@ static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
        if (link_up) {
                ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
                if (ret_val) {
-                       DEBUGOUT("Error getting link speed and duplex\n");
+                       e_dbg("Error getting link speed and duplex\n");
                        return ret_val;
                }
 
@@ -5289,7 +5287,7 @@ static s32 e1000_set_phy_mode(struct e1000_hw *hw)
        s32 ret_val;
        u16 eeprom_data;
 
-       DEBUGFUNC("e1000_set_phy_mode");
+       e_dbg("e1000_set_phy_mode");
 
        if ((hw->mac_type == e1000_82545_rev_3) &&
            (hw->media_type == e1000_media_type_copper)) {
@@ -5337,7 +5335,7 @@ static s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
 {
        s32 ret_val;
        u16 phy_data;
-       DEBUGFUNC("e1000_set_d3_lplu_state");
+       e_dbg("e1000_set_d3_lplu_state");
 
        if (hw->phy_type != e1000_phy_igp)
                return E1000_SUCCESS;
@@ -5440,7 +5438,7 @@ static s32 e1000_set_vco_speed(struct e1000_hw *hw)
        u16 default_page = 0;
        u16 phy_data;
 
-       DEBUGFUNC("e1000_set_vco_speed");
+       e_dbg("e1000_set_vco_speed");
 
        switch (hw->mac_type) {
        case e1000_82545_rev_3:
@@ -5613,7 +5611,7 @@ static s32 e1000_polarity_reversal_workaround(struct e1000_hw *hw)
  */
 static s32 e1000_get_auto_rd_done(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_get_auto_rd_done");
+       e_dbg("e1000_get_auto_rd_done");
        msleep(5);
        return E1000_SUCCESS;
 }
@@ -5628,7 +5626,7 @@ static s32 e1000_get_auto_rd_done(struct e1000_hw *hw)
  */
 static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
 {
-       DEBUGFUNC("e1000_get_phy_cfg_done");
+       e_dbg("e1000_get_phy_cfg_done");
        mdelay(10);
        return E1000_SUCCESS;
 }
index 9acfddb0dafb2638983e782722bf0bf0ecb40577..ecd9f6c6bcd534d96dbf17f9d8bd34edc68d6cfa 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "e1000_osdep.h"
 
+
 /* Forward declarations of structures used by the shared code */
 struct e1000_hw;
 struct e1000_hw_stats;
index b15ece26ed8469136df4d40eced1b98839e4acce..ebdea0891665dbb81fbd6e7894abc4e97b6fd2c4 100644 (file)
@@ -31,7 +31,7 @@
 
 char e1000_driver_name[] = "e1000";
 static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-#define DRV_VERSION "7.3.21-k5-NAPI"
+#define DRV_VERSION "7.3.21-k6-NAPI"
 const char e1000_driver_version[] = DRV_VERSION;
 static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 
@@ -213,6 +213,17 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
+/**
+ * e1000_get_hw_dev - return device
+ * used by hardware layer to print debugging information
+ *
+ **/
+struct net_device *e1000_get_hw_dev(struct e1000_hw *hw)
+{
+       struct e1000_adapter *adapter = hw->back;
+       return adapter->netdev;
+}
+
 /**
  * e1000_init_module - Driver Registration Routine
  *
@@ -223,18 +234,17 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 static int __init e1000_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "%s - version %s\n",
-              e1000_driver_string, e1000_driver_version);
+       pr_info("%s - version %s\n", e1000_driver_string, e1000_driver_version);
 
-       printk(KERN_INFO "%s\n", e1000_copyright);
+       pr_info("%s\n", e1000_copyright);
 
        ret = pci_register_driver(&e1000_driver);
        if (copybreak != COPYBREAK_DEFAULT) {
                if (copybreak == 0)
-                       printk(KERN_INFO "e1000: copybreak disabled\n");
+                       pr_info("copybreak disabled\n");
                else
-                       printk(KERN_INFO "e1000: copybreak enabled for "
-                              "packets <= %u bytes\n", copybreak);
+                       pr_info("copybreak enabled for "
+                                  "packets <= %u bytes\n", copybreak);
        }
        return ret;
 }
@@ -265,8 +275,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter)
        err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
                          netdev);
        if (err) {
-               DPRINTK(PROBE, ERR,
-                       "Unable to allocate interrupt Error: %d\n", err);
+               e_err("Unable to allocate interrupt Error: %d\n", err);
        }
 
        return err;
@@ -648,7 +657,7 @@ void e1000_reset(struct e1000_adapter *adapter)
                ew32(WUC, 0);
 
        if (e1000_init_hw(hw))
-               DPRINTK(PROBE, ERR, "Hardware Error\n");
+               e_err("Hardware Error\n");
        e1000_update_mng_vlan(adapter);
 
        /* if (adapter->hwflags & HWFLAGS_PHY_PWR_BIT) { */
@@ -689,8 +698,7 @@ static void e1000_dump_eeprom(struct e1000_adapter *adapter)
 
        data = kmalloc(eeprom.len, GFP_KERNEL);
        if (!data) {
-               printk(KERN_ERR "Unable to allocate memory to dump EEPROM"
-                      " data\n");
+               pr_err("Unable to allocate memory to dump EEPROM data\n");
                return;
        }
 
@@ -702,30 +710,25 @@ static void e1000_dump_eeprom(struct e1000_adapter *adapter)
                csum_new += data[i] + (data[i + 1] << 8);
        csum_new = EEPROM_SUM - csum_new;
 
-       printk(KERN_ERR "/*********************/\n");
-       printk(KERN_ERR "Current EEPROM Checksum : 0x%04x\n", csum_old);
-       printk(KERN_ERR "Calculated              : 0x%04x\n", csum_new);
+       pr_err("/*********************/\n");
+       pr_err("Current EEPROM Checksum : 0x%04x\n", csum_old);
+       pr_err("Calculated              : 0x%04x\n", csum_new);
 
-       printk(KERN_ERR "Offset    Values\n");
-       printk(KERN_ERR "========  ======\n");
+       pr_err("Offset    Values\n");
+       pr_err("========  ======\n");
        print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, data, 128, 0);
 
-       printk(KERN_ERR "Include this output when contacting your support "
-              "provider.\n");
-       printk(KERN_ERR "This is not a software error! Something bad "
-              "happened to your hardware or\n");
-       printk(KERN_ERR "EEPROM image. Ignoring this "
-              "problem could result in further problems,\n");
-       printk(KERN_ERR "possibly loss of data, corruption or system hangs!\n");
-       printk(KERN_ERR "The MAC Address will be reset to 00:00:00:00:00:00, "
-              "which is invalid\n");
-       printk(KERN_ERR "and requires you to set the proper MAC "
-              "address manually before continuing\n");
-       printk(KERN_ERR "to enable this network device.\n");
-       printk(KERN_ERR "Please inspect the EEPROM dump and report the issue "
-              "to your hardware vendor\n");
-       printk(KERN_ERR "or Intel Customer Support.\n");
-       printk(KERN_ERR "/*********************/\n");
+       pr_err("Include this output when contacting your support provider.\n");
+       pr_err("This is not a software error! Something bad happened to\n");
+       pr_err("your hardware or EEPROM image. Ignoring this problem could\n");
+       pr_err("result in further problems, possibly loss of data,\n");
+       pr_err("corruption or system hangs!\n");
+       pr_err("The MAC Address will be reset to 00:00:00:00:00:00,\n");
+       pr_err("which is invalid and requires you to set the proper MAC\n");
+       pr_err("address manually before continuing to enable this network\n");
+       pr_err("device. Please inspect the EEPROM dump and report the\n");
+       pr_err("issue to your hardware vendor or Intel Customer Support.\n");
+       pr_err("/*********************/\n");
 
        kfree(data);
 }
@@ -823,16 +826,16 @@ static int __devinit e1000_probe(struct pci_dev *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))) {
+       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
+           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
                pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
                        if (err) {
-                               E1000_ERR("No usable DMA configuration, "
-                                         "aborting\n");
+                               pr_err("No usable DMA config, aborting\n");
                                goto err_dma;
                        }
                }
@@ -922,7 +925,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        /* initialize eeprom parameters */
        if (e1000_init_eeprom_params(hw)) {
-               E1000_ERR("EEPROM initialization failed\n");
+               e_err("EEPROM initialization failed\n");
                goto err_eeprom;
        }
 
@@ -933,7 +936,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        /* make sure the EEPROM is good */
        if (e1000_validate_eeprom_checksum(hw) < 0) {
-               DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
+               e_err("The EEPROM Checksum Is Not Valid\n");
                e1000_dump_eeprom(adapter);
                /*
                 * set MAC address to all zeroes to invalidate and temporary
@@ -947,14 +950,14 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        } else {
                /* copy the MAC address out of the EEPROM */
                if (e1000_read_mac_addr(hw))
-                       DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
+                       e_err("EEPROM Read Error\n");
        }
        /* don't block initalization here due to bad MAC address */
        memcpy(netdev->dev_addr, hw->mac_addr, netdev->addr_len);
        memcpy(netdev->perm_addr, hw->mac_addr, netdev->addr_len);
 
        if (!is_valid_ether_addr(netdev->perm_addr))
-               DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
+               e_err("Invalid MAC Address\n");
 
        e1000_get_bus_info(hw);
 
@@ -1035,8 +1038,16 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
        adapter->wol = adapter->eeprom_wol;
        device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
+       /* reset the hardware with the new settings */
+       e1000_reset(adapter);
+
+       strcpy(netdev->name, "eth%d");
+       err = register_netdev(netdev);
+       if (err)
+               goto err_register;
+
        /* print bus type/speed/width info */
-       DPRINTK(PROBE, INFO, "(PCI%s:%s:%s) ",
+       e_info("(PCI%s:%s:%s) ",
                ((hw->bus_type == e1000_bus_type_pcix) ? "-X" : ""),
                ((hw->bus_speed == e1000_bus_speed_133) ? "133MHz" :
                 (hw->bus_speed == e1000_bus_speed_120) ? "120MHz" :
@@ -1044,20 +1055,12 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                 (hw->bus_speed == e1000_bus_speed_66) ? "66MHz" : "33MHz"),
                ((hw->bus_width == e1000_bus_width_64) ? "64-bit" : "32-bit"));
 
-       printk("%pM\n", netdev->dev_addr);
-
-       /* reset the hardware with the new settings */
-       e1000_reset(adapter);
-
-       strcpy(netdev->name, "eth%d");
-       err = register_netdev(netdev);
-       if (err)
-               goto err_register;
+       e_info("%pM\n", netdev->dev_addr);
 
        /* carrier off reporting is important to ethtool even BEFORE open */
        netif_carrier_off(netdev);
 
-       DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n");
+       e_info("Intel(R) PRO/1000 Network Connection\n");
 
        cards_found++;
        return 0;
@@ -1157,7 +1160,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
        /* identify the MAC */
 
        if (e1000_set_mac_type(hw)) {
-               DPRINTK(PROBE, ERR, "Unknown MAC Type\n");
+               e_err("Unknown MAC Type\n");
                return -EIO;
        }
 
@@ -1190,7 +1193,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
        adapter->num_rx_queues = 1;
 
        if (e1000_alloc_queues(adapter)) {
-               DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n");
+               e_err("Unable to allocate memory for queues\n");
                return -ENOMEM;
        }
 
@@ -1384,8 +1387,7 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
        size = sizeof(struct e1000_buffer) * txdr->count;
        txdr->buffer_info = vmalloc(size);
        if (!txdr->buffer_info) {
-               DPRINTK(PROBE, ERR,
-               "Unable to allocate memory for the transmit descriptor ring\n");
+               e_err("Unable to allocate memory for the Tx descriptor ring\n");
                return -ENOMEM;
        }
        memset(txdr->buffer_info, 0, size);
@@ -1395,12 +1397,12 @@ static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
        txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
        txdr->size = ALIGN(txdr->size, 4096);
 
-       txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+       txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma,
+                                       GFP_KERNEL);
        if (!txdr->desc) {
 setup_tx_desc_die:
                vfree(txdr->buffer_info);
-               DPRINTK(PROBE, ERR,
-               "Unable to allocate memory for the transmit descriptor ring\n");
+               e_err("Unable to allocate memory for the Tx descriptor ring\n");
                return -ENOMEM;
        }
 
@@ -1408,29 +1410,32 @@ setup_tx_desc_die:
        if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
                void *olddesc = txdr->desc;
                dma_addr_t olddma = txdr->dma;
-               DPRINTK(TX_ERR, ERR, "txdr align check failed: %u bytes "
-                                    "at %p\n", txdr->size, txdr->desc);
+               e_err("txdr align check failed: %u bytes at %p\n",
+                     txdr->size, txdr->desc);
                /* Try again, without freeing the previous */
-               txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+               txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size,
+                                               &txdr->dma, GFP_KERNEL);
                /* Failed allocation, critical failure */
                if (!txdr->desc) {
-                       pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+                       dma_free_coherent(&pdev->dev, txdr->size, olddesc,
+                                         olddma);
                        goto setup_tx_desc_die;
                }
 
                if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
                        /* give up */
-                       pci_free_consistent(pdev, txdr->size, txdr->desc,
-                                           txdr->dma);
-                       pci_free_consistent(pdev, txdr->size, olddesc, olddma);
-                       DPRINTK(PROBE, ERR,
-                               "Unable to allocate aligned memory "
-                               "for the transmit descriptor ring\n");
+                       dma_free_coherent(&pdev->dev, txdr->size, txdr->desc,
+                                         txdr->dma);
+                       dma_free_coherent(&pdev->dev, txdr->size, olddesc,
+                                         olddma);
+                       e_err("Unable to allocate aligned memory "
+                             "for the transmit descriptor ring\n");
                        vfree(txdr->buffer_info);
                        return -ENOMEM;
                } else {
                        /* Free old allocation, new allocation was successful */
-                       pci_free_consistent(pdev, txdr->size, olddesc, olddma);
+                       dma_free_coherent(&pdev->dev, txdr->size, olddesc,
+                                         olddma);
                }
        }
        memset(txdr->desc, 0, txdr->size);
@@ -1456,8 +1461,7 @@ int e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
        for (i = 0; i < adapter->num_tx_queues; i++) {
                err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]);
                if (err) {
-                       DPRINTK(PROBE, ERR,
-                               "Allocation for Tx Queue %u failed\n", i);
+                       e_err("Allocation for Tx Queue %u failed\n", i);
                        for (i-- ; i >= 0; i--)
                                e1000_free_tx_resources(adapter,
                                                        &adapter->tx_ring[i]);
@@ -1577,8 +1581,7 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
        size = sizeof(struct e1000_buffer) * rxdr->count;
        rxdr->buffer_info = vmalloc(size);
        if (!rxdr->buffer_info) {
-               DPRINTK(PROBE, ERR,
-               "Unable to allocate memory for the receive descriptor ring\n");
+               e_err("Unable to allocate memory for the Rx descriptor ring\n");
                return -ENOMEM;
        }
        memset(rxdr->buffer_info, 0, size);
@@ -1590,11 +1593,11 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
        rxdr->size = rxdr->count * desc_len;
        rxdr->size = ALIGN(rxdr->size, 4096);
 
-       rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+       rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,
+                                       GFP_KERNEL);
 
        if (!rxdr->desc) {
-               DPRINTK(PROBE, ERR,
-               "Unable to allocate memory for the receive descriptor ring\n");
+               e_err("Unable to allocate memory for the Rx descriptor ring\n");
 setup_rx_desc_die:
                vfree(rxdr->buffer_info);
                return -ENOMEM;
@@ -1604,31 +1607,33 @@ setup_rx_desc_die:
        if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
                void *olddesc = rxdr->desc;
                dma_addr_t olddma = rxdr->dma;
-               DPRINTK(RX_ERR, ERR, "rxdr align check failed: %u bytes "
-                                    "at %p\n", rxdr->size, rxdr->desc);
+               e_err("rxdr align check failed: %u bytes at %p\n",
+                     rxdr->size, rxdr->desc);
                /* Try again, without freeing the previous */
-               rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+               rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size,
+                                               &rxdr->dma, GFP_KERNEL);
                /* Failed allocation, critical failure */
                if (!rxdr->desc) {
-                       pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
-                       DPRINTK(PROBE, ERR,
-                               "Unable to allocate memory "
-                               "for the receive descriptor ring\n");
+                       dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
+                                         olddma);
+                       e_err("Unable to allocate memory for the Rx descriptor "
+                             "ring\n");
                        goto setup_rx_desc_die;
                }
 
                if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
                        /* give up */
-                       pci_free_consistent(pdev, rxdr->size, rxdr->desc,
-                                           rxdr->dma);
-                       pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
-                       DPRINTK(PROBE, ERR,
-                               "Unable to allocate aligned memory "
-                               "for the receive descriptor ring\n");
+                       dma_free_coherent(&pdev->dev, rxdr->size, rxdr->desc,
+                                         rxdr->dma);
+                       dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
+                                         olddma);
+                       e_err("Unable to allocate aligned memory for the Rx "
+                             "descriptor ring\n");
                        goto setup_rx_desc_die;
                } else {
                        /* Free old allocation, new allocation was successful */
-                       pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+                       dma_free_coherent(&pdev->dev, rxdr->size, olddesc,
+                                         olddma);
                }
        }
        memset(rxdr->desc, 0, rxdr->size);
@@ -1655,8 +1660,7 @@ int e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
        for (i = 0; i < adapter->num_rx_queues; i++) {
                err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]);
                if (err) {
-                       DPRINTK(PROBE, ERR,
-                               "Allocation for Rx Queue %u failed\n", i);
+                       e_err("Allocation for Rx Queue %u failed\n", i);
                        for (i-- ; i >= 0; i--)
                                e1000_free_rx_resources(adapter,
                                                        &adapter->rx_ring[i]);
@@ -1804,7 +1808,8 @@ static void e1000_free_tx_resources(struct e1000_adapter *adapter,
        vfree(tx_ring->buffer_info);
        tx_ring->buffer_info = NULL;
 
-       pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+       dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+                         tx_ring->dma);
 
        tx_ring->desc = NULL;
 }
@@ -1829,12 +1834,12 @@ static void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
 {
        if (buffer_info->dma) {
                if (buffer_info->mapped_as_page)
-                       pci_unmap_page(adapter->pdev, buffer_info->dma,
-                                      buffer_info->length, PCI_DMA_TODEVICE);
+                       dma_unmap_page(&adapter->pdev->dev, buffer_info->dma,
+                                      buffer_info->length, DMA_TO_DEVICE);
                else
-                       pci_unmap_single(adapter->pdev, buffer_info->dma,
+                       dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
                                         buffer_info->length,
-                                        PCI_DMA_TODEVICE);
+                                        DMA_TO_DEVICE);
                buffer_info->dma = 0;
        }
        if (buffer_info->skb) {
@@ -1912,7 +1917,8 @@ static void e1000_free_rx_resources(struct e1000_adapter *adapter,
        vfree(rx_ring->buffer_info);
        rx_ring->buffer_info = NULL;
 
-       pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+       dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+                         rx_ring->dma);
 
        rx_ring->desc = NULL;
 }
@@ -1952,14 +1958,14 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
                buffer_info = &rx_ring->buffer_info[i];
                if (buffer_info->dma &&
                    adapter->clean_rx == e1000_clean_rx_irq) {
-                       pci_unmap_single(pdev, buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, buffer_info->dma,
                                         buffer_info->length,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                } else if (buffer_info->dma &&
                           adapter->clean_rx == e1000_clean_jumbo_rx_irq) {
-                       pci_unmap_page(pdev, buffer_info->dma,
-                                      buffer_info->length,
-                                      PCI_DMA_FROMDEVICE);
+                       dma_unmap_page(&pdev->dev, buffer_info->dma,
+                                      buffer_info->length,
+                                      DMA_FROM_DEVICE);
                }
 
                buffer_info->dma = 0;
@@ -2098,7 +2104,6 @@ static void e1000_set_rx_mode(struct net_device *netdev)
        struct e1000_hw *hw = &adapter->hw;
        struct netdev_hw_addr *ha;
        bool use_uc = false;
-       struct dev_addr_list *mc_ptr;
        u32 rctl;
        u32 hash_value;
        int i, rar_entries = E1000_RAR_ENTRIES;
@@ -2106,7 +2111,7 @@ static void e1000_set_rx_mode(struct net_device *netdev)
        u32 *mcarray = kcalloc(mta_reg_count, sizeof(u32), GFP_ATOMIC);
 
        if (!mcarray) {
-               DPRINTK(PROBE, ERR, "memory allocation failed\n");
+               e_err("memory allocation failed\n");
                return;
        }
 
@@ -2156,19 +2161,17 @@ static void e1000_set_rx_mode(struct net_device *netdev)
                        e1000_rar_set(hw, ha->addr, i++);
                }
 
-       WARN_ON(i == rar_entries);
-
-       netdev_for_each_mc_addr(mc_ptr, netdev) {
+       netdev_for_each_mc_addr(ha, netdev) {
                if (i == rar_entries) {
                        /* load any remaining addresses into the hash table */
                        u32 hash_reg, hash_bit, mta;
-                       hash_value = e1000_hash_mc_addr(hw, mc_ptr->da_addr);
+                       hash_value = e1000_hash_mc_addr(hw, ha->addr);
                        hash_reg = (hash_value >> 5) & 0x7F;
                        hash_bit = hash_value & 0x1F;
                        mta = (1 << hash_bit);
                        mcarray[hash_reg] |= mta;
                } else {
-                       e1000_rar_set(hw, mc_ptr->da_addr, i++);
+                       e1000_rar_set(hw, ha->addr, i++);
                }
        }
 
@@ -2302,16 +2305,16 @@ static void e1000_watchdog(unsigned long data)
                                                   &adapter->link_duplex);
 
                        ctrl = er32(CTRL);
-                       printk(KERN_INFO "e1000: %s NIC Link is Up %d Mbps %s, "
-                              "Flow Control: %s\n",
-                              netdev->name,
-                              adapter->link_speed,
-                              adapter->link_duplex == FULL_DUPLEX ?
-                               "Full Duplex" : "Half Duplex",
-                               ((ctrl & E1000_CTRL_TFCE) && (ctrl &
-                               E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
-                               E1000_CTRL_RFCE) ? "RX" : ((ctrl &
-                               E1000_CTRL_TFCE) ? "TX" : "None" )));
+                       pr_info("%s NIC Link is Up %d Mbps %s, "
+                               "Flow Control: %s\n",
+                               netdev->name,
+                               adapter->link_speed,
+                               adapter->link_duplex == FULL_DUPLEX ?
+                               "Full Duplex" : "Half Duplex",
+                               ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+                               E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+                               E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+                               E1000_CTRL_TFCE) ? "TX" : "None")));
 
                        /* adjust timeout factor according to speed/duplex */
                        adapter->tx_timeout_factor = 1;
@@ -2341,8 +2344,8 @@ static void e1000_watchdog(unsigned long data)
                if (netif_carrier_ok(netdev)) {
                        adapter->link_speed = 0;
                        adapter->link_duplex = 0;
-                       printk(KERN_INFO "e1000: %s NIC Link is Down\n",
-                              netdev->name);
+                       pr_info("%s NIC Link is Down\n",
+                               netdev->name);
                        netif_carrier_off(netdev);
 
                        if (!test_bit(__E1000_DOWN, &adapter->flags))
@@ -2381,6 +2384,22 @@ link_up:
                }
        }
 
+       /* Simple mode for Interrupt Throttle Rate (ITR) */
+       if (hw->mac_type >= e1000_82540 && adapter->itr_setting == 4) {
+               /*
+                * Symmetric Tx/Rx gets a reduced ITR=2000;
+                * Total asymmetrical Tx or Rx gets ITR=8000;
+                * everyone else is between 2000-8000.
+                */
+               u32 goc = (adapter->gotcl + adapter->gorcl) / 10000;
+               u32 dif = (adapter->gotcl > adapter->gorcl ?
+                           adapter->gotcl - adapter->gorcl :
+                           adapter->gorcl - adapter->gotcl) / 10000;
+               u32 itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000;
+
+               ew32(ITR, 1000000000 / (itr * 256));
+       }
+
        /* Cause software interrupt to ensure rx ring is cleaned */
        ew32(ICS, E1000_ICS_RXDMT0);
 
@@ -2525,8 +2544,6 @@ set_itr_now:
                adapter->itr = new_itr;
                ew32(ITR, 1000000000 / (new_itr * 256));
        }
-
-       return;
 }
 
 #define E1000_TX_FLAGS_CSUM            0x00000001
@@ -2632,8 +2649,7 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter,
                break;
        default:
                if (unlikely(net_ratelimit()))
-                       DPRINTK(DRV, WARNING,
-                               "checksum_partial proto=%x!\n", skb->protocol);
+                       e_warn("checksum_partial proto=%x!\n", skb->protocol);
                break;
        }
 
@@ -2715,9 +2731,10 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                /* set time_stamp *before* dma to help avoid a possible race */
                buffer_info->time_stamp = jiffies;
                buffer_info->mapped_as_page = false;
-               buffer_info->dma = pci_map_single(pdev, skb->data + offset,
-                                                 size, PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma))
+               buffer_info->dma = dma_map_single(&pdev->dev,
+                                                 skb->data + offset,
+                                                 size, DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                        goto dma_error;
                buffer_info->next_to_watch = i;
 
@@ -2761,10 +2778,10 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                        buffer_info->length = size;
                        buffer_info->time_stamp = jiffies;
                        buffer_info->mapped_as_page = true;
-                       buffer_info->dma = pci_map_page(pdev, frag->page,
+                       buffer_info->dma = dma_map_page(&pdev->dev, frag->page,
                                                        offset, size,
-                                                       PCI_DMA_TODEVICE);
-                       if (pci_dma_mapping_error(pdev, buffer_info->dma))
+                                                       DMA_TO_DEVICE);
+                       if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                                goto dma_error;
                        buffer_info->next_to_watch = i;
 
@@ -2930,7 +2947,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
        unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
        unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
        unsigned int tx_flags = 0;
-       unsigned int len = skb->len - skb->data_len;
+       unsigned int len = skb_headlen(skb);
        unsigned int nr_frags;
        unsigned int mss;
        int count = 0;
@@ -2976,12 +2993,11 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
                                /* fall through */
                                pull_size = min((unsigned int)4, skb->data_len);
                                if (!__pskb_pull_tail(skb, pull_size)) {
-                                       DPRINTK(DRV, ERR,
-                                               "__pskb_pull_tail failed.\n");
+                                       e_err("__pskb_pull_tail failed.\n");
                                        dev_kfree_skb_any(skb);
                                        return NETDEV_TX_OK;
                                }
-                               len = skb->len - skb->data_len;
+                               len = skb_headlen(skb);
                                break;
                        default:
                                /* do nothing */
@@ -3125,7 +3141,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
 
        if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
            (max_frame > MAX_JUMBO_FRAME_SIZE)) {
-               DPRINTK(PROBE, ERR, "Invalid MTU setting\n");
+               e_err("Invalid MTU setting\n");
                return -EINVAL;
        }
 
@@ -3133,7 +3149,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        switch (hw->mac_type) {
        case e1000_undefined ... e1000_82542_rev2_1:
                if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
-                       DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
+                       e_err("Jumbo Frames not supported.\n");
                        return -EINVAL;
                }
                break;
@@ -3171,8 +3187,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
             (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
                adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
 
-       printk(KERN_INFO "e1000: %s changing MTU from %d to %d\n",
-              netdev->name, netdev->mtu, new_mtu);
+       pr_info("%s changing MTU from %d to %d\n",
+               netdev->name, netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
 
        if (netif_running(netdev))
@@ -3485,17 +3501,17 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
                    !(er32(STATUS) & E1000_STATUS_TXOFF)) {
 
                        /* detected Tx unit hang */
-                       DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
-                                       "  Tx Queue             <%lu>\n"
-                                       "  TDH                  <%x>\n"
-                                       "  TDT                  <%x>\n"
-                                       "  next_to_use          <%x>\n"
-                                       "  next_to_clean        <%x>\n"
-                                       "buffer_info[next_to_clean]\n"
-                                       "  time_stamp           <%lx>\n"
-                                       "  next_to_watch        <%x>\n"
-                                       "  jiffies              <%lx>\n"
-                                       "  next_to_watch.status <%x>\n",
+                       e_err("Detected Tx Unit Hang\n"
+                             "  Tx Queue             <%lu>\n"
+                             "  TDH                  <%x>\n"
+                             "  TDT                  <%x>\n"
+                             "  next_to_use          <%x>\n"
+                             "  next_to_clean        <%x>\n"
+                             "buffer_info[next_to_clean]\n"
+                             "  time_stamp           <%lx>\n"
+                             "  next_to_watch        <%x>\n"
+                             "  jiffies              <%lx>\n"
+                             "  next_to_watch.status <%x>\n",
                                (unsigned long)((tx_ring - adapter->tx_ring) /
                                        sizeof(struct e1000_tx_ring)),
                                readl(hw->hw_addr + tx_ring->tdh),
@@ -3635,8 +3651,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
 
                cleaned = true;
                cleaned_count++;
-               pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
-                              PCI_DMA_FROMDEVICE);
+               dma_unmap_page(&pdev->dev, buffer_info->dma,
+                              buffer_info->length, DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                length = le16_to_cpu(rx_desc->length);
@@ -3734,7 +3750,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
 
                /* eth type trans needs skb->data to point to something */
                if (!pskb_may_pull(skb, ETH_HLEN)) {
-                       DPRINTK(DRV, ERR, "pskb_may_pull failed.\n");
+                       e_err("pskb_may_pull failed.\n");
                        dev_kfree_skb(skb);
                        goto next_desc;
                }
@@ -3769,6 +3785,31 @@ next_desc:
        return cleaned;
 }
 
+/*
+ * this should improve performance for small packets with large amounts
+ * of reassembly being done in the stack
+ */
+static void e1000_check_copybreak(struct net_device *netdev,
+                                struct e1000_buffer *buffer_info,
+                                u32 length, struct sk_buff **skb)
+{
+       struct sk_buff *new_skb;
+
+       if (length > copybreak)
+               return;
+
+       new_skb = netdev_alloc_skb_ip_align(netdev, length);
+       if (!new_skb)
+               return;
+
+       skb_copy_to_linear_data_offset(new_skb, -NET_IP_ALIGN,
+                                      (*skb)->data - NET_IP_ALIGN,
+                                      length + NET_IP_ALIGN);
+       /* save the skb in buffer_info as good */
+       buffer_info->skb = *skb;
+       *skb = new_skb;
+}
+
 /**
  * e1000_clean_rx_irq - Send received data up the network stack; legacy
  * @adapter: board private structure
@@ -3818,8 +3859,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 
                cleaned = true;
                cleaned_count++;
-               pci_unmap_single(pdev, buffer_info->dma, buffer_info->length,
-                                PCI_DMA_FROMDEVICE);
+               dma_unmap_single(&pdev->dev, buffer_info->dma,
+                                buffer_info->length, DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                length = le16_to_cpu(rx_desc->length);
@@ -3834,8 +3875,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 
                if (adapter->discarding) {
                        /* All receives must fit into a single buffer */
-                       E1000_DBG("%s: Receive packet consumed multiple"
-                                 " buffers\n", netdev->name);
+                       e_info("Receive packet consumed multiple buffers\n");
                        /* recycle */
                        buffer_info->skb = skb;
                        if (status & E1000_RXD_STAT_EOP)
@@ -3868,26 +3908,8 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
                total_rx_bytes += length;
                total_rx_packets++;
 
-               /* code added for copybreak, this should improve
-                * performance for small packets with large amounts
-                * of reassembly being done in the stack */
-               if (length < copybreak) {
-                       struct sk_buff *new_skb =
-                           netdev_alloc_skb_ip_align(netdev, length);
-                       if (new_skb) {
-                               skb_copy_to_linear_data_offset(new_skb,
-                                                              -NET_IP_ALIGN,
-                                                              (skb->data -
-                                                               NET_IP_ALIGN),
-                                                              (length +
-                                                               NET_IP_ALIGN));
-                               /* save the skb in buffer_info as good */
-                               buffer_info->skb = skb;
-                               skb = new_skb;
-                       }
-                       /* else just continue with the old one */
-               }
-               /* end copybreak code */
+               e1000_check_copybreak(netdev, buffer_info, length, &skb);
+
                skb_put(skb, length);
 
                /* Receive Checksum Offload */
@@ -3965,8 +3987,8 @@ e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
                /* Fix for errata 23, can't cross 64kB boundary */
                if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
                        struct sk_buff *oldskb = skb;
-                       DPRINTK(PROBE, ERR, "skb align check failed: %u bytes "
-                                            "at %p\n", bufsz, skb->data);
+                       e_err("skb align check failed: %u bytes at %p\n",
+                             bufsz, skb->data);
                        /* Try again, without freeing the previous */
                        skb = netdev_alloc_skb_ip_align(netdev, bufsz);
                        /* Failed allocation, critical failure */
@@ -3999,11 +4021,11 @@ check_page:
                }
 
                if (!buffer_info->dma) {
-                       buffer_info->dma = pci_map_page(pdev,
+                       buffer_info->dma = dma_map_page(&pdev->dev,
                                                        buffer_info->page, 0,
-                                                       buffer_info->length,
-                                                       PCI_DMA_FROMDEVICE);
-                       if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+                                                       buffer_info->length,
+                                                       DMA_FROM_DEVICE);
+                       if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
                                put_page(buffer_info->page);
                                dev_kfree_skb(skb);
                                buffer_info->page = NULL;
@@ -4074,8 +4096,8 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
                /* Fix for errata 23, can't cross 64kB boundary */
                if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
                        struct sk_buff *oldskb = skb;
-                       DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes "
-                                            "at %p\n", bufsz, skb->data);
+                       e_err("skb align check failed: %u bytes at %p\n",
+                             bufsz, skb->data);
                        /* Try again, without freeing the previous */
                        skb = netdev_alloc_skb_ip_align(netdev, bufsz);
                        /* Failed allocation, critical failure */
@@ -4099,11 +4121,11 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
                buffer_info->skb = skb;
                buffer_info->length = adapter->rx_buffer_len;
 map_skb:
-               buffer_info->dma = pci_map_single(pdev,
+               buffer_info->dma = dma_map_single(&pdev->dev,
                                                  skb->data,
                                                  buffer_info->length,
-                                                 PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+                                                 DMA_FROM_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
                        dev_kfree_skb(skb);
                        buffer_info->skb = NULL;
                        buffer_info->dma = 0;
@@ -4120,16 +4142,15 @@ map_skb:
                if (!e1000_check_64k_bound(adapter,
                                        (void *)(unsigned long)buffer_info->dma,
                                        adapter->rx_buffer_len)) {
-                       DPRINTK(RX_ERR, ERR,
-                               "dma align check failed: %u bytes at %p\n",
-                               adapter->rx_buffer_len,
-                               (void *)(unsigned long)buffer_info->dma);
+                       e_err("dma align check failed: %u bytes at %p\n",
+                             adapter->rx_buffer_len,
+                             (void *)(unsigned long)buffer_info->dma);
                        dev_kfree_skb(skb);
                        buffer_info->skb = NULL;
 
-                       pci_unmap_single(pdev, buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, buffer_info->dma,
                                         adapter->rx_buffer_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        buffer_info->dma = 0;
 
                        adapter->alloc_rx_buff_failed++;
@@ -4335,7 +4356,7 @@ void e1000_pci_set_mwi(struct e1000_hw *hw)
        int ret_val = pci_set_mwi(adapter->pdev);
 
        if (ret_val)
-               DPRINTK(PROBE, ERR, "Error in setting MWI\n");
+               e_err("Error in setting MWI\n");
 }
 
 void e1000_pci_clear_mwi(struct e1000_hw *hw)
@@ -4466,7 +4487,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
        /* Fiber NICs only allow 1000 gbps Full duplex */
        if ((hw->media_type == e1000_media_type_fiber) &&
                spddplx != (SPEED_1000 + DUPLEX_FULL)) {
-               DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+               e_err("Unsupported Speed/Duplex configuration\n");
                return -EINVAL;
        }
 
@@ -4489,7 +4510,7 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
                break;
        case SPEED_1000 + DUPLEX_HALF: /* not supported */
        default:
-               DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+               e_err("Unsupported Speed/Duplex configuration\n");
                return -EINVAL;
        }
        return 0;
@@ -4612,7 +4633,7 @@ static int e1000_resume(struct pci_dev *pdev)
        else
                err = pci_enable_device_mem(pdev);
        if (err) {
-               printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n");
+               pr_err("Cannot enable PCI device from suspend\n");
                return err;
        }
        pci_set_master(pdev);
@@ -4715,7 +4736,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
        else
                err = pci_enable_device_mem(pdev);
        if (err) {
-               printk(KERN_ERR "e1000: Cannot re-enable PCI device after reset.\n");
+               pr_err("Cannot re-enable PCI device after reset.\n");
                return PCI_ERS_RESULT_DISCONNECT;
        }
        pci_set_master(pdev);
@@ -4746,7 +4767,7 @@ static void e1000_io_resume(struct pci_dev *pdev)
 
        if (netif_running(netdev)) {
                if (e1000_up(adapter)) {
-                       printk("e1000: can't bring device back up after reset\n");
+                       pr_info("can't bring device back up after reset\n");
                        return;
                }
        }
index d9298522f5aeef3f5f84baefc3f0f3961b21a1c0..edd1c75aa8951266ccc68bd96c4e51830e9fc833 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 
-#ifdef DBG
-#define DEBUGOUT(S)            printk(KERN_DEBUG S "\n")
-#define DEBUGOUT1(S, A...)     printk(KERN_DEBUG S "\n", A)
-#else
-#define DEBUGOUT(S)
-#define DEBUGOUT1(S, A...)
-#endif
-
-#define DEBUGFUNC(F) DEBUGOUT(F "\n")
-#define DEBUGOUT2 DEBUGOUT1
-#define DEBUGOUT3 DEBUGOUT2
-#define DEBUGOUT7 DEBUGOUT3
-
-
 #define er32(reg)                                                      \
        (readl(hw->hw_addr + ((hw->mac_type >= e1000_82543)             \
                               ? E1000_##reg : E1000_82542_##reg)))
index 38d2741ccae9982834f3811825805d503be0c1b6..10d8d98bb797f1c8f6576157ad5d91744403b5a9 100644 (file)
@@ -188,14 +188,6 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
  */
 E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
 
-/* Enable Kumeran Lock Loss workaround
- *
- * Valid Range: 0, 1
- *
- * Default Value: 1 (enabled)
- */
-E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
-
 struct e1000_option {
        enum { enable_option, range_option, list_option } type;
        const char *name;
@@ -226,17 +218,16 @@ static int __devinit e1000_validate_option(unsigned int *value,
        case enable_option:
                switch (*value) {
                case OPTION_ENABLED:
-                       DPRINTK(PROBE, INFO, "%s Enabled\n", opt->name);
+                       e_dev_info("%s Enabled\n", opt->name);
                        return 0;
                case OPTION_DISABLED:
-                       DPRINTK(PROBE, INFO, "%s Disabled\n", opt->name);
+                       e_dev_info("%s Disabled\n", opt->name);
                        return 0;
                }
                break;
        case range_option:
                if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
-                       DPRINTK(PROBE, INFO,
-                                       "%s set to %i\n", opt->name, *value);
+                       e_dev_info("%s set to %i\n", opt->name, *value);
                        return 0;
                }
                break;
@@ -248,7 +239,7 @@ static int __devinit e1000_validate_option(unsigned int *value,
                        ent = &opt->arg.l.p[i];
                        if (*value == ent->i) {
                                if (ent->str[0] != '\0')
-                                       DPRINTK(PROBE, INFO, "%s\n", ent->str);
+                                       e_dev_info("%s\n", ent->str);
                                return 0;
                        }
                }
@@ -258,7 +249,7 @@ static int __devinit e1000_validate_option(unsigned int *value,
                BUG();
        }
 
-       DPRINTK(PROBE, INFO, "Invalid %s value specified (%i) %s\n",
+       e_dev_info("Invalid %s value specified (%i) %s\n",
               opt->name, *value, opt->err);
        *value = opt->def;
        return -1;
@@ -283,9 +274,8 @@ void __devinit e1000_check_options(struct e1000_adapter *adapter)
        int bd = adapter->bd_number;
 
        if (bd >= E1000_MAX_NIC) {
-               DPRINTK(PROBE, NOTICE,
-                      "Warning: no configuration for board #%i\n", bd);
-               DPRINTK(PROBE, NOTICE, "Using defaults for all values\n");
+               e_dev_warn("Warning: no configuration for board #%i "
+                          "using defaults for all values\n", bd);
        }
 
        { /* Transmit Descriptor Count */
@@ -472,27 +462,31 @@ void __devinit e1000_check_options(struct e1000_adapter *adapter)
                        adapter->itr = InterruptThrottleRate[bd];
                        switch (adapter->itr) {
                        case 0:
-                               DPRINTK(PROBE, INFO, "%s turned off\n",
-                                       opt.name);
+                               e_dev_info("%s turned off\n", opt.name);
                                break;
                        case 1:
-                               DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
-                                       opt.name);
+                               e_dev_info("%s set to dynamic mode\n",
+                                          opt.name);
                                adapter->itr_setting = adapter->itr;
                                adapter->itr = 20000;
                                break;
                        case 3:
-                               DPRINTK(PROBE, INFO,
-                                       "%s set to dynamic conservative mode\n",
-                                       opt.name);
+                               e_dev_info("%s set to dynamic conservative "
+                                          "mode\n", opt.name);
                                adapter->itr_setting = adapter->itr;
                                adapter->itr = 20000;
                                break;
+                       case 4:
+                               e_dev_info("%s set to simplified "
+                                          "(2000-8000) ints mode\n", opt.name);
+                               adapter->itr_setting = adapter->itr;
+                               break;
                        default:
                                e1000_validate_option(&adapter->itr, &opt,
                                        adapter);
-                               /* save the setting, because the dynamic bits change itr */
-                               /* clear the lower two bits because they are
+                               /* save the setting, because the dynamic bits
+                                * change itr.
+                                * clear the lower two bits because they are
                                 * used as control */
                                adapter->itr_setting = adapter->itr & ~3;
                                break;
@@ -543,19 +537,18 @@ static void __devinit e1000_check_fiber_options(struct e1000_adapter *adapter)
 {
        int bd = adapter->bd_number;
        if (num_Speed > bd) {
-               DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
-                      "parameter ignored\n");
+               e_dev_info("Speed not valid for fiber adapters, parameter "
+                          "ignored\n");
        }
 
        if (num_Duplex > bd) {
-               DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
-                      "parameter ignored\n");
+               e_dev_info("Duplex not valid for fiber adapters, parameter "
+                          "ignored\n");
        }
 
        if ((num_AutoNeg > bd) && (AutoNeg[bd] != 0x20)) {
-               DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
-                                "not valid for fiber adapters, "
-                                "parameter ignored\n");
+               e_dev_info("AutoNeg other than 1000/Full is not valid for fiber"
+                          "adapters, parameter ignored\n");
        }
 }
 
@@ -619,9 +612,8 @@ static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter)
        }
 
        if ((num_AutoNeg > bd) && (speed != 0 || dplx != 0)) {
-               DPRINTK(PROBE, INFO,
-                      "AutoNeg specified along with Speed or Duplex, "
-                      "parameter ignored\n");
+               e_dev_info("AutoNeg specified along with Speed or Duplex, "
+                          "parameter ignored\n");
                adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
        } else { /* Autoneg */
                static const struct e1000_opt_list an_list[] =
@@ -680,79 +672,72 @@ static void __devinit e1000_check_copper_options(struct e1000_adapter *adapter)
        case 0:
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
                if ((num_Speed > bd) && (speed != 0 || dplx != 0))
-                       DPRINTK(PROBE, INFO,
-                              "Speed and duplex autonegotiation enabled\n");
+                       e_dev_info("Speed and duplex autonegotiation "
+                                  "enabled\n");
                break;
        case HALF_DUPLEX:
-               DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n");
-               DPRINTK(PROBE, INFO, "Using Autonegotiation at "
-                       "Half Duplex only\n");
+               e_dev_info("Half Duplex specified without Speed\n");
+               e_dev_info("Using Autonegotiation at Half Duplex only\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
                                                 ADVERTISE_100_HALF;
                break;
        case FULL_DUPLEX:
-               DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n");
-               DPRINTK(PROBE, INFO, "Using Autonegotiation at "
-                       "Full Duplex only\n");
+               e_dev_info("Full Duplex specified without Speed\n");
+               e_dev_info("Using Autonegotiation at Full Duplex only\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
                                                 ADVERTISE_100_FULL |
                                                 ADVERTISE_1000_FULL;
                break;
        case SPEED_10:
-               DPRINTK(PROBE, INFO, "10 Mbps Speed specified "
-                       "without Duplex\n");
-               DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n");
+               e_dev_info("10 Mbps Speed specified without Duplex\n");
+               e_dev_info("Using Autonegotiation at 10 Mbps only\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
                                                 ADVERTISE_10_FULL;
                break;
        case SPEED_10 + HALF_DUPLEX:
-               DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Half Duplex\n");
+               e_dev_info("Forcing to 10 Mbps Half Duplex\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_10_half;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_10 + FULL_DUPLEX:
-               DPRINTK(PROBE, INFO, "Forcing to 10 Mbps Full Duplex\n");
+               e_dev_info("Forcing to 10 Mbps Full Duplex\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_10_full;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_100:
-               DPRINTK(PROBE, INFO, "100 Mbps Speed specified "
-                       "without Duplex\n");
-               DPRINTK(PROBE, INFO, "Using Autonegotiation at "
-                       "100 Mbps only\n");
+               e_dev_info("100 Mbps Speed specified without Duplex\n");
+               e_dev_info("Using Autonegotiation at 100 Mbps only\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
                                                 ADVERTISE_100_FULL;
                break;
        case SPEED_100 + HALF_DUPLEX:
-               DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Half Duplex\n");
+               e_dev_info("Forcing to 100 Mbps Half Duplex\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_100_half;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_100 + FULL_DUPLEX:
-               DPRINTK(PROBE, INFO, "Forcing to 100 Mbps Full Duplex\n");
+               e_dev_info("Forcing to 100 Mbps Full Duplex\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 0;
                adapter->hw.forced_speed_duplex = e1000_100_full;
                adapter->hw.autoneg_advertised = 0;
                break;
        case SPEED_1000:
-               DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
-                       "Duplex\n");
+               e_dev_info("1000 Mbps Speed specified without Duplex\n");
                goto full_duplex_only;
        case SPEED_1000 + HALF_DUPLEX:
-               DPRINTK(PROBE, INFO,
-                       "Half Duplex is not supported at 1000 Mbps\n");
+               e_dev_info("Half Duplex is not supported at 1000 Mbps\n");
                /* fall through */
        case SPEED_1000 + FULL_DUPLEX:
 full_duplex_only:
-               DPRINTK(PROBE, INFO,
-                      "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+               e_dev_info("Using Autonegotiation at 1000 Mbps Full Duplex "
+                          "only\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
                adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
                break;
@@ -762,9 +747,8 @@ full_duplex_only:
 
        /* Speed, AutoNeg and MDI/MDI-X must all play nice */
        if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
-               DPRINTK(PROBE, INFO,
-                       "Speed, AutoNeg and MDI-X specifications are "
-                       "incompatible. Setting MDI-X to a compatible value.\n");
+               e_dev_info("Speed, AutoNeg and MDI-X specs are incompatible. "
+                          "Setting MDI-X to a compatible value.\n");
        }
 }
 
index 90155552ea0927670fdf412b647c2ae54d3e6af4..f654db9121def8a84df0d154d9c5e54cdffa0d32 100644 (file)
@@ -234,9 +234,6 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
        mac->mta_reg_count = 128;
        /* Set rar entry count */
        mac->rar_entry_count = E1000_RAR_ENTRIES;
-       /* Set if manageability features are enabled. */
-       mac->arc_subsystem_valid = (er32(FWSM) & E1000_FWSM_MODE_MASK)
-                       ? true : false;
        /* Adaptive IFS supported */
        mac->adaptive_ifs = true;
 
@@ -271,6 +268,16 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
                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;
+
+               /* FWSM register */
+               mac->has_fwsm = true;
+               /*
+                * ARC supported; valid only if manageability features are
+                * enabled.
+                */
+               mac->arc_subsystem_valid =
+                       (er32(FWSM) & E1000_FWSM_MODE_MASK)
+                       ? true : false;
                break;
        case e1000_82574:
        case e1000_82583:
@@ -281,6 +288,9 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
        default:
                func->check_mng_mode = e1000e_check_mng_mode_generic;
                func->led_on = e1000e_led_on_generic;
+
+               /* FWSM register */
+               mac->has_fwsm = true;
                break;
        }
 
@@ -323,7 +333,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
        }
 
        /*
-        * Initialze device specific counter of SMBI acquisition
+        * Initialize device specific counter of SMBI acquisition
         * timeouts.
         */
         hw->dev_spec.e82571.smb_counter = 0;
@@ -993,9 +1003,10 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
        /* ...for both queues. */
        switch (mac->type) {
        case e1000_82573:
+               e1000e_enable_tx_pkt_filtering(hw);
+               /* fall through */
        case e1000_82574:
        case e1000_82583:
-               e1000e_enable_tx_pkt_filtering(hw);
                reg_data = er32(GCR);
                reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
                ew32(GCR, reg_data);
@@ -1137,8 +1148,6 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
        default:
                break;
        }
-
-       return;
 }
 
 /**
@@ -1642,8 +1651,6 @@ static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw)
        /* If the management interface is not enabled, then power down */
        if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw)))
                e1000_power_down_phy_copper(hw);
-
-       return;
 }
 
 /**
@@ -1845,7 +1852,7 @@ struct e1000_info e1000_82574_info = {
                                  | FLAG_HAS_SMART_POWER_DOWN
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
-       .pba                    = 20,
+       .pba                    = 36,
        .max_hw_frame_size      = DEFAULT_JUMBO,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
@@ -1862,7 +1869,7 @@ struct e1000_info e1000_82583_info = {
                                  | FLAG_HAS_SMART_POWER_DOWN
                                  | FLAG_HAS_AMT
                                  | FLAG_HAS_CTRLEXT_ON_LOAD,
-       .pba                    = 20,
+       .pba                    = 36,
        .max_hw_frame_size      = ETH_FRAME_LEN + ETH_FCS_LEN,
        .get_variants           = e1000_get_variants_82571,
        .mac_ops                = &e82571_mac_ops,
index e301e26d689770097f16d772ef7e4d17892b8b14..4dc02c71ffd6094417f7d742e0c2e768382fddd4 100644 (file)
 /* Enable MNG packets to host memory */
 #define E1000_MANC_EN_MNG2HOST   0x00200000
 
+#define E1000_MANC2H_PORT_623    0x00000020 /* Port 0x26f */
+#define E1000_MANC2H_PORT_664    0x00000040 /* Port 0x298 */
+#define E1000_MDEF_PORT_623      0x00000800 /* Port 0x26f */
+#define E1000_MDEF_PORT_664      0x00000400 /* Port 0x298 */
+
 /* Receive Control */
 #define E1000_RCTL_EN             0x00000002    /* enable */
 #define E1000_RCTL_SBP            0x00000004    /* store bad packet */
 #define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
 #define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
 #define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_LANPHYPC_OVERRIDE 0x00010000 /* SW control of LANPHYPC */
+#define E1000_CTRL_LANPHYPC_VALUE    0x00020000 /* SW value of LANPHYPC */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
 #define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
 #define NVM_ALT_MAC_ADDR_PTR       0x0037
 #define NVM_CHECKSUM_REG           0x003F
 
+#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
+
 #define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
 #define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
 
index ee32b9b27a9fc7c8eda3b74931a887db2a0ae98b..c0b3db40bd73d1dce3dea5d1fa686adbc45196c7 100644 (file)
 
 struct e1000_info;
 
-#define e_printk(level, adapter, format, arg...) \
-       printk(level "%s: %s: " format, pci_name(adapter->pdev), \
-              adapter->netdev->name, ## arg)
-
-#ifdef DEBUG
 #define e_dbg(format, arg...) \
-       e_printk(KERN_DEBUG , hw->adapter, format, ## arg)
-#else
-#define e_dbg(format, arg...) do { (void)(hw); } while (0)
-#endif
-
+       netdev_dbg(hw->adapter->netdev, format, ## arg)
 #define e_err(format, arg...) \
-       e_printk(KERN_ERR, adapter, format, ## arg)
+       netdev_err(adapter->netdev, format, ## arg)
 #define e_info(format, arg...) \
-       e_printk(KERN_INFO, adapter, format, ## arg)
+       netdev_info(adapter->netdev, format, ## arg)
 #define e_warn(format, arg...) \
-       e_printk(KERN_WARNING, adapter, format, ## arg)
+       netdev_warn(adapter->netdev, format, ## arg)
 #define e_notice(format, arg...) \
-       e_printk(KERN_NOTICE, adapter, format, ## arg)
+       netdev_notice(adapter->netdev, format, ## arg)
 
 
 /* Interrupt modes, as used by the IntMode parameter */
@@ -159,6 +150,9 @@ struct e1000_info;
 #define HV_M_STATUS_SPEED_1000            0x0200
 #define HV_M_STATUS_LINK_UP               0x0040
 
+/* Time to wait before putting the device into D3 if there's no link (in ms). */
+#define LINK_TIMEOUT           100
+
 enum e1000_boards {
        board_82571,
        board_82572,
@@ -195,6 +189,8 @@ struct e1000_buffer {
                        unsigned long time_stamp;
                        u16 length;
                        u16 next_to_watch;
+                       unsigned int segs;
+                       unsigned int bytecount;
                        u16 mapped_as_page;
                };
                /* Rx */
@@ -370,6 +366,8 @@ struct e1000_adapter {
        struct work_struct update_phy_task;
        struct work_struct led_blink_task;
        struct work_struct print_hang_task;
+
+       bool idle_check;
 };
 
 struct e1000_info {
index 27d21589a69afa128e7a6f0be459703a6e917053..38d79a669059650fa538547af6d240d36679bcaa 100644 (file)
@@ -221,9 +221,12 @@ static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
        mac->mta_reg_count = 128;
        /* Set rar entry count */
        mac->rar_entry_count = E1000_RAR_ENTRIES;
-       /* Set if manageability features are enabled. */
-       mac->arc_subsystem_valid = (er32(FWSM) & E1000_FWSM_MODE_MASK)
-                        ? true : false;
+       /* FWSM register */
+       mac->has_fwsm = true;
+       /* ARC supported; valid only if manageability features are enabled. */
+       mac->arc_subsystem_valid =
+               (er32(FWSM) & E1000_FWSM_MODE_MASK)
+                       ? true : false;
        /* Adaptive IFS not supported */
        mac->adaptive_ifs = false;
 
@@ -1380,8 +1383,6 @@ static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw)
        if (!(hw->mac.ops.check_mng_mode(hw) ||
              hw->phy.ops.check_reset_block(hw)))
                e1000_power_down_phy_copper(hw);
-
-       return;
 }
 
 /**
index 983493f2330c37e6e89fb89e1525310ed779c6f2..2c521218102b6073e8eee24026daada13028f18a 100644 (file)
@@ -412,7 +412,6 @@ static int e1000_set_tso(struct net_device *netdev, u32 data)
                netdev->features &= ~NETIF_F_TSO6;
        }
 
-       e_info("TSO is %s\n", data ? "Enabled" : "Disabled");
        adapter->flags |= FLAG_TSO_FORCE;
        return 0;
 }
@@ -1069,10 +1068,10 @@ static void e1000_free_desc_rings(struct e1000_adapter *adapter)
        if (tx_ring->desc && tx_ring->buffer_info) {
                for (i = 0; i < tx_ring->count; i++) {
                        if (tx_ring->buffer_info[i].dma)
-                               pci_unmap_single(pdev,
+                               dma_unmap_single(&pdev->dev,
                                        tx_ring->buffer_info[i].dma,
                                        tx_ring->buffer_info[i].length,
-                                       PCI_DMA_TODEVICE);
+                                       DMA_TO_DEVICE);
                        if (tx_ring->buffer_info[i].skb)
                                dev_kfree_skb(tx_ring->buffer_info[i].skb);
                }
@@ -1081,9 +1080,9 @@ static void e1000_free_desc_rings(struct e1000_adapter *adapter)
        if (rx_ring->desc && rx_ring->buffer_info) {
                for (i = 0; i < rx_ring->count; i++) {
                        if (rx_ring->buffer_info[i].dma)
-                               pci_unmap_single(pdev,
+                               dma_unmap_single(&pdev->dev,
                                        rx_ring->buffer_info[i].dma,
-                                       2048, PCI_DMA_FROMDEVICE);
+                                       2048, DMA_FROM_DEVICE);
                        if (rx_ring->buffer_info[i].skb)
                                dev_kfree_skb(rx_ring->buffer_info[i].skb);
                }
@@ -1163,9 +1162,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
                tx_ring->buffer_info[i].skb = skb;
                tx_ring->buffer_info[i].length = skb->len;
                tx_ring->buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, skb->len,
-                                      PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, tx_ring->buffer_info[i].dma)) {
+                       dma_map_single(&pdev->dev, skb->data, skb->len,
+                                      DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev,
+                                     tx_ring->buffer_info[i].dma)) {
                        ret_val = 4;
                        goto err_nomem;
                }
@@ -1226,9 +1226,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
                skb_reserve(skb, NET_IP_ALIGN);
                rx_ring->buffer_info[i].skb = skb;
                rx_ring->buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, 2048,
-                                      PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(pdev, rx_ring->buffer_info[i].dma)) {
+                       dma_map_single(&pdev->dev, skb->data, 2048,
+                                      DMA_FROM_DEVICE);
+               if (dma_mapping_error(&pdev->dev,
+                                     rx_ring->buffer_info[i].dma)) {
                        ret_val = 8;
                        goto err_nomem;
                }
@@ -1556,10 +1557,10 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                for (i = 0; i < 64; i++) { /* send the packets */
                        e1000_create_lbtest_frame(tx_ring->buffer_info[k].skb,
                                                  1024);
-                       pci_dma_sync_single_for_device(pdev,
+                       dma_sync_single_for_device(&pdev->dev,
                                        tx_ring->buffer_info[k].dma,
                                        tx_ring->buffer_info[k].length,
-                                       PCI_DMA_TODEVICE);
+                                       DMA_TO_DEVICE);
                        k++;
                        if (k == tx_ring->count)
                                k = 0;
@@ -1569,9 +1570,9 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
                time = jiffies; /* set the start time for the receive */
                good_cnt = 0;
                do { /* receive the sent packets */
-                       pci_dma_sync_single_for_cpu(pdev,
+                       dma_sync_single_for_cpu(&pdev->dev,
                                        rx_ring->buffer_info[l].dma, 2048,
-                                       PCI_DMA_FROMDEVICE);
+                                       DMA_FROM_DEVICE);
 
                        ret_val = e1000_check_lbtest_frame(
                                        rx_ring->buffer_info[l].skb, 1024);
@@ -1736,6 +1737,12 @@ static void e1000_diag_test(struct net_device *netdev,
                if (if_running)
                        dev_open(netdev);
        } else {
+               if (!if_running && (adapter->flags & FLAG_HAS_AMT)) {
+                       clear_bit(__E1000_TESTING, &adapter->state);
+                       dev_open(netdev);
+                       set_bit(__E1000_TESTING, &adapter->state);
+               }
+
                e_info("online testing starting\n");
                /* Online tests */
                if (e1000_link_test(adapter, &data[4]))
@@ -1747,6 +1754,9 @@ static void e1000_diag_test(struct net_device *netdev,
                data[2] = 0;
                data[3] = 0;
 
+               if (!if_running && (adapter->flags & FLAG_HAS_AMT))
+                       dev_close(netdev);
+
                clear_bit(__E1000_TESTING, &adapter->state);
        }
        msleep_interruptible(4 * 1000);
@@ -1889,7 +1899,7 @@ static int e1000_get_coalesce(struct net_device *netdev,
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (adapter->itr_setting <= 3)
+       if (adapter->itr_setting <= 4)
                ec->rx_coalesce_usecs = adapter->itr_setting;
        else
                ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
@@ -1904,12 +1914,14 @@ static int e1000_set_coalesce(struct net_device *netdev,
        struct e1000_hw *hw = &adapter->hw;
 
        if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
-           ((ec->rx_coalesce_usecs > 3) &&
+           ((ec->rx_coalesce_usecs > 4) &&
             (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
            (ec->rx_coalesce_usecs == 2))
                return -EINVAL;
 
-       if (ec->rx_coalesce_usecs <= 3) {
+       if (ec->rx_coalesce_usecs == 4) {
+               adapter->itr = adapter->itr_setting = 4;
+       } else if (ec->rx_coalesce_usecs <= 3) {
                adapter->itr = 20000;
                adapter->itr_setting = ec->rx_coalesce_usecs;
        } else {
index 8bdcd5f24eff1b4c3d99e3ca7cb99b7ef2c9ecbd..5d1220d188d46f88e29d6f8c9760a3fc3c92a54d 100644 (file)
@@ -208,6 +208,8 @@ enum e1e_registers {
 
        E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
        E1000_MANC2H    = 0x05860, /* Management Control To Host - RW */
+       E1000_MDEF_BASE = 0x05890, /* Management Decision Filters */
+#define E1000_MDEF(_n)   (E1000_MDEF_BASE + ((_n) * 4))
        E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
        E1000_GCR       = 0x05B00, /* PCI-Ex Control */
        E1000_GCR2      = 0x05B64, /* PCI-Ex Control #2 */
@@ -380,6 +382,7 @@ enum e1e_registers {
 #define E1000_DEV_ID_ICH10_R_BM_V              0x10CE
 #define E1000_DEV_ID_ICH10_D_BM_LM             0x10DE
 #define E1000_DEV_ID_ICH10_D_BM_LF             0x10DF
+#define E1000_DEV_ID_ICH10_D_BM_V              0x1525
 #define E1000_DEV_ID_PCH_M_HV_LM               0x10EA
 #define E1000_DEV_ID_PCH_M_HV_LC               0x10EB
 #define E1000_DEV_ID_PCH_D_HV_DM               0x10EF
@@ -828,6 +831,7 @@ struct e1000_mac_info {
        u8  forced_speed_duplex;
 
        bool adaptive_ifs;
+       bool has_fwsm;
        bool arc_subsystem_valid;
        bool autoneg;
        bool autoneg_failed;
@@ -898,6 +902,7 @@ struct e1000_fc_info {
        u32 high_water;          /* Flow control high-water mark */
        u32 low_water;           /* Flow control low-water mark */
        u16 pause_time;          /* Flow control pause timer */
+       u16 refresh_time;        /* Flow control refresh timer */
        bool send_xon;           /* Flow control send XON */
        bool strict_ieee;        /* Strict IEEE mode */
        enum e1000_fc_mode current_mode; /* FC mode in effect */
index 8b5e157e9c879e2cd0c7d4373ada56e31d0ce251..b2507d93de99834be065cc638fe105796863e227 100644 (file)
@@ -83,6 +83,8 @@
 
 
 #define E1000_ICH_FWSM_RSPCIPHY        0x00000040 /* Reset PHY on PCI Reset */
+/* FW established a valid mode */
+#define E1000_ICH_FWSM_FW_VALID                0x00008000
 
 #define E1000_ICH_MNG_IAMT_MODE                0x2
 
@@ -259,6 +261,7 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
 static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
 {
        struct e1000_phy_info *phy = &hw->phy;
+       u32 ctrl;
        s32 ret_val = 0;
 
        phy->addr                     = 1;
@@ -274,6 +277,33 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
        phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
        phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
+       if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+               /*
+                * The MAC-PHY interconnect may still be in SMBus mode
+                * after Sx->S0.  Toggle the LANPHYPC Value bit to force
+                * the interconnect to PCIe mode, but only if there is no
+                * firmware present otherwise firmware will have done it.
+                */
+               ctrl = er32(CTRL);
+               ctrl |=  E1000_CTRL_LANPHYPC_OVERRIDE;
+               ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
+               ew32(CTRL, ctrl);
+               udelay(10);
+               ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+               ew32(CTRL, ctrl);
+               msleep(50);
+       }
+
+       /*
+        * Reset the PHY before any acccess to it.  Doing so, ensures that
+        * the PHY is in a known good state before we read/write PHY registers.
+        * The generic reset is sufficient here, because we haven't determined
+        * the PHY type yet.
+        */
+       ret_val = e1000e_phy_hw_reset_generic(hw);
+       if (ret_val)
+               goto out;
+
        phy->id = e1000_phy_unknown;
        ret_val = e1000e_get_phy_id(hw);
        if (ret_val)
@@ -300,6 +330,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
                phy->ops.get_cable_length = e1000_get_cable_length_82577;
                phy->ops.get_info = e1000_get_phy_info_82577;
                phy->ops.commit = e1000e_phy_sw_reset;
+               break;
        case e1000_phy_82578:
                phy->ops.check_polarity = e1000_check_polarity_m88;
                phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88;
@@ -472,8 +503,10 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
        if (mac->type == e1000_ich8lan)
                mac->rar_entry_count--;
-       /* Set if manageability features are enabled. */
-       mac->arc_subsystem_valid = true;
+       /* FWSM register */
+       mac->has_fwsm = true;
+       /* ARC subsystem not supported */
+       mac->arc_subsystem_valid = false;
        /* Adaptive IFS supported */
        mac->adaptive_ifs = true;
 
@@ -657,8 +690,6 @@ static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
 static void e1000_release_nvm_ich8lan(struct e1000_hw *hw)
 {
        mutex_unlock(&nvm_mutex);
-
-       return;
 }
 
 static DEFINE_MUTEX(swflag_mutex);
@@ -737,8 +768,6 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
        ew32(EXTCNF_CTRL, extcnf_ctrl);
 
        mutex_unlock(&swflag_mutex);
-
-       return;
 }
 
 /**
@@ -785,11 +814,16 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
  **/
 static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
 {
+       struct e1000_adapter *adapter = hw->adapter;
        struct e1000_phy_info *phy = &hw->phy;
        u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
-       s32 ret_val;
+       s32 ret_val = 0;
        u16 word_addr, reg_data, reg_addr, phy_page = 0;
 
+       if (!(hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) &&
+               !(hw->mac.type == e1000_pchlan))
+               return ret_val;
+
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
@@ -801,97 +835,87 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
         * Therefore, after each PHY reset, we will load the
         * configuration data out of the NVM manually.
         */
-       if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) ||
-               (hw->mac.type == e1000_pchlan)) {
-               struct e1000_adapter *adapter = hw->adapter;
-
-               /* Check if SW needs to configure the PHY */
-               if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
-                   (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) ||
-                   (hw->mac.type == e1000_pchlan))
-                       sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
-               else
-                       sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+       if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+           (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M) ||
+           (hw->mac.type == e1000_pchlan))
+               sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+       else
+               sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
 
-               data = er32(FEXTNVM);
-               if (!(data & sw_cfg_mask))
-                       goto out;
+       data = er32(FEXTNVM);
+       if (!(data & sw_cfg_mask))
+               goto out;
 
-               /* Wait for basic configuration completes before proceeding */
-               e1000_lan_init_done_ich8lan(hw);
+       /*
+        * Make sure HW does not configure LCD from PHY
+        * extended configuration before SW configuration
+        */
+       data = er32(EXTCNF_CTRL);
+       if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+               goto out;
+
+       cnf_size = er32(EXTCNF_SIZE);
+       cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+       cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+       if (!cnf_size)
+               goto out;
+
+       cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+       cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
 
+       if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
+           (hw->mac.type == e1000_pchlan)) {
                /*
-                * Make sure HW does not configure LCD from PHY
-                * extended configuration before SW configuration
+                * HW configures the SMBus address and LEDs when the
+                * OEM and LCD Write Enable bits are set in the NVM.
+                * When both NVM bits are cleared, SW will configure
+                * them instead.
                 */
-               data = er32(EXTCNF_CTRL);
-               if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+               data = er32(STRAP);
+               data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
+               reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
+               reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+               ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
+                                                       reg_data);
+               if (ret_val)
                        goto out;
 
-               cnf_size = er32(EXTCNF_SIZE);
-               cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
-               cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
-               if (!cnf_size)
+               data = er32(LEDCTL);
+               ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG,
+                                                       (u16)data);
+               if (ret_val)
                        goto out;
+       }
 
-               cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
-               cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
-
-               if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
-                   (hw->mac.type == e1000_pchlan)) {
-                       /*
-                        * HW configures the SMBus address and LEDs when the
-                        * OEM and LCD Write Enable bits are set in the NVM.
-                        * When both NVM bits are cleared, SW will configure
-                        * them instead.
-                        */
-                       data = er32(STRAP);
-                       data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
-                       reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
-                       reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
-                       ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
-                                                               reg_data);
-                       if (ret_val)
-                               goto out;
-
-                       data = er32(LEDCTL);
-                       ret_val = e1000_write_phy_reg_hv_locked(hw,
-                                                               HV_LED_CONFIG,
-                                                               (u16)data);
-                       if (ret_val)
-                               goto out;
-               }
-               /* Configure LCD from extended configuration region. */
+       /* Configure LCD from extended configuration region. */
 
-               /* cnf_base_addr is in DWORD */
-               word_addr = (u16)(cnf_base_addr << 1);
+       /* cnf_base_addr is in DWORD */
+       word_addr = (u16)(cnf_base_addr << 1);
 
-               for (i = 0; i < cnf_size; i++) {
-                       ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1,
-                                                  &reg_data);
-                       if (ret_val)
-                               goto out;
+       for (i = 0; i < cnf_size; i++) {
+               ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1,
+                                        &reg_data);
+               if (ret_val)
+                       goto out;
 
-                       ret_val = e1000_read_nvm(hw, (word_addr + i * 2 + 1),
-                                                  1, &reg_addr);
-                       if (ret_val)
-                               goto out;
+               ret_val = e1000_read_nvm(hw, (word_addr + i * 2 + 1),
+                                        1, &reg_addr);
+               if (ret_val)
+                       goto out;
 
-                       /* Save off the PHY page for future writes. */
-                       if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
-                               phy_page = reg_data;
-                               continue;
-                       }
+               /* Save off the PHY page for future writes. */
+               if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+                       phy_page = reg_data;
+                       continue;
+               }
 
-                       reg_addr &= PHY_REG_MASK;
-                       reg_addr |= phy_page;
+               reg_addr &= PHY_REG_MASK;
+               reg_addr |= phy_page;
 
-                       ret_val = phy->ops.write_reg_locked(hw,
-                                                           (u32)reg_addr,
-                                                           reg_data);
-                       if (ret_val)
-                               goto out;
-               }
+               ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
+                                                   reg_data);
+               if (ret_val)
+                       goto out;
        }
 
 out:
@@ -1229,30 +1253,26 @@ static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
 }
 
 /**
- *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ *  e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset
  *  @hw: pointer to the HW structure
- *
- *  Resets the PHY
- *  This is a function pointer entry point called by drivers
- *  or other shared routines.
  **/
-static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
 {
        s32 ret_val = 0;
        u16 reg;
 
-       ret_val = e1000e_phy_hw_reset_generic(hw);
-       if (ret_val)
-               return ret_val;
-
-       /* Allow time for h/w to get to a quiescent state after reset */
-       mdelay(10);
+       if (e1000_check_reset_block(hw))
+               goto out;
 
        /* Perform any necessary post-reset workarounds */
-       if (hw->mac.type == e1000_pchlan) {
+       switch (hw->mac.type) {
+       case e1000_pchlan:
                ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
                if (ret_val)
-                       return ret_val;
+                       goto out;
+               break;
+       default:
+               break;
        }
 
        /* Dummy read to clear the phy wakeup bit after lcd reset */
@@ -1265,11 +1285,32 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
                goto out;
 
        /* Configure the LCD with the OEM bits in NVM */
-       if (hw->mac.type == e1000_pchlan)
-               ret_val = e1000_oem_bits_config_ich8lan(hw, true);
+       ret_val = e1000_oem_bits_config_ich8lan(hw, true);
 
 out:
-       return 0;
+       return ret_val;
+}
+
+/**
+ *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       ret_val = e1000e_phy_hw_reset_generic(hw);
+       if (ret_val)
+               goto out;
+
+       ret_val = e1000_post_phy_reset_ich8lan(hw);
+
+out:
+       return ret_val;
 }
 
 /**
@@ -1622,7 +1663,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
        /* Check if the flash descriptor is valid */
        if (hsfsts.hsf_status.fldesvalid == 0) {
                e_dbg("Flash descriptor invalid.  "
-                        "SW Sequencing must be used.");
+                        "SW Sequencing must be used.\n");
                return -E1000_ERR_NVM;
        }
 
@@ -1671,7 +1712,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
                        hsfsts.hsf_status.flcdone = 1;
                        ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
                } else {
-                       e_dbg("Flash controller busy, cannot get access");
+                       e_dbg("Flash controller busy, cannot get access\n");
                }
        }
 
@@ -1822,7 +1863,7 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
                                continue;
                        } else if (hsfsts.hsf_status.flcdone == 0) {
                                e_dbg("Timeout error - flash cycle "
-                                        "did not complete.");
+                                        "did not complete.\n");
                                break;
                        }
                }
@@ -1908,18 +1949,14 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
                new_bank_offset = nvm->flash_bank_size;
                old_bank_offset = 0;
                ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
-               if (ret_val) {
-                       nvm->ops.release(hw);
-                       goto out;
-               }
+               if (ret_val)
+                       goto release;
        } else {
                old_bank_offset = nvm->flash_bank_size;
                new_bank_offset = 0;
                ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
-               if (ret_val) {
-                       nvm->ops.release(hw);
-                       goto out;
-               }
+               if (ret_val)
+                       goto release;
        }
 
        for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
@@ -1975,8 +2012,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
        if (ret_val) {
                /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
                e_dbg("Flash commit failed.\n");
-               nvm->ops.release(hw);
-               goto out;
+               goto release;
        }
 
        /*
@@ -1987,18 +2023,15 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
         */
        act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
        ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
-       if (ret_val) {
-               nvm->ops.release(hw);
-               goto out;
-       }
+       if (ret_val)
+               goto release;
+
        data &= 0xBFFF;
        ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
                                                       act_offset * 2 + 1,
                                                       (u8)(data >> 8));
-       if (ret_val) {
-               nvm->ops.release(hw);
-               goto out;
-       }
+       if (ret_val)
+               goto release;
 
        /*
         * And invalidate the previously valid segment by setting
@@ -2008,10 +2041,8 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
         */
        act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
        ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
-       if (ret_val) {
-               nvm->ops.release(hw);
-               goto out;
-       }
+       if (ret_val)
+               goto release;
 
        /* Great!  Everything worked, we can now clear the cached entries. */
        for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
@@ -2019,14 +2050,17 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
                dev_spec->shadow_ram[i].value = 0xFFFF;
        }
 
+release:
        nvm->ops.release(hw);
 
        /*
         * Reload the EEPROM, or else modifications will not appear
         * until after the next adapter reset.
         */
-       e1000e_reload_nvm(hw);
-       msleep(10);
+       if (!ret_val) {
+               e1000e_reload_nvm(hw);
+               msleep(10);
+       }
 
 out:
        if (ret_val)
@@ -2487,9 +2521,8 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
         * on the last TLP read/write transaction when MAC is reset.
         */
        ret_val = e1000e_disable_pcie_master(hw);
-       if (ret_val) {
+       if (ret_val)
                e_dbg("PCI-E Master disable polling has failed.\n");
-       }
 
        e_dbg("Masking off all interrupts\n");
        ew32(IMC, 0xffffffff);
@@ -2528,14 +2561,8 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        ctrl = er32(CTRL);
 
        if (!e1000_check_reset_block(hw)) {
-               /* Clear PHY Reset Asserted bit */
-               if (hw->mac.type >= e1000_pchlan) {
-                       u32 status = er32(STATUS);
-                       ew32(STATUS, status & ~E1000_STATUS_PHYRA);
-               }
-
                /*
-                * PHY HW reset requires MAC CORE reset at the same
+                * Full-chip reset requires MAC and PHY reset at the same
                 * time to make sure the interface between MAC and the
                 * external PHY is reset.
                 */
@@ -2549,39 +2576,16 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
        if (!ret_val)
                e1000_release_swflag_ich8lan(hw);
 
-       /* Perform any necessary post-reset workarounds */
-       if (hw->mac.type == e1000_pchlan)
-               ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
-
-       if (ctrl & E1000_CTRL_PHY_RST)
+       if (ctrl & E1000_CTRL_PHY_RST) {
                ret_val = hw->phy.ops.get_cfg_done(hw);
+               if (ret_val)
+                       goto out;
 
-       if (hw->mac.type >= e1000_ich10lan) {
-               e1000_lan_init_done_ich8lan(hw);
-       } else {
-               ret_val = e1000e_get_auto_rd_done(hw);
-               if (ret_val) {
-                       /*
-                        * When auto config read does not complete, do not
-                        * return with an error. This can happen in situations
-                        * where there is no eeprom and prevents getting link.
-                        */
-                       e_dbg("Auto Read Done did not complete\n");
-               }
-       }
-       /* Dummy read to clear the phy wakeup bit after lcd reset */
-       if (hw->mac.type == e1000_pchlan)
-               e1e_rphy(hw, BM_WUC, &reg);
-
-       ret_val = e1000_sw_lcd_config_ich8lan(hw);
-       if (ret_val)
-               goto out;
-
-       if (hw->mac.type == e1000_pchlan) {
-               ret_val = e1000_oem_bits_config_ich8lan(hw, true);
+               ret_val = e1000_post_phy_reset_ich8lan(hw);
                if (ret_val)
                        goto out;
        }
+
        /*
         * For PCH, this write will make sure that any noise
         * will be detected as a CRC error and be dropped rather than show up
@@ -2748,8 +2752,6 @@ static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
        reg = er32(RFCTL);
        reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS);
        ew32(RFCTL, reg);
-
-       return;
 }
 
 /**
@@ -2799,6 +2801,8 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
        ew32(FCTTV, hw->fc.pause_time);
        if ((hw->phy.type == e1000_phy_82578) ||
            (hw->phy.type == e1000_phy_82577)) {
+               ew32(FCRTV_PCH, hw->fc.refresh_time);
+
                ret_val = hw->phy.ops.write_reg(hw,
                                             PHY_REG(BM_PORT_CTRL_PAGE, 27),
                                             hw->fc.pause_time);
@@ -3127,8 +3131,6 @@ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
        default:
                break;
        }
-
-       return;
 }
 
 /**
@@ -3265,33 +3267,50 @@ static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
 }
 
 /**
- *  e1000_get_cfg_done_ich8lan - Read config done bit
+ *  e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset
  *  @hw: pointer to the HW structure
  *
- *  Read the management control register for the config done bit for
- *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
- *  to read the config done bit, so an error is *ONLY* logged and returns
- *  0.  If we were to return with error, EEPROM-less silicon
- *  would not be able to be reset or change link.
+ *  Read appropriate register for the config done bit for completion status
+ *  and configure the PHY through s/w for EEPROM-less parts.
+ *
+ *  NOTE: some silicon which is EEPROM-less will fail trying to read the
+ *  config done bit, so only an error is logged and continues.  If we were
+ *  to return with error, EEPROM-less silicon would not be able to be reset
+ *  or change link.
  **/
 static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
 {
+       s32 ret_val = 0;
        u32 bank = 0;
+       u32 status;
 
-       if (hw->mac.type >= e1000_pchlan) {
-               u32 status = er32(STATUS);
+       e1000e_get_cfg_done(hw);
 
-               if (status & E1000_STATUS_PHYRA)
-                       ew32(STATUS, status & ~E1000_STATUS_PHYRA);
-               else
-                       e_dbg("PHY Reset Asserted not set - needs delay\n");
+       /* Wait for indication from h/w that it has completed basic config */
+       if (hw->mac.type >= e1000_ich10lan) {
+               e1000_lan_init_done_ich8lan(hw);
+       } else {
+               ret_val = e1000e_get_auto_rd_done(hw);
+               if (ret_val) {
+                       /*
+                        * When auto config read does not complete, do not
+                        * return with an error. This can happen in situations
+                        * where there is no eeprom and prevents getting link.
+                        */
+                       e_dbg("Auto Read Done did not complete\n");
+                       ret_val = 0;
+               }
        }
 
-       e1000e_get_cfg_done(hw);
+       /* Clear PHY Reset Asserted bit */
+       status = er32(STATUS);
+       if (status & E1000_STATUS_PHYRA)
+               ew32(STATUS, status & ~E1000_STATUS_PHYRA);
+       else
+               e_dbg("PHY Reset Asserted not set - needs delay\n");
 
        /* If EEPROM is not marked present, init the IGP 3 PHY manually */
-       if ((hw->mac.type != e1000_ich10lan) &&
-           (hw->mac.type != e1000_pchlan)) {
+       if (hw->mac.type <= e1000_ich9lan) {
                if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
                    (hw->phy.type == e1000_phy_igp_3)) {
                        e1000e_phy_init_script_igp3(hw);
@@ -3300,11 +3319,11 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
                if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
                        /* Maybe we should do a basic PHY config */
                        e_dbg("EEPROM not present\n");
-                       return -E1000_ERR_CONFIG;
+                       ret_val = -E1000_ERR_CONFIG;
                }
        }
 
-       return 0;
+       return ret_val;
 }
 
 /**
@@ -3320,8 +3339,6 @@ static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
        if (!(hw->mac.ops.check_mng_mode(hw) ||
              hw->phy.ops.check_reset_block(hw)))
                e1000_power_down_phy_copper(hw);
-
-       return;
 }
 
 /**
index a8b2c0de27c4084f138f510bf51a274fdd78bf80..a968e3a416ac4609678426ce25cc7ce484d16727 100644 (file)
@@ -1262,24 +1262,21 @@ s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *dup
        u32 status;
 
        status = er32(STATUS);
-       if (status & E1000_STATUS_SPEED_1000) {
+       if (status & E1000_STATUS_SPEED_1000)
                *speed = SPEED_1000;
-               e_dbg("1000 Mbs, ");
-       } else if (status & E1000_STATUS_SPEED_100) {
+       else if (status & E1000_STATUS_SPEED_100)
                *speed = SPEED_100;
-               e_dbg("100 Mbs, ");
-       } else {
+       else
                *speed = SPEED_10;
-               e_dbg("10 Mbs, ");
-       }
 
-       if (status & E1000_STATUS_FD) {
+       if (status & E1000_STATUS_FD)
                *duplex = FULL_DUPLEX;
-               e_dbg("Full Duplex\n");
-       } else {
+       else
                *duplex = HALF_DUPLEX;
-               e_dbg("Half Duplex\n");
-       }
+
+       e_dbg("%u Mbps, %s Duplex\n",
+             *speed == SPEED_1000 ? 1000 : *speed == SPEED_100 ? 100 : 10,
+             *duplex == FULL_DUPLEX ? "Full" : "Half");
 
        return 0;
 }
@@ -2275,6 +2272,11 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
        u32 hicr;
        u8 i;
 
+       if (!(hw->mac.arc_subsystem_valid)) {
+               e_dbg("ARC subsystem not valid.\n");
+               return -E1000_ERR_HOST_INTERFACE_COMMAND;
+       }
+
        /* Check that the host interface is enabled. */
        hicr = er32(HICR);
        if ((hicr & E1000_HICR_EN) == 0) {
@@ -2518,10 +2520,11 @@ s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
 }
 
 /**
- *  e1000e_enable_mng_pass_thru - Enable processing of ARP's
+ *  e1000e_enable_mng_pass_thru - Check if management passthrough is needed
  *  @hw: pointer to the HW structure
  *
- *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ *  Verifies the hardware needs to leave interface enabled so that frames can
+ *  be directed to and from the management interface.
  **/
 bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
 {
@@ -2531,11 +2534,10 @@ bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
 
        manc = er32(MANC);
 
-       if (!(manc & E1000_MANC_RCV_TCO_EN) ||
-           !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
-               return ret_val;
+       if (!(manc & E1000_MANC_RCV_TCO_EN))
+               goto out;
 
-       if (hw->mac.arc_subsystem_valid) {
+       if (hw->mac.has_fwsm) {
                fwsm = er32(FWSM);
                factps = er32(FACTPS);
 
@@ -2543,16 +2545,28 @@ bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
                    ((fwsm & E1000_FWSM_MODE_MASK) ==
                     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
                        ret_val = true;
-                       return ret_val;
+                       goto out;
                }
-       } else {
-               if ((manc & E1000_MANC_SMBUS_EN) &&
-                   !(manc & E1000_MANC_ASF_EN)) {
+       } else if ((hw->mac.type == e1000_82574) ||
+                  (hw->mac.type == e1000_82583)) {
+               u16 data;
+
+               factps = er32(FACTPS);
+               e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
+
+               if (!(factps & E1000_FACTPS_MNGCG) &&
+                   ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
+                    (e1000_mng_mode_pt << 13))) {
                        ret_val = true;
-                       return ret_val;
+                       goto out;
                }
+       } else if ((manc & E1000_MANC_SMBUS_EN) &&
+                   !(manc & E1000_MANC_ASF_EN)) {
+                       ret_val = true;
+                       goto out;
        }
 
+out:
        return ret_val;
 }
 
index d5d55c6a373f8d4aa4774ce8d5f8d28b8700f3dc..24507f3b8b1708755e0631d9c28be2fe08f67493 100644 (file)
@@ -26,6 +26,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/smp.h>
 #include <linux/pm_qos_params.h>
+#include <linux/pm_runtime.h>
 #include <linux/aer.h>
 
 #include "e1000.h"
 
-#define DRV_VERSION "1.0.2-k2"
+#define DRV_VERSION "1.0.2-k4"
 char e1000e_driver_name[] = "e1000e";
 const char e1000e_driver_version[] = DRV_VERSION;
 
@@ -66,6 +69,361 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_pchlan]          = &e1000_pch_info,
 };
 
+struct e1000_reg_info {
+       u32 ofs;
+       char *name;
+};
+
+#define E1000_RDFH     0x02410 /* Rx Data FIFO Head - RW */
+#define E1000_RDFT     0x02418 /* Rx Data FIFO Tail - RW */
+#define E1000_RDFHS    0x02420 /* Rx Data FIFO Head Saved - RW */
+#define E1000_RDFTS    0x02428 /* Rx Data FIFO Tail Saved - RW */
+#define E1000_RDFPC    0x02430 /* Rx Data FIFO Packet Count - RW */
+
+#define E1000_TDFH     0x03410 /* Tx Data FIFO Head - RW */
+#define E1000_TDFT     0x03418 /* Tx Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420 /* Tx Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428 /* Tx Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430 /* Tx Data FIFO Packet Count - RW */
+
+static const struct e1000_reg_info e1000_reg_info_tbl[] = {
+
+       /* General Registers */
+       {E1000_CTRL, "CTRL"},
+       {E1000_STATUS, "STATUS"},
+       {E1000_CTRL_EXT, "CTRL_EXT"},
+
+       /* Interrupt Registers */
+       {E1000_ICR, "ICR"},
+
+       /* RX Registers */
+       {E1000_RCTL, "RCTL"},
+       {E1000_RDLEN, "RDLEN"},
+       {E1000_RDH, "RDH"},
+       {E1000_RDT, "RDT"},
+       {E1000_RDTR, "RDTR"},
+       {E1000_RXDCTL(0), "RXDCTL"},
+       {E1000_ERT, "ERT"},
+       {E1000_RDBAL, "RDBAL"},
+       {E1000_RDBAH, "RDBAH"},
+       {E1000_RDFH, "RDFH"},
+       {E1000_RDFT, "RDFT"},
+       {E1000_RDFHS, "RDFHS"},
+       {E1000_RDFTS, "RDFTS"},
+       {E1000_RDFPC, "RDFPC"},
+
+       /* TX Registers */
+       {E1000_TCTL, "TCTL"},
+       {E1000_TDBAL, "TDBAL"},
+       {E1000_TDBAH, "TDBAH"},
+       {E1000_TDLEN, "TDLEN"},
+       {E1000_TDH, "TDH"},
+       {E1000_TDT, "TDT"},
+       {E1000_TIDV, "TIDV"},
+       {E1000_TXDCTL(0), "TXDCTL"},
+       {E1000_TADV, "TADV"},
+       {E1000_TARC(0), "TARC"},
+       {E1000_TDFH, "TDFH"},
+       {E1000_TDFT, "TDFT"},
+       {E1000_TDFHS, "TDFHS"},
+       {E1000_TDFTS, "TDFTS"},
+       {E1000_TDFPC, "TDFPC"},
+
+       /* List Terminator */
+       {}
+};
+
+/*
+ * e1000_regdump - register printout routine
+ */
+static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
+{
+       int n = 0;
+       char rname[16];
+       u32 regs[8];
+
+       switch (reginfo->ofs) {
+       case E1000_RXDCTL(0):
+               for (n = 0; n < 2; n++)
+                       regs[n] = __er32(hw, E1000_RXDCTL(n));
+               break;
+       case E1000_TXDCTL(0):
+               for (n = 0; n < 2; n++)
+                       regs[n] = __er32(hw, E1000_TXDCTL(n));
+               break;
+       case E1000_TARC(0):
+               for (n = 0; n < 2; n++)
+                       regs[n] = __er32(hw, E1000_TARC(n));
+               break;
+       default:
+               printk(KERN_INFO "%-15s %08x\n",
+                       reginfo->name, __er32(hw, reginfo->ofs));
+               return;
+       }
+
+       snprintf(rname, 16, "%s%s", reginfo->name, "[0-1]");
+       printk(KERN_INFO "%-15s ", rname);
+       for (n = 0; n < 2; n++)
+               printk(KERN_CONT "%08x ", regs[n]);
+       printk(KERN_CONT "\n");
+}
+
+
+/*
+ * e1000e_dump - Print registers, tx-ring and rx-ring
+ */
+static void e1000e_dump(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+       struct e1000_reg_info *reginfo;
+       struct e1000_ring *tx_ring = adapter->tx_ring;
+       struct e1000_tx_desc *tx_desc;
+       struct my_u0 { u64 a; u64 b; } *u0;
+       struct e1000_buffer *buffer_info;
+       struct e1000_ring *rx_ring = adapter->rx_ring;
+       union e1000_rx_desc_packet_split *rx_desc_ps;
+       struct e1000_rx_desc *rx_desc;
+       struct my_u1 { u64 a; u64 b; u64 c; u64 d; } *u1;
+       u32 staterr;
+       int i = 0;
+
+       if (!netif_msg_hw(adapter))
+               return;
+
+       /* Print netdevice Info */
+       if (netdev) {
+               dev_info(&adapter->pdev->dev, "Net device Info\n");
+               printk(KERN_INFO "Device Name     state            "
+                       "trans_start      last_rx\n");
+               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
+                       netdev->name,
+                       netdev->state,
+                       netdev->trans_start,
+                       netdev->last_rx);
+       }
+
+       /* Print Registers */
+       dev_info(&adapter->pdev->dev, "Register Dump\n");
+       printk(KERN_INFO " Register Name   Value\n");
+       for (reginfo = (struct e1000_reg_info *)e1000_reg_info_tbl;
+            reginfo->name; reginfo++) {
+               e1000_regdump(hw, reginfo);
+       }
+
+       /* Print TX Ring Summary */
+       if (!netdev || !netif_running(netdev))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+               " leng ntw timestamp\n");
+       buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+       printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
+               0, tx_ring->next_to_use, tx_ring->next_to_clean,
+               (u64)buffer_info->dma,
+               buffer_info->length,
+               buffer_info->next_to_watch,
+               (u64)buffer_info->time_stamp);
+
+       /* Print TX Rings */
+       if (!netif_msg_tx_done(adapter))
+               goto rx_ring_summary;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+
+       /* Transmit Descriptor Formats - DEXT[29] is 0 (Legacy) or 1 (Extended)
+        *
+        * Legacy Transmit Descriptor
+        *   +--------------------------------------------------------------+
+        * 0 |         Buffer Address [63:0] (Reserved on Write Back)       |
+        *   +--------------------------------------------------------------+
+        * 8 | Special  |    CSS     | Status |  CMD    |  CSO   |  Length  |
+        *   +--------------------------------------------------------------+
+        *   63       48 47        36 35    32 31     24 23    16 15        0
+        *
+        * Extended Context Descriptor (DTYP=0x0) for TSO or checksum offload
+        *   63      48 47    40 39       32 31             16 15    8 7      0
+        *   +----------------------------------------------------------------+
+        * 0 |  TUCSE  | TUCS0  |   TUCSS   |     IPCSE       | IPCS0 | IPCSS |
+        *   +----------------------------------------------------------------+
+        * 8 |   MSS   | HDRLEN | RSV | STA | TUCMD | DTYP |      PAYLEN      |
+        *   +----------------------------------------------------------------+
+        *   63      48 47    40 39 36 35 32 31   24 23  20 19                0
+        *
+        * Extended Data Descriptor (DTYP=0x1)
+        *   +----------------------------------------------------------------+
+        * 0 |                     Buffer Address [63:0]                      |
+        *   +----------------------------------------------------------------+
+        * 8 | VLAN tag |  POPTS  | Rsvd | Status | Command | DTYP |  DTALEN  |
+        *   +----------------------------------------------------------------+
+        *   63       48 47     40 39  36 35    32 31     24 23  20 19        0
+        */
+       printk(KERN_INFO "Tl[desc]     [address 63:0  ] [SpeCssSCmCsLen]"
+               " [bi->dma       ] leng  ntw timestamp        bi->skb "
+               "<-- Legacy format\n");
+       printk(KERN_INFO "Tc[desc]     [Ce CoCsIpceCoS] [MssHlRSCm0Plen]"
+               " [bi->dma       ] leng  ntw timestamp        bi->skb "
+               "<-- Ext Context format\n");
+       printk(KERN_INFO "Td[desc]     [address 63:0  ] [VlaPoRSCm1Dlen]"
+               " [bi->dma       ] leng  ntw timestamp        bi->skb "
+               "<-- Ext Data format\n");
+       for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+               tx_desc = E1000_TX_DESC(*tx_ring, i);
+               buffer_info = &tx_ring->buffer_info[i];
+               u0 = (struct my_u0 *)tx_desc;
+               printk(KERN_INFO "T%c[0x%03X]    %016llX %016llX %016llX "
+                       "%04X  %3X %016llX %p",
+                      (!(le64_to_cpu(u0->b) & (1<<29)) ? 'l' :
+                       ((le64_to_cpu(u0->b) & (1<<20)) ? 'd' : 'c')), i,
+                      le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+                      (u64)buffer_info->dma, buffer_info->length,
+                      buffer_info->next_to_watch, (u64)buffer_info->time_stamp,
+                      buffer_info->skb);
+               if (i == tx_ring->next_to_use && i == tx_ring->next_to_clean)
+                       printk(KERN_CONT " NTC/U\n");
+               else if (i == tx_ring->next_to_use)
+                       printk(KERN_CONT " NTU\n");
+               else if (i == tx_ring->next_to_clean)
+                       printk(KERN_CONT " NTC\n");
+               else
+                       printk(KERN_CONT "\n");
+
+               if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+                       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
+                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       buffer_info->length, true);
+       }
+
+       /* Print RX Rings Summary */
+rx_ring_summary:
+       dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       printk(KERN_INFO " %5d %5X %5X\n", 0,
+               rx_ring->next_to_use, rx_ring->next_to_clean);
+
+       /* Print RX Rings */
+       if (!netif_msg_rx_status(adapter))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+       switch (adapter->rx_ps_pages) {
+       case 1:
+       case 2:
+       case 3:
+               /* [Extended] Packet Split Receive Descriptor Format
+                *
+                *    +-----------------------------------------------------+
+                *  0 |                Buffer Address 0 [63:0]              |
+                *    +-----------------------------------------------------+
+                *  8 |                Buffer Address 1 [63:0]              |
+                *    +-----------------------------------------------------+
+                * 16 |                Buffer Address 2 [63:0]              |
+                *    +-----------------------------------------------------+
+                * 24 |                Buffer Address 3 [63:0]              |
+                *    +-----------------------------------------------------+
+                */
+               printk(KERN_INFO "R  [desc]      [buffer 0 63:0 ] "
+                       "[buffer 1 63:0 ] "
+                      "[buffer 2 63:0 ] [buffer 3 63:0 ] [bi->dma       ] "
+                      "[bi->skb] <-- Ext Pkt Split format\n");
+               /* [Extended] Receive Descriptor (Write-Back) Format
+                *
+                *   63       48 47    32 31     13 12    8 7    4 3        0
+                *   +------------------------------------------------------+
+                * 0 | Packet   | IP     |  Rsvd   | MRQ   | Rsvd | MRQ RSS |
+                *   | Checksum | Ident  |         | Queue |      |  Type   |
+                *   +------------------------------------------------------+
+                * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+                *   +------------------------------------------------------+
+                *   63       48 47    32 31            20 19               0
+                */
+               printk(KERN_INFO "RWB[desc]      [ck ipid mrqhsh] "
+                       "[vl   l0 ee  es] "
+                      "[ l3  l2  l1 hs] [reserved      ] ---------------- "
+                      "[bi->skb] <-- Ext Rx Write-Back format\n");
+               for (i = 0; i < rx_ring->count; i++) {
+                       buffer_info = &rx_ring->buffer_info[i];
+                       rx_desc_ps = E1000_RX_DESC_PS(*rx_ring, i);
+                       u1 = (struct my_u1 *)rx_desc_ps;
+                       staterr =
+                               le32_to_cpu(rx_desc_ps->wb.middle.status_error);
+                       if (staterr & E1000_RXD_STAT_DD) {
+                               /* Descriptor Done */
+                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
+                                       "%016llX %016llX %016llX "
+                                       "---------------- %p", i,
+                                       le64_to_cpu(u1->a),
+                                       le64_to_cpu(u1->b),
+                                       le64_to_cpu(u1->c),
+                                       le64_to_cpu(u1->d),
+                                       buffer_info->skb);
+                       } else {
+                               printk(KERN_INFO "R  [0x%03X]     %016llX "
+                                       "%016llX %016llX %016llX %016llX %p", i,
+                                       le64_to_cpu(u1->a),
+                                       le64_to_cpu(u1->b),
+                                       le64_to_cpu(u1->c),
+                                       le64_to_cpu(u1->d),
+                                       (u64)buffer_info->dma,
+                                       buffer_info->skb);
+
+                               if (netif_msg_pktdata(adapter))
+                                       print_hex_dump(KERN_INFO, "",
+                                               DUMP_PREFIX_ADDRESS, 16, 1,
+                                               phys_to_virt(buffer_info->dma),
+                                               adapter->rx_ps_bsize0, true);
+                       }
+
+                       if (i == rx_ring->next_to_use)
+                               printk(KERN_CONT " NTU\n");
+                       else if (i == rx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC\n");
+                       else
+                               printk(KERN_CONT "\n");
+               }
+               break;
+       default:
+       case 0:
+               /* Legacy Receive Descriptor Format
+                *
+                * +-----------------------------------------------------+
+                * |                Buffer Address [63:0]                |
+                * +-----------------------------------------------------+
+                * | VLAN Tag | Errors | Status 0 | Packet csum | Length |
+                * +-----------------------------------------------------+
+                * 63       48 47    40 39      32 31         16 15      0
+                */
+               printk(KERN_INFO "Rl[desc]     [address 63:0  ] "
+                       "[vl er S cks ln] [bi->dma       ] [bi->skb] "
+                       "<-- Legacy format\n");
+               for (i = 0; rx_ring->desc && (i < rx_ring->count); i++) {
+                       rx_desc = E1000_RX_DESC(*rx_ring, i);
+                       buffer_info = &rx_ring->buffer_info[i];
+                       u0 = (struct my_u0 *)rx_desc;
+                       printk(KERN_INFO "Rl[0x%03X]    %016llX %016llX "
+                               "%016llX %p",
+                               i, le64_to_cpu(u0->a), le64_to_cpu(u0->b),
+                               (u64)buffer_info->dma, buffer_info->skb);
+                       if (i == rx_ring->next_to_use)
+                               printk(KERN_CONT " NTU\n");
+                       else if (i == rx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC\n");
+                       else
+                               printk(KERN_CONT "\n");
+
+                       if (netif_msg_pktdata(adapter))
+                               print_hex_dump(KERN_INFO, "",
+                                       DUMP_PREFIX_ADDRESS,
+                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       adapter->rx_buffer_len, true);
+               }
+       }
+
+exit:
+       return;
+}
+
 /**
  * e1000_desc_unused - calculate if we have unused descriptors
  **/
@@ -178,10 +536,10 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
 
                buffer_info->skb = skb;
 map_skb:
-               buffer_info->dma = pci_map_single(pdev, skb->data,
+               buffer_info->dma = dma_map_single(&pdev->dev, skb->data,
                                                  adapter->rx_buffer_len,
-                                                 PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+                                                 DMA_FROM_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
                        dev_err(&pdev->dev, "RX DMA map failed\n");
                        adapter->rx_dma_failed++;
                        break;
@@ -190,26 +548,23 @@ map_skb:
                rx_desc = E1000_RX_DESC(*rx_ring, i);
                rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
 
+               if (unlikely(!(i & (E1000_RX_BUFFER_WRITE - 1)))) {
+                       /*
+                        * 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();
+                       writel(i, adapter->hw.hw_addr + rx_ring->tail);
+               }
                i++;
                if (i == rx_ring->count)
                        i = 0;
                buffer_info = &rx_ring->buffer_info[i];
        }
 
-       if (rx_ring->next_to_use != i) {
-               rx_ring->next_to_use = i;
-               if (i-- == 0)
-                       i = (rx_ring->count - 1);
-
-               /*
-                * 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();
-               writel(i, adapter->hw.hw_addr + rx_ring->tail);
-       }
+       rx_ring->next_to_use = i;
 }
 
 /**
@@ -247,11 +602,12 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                                        adapter->alloc_rx_buff_failed++;
                                        goto no_buffers;
                                }
-                               ps_page->dma = pci_map_page(pdev,
-                                                  ps_page->page,
-                                                  0, PAGE_SIZE,
-                                                  PCI_DMA_FROMDEVICE);
-                               if (pci_dma_mapping_error(pdev, ps_page->dma)) {
+                               ps_page->dma = dma_map_page(&pdev->dev,
+                                                           ps_page->page,
+                                                           0, PAGE_SIZE,
+                                                           DMA_FROM_DEVICE);
+                               if (dma_mapping_error(&pdev->dev,
+                                                     ps_page->dma)) {
                                        dev_err(&adapter->pdev->dev,
                                          "RX DMA page map failed\n");
                                        adapter->rx_dma_failed++;
@@ -276,10 +632,10 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
                }
 
                buffer_info->skb = skb;
-               buffer_info->dma = pci_map_single(pdev, skb->data,
+               buffer_info->dma = dma_map_single(&pdev->dev, skb->data,
                                                  adapter->rx_ps_bsize0,
-                                                 PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+                                                 DMA_FROM_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
                        dev_err(&pdev->dev, "RX DMA map failed\n");
                        adapter->rx_dma_failed++;
                        /* cleanup skb */
@@ -290,6 +646,17 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
 
                rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
 
+               if (unlikely(!(i & (E1000_RX_BUFFER_WRITE - 1)))) {
+                       /*
+                        * 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();
+                       writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+               }
+
                i++;
                if (i == rx_ring->count)
                        i = 0;
@@ -297,26 +664,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
        }
 
 no_buffers:
-       if (rx_ring->next_to_use != i) {
-               rx_ring->next_to_use = i;
-
-               if (!(i--))
-                       i = (rx_ring->count - 1);
-
-               /*
-                * 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();
-               /*
-                * Hardware increments by 16 bytes, but packet split
-                * descriptors are 32 bytes...so we increment tail
-                * twice as much.
-                */
-               writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
-       }
+       rx_ring->next_to_use = i;
 }
 
 /**
@@ -366,10 +714,10 @@ check_page:
                }
 
                if (!buffer_info->dma)
-                       buffer_info->dma = pci_map_page(pdev,
+                       buffer_info->dma = dma_map_page(&pdev->dev,
                                                        buffer_info->page, 0,
                                                        PAGE_SIZE,
-                                                       PCI_DMA_FROMDEVICE);
+                                                       DMA_FROM_DEVICE);
 
                rx_desc = E1000_RX_DESC(*rx_ring, i);
                rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -443,10 +791,10 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
 
                cleaned = 1;
                cleaned_count++;
-               pci_unmap_single(pdev,
+               dma_unmap_single(&pdev->dev,
                                 buffer_info->dma,
                                 adapter->rx_buffer_len,
-                                PCI_DMA_FROMDEVICE);
+                                DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                length = le16_to_cpu(rx_desc->length);
@@ -547,12 +895,11 @@ static void e1000_put_txbuf(struct e1000_adapter *adapter,
 {
        if (buffer_info->dma) {
                if (buffer_info->mapped_as_page)
-                       pci_unmap_page(adapter->pdev, buffer_info->dma,
-                                      buffer_info->length, PCI_DMA_TODEVICE);
+                       dma_unmap_page(&adapter->pdev->dev, buffer_info->dma,
+                                      buffer_info->length, DMA_TO_DEVICE);
                else
-                       pci_unmap_single(adapter->pdev, buffer_info->dma,
-                                        buffer_info->length,
-                                        PCI_DMA_TODEVICE);
+                       dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
+                                        buffer_info->length, DMA_TO_DEVICE);
                buffer_info->dma = 0;
        }
        if (buffer_info->skb) {
@@ -643,14 +990,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
                        cleaned = (i == eop);
 
                        if (cleaned) {
-                               struct sk_buff *skb = buffer_info->skb;
-                               unsigned int segs, bytecount;
-                               segs = skb_shinfo(skb)->gso_segs ?: 1;
-                               /* multiply data chunks by size of headers */
-                               bytecount = ((segs - 1) * skb_headlen(skb)) +
-                                           skb->len;
-                               total_tx_packets += segs;
-                               total_tx_bytes += bytecount;
+                               total_tx_packets += buffer_info->segs;
+                               total_tx_bytes += buffer_info->bytecount;
                        }
 
                        e1000_put_txbuf(adapter, buffer_info);
@@ -753,9 +1094,9 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
 
                cleaned = 1;
                cleaned_count++;
-               pci_unmap_single(pdev, buffer_info->dma,
+               dma_unmap_single(&pdev->dev, buffer_info->dma,
                                 adapter->rx_ps_bsize0,
-                                PCI_DMA_FROMDEVICE);
+                                DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                /* see !EOP comment in other rx routine */
@@ -811,13 +1152,13 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                         * kmap_atomic, so we can't hold the mapping
                         * very long
                         */
-                       pci_dma_sync_single_for_cpu(pdev, ps_page->dma,
-                               PAGE_SIZE, PCI_DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(&pdev->dev, ps_page->dma,
+                                               PAGE_SIZE, DMA_FROM_DEVICE);
                        vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ);
                        memcpy(skb_tail_pointer(skb), vaddr, l1);
                        kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
-                       pci_dma_sync_single_for_device(pdev, ps_page->dma,
-                               PAGE_SIZE, PCI_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&pdev->dev, ps_page->dma,
+                                                  PAGE_SIZE, DMA_FROM_DEVICE);
 
                        /* remove the CRC */
                        if (!(adapter->flags2 & FLAG2_CRC_STRIPPING))
@@ -834,8 +1175,8 @@ static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
                                break;
 
                        ps_page = &buffer_info->ps_pages[j];
-                       pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
-                                      PCI_DMA_FROMDEVICE);
+                       dma_unmap_page(&pdev->dev, ps_page->dma, PAGE_SIZE,
+                                      DMA_FROM_DEVICE);
                        ps_page->dma = 0;
                        skb_fill_page_desc(skb, j, ps_page->page, 0, length);
                        ps_page->page = NULL;
@@ -953,8 +1294,8 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
 
                cleaned = true;
                cleaned_count++;
-               pci_unmap_page(pdev, buffer_info->dma, PAGE_SIZE,
-                              PCI_DMA_FROMDEVICE);
+               dma_unmap_page(&pdev->dev, buffer_info->dma, PAGE_SIZE,
+                              DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                length = le16_to_cpu(rx_desc->length);
@@ -1090,17 +1431,17 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
                buffer_info = &rx_ring->buffer_info[i];
                if (buffer_info->dma) {
                        if (adapter->clean_rx == e1000_clean_rx_irq)
-                               pci_unmap_single(pdev, buffer_info->dma,
+                               dma_unmap_single(&pdev->dev, buffer_info->dma,
                                                 adapter->rx_buffer_len,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        else if (adapter->clean_rx == e1000_clean_jumbo_rx_irq)
-                               pci_unmap_page(pdev, buffer_info->dma,
+                               dma_unmap_page(&pdev->dev, buffer_info->dma,
                                               PAGE_SIZE,
-                                              PCI_DMA_FROMDEVICE);
+                                              DMA_FROM_DEVICE);
                        else if (adapter->clean_rx == e1000_clean_rx_irq_ps)
-                               pci_unmap_single(pdev, buffer_info->dma,
+                               dma_unmap_single(&pdev->dev, buffer_info->dma,
                                                 adapter->rx_ps_bsize0,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        buffer_info->dma = 0;
                }
 
@@ -1118,8 +1459,8 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
                        ps_page = &buffer_info->ps_pages[j];
                        if (!ps_page->page)
                                break;
-                       pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
-                                      PCI_DMA_FROMDEVICE);
+                       dma_unmap_page(&pdev->dev, ps_page->dma, PAGE_SIZE,
+                                      DMA_FROM_DEVICE);
                        ps_page->dma = 0;
                        put_page(ps_page->page);
                        ps_page->page = NULL;
@@ -1426,8 +1767,6 @@ void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
                pci_disable_msi(adapter->pdev);
                adapter->flags &= ~FLAG_MSI_ENABLED;
        }
-
-       return;
 }
 
 /**
@@ -1479,8 +1818,6 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
                /* Don't do anything; this is the system default */
                break;
        }
-
-       return;
 }
 
 /**
@@ -2185,10 +2522,10 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter)
        }
 }
 
-static void e1000_init_manageability(struct e1000_adapter *adapter)
+static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u32 manc, manc2h;
+       u32 manc, manc2h, mdef, i, j;
 
        if (!(adapter->flags & FLAG_MNG_PT_ENABLED))
                return;
@@ -2202,10 +2539,49 @@ static void e1000_init_manageability(struct e1000_adapter *adapter)
         */
        manc |= E1000_MANC_EN_MNG2HOST;
        manc2h = er32(MANC2H);
-#define E1000_MNG2HOST_PORT_623 (1 << 5)
-#define E1000_MNG2HOST_PORT_664 (1 << 6)
-       manc2h |= E1000_MNG2HOST_PORT_623;
-       manc2h |= E1000_MNG2HOST_PORT_664;
+
+       switch (hw->mac.type) {
+       default:
+               manc2h |= (E1000_MANC2H_PORT_623 | E1000_MANC2H_PORT_664);
+               break;
+       case e1000_82574:
+       case e1000_82583:
+               /*
+                * Check if IPMI pass-through decision filter already exists;
+                * if so, enable it.
+                */
+               for (i = 0, j = 0; i < 8; i++) {
+                       mdef = er32(MDEF(i));
+
+                       /* Ignore filters with anything other than IPMI ports */
+                       if (mdef & !(E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664))
+                               continue;
+
+                       /* Enable this decision filter in MANC2H */
+                       if (mdef)
+                               manc2h |= (1 << i);
+
+                       j |= mdef;
+               }
+
+               if (j == (E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664))
+                       break;
+
+               /* Create new decision filter in an empty filter */
+               for (i = 0, j = 0; i < 8; i++)
+                       if (er32(MDEF(i)) == 0) {
+                               ew32(MDEF(i), (E1000_MDEF_PORT_623 |
+                                              E1000_MDEF_PORT_664));
+                               manc2h |= (1 << 1);
+                               j++;
+                               break;
+                       }
+
+               if (!j)
+                       e_warn("Unable to create IPMI pass-through filter\n");
+               break;
+       }
+
        ew32(MANC2H, manc2h);
        ew32(MANC, manc);
 }
@@ -2565,7 +2941,7 @@ static void e1000_set_multi(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u8  *mta_list;
        u32 rctl;
        int i;
@@ -2597,9 +2973,8 @@ static void e1000_set_multi(struct net_device *netdev)
 
                /* prepare a packed array of only addresses. */
                i = 0;
-               netdev_for_each_mc_addr(mc_ptr, netdev)
-                       memcpy(mta_list + (i++ * ETH_ALEN),
-                              mc_ptr->dmi_addr, ETH_ALEN);
+               netdev_for_each_mc_addr(ha, netdev)
+                       memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
 
                e1000_update_mc_addr_list(hw, mta_list, i);
                kfree(mta_list);
@@ -2621,7 +2996,7 @@ static void e1000_configure(struct e1000_adapter *adapter)
        e1000_set_multi(adapter->netdev);
 
        e1000_restore_vlan(adapter);
-       e1000_init_manageability(adapter);
+       e1000_init_manageability_pt(adapter);
 
        e1000_configure_tx(adapter);
        e1000_setup_rctl(adapter);
@@ -2755,6 +3130,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
                        fc->high_water = 0x5000;
                        fc->low_water  = 0x3000;
                }
+               fc->refresh_time = 0x1000;
        } else {
                if ((adapter->flags & FLAG_HAS_ERT) &&
                    (adapter->netdev->mtu > ETH_DATA_LEN))
@@ -2792,10 +3168,6 @@ void e1000e_reset(struct e1000_adapter *adapter)
        if (mac->ops.init_hw(hw))
                e_err("Hardware Error\n");
 
-       /* additional part of the flow-control workaround above */
-       if (hw->mac.type == e1000_pchlan)
-               ew32(FCRTV_PCH, 0x1000);
-
        e1000_update_mng_vlan(adapter);
 
        /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
@@ -2841,7 +3213,11 @@ int e1000e_up(struct e1000_adapter *adapter)
        netif_wake_queue(adapter->netdev);
 
        /* fire a link change interrupt to start the watchdog */
-       ew32(ICS, E1000_ICS_LSC);
+       if (adapter->msix_entries)
+               ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
+       else
+               ew32(ICS, E1000_ICS_LSC);
+
        return 0;
 }
 
@@ -3085,12 +3461,15 @@ static int e1000_open(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
+       struct pci_dev *pdev = adapter->pdev;
        int err;
 
        /* disallow open during test */
        if (test_bit(__E1000_TESTING, &adapter->state))
                return -EBUSY;
 
+       pm_runtime_get_sync(&pdev->dev);
+
        netif_carrier_off(netdev);
 
        /* allocate transmit descriptors */
@@ -3103,6 +3482,15 @@ static int e1000_open(struct net_device *netdev)
        if (err)
                goto err_setup_rx;
 
+       /*
+        * If AMT is enabled, let the firmware know that the network
+        * interface is now open and reset the part to a known state.
+        */
+       if (adapter->flags & FLAG_HAS_AMT) {
+               e1000_get_hw_control(adapter);
+               e1000e_reset(adapter);
+       }
+
        e1000e_power_up_phy(adapter);
 
        adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
@@ -3110,13 +3498,6 @@ static int e1000_open(struct net_device *netdev)
             E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
                e1000_update_mng_vlan(adapter);
 
-       /*
-        * If AMT is enabled, let the firmware know that the network
-        * interface is now open
-        */
-       if (adapter->flags & FLAG_HAS_AMT)
-               e1000_get_hw_control(adapter);
-
        /*
         * before we allocate an interrupt, we must be ready to handle it.
         * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -3151,8 +3532,14 @@ static int e1000_open(struct net_device *netdev)
 
        netif_start_queue(netdev);
 
+       adapter->idle_check = true;
+       pm_runtime_put(&pdev->dev);
+
        /* fire a link status change interrupt to start the watchdog */
-       ew32(ICS, E1000_ICS_LSC);
+       if (adapter->msix_entries)
+               ew32(ICS, E1000_ICS_LSC | E1000_ICR_OTHER);
+       else
+               ew32(ICS, E1000_ICS_LSC);
 
        return 0;
 
@@ -3164,6 +3551,7 @@ err_setup_rx:
        e1000e_free_tx_resources(adapter);
 err_setup_tx:
        e1000e_reset(adapter);
+       pm_runtime_put_sync(&pdev->dev);
 
        return err;
 }
@@ -3182,11 +3570,17 @@ err_setup_tx:
 static int e1000_close(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct pci_dev *pdev = adapter->pdev;
 
        WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
-       e1000e_down(adapter);
+
+       pm_runtime_get_sync(&pdev->dev);
+
+       if (!test_bit(__E1000_DOWN, &adapter->state)) {
+               e1000e_down(adapter);
+               e1000_free_irq(adapter);
+       }
        e1000_power_down_phy(adapter);
-       e1000_free_irq(adapter);
 
        e1000e_free_tx_resources(adapter);
        e1000e_free_rx_resources(adapter);
@@ -3208,6 +3602,8 @@ static int e1000_close(struct net_device *netdev)
        if (adapter->flags & FLAG_HAS_AMT)
                e1000_release_hw_control(adapter);
 
+       pm_runtime_put_sync(&pdev->dev);
+
        return 0;
 }
 /**
@@ -3552,6 +3948,9 @@ static void e1000_watchdog_task(struct work_struct *work)
 
        link = e1000e_has_link(adapter);
        if ((netif_carrier_ok(netdev)) && link) {
+               /* Cancel scheduled suspend requests. */
+               pm_runtime_resume(netdev->dev.parent);
+
                e1000e_enable_receives(adapter);
                goto link_up;
        }
@@ -3563,6 +3962,10 @@ static void e1000_watchdog_task(struct work_struct *work)
        if (link) {
                if (!netif_carrier_ok(netdev)) {
                        bool txb2b = 1;
+
+                       /* Cancel scheduled suspend requests. */
+                       pm_runtime_resume(netdev->dev.parent);
+
                        /* update snapshot of PHY registers on LSC */
                        e1000_phy_read_status(adapter);
                        mac->ops.get_link_up_info(&adapter->hw,
@@ -3672,6 +4075,9 @@ static void e1000_watchdog_task(struct work_struct *work)
 
                        if (adapter->flags & FLAG_RX_NEEDS_RESTART)
                                schedule_work(&adapter->reset_task);
+                       else
+                               pm_schedule_suspend(netdev->dev.parent,
+                                                       LINK_TIMEOUT);
                }
        }
 
@@ -3707,6 +4113,22 @@ link_up:
                }
        }
 
+       /* Simple mode for Interrupt Throttle Rate (ITR) */
+       if (adapter->itr_setting == 4) {
+               /*
+                * Symmetric Tx/Rx gets a reduced ITR=2000;
+                * Total asymmetrical Tx or Rx gets ITR=8000;
+                * everyone else is between 2000-8000.
+                */
+               u32 goc = (adapter->gotc + adapter->gorc) / 10000;
+               u32 dif = (adapter->gotc > adapter->gorc ?
+                           adapter->gotc - adapter->gorc :
+                           adapter->gorc - adapter->gotc) / 10000;
+               u32 itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000;
+
+               ew32(ITR, 1000000000 / (itr * 256));
+       }
+
        /* Cause software interrupt to ensure Rx ring is cleaned */
        if (adapter->msix_entries)
                ew32(ICS, adapter->rx_ring->ims_val);
@@ -3881,7 +4303,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
        struct e1000_buffer *buffer_info;
        unsigned int len = skb_headlen(skb);
        unsigned int offset = 0, size, count = 0, i;
-       unsigned int f;
+       unsigned int f, bytecount, segs;
 
        i = tx_ring->next_to_use;
 
@@ -3892,10 +4314,11 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                buffer_info->length = size;
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
-               buffer_info->dma = pci_map_single(pdev, skb->data + offset,
-                                                 size, PCI_DMA_TODEVICE);
+               buffer_info->dma = dma_map_single(&pdev->dev,
+                                                 skb->data + offset,
+                                                 size, DMA_TO_DEVICE);
                buffer_info->mapped_as_page = false;
-               if (pci_dma_mapping_error(pdev, buffer_info->dma))
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                        goto dma_error;
 
                len -= size;
@@ -3927,11 +4350,11 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                        buffer_info->length = size;
                        buffer_info->time_stamp = jiffies;
                        buffer_info->next_to_watch = i;
-                       buffer_info->dma = pci_map_page(pdev, frag->page,
+                       buffer_info->dma = dma_map_page(&pdev->dev, frag->page,
                                                        offset, size,
-                                                       PCI_DMA_TODEVICE);
+                                                       DMA_TO_DEVICE);
                        buffer_info->mapped_as_page = true;
-                       if (pci_dma_mapping_error(pdev, buffer_info->dma))
+                       if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                                goto dma_error;
 
                        len -= size;
@@ -3940,7 +4363,13 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                }
        }
 
+       segs = skb_shinfo(skb)->gso_segs ?: 1;
+       /* multiply data chunks by size of headers */
+       bytecount = ((segs - 1) * skb_headlen(skb)) + skb->len;
+
        tx_ring->buffer_info[i].skb = skb;
+       tx_ring->buffer_info[i].segs = segs;
+       tx_ring->buffer_info[i].bytecount = bytecount;
        tx_ring->buffer_info[first].next_to_watch = i;
 
        return count;
@@ -4107,7 +4536,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
        unsigned int max_per_txd = E1000_MAX_PER_TXD;
        unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
        unsigned int tx_flags = 0;
-       unsigned int len = skb->len - skb->data_len;
+       unsigned int len = skb_headlen(skb);
        unsigned int nr_frags;
        unsigned int mss;
        int count = 0;
@@ -4157,7 +4586,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
                                dev_kfree_skb_any(skb);
                                return NETDEV_TX_OK;
                        }
-                       len = skb->len - skb->data_len;
+                       len = skb_headlen(skb);
                }
        }
 
@@ -4243,6 +4672,8 @@ static void e1000_reset_task(struct work_struct *work)
        struct e1000_adapter *adapter;
        adapter = container_of(work, struct e1000_adapter, reset_task);
 
+       e1000e_dump(adapter);
+       e_err("Reset adapter\n");
        e1000e_reinit_locked(adapter);
 }
 
@@ -4477,13 +4908,15 @@ out:
        return retval;
 }
 
-static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
+static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake,
+                           bool runtime)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        u32 ctrl, ctrl_ext, rctl, status;
-       u32 wufc = adapter->wol;
+       /* Runtime suspend should only enable wakeup for link changes */
+       u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
        int retval = 0;
 
        netif_device_detach(netdev);
@@ -4653,20 +5086,13 @@ void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
        __e1000e_disable_aspm(pdev, state);
 }
 
-#ifdef CONFIG_PM
-static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
+#ifdef CONFIG_PM_OPS
+static bool e1000e_pm_ready(struct e1000_adapter *adapter)
 {
-       int retval;
-       bool wake;
-
-       retval = __e1000_shutdown(pdev, &wake);
-       if (!retval)
-               e1000_complete_shutdown(pdev, true, wake);
-
-       return retval;
+       return !!adapter->tx_ring->buffer_info;
 }
 
-static int e1000_resume(struct pci_dev *pdev)
+static int __e1000_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -4679,18 +5105,6 @@ static int e1000_resume(struct pci_dev *pdev)
        if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1)
                e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
 
-       err = pci_enable_device_mem(pdev);
-       if (err) {
-               dev_err(&pdev->dev,
-                       "Cannot enable PCI device from suspend\n");
-               return err;
-       }
-
-       pci_set_master(pdev);
-
-       pci_enable_wake(pdev, PCI_D3hot, 0);
-       pci_enable_wake(pdev, PCI_D3cold, 0);
-
        e1000e_set_interrupt_capability(adapter);
        if (netif_running(netdev)) {
                err = e1000_request_irq(adapter);
@@ -4731,7 +5145,7 @@ static int e1000_resume(struct pci_dev *pdev)
 
        e1000e_reset(adapter);
 
-       e1000_init_manageability(adapter);
+       e1000_init_manageability_pt(adapter);
 
        if (netif_running(netdev))
                e1000e_up(adapter);
@@ -4748,13 +5162,88 @@ static int e1000_resume(struct pci_dev *pdev)
 
        return 0;
 }
-#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int e1000_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       int retval;
+       bool wake;
+
+       retval = __e1000_shutdown(pdev, &wake, false);
+       if (!retval)
+               e1000_complete_shutdown(pdev, true, wake);
+
+       return retval;
+}
+
+static int e1000_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       if (e1000e_pm_ready(adapter))
+               adapter->idle_check = true;
+
+       return __e1000_resume(pdev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int e1000_runtime_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       if (e1000e_pm_ready(adapter)) {
+               bool wake;
+
+               __e1000_shutdown(pdev, &wake, true);
+       }
+
+       return 0;
+}
+
+static int e1000_idle(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       if (!e1000e_pm_ready(adapter))
+               return 0;
+
+       if (adapter->idle_check) {
+               adapter->idle_check = false;
+               if (!e1000e_has_link(adapter))
+                       pm_schedule_suspend(dev, MSEC_PER_SEC);
+       }
+
+       return -EBUSY;
+}
+
+static int e1000_runtime_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       if (!e1000e_pm_ready(adapter))
+               return 0;
+
+       adapter->idle_check = !dev->power.runtime_auto;
+       return __e1000_resume(pdev);
+}
+#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM_OPS */
 
 static void e1000_shutdown(struct pci_dev *pdev)
 {
        bool wake = false;
 
-       __e1000_shutdown(pdev, &wake);
+       __e1000_shutdown(pdev, &wake, false);
 
        if (system_state == SYSTEM_POWER_OFF)
                e1000_complete_shutdown(pdev, false, wake);
@@ -4828,8 +5317,8 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
                result = PCI_ERS_RESULT_DISCONNECT;
        } else {
                pci_set_master(pdev);
+               pdev->state_saved = true;
                pci_restore_state(pdev);
-               pci_save_state(pdev);
 
                pci_enable_wake(pdev, PCI_D3hot, 0);
                pci_enable_wake(pdev, PCI_D3cold, 0);
@@ -4857,7 +5346,7 @@ static void e1000_io_resume(struct pci_dev *pdev)
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       e1000_init_manageability(adapter);
+       e1000_init_manageability_pt(adapter);
 
        if (netif_running(netdev)) {
                if (e1000e_up(adapter)) {
@@ -4970,16 +5459,16 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
                return err;
 
        pci_using_dac = 0;
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
        if (!err) {
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
                if (!err)
                        pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = pci_set_consistent_dma_mask(pdev,
-                                                         DMA_BIT_MASK(32));
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
                        if (err) {
                                dev_err(&pdev->dev, "No usable DMA "
                                        "configuration, aborting\n");
@@ -5010,6 +5499,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        SET_NETDEV_DEV(netdev, &pdev->dev);
 
+       netdev->irq = pdev->irq;
+
        pci_set_drvdata(pdev, netdev);
        adapter = netdev_priv(netdev);
        hw = &adapter->hw;
@@ -5230,6 +5721,12 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        e1000_print_device_info(adapter);
 
+       if (pci_dev_run_wake(pdev)) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_enable(&pdev->dev);
+       }
+       pm_schedule_suspend(&pdev->dev, MSEC_PER_SEC);
+
        return 0;
 
 err_register:
@@ -5272,12 +5769,16 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
+       bool down = test_bit(__E1000_DOWN, &adapter->state);
+
+       pm_runtime_get_sync(&pdev->dev);
 
        /*
         * flush_scheduled work may reschedule our watchdog task, so
         * explicitly disable watchdog tasks from being rescheduled
         */
-       set_bit(__E1000_DOWN, &adapter->state);
+       if (!down)
+               set_bit(__E1000_DOWN, &adapter->state);
        del_timer_sync(&adapter->watchdog_timer);
        del_timer_sync(&adapter->phy_info_timer);
 
@@ -5291,8 +5792,17 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
        if (!(netdev->flags & IFF_UP))
                e1000_power_down_phy(adapter);
 
+       /* Don't lie to e1000_close() down the road. */
+       if (!down)
+               clear_bit(__E1000_DOWN, &adapter->state);
        unregister_netdev(netdev);
 
+       if (pci_dev_run_wake(pdev)) {
+               pm_runtime_disable(&pdev->dev);
+               pm_runtime_set_suspended(&pdev->dev);
+       }
+       pm_runtime_put_noidle(&pdev->dev);
+
        /*
         * Release control of h/w to f/w.  If f/w is AMT enabled, this
         * would have already happened in close and is redundant.
@@ -5382,6 +5892,7 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
 
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_V), board_ich10lan },
 
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LM), board_pchlan },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_M_HV_LC), board_pchlan },
@@ -5392,16 +5903,22 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
 };
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
 
+#ifdef CONFIG_PM_OPS
+static const struct dev_pm_ops e1000_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume)
+       SET_RUNTIME_PM_OPS(e1000_runtime_suspend,
+                               e1000_runtime_resume, e1000_idle)
+};
+#endif
+
 /* PCI Device API Driver */
 static struct pci_driver e1000_driver = {
        .name     = e1000e_driver_name,
        .id_table = e1000_pci_tbl,
        .probe    = e1000_probe,
        .remove   = __devexit_p(e1000_remove),
-#ifdef CONFIG_PM
-       /* Power Management Hooks */
-       .suspend  = e1000_suspend,
-       .resume   = e1000_resume,
+#ifdef CONFIG_PM_OPS
+       .driver.pm = &e1000_pm_ops,
 #endif
        .shutdown = e1000_shutdown,
        .err_handler = &e1000_err_handler
@@ -5416,10 +5933,9 @@ static struct pci_driver e1000_driver = {
 static int __init e1000_init_module(void)
 {
        int ret;
-       printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n",
-              e1000e_driver_name, e1000e_driver_version);
-       printk(KERN_INFO "%s: Copyright (c) 1999 - 2009 Intel Corporation.\n",
-              e1000e_driver_name);
+       pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
+               e1000e_driver_version);
+       pr_info("Copyright (c) 1999 - 2009 Intel Corporation.\n");
        ret = pci_register_driver(&e1000_driver);
 
        return ret;
index 2e399778cae5bc2cc84303ecf3436cd1bc9fcadb..a150e48a117f2da94ff73727252263672e51bb8f 100644 (file)
@@ -248,7 +248,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
        }
 
        { /* Transmit Interrupt Delay */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = range_option,
                        .name = "Transmit Interrupt Delay",
                        .err  = "using default of "
@@ -267,7 +267,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Transmit Absolute Interrupt Delay */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = range_option,
                        .name = "Transmit Absolute Interrupt Delay",
                        .err  = "using default of "
@@ -286,7 +286,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Receive Interrupt Delay */
-               struct e1000_option opt = {
+               static struct e1000_option opt = {
                        .type = range_option,
                        .name = "Receive Interrupt Delay",
                        .err  = "using default of "
@@ -305,7 +305,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Receive Absolute Interrupt Delay */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = range_option,
                        .name = "Receive Absolute Interrupt Delay",
                        .err  = "using default of "
@@ -324,7 +324,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Interrupt Throttling Rate */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = range_option,
                        .name = "Interrupt Throttling Rate (ints/sec)",
                        .err  = "using default of "
@@ -351,6 +351,11 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                                adapter->itr_setting = adapter->itr;
                                adapter->itr = 20000;
                                break;
+                       case 4:
+                               e_info("%s set to simplified (2000-8000 ints) "
+                                      "mode\n", opt.name);
+                               adapter->itr_setting = 4;
+                               break;
                        default:
                                /*
                                 * Save the setting, because the dynamic bits
@@ -381,7 +386,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Interrupt Mode */
-               struct e1000_option opt = {
+               static struct e1000_option opt = {
                        .type = range_option,
                        .name = "Interrupt Mode",
                        .err  = "defaulting to 2 (MSI-X)",
@@ -399,7 +404,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Smart Power Down */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = enable_option,
                        .name = "PHY Smart Power Down",
                        .err  = "defaulting to Disabled",
@@ -415,7 +420,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* CRC Stripping */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = enable_option,
                        .name = "CRC Stripping",
                        .err  = "defaulting to enabled",
@@ -432,7 +437,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Kumeran Lock Loss Workaround */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = enable_option,
                        .name = "Kumeran Lock Loss Workaround",
                        .err  = "defaulting to Enabled",
@@ -452,7 +457,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
                }
        }
        { /* Write-protect NVM */
-               const struct e1000_option opt = {
+               static const struct e1000_option opt = {
                        .type = enable_option,
                        .name = "Write-protect NVM",
                        .err  = "defaulting to Enabled",
index 7f3ceb9dad6a3c1d7982cde8996ab8e4e7501cf8..b4ac82d51b2016809a2aee7e1dd61cb644868d5e 100644 (file)
@@ -3116,9 +3116,7 @@ s32 e1000_check_polarity_82577(struct e1000_hw *hw)
  *  e1000_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY
  *  @hw: pointer to the HW structure
  *
- *  Calls the PHY setup function to force speed and duplex.  Clears the
- *  auto-crossover to force MDI manually.  Waits for link and returns
- *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ *  Calls the PHY setup function to force speed and duplex.
  **/
 s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
 {
@@ -3137,23 +3135,6 @@ s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw)
        if (ret_val)
                goto out;
 
-       /*
-        * Clear Auto-Crossover to force MDI manually.  82577 requires MDI
-        * forced whenever speed and duplex are forced.
-        */
-       ret_val = phy->ops.read_reg(hw, I82577_PHY_CTRL_2, &phy_data);
-       if (ret_val)
-               goto out;
-
-       phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX;
-       phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX;
-
-       ret_val = phy->ops.write_reg(hw, I82577_PHY_CTRL_2, phy_data);
-       if (ret_val)
-               goto out;
-
-       e_dbg("I82577_PHY_CTRL_2: %X\n", phy_data);
-
        udelay(1);
 
        if (phy->autoneg_wait_to_complete) {
index ca93c9a9d372dd48510feb4fd57f9dc1a12bb931..06e72fbef86207f52ce4737d9a3f496aef0b7060 100644 (file)
@@ -328,7 +328,6 @@ e21_reset_8390(struct net_device *dev)
        /* Set up the ASIC registers, just in case something changed them. */
 
        if (ei_debug > 1) printk("reset done\n");
-       return;
 }
 
 /* Grab the 8390 specific header. We put the 2k window so the header page
index 27c7bdbfa0030a2d6274716d6c91eaa0fb926341..8d97f168f018734bcaeb1af1372b77ba9fca2eef 100644 (file)
@@ -645,7 +645,7 @@ static void __init printEEPROMInfo(struct net_device *dev)
        if (GetBit(Word,ee_PortTPE)) printk(KERN_DEBUG "TPE ");
        if (GetBit(Word,ee_PortBNC)) printk(KERN_DEBUG "BNC ");
        if (GetBit(Word,ee_PortAUI)) printk(KERN_DEBUG "AUI ");
-       printk(KERN_DEBUG "port(s) \n");
+       printk(KERN_DEBUG "port(s)\n");
 
        Word = lp->word[6];
        printk(KERN_DEBUG "Word6:\n");
@@ -765,7 +765,7 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
        /* Grab the region so we can find another board if autoIRQ fails. */
        if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
                if (!autoprobe)
-                       printk(KERN_WARNING "EEPRO: io-port 0x%04x in use \n",
+                       printk(KERN_WARNING "EEPRO: io-port 0x%04x in use\n",
                                ioaddr);
                return -EBUSY;
        }
@@ -1161,8 +1161,7 @@ static netdev_tx_t eepro_send_packet(struct sk_buff *skb,
                        /* we won't wake queue here because we're out of space */
                        dev->stats.tx_dropped++;
                else {
-               dev->stats.tx_bytes+=skb->len;
-               dev->trans_start = jiffies;
+                       dev->stats.tx_bytes+=skb->len;
                        netif_wake_queue(dev);
                }
 
@@ -1286,7 +1285,7 @@ set_multicast_list(struct net_device *dev)
        struct eepro_local *lp = netdev_priv(dev);
        short ioaddr = dev->base_addr;
        unsigned short mode;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int mc_count = netdev_mc_count(dev);
 
        if (dev->flags&(IFF_ALLMULTI|IFF_PROMISC) || mc_count > 63)
@@ -1331,8 +1330,8 @@ set_multicast_list(struct net_device *dev)
                outw(0, ioaddr + IO_PORT);
                outw(6 * (mc_count + 1), ioaddr + IO_PORT);
 
-               netdev_for_each_mc_addr(dmi, dev) {
-                       eaddrs = (unsigned short *) dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       eaddrs = (unsigned short *) ha->addr;
                        outw(*eaddrs++, ioaddr + IO_PORT);
                        outw(*eaddrs++, ioaddr + IO_PORT);
                        outw(*eaddrs++, ioaddr + IO_PORT);
index 1a7322b80ea7e6dfee43d84f7a0d793753d26fdd..12c37d264108fec7290900d89cab3a63806f1f35 100644 (file)
@@ -543,7 +543,7 @@ static void unstick_cu(struct net_device *dev)
 
        if (lp->started)
        {
-               if (time_after(jiffies, dev->trans_start + 50))
+               if (time_after(jiffies, dev_trans_start(dev) + HZ/2))
                {
                        if (lp->tx_link==lp->last_tx_restart)
                        {
@@ -1018,7 +1018,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
        outw(lp->tx_head+0x16, ioaddr + DATAPORT);
        outw(0, ioaddr + DATAPORT);
 
-        outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
+       outsw(ioaddr + DATAPORT, buf, (len+1)>>1);
 
        outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);
        outw(lp->tx_head, ioaddr + DATAPORT);
@@ -1570,12 +1570,11 @@ static void eexp_hw_init586(struct net_device *dev)
 #if NET_DEBUG > 6
         printk("%s: leaving eexp_hw_init586()\n", dev->name);
 #endif
-       return;
 }
 
 static void eexp_setup_filter(struct net_device *dev)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned short ioaddr = dev->base_addr;
        int count = netdev_mc_count(dev);
        int i;
@@ -1588,8 +1587,8 @@ static void eexp_setup_filter(struct net_device *dev)
        outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
        outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST));
        i = 0;
-       netdev_for_each_mc_addr(dmi, dev) {
-               unsigned short *data = (unsigned short *) dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               unsigned short *data = (unsigned short *) ha->addr;
 
                if (i == count)
                        break;
index fa311a950996720895026f7e3e9d079165f5759c..0630980a27222ce31ab4bb77d8af754d5ddc0c09 100644 (file)
@@ -40,7 +40,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ehea"
-#define DRV_VERSION    "EHEA_0102"
+#define DRV_VERSION    "EHEA_0103"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
index 809ccc9ff09cc8913a8e19ab1982cf76e7d69000..02698a1c80b057a4f57eba4e5e72f40c2c7da293 100644 (file)
@@ -791,11 +791,17 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
                cqe_counter++;
                rmb();
                if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
-                       ehea_error("Send Completion Error: Resetting port");
+                       ehea_error("Bad send completion status=0x%04X",
+                                  cqe->status);
+
                        if (netif_msg_tx_err(pr->port))
                                ehea_dump(cqe, sizeof(*cqe), "Send CQE");
-                       ehea_schedule_port_reset(pr->port);
-                       break;
+
+                       if (cqe->status & EHEA_CQE_STAT_RESET_MASK) {
+                               ehea_error("Resetting port");
+                               ehea_schedule_port_reset(pr->port);
+                               break;
+                       }
                }
 
                if (netif_msg_tx_done(pr->port))
@@ -814,7 +820,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
                quota--;
 
                cqe = ehea_poll_cq(send_cq);
-       };
+       }
 
        ehea_update_feca(send_cq, cqe_counter);
        atomic_add(swqe_av, &pr->swqe_avail);
@@ -901,6 +907,8 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
        struct ehea_eqe *eqe;
        struct ehea_qp *qp;
        u32 qp_token;
+       u64 resource_type, aer, aerr;
+       int reset_port = 0;
 
        eqe = ehea_poll_eq(port->qp_eq);
 
@@ -910,11 +918,24 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
                           eqe->entry, qp_token);
 
                qp = port->port_res[qp_token].qp;
-               ehea_error_data(port->adapter, qp->fw_handle);
+
+               resource_type = ehea_error_data(port->adapter, qp->fw_handle,
+                                               &aer, &aerr);
+
+               if (resource_type == EHEA_AER_RESTYPE_QP) {
+                       if ((aer & EHEA_AER_RESET_MASK) ||
+                           (aerr & EHEA_AERR_RESET_MASK))
+                                reset_port = 1;
+               } else
+                       reset_port = 1;   /* Reset in case of CQ or EQ error */
+
                eqe = ehea_poll_eq(port->qp_eq);
        }
 
-       ehea_schedule_port_reset(port);
+       if (reset_port) {
+               ehea_error("Resetting port");
+               ehea_schedule_port_reset(port);
+       }
 
        return IRQ_HANDLED;
 }
@@ -1618,7 +1639,7 @@ static void write_swqe2_TSO(struct sk_buff *skb,
 {
        struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
        u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
-       int skb_data_size = skb->len - skb->data_len;
+       int skb_data_size = skb_headlen(skb);
        int headersize;
 
        /* Packet is TCP with TSO enabled */
@@ -1629,7 +1650,7 @@ static void write_swqe2_TSO(struct sk_buff *skb,
         */
        headersize = ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
 
-       skb_data_size = skb->len - skb->data_len;
+       skb_data_size = skb_headlen(skb);
 
        if (skb_data_size >= headersize) {
                /* copy immediate data */
@@ -1651,7 +1672,7 @@ static void write_swqe2_TSO(struct sk_buff *skb,
 static void write_swqe2_nonTSO(struct sk_buff *skb,
                               struct ehea_swqe *swqe, u32 lkey)
 {
-       int skb_data_size = skb->len - skb->data_len;
+       int skb_data_size = skb_headlen(skb);
        u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
        struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
 
@@ -1860,7 +1881,6 @@ static void ehea_promiscuous(struct net_device *dev, int enable)
        port->promisc = enable;
 out:
        free_page((unsigned long)cb7);
-       return;
 }
 
 static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
@@ -1967,7 +1987,7 @@ static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
 static void ehea_set_multicast_list(struct net_device *dev)
 {
        struct ehea_port *port = netdev_priv(dev);
-       struct dev_mc_list *k_mcl_entry;
+       struct netdev_hw_addr *ha;
        int ret;
 
        if (dev->flags & IFF_PROMISC) {
@@ -1998,13 +2018,12 @@ static void ehea_set_multicast_list(struct net_device *dev)
                        goto out;
                }
 
-               netdev_for_each_mc_addr(k_mcl_entry, dev)
-                       ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       ehea_add_multicast_entry(port, ha->addr);
 
        }
 out:
        ehea_update_bcmc_registrations();
-       return;
 }
 
 static int ehea_change_mtu(struct net_device *dev, int new_mtu)
@@ -2108,8 +2127,8 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
        } else {
                /* first copy data from the skb->data buffer ... */
                skb_copy_from_linear_data(skb, imm_data,
-                                         skb->len - skb->data_len);
-               imm_data += skb->len - skb->data_len;
+                                         skb_headlen(skb));
+               imm_data += skb_headlen(skb);
 
                /* ... then copy data from the fragments */
                for (i = 0; i < nfrags; i++) {
@@ -2220,7 +2239,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
                spin_unlock_irqrestore(&pr->netif_queue, flags);
        }
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
        spin_unlock(&pr->xmit_lock);
 
        return NETDEV_TX_OK;
@@ -2317,7 +2336,6 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
                ehea_error("modify_ehea_port failed");
 out:
        free_page((unsigned long)cb1);
-       return;
 }
 
 int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
@@ -2860,7 +2878,6 @@ static void ehea_reset_port(struct work_struct *work)
        netif_wake_queue(dev);
 out:
        mutex_unlock(&port->port_lock);
-       return;
 }
 
 static void ehea_rereg_mrs(struct work_struct *work)
@@ -2868,7 +2885,6 @@ static void ehea_rereg_mrs(struct work_struct *work)
        int ret, i;
        struct ehea_adapter *adapter;
 
-       mutex_lock(&dlpar_mem_lock);
        ehea_info("LPAR memory changed - re-initializing driver");
 
        list_for_each_entry(adapter, &adapter_list, list)
@@ -2938,7 +2954,6 @@ static void ehea_rereg_mrs(struct work_struct *work)
                }
        ehea_info("re-initializing driver complete");
 out:
-       mutex_unlock(&dlpar_mem_lock);
        return;
 }
 
@@ -3238,7 +3253,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
                        ehea_remove_adapter_mr(adapter);
 
                i++;
-       };
+       }
        return 0;
 }
 
@@ -3257,7 +3272,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
                if (dn_log_port_id)
                        if (*dn_log_port_id == logical_port_id)
                                return eth_dn;
-       };
+       }
 
        return NULL;
 }
@@ -3521,7 +3536,14 @@ void ehea_crash_handler(void)
 static int ehea_mem_notifier(struct notifier_block *nb,
                              unsigned long action, void *data)
 {
+       int ret = NOTIFY_BAD;
        struct memory_notify *arg = data;
+
+       if (!mutex_trylock(&dlpar_mem_lock)) {
+               ehea_info("ehea_mem_notifier must not be called parallelized");
+               goto out;
+       }
+
        switch (action) {
        case MEM_CANCEL_OFFLINE:
                ehea_info("memory offlining canceled");
@@ -3530,14 +3552,14 @@ static int ehea_mem_notifier(struct notifier_block *nb,
                ehea_info("memory is going online");
                set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
                if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       return NOTIFY_BAD;
+                       goto out_unlock;
                ehea_rereg_mrs(NULL);
                break;
        case MEM_GOING_OFFLINE:
                ehea_info("memory is going offline");
                set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
                if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
-                       return NOTIFY_BAD;
+                       goto out_unlock;
                ehea_rereg_mrs(NULL);
                break;
        default:
@@ -3545,8 +3567,12 @@ static int ehea_mem_notifier(struct notifier_block *nb,
        }
 
        ehea_update_firmware_handles();
+       ret = NOTIFY_OK;
 
-       return NOTIFY_OK;
+out_unlock:
+       mutex_unlock(&dlpar_mem_lock);
+out:
+       return ret;
 }
 
 static struct notifier_block ehea_mem_nb = {
index a1b4c7e563679f854b698e7f5f5f0f585a2d9fa6..89128b6373e3a16eaf945ff94f7b849cbcb8dc64 100644 (file)
@@ -229,14 +229,14 @@ u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
 
 int ehea_destroy_cq(struct ehea_cq *cq)
 {
-       u64 hret;
+       u64 hret, aer, aerr;
        if (!cq)
                return 0;
 
        hcp_epas_dtor(&cq->epas);
        hret = ehea_destroy_cq_res(cq, NORMAL_FREE);
        if (hret == H_R_STATE) {
-               ehea_error_data(cq->adapter, cq->fw_handle);
+               ehea_error_data(cq->adapter, cq->fw_handle, &aer, &aerr);
                hret = ehea_destroy_cq_res(cq, FORCE_FREE);
        }
 
@@ -357,7 +357,7 @@ u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
 
 int ehea_destroy_eq(struct ehea_eq *eq)
 {
-       u64 hret;
+       u64 hret, aer, aerr;
        if (!eq)
                return 0;
 
@@ -365,7 +365,7 @@ int ehea_destroy_eq(struct ehea_eq *eq)
 
        hret = ehea_destroy_eq_res(eq, NORMAL_FREE);
        if (hret == H_R_STATE) {
-               ehea_error_data(eq->adapter, eq->fw_handle);
+               ehea_error_data(eq->adapter, eq->fw_handle, &aer, &aerr);
                hret = ehea_destroy_eq_res(eq, FORCE_FREE);
        }
 
@@ -540,7 +540,7 @@ u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
 
 int ehea_destroy_qp(struct ehea_qp *qp)
 {
-       u64 hret;
+       u64 hret, aer, aerr;
        if (!qp)
                return 0;
 
@@ -548,7 +548,7 @@ int ehea_destroy_qp(struct ehea_qp *qp)
 
        hret = ehea_destroy_qp_res(qp, NORMAL_FREE);
        if (hret == H_R_STATE) {
-               ehea_error_data(qp->adapter, qp->fw_handle);
+               ehea_error_data(qp->adapter, qp->fw_handle, &aer, &aerr);
                hret = ehea_destroy_qp_res(qp, FORCE_FREE);
        }
 
@@ -986,42 +986,45 @@ void print_error_data(u64 *data)
        if (length > EHEA_PAGESIZE)
                length = EHEA_PAGESIZE;
 
-       if (type == 0x8) /* Queue Pair */
+       if (type == EHEA_AER_RESTYPE_QP)
                ehea_error("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, "
                           "port=%llX", resource, data[6], data[12], data[22]);
-
-       if (type == 0x4) /* Completion Queue */
+       else if (type == EHEA_AER_RESTYPE_CQ)
                ehea_error("CQ (resource=%llX) state: AER=0x%llX", resource,
                           data[6]);
-
-       if (type == 0x3) /* Event Queue */
+       else if (type == EHEA_AER_RESTYPE_EQ)
                ehea_error("EQ (resource=%llX) state: AER=0x%llX", resource,
                           data[6]);
 
        ehea_dump(data, length, "error data");
 }
 
-void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle)
+u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
+                   u64 *aer, u64 *aerr)
 {
        unsigned long ret;
        u64 *rblock;
+       u64 type = 0;
 
        rblock = (void *)get_zeroed_page(GFP_KERNEL);
        if (!rblock) {
                ehea_error("Cannot allocate rblock memory.");
-               return;
+               goto out;
        }
 
-       ret = ehea_h_error_data(adapter->handle,
-                               res_handle,
-                               rblock);
+       ret = ehea_h_error_data(adapter->handle, res_handle, rblock);
 
-       if (ret == H_R_STATE)
-               ehea_error("No error data is available: %llX.", res_handle);
-       else if (ret == H_SUCCESS)
+       if (ret == H_SUCCESS) {
+               type = EHEA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
+               *aer = rblock[6];
+               *aerr = rblock[12];
                print_error_data(rblock);
-       else
+       } else if (ret == H_R_STATE) {
+               ehea_error("No error data available: %llX.", res_handle);
+       } else
                ehea_error("Error data could not be fetched: %llX", res_handle);
 
        free_page((unsigned long)rblock);
+out:
+       return type;
 }
index 0817c1e74a1960470a1823dfdeb45f0087f309bc..882c50c9c34fdaac9970fdf3d0c65d93da48f4a0 100644 (file)
@@ -154,6 +154,9 @@ struct ehea_rwqe {
 #define EHEA_CQE_STAT_ERR_IP       0x2000
 #define EHEA_CQE_STAT_ERR_CRC      0x1000
 
+/* Defines which bad send cqe stati lead to a port reset */
+#define EHEA_CQE_STAT_RESET_MASK   0x0002
+
 struct ehea_cqe {
        u64 wr_id;              /* work request ID from WQE */
        u8 type;
@@ -187,6 +190,14 @@ struct ehea_cqe {
 #define EHEA_EQE_SM_MECH_NUMBER  EHEA_BMASK_IBM(48, 55)
 #define EHEA_EQE_SM_PORT_NUMBER  EHEA_BMASK_IBM(56, 63)
 
+#define EHEA_AER_RESTYPE_QP  0x8
+#define EHEA_AER_RESTYPE_CQ  0x4
+#define EHEA_AER_RESTYPE_EQ  0x3
+
+/* Defines which affiliated errors lead to a port reset */
+#define EHEA_AER_RESET_MASK   0xFFFFFFFFFEFFFFFFULL
+#define EHEA_AERR_RESET_MASK  0xFFFFFFFFFFFFFFFFULL
+
 struct ehea_eqe {
        u64 entry;
 };
@@ -379,7 +390,8 @@ int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
 
 int ehea_rem_mr(struct ehea_mr *mr);
 
-void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
+u64 ehea_error_data(struct ehea_adapter *adapter, u64 res_handle,
+                   u64 *aer, u64 *aerr);
 
 int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages);
 int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages);
index ff27f728fd9db290132db8f6a0a91952a1962079..112c5aa9af7f84f353156929671b0456e2796715 100644 (file)
@@ -1293,8 +1293,6 @@ static netdev_tx_t enc28j60_send_packet(struct sk_buff *skb,
         */
        netif_stop_queue(dev);
 
-       /* save the timestamp */
-       priv->netdev->trans_start = jiffies;
        /* Remember the skb for deferred processing */
        priv->tx_skb = skb;
        schedule_work(&priv->tx_work);
index 391c3bce5b79e32019b227cd64516918cc79c5f1..e7b6c31880bacadc85262c39324a8773353d0ae4 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_ENIC) := enic.o
 
 enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
-       enic_res.o vnic_dev.o vnic_rq.o
+       enic_res.o vnic_dev.o vnic_rq.o vnic_vic.o
 
index 03dce9ed612cf4df66fd3d554850198642eabebf..337d1943af4645f8fe3999c9d6d51494eecf1fc4 100644 (file)
@@ -101,14 +101,18 @@ static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
        u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
        u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
 {
-       u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags);
-       u16 q_number_rss_type_flags =
-               le16_to_cpu(desc->q_number_rss_type_flags);
-       u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags);
+       u16 completed_index_flags;
+       u16 q_number_rss_type_flags;
+       u16 bytes_written_flags;
 
        cq_desc_dec((struct cq_desc *)desc, type,
                color, q_number, completed_index);
 
+       completed_index_flags = le16_to_cpu(desc->completed_index_flags);
+       q_number_rss_type_flags =
+               le16_to_cpu(desc->q_number_rss_type_flags);
+       bytes_written_flags = le16_to_cpu(desc->bytes_written_flags);
+
        *ingress_port = (completed_index_flags &
                CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0;
        *fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ?
index ee01f5a6d0d4c540f4bfd49f097d2a8ac7445676..85f2a2e7030aa2e1962385f9c8e92a04e1aaa29d 100644 (file)
@@ -33,8 +33,8 @@
 #include "vnic_rss.h"
 
 #define DRV_NAME               "enic"
-#define DRV_DESCRIPTION                "Cisco 10G Ethernet Driver"
-#define DRV_VERSION            "1.1.0.241a"
+#define DRV_DESCRIPTION                "Cisco VIC Ethernet NIC Driver"
+#define DRV_VERSION            "1.3.1.1-pp"
 #define DRV_COPYRIGHT          "Copyright 2008-2009 Cisco Systems, Inc"
 #define PFX                    DRV_NAME ": "
 
@@ -74,6 +74,13 @@ struct enic_msix_entry {
        void *devid;
 };
 
+struct enic_port_profile {
+       u8 request;
+       char name[PORT_PROFILE_MAX];
+       u8 instance_uuid[PORT_UUID_MAX];
+       u8 host_uuid[PORT_UUID_MAX];
+};
+
 /* Per-instance private data structure */
 struct enic {
        struct net_device *netdev;
@@ -95,6 +102,7 @@ struct enic {
        u32 port_mtu;
        u32 rx_coalesce_usecs;
        u32 tx_coalesce_usecs;
+       struct enic_port_profile pp;
 
        /* work queue cache line section */
        ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
index cf098bb636b802a48e0187218744e6461173d4ec..e125113759a5e1a09e6851b3a145f4042d0b0040 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/if_link.h>
 #include <linux/ethtool.h>
 #include <linux/in.h>
 #include <linux/ip.h>
@@ -40,6 +41,7 @@
 #include "vnic_dev.h"
 #include "vnic_intr.h"
 #include "vnic_stats.h"
+#include "vnic_vic.h"
 #include "enic_res.h"
 #include "enic.h"
 
 #define ENIC_DESC_MAX_SPLITS           (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1)
 
 #define PCI_DEVICE_ID_CISCO_VIC_ENET         0x0043  /* ethernet vnic */
+#define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN     0x0044  /* enet dynamic vnic */
 
 /* Supported devices */
 static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = {
        { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
+       { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) },
        { 0, }  /* end of table */
 };
 
@@ -113,6 +117,11 @@ static const struct enic_stat enic_rx_stats[] = {
 static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
 static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
 
+static int enic_is_dynamic(struct enic *enic)
+{
+       return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
+}
+
 static int enic_get_settings(struct net_device *netdev,
        struct ethtool_cmd *ecmd)
 {
@@ -810,26 +819,90 @@ static void enic_reset_mcaddrs(struct enic *enic)
 
 static int enic_set_mac_addr(struct net_device *netdev, char *addr)
 {
-       if (!is_valid_ether_addr(addr))
-               return -EADDRNOTAVAIL;
+       struct enic *enic = netdev_priv(netdev);
+
+       if (enic_is_dynamic(enic)) {
+               if (!is_valid_ether_addr(addr) && !is_zero_ether_addr(addr))
+                       return -EADDRNOTAVAIL;
+       } else {
+               if (!is_valid_ether_addr(addr))
+                       return -EADDRNOTAVAIL;
+       }
 
        memcpy(netdev->dev_addr, addr, netdev->addr_len);
 
        return 0;
 }
 
+static int enic_dev_add_station_addr(struct enic *enic)
+{
+       int err = 0;
+
+       if (is_valid_ether_addr(enic->netdev->dev_addr)) {
+               spin_lock(&enic->devcmd_lock);
+               err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr);
+               spin_unlock(&enic->devcmd_lock);
+       }
+
+       return err;
+}
+
+static int enic_dev_del_station_addr(struct enic *enic)
+{
+       int err = 0;
+
+       if (is_valid_ether_addr(enic->netdev->dev_addr)) {
+               spin_lock(&enic->devcmd_lock);
+               err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr);
+               spin_unlock(&enic->devcmd_lock);
+       }
+
+       return err;
+}
+
+static int enic_set_mac_address_dynamic(struct net_device *netdev, void *p)
+{
+       struct enic *enic = netdev_priv(netdev);
+       struct sockaddr *saddr = p;
+       char *addr = saddr->sa_data;
+       int err;
+
+       if (netif_running(enic->netdev)) {
+               err = enic_dev_del_station_addr(enic);
+               if (err)
+                       return err;
+       }
+
+       err = enic_set_mac_addr(netdev, addr);
+       if (err)
+               return err;
+
+       if (netif_running(enic->netdev)) {
+               err = enic_dev_add_station_addr(enic);
+               if (err)
+                       return err;
+       }
+
+       return err;
+}
+
+static int enic_set_mac_address(struct net_device *netdev, void *p)
+{
+       return -EOPNOTSUPP;
+}
+
 /* netif_tx_lock held, BHs disabled */
 static void enic_set_multicast_list(struct net_device *netdev)
 {
        struct enic *enic = netdev_priv(netdev);
-       struct dev_mc_list *list;
+       struct netdev_hw_addr *ha;
        int directed = 1;
        int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
        int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
        int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0;
        unsigned int mc_count = netdev_mc_count(netdev);
        int allmulti = (netdev->flags & IFF_ALLMULTI) ||
-                      mc_count > ENIC_MULTICAST_PERFECT_FILTERS;
+               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 i, j;
@@ -852,10 +925,10 @@ static void enic_set_multicast_list(struct net_device *netdev)
         */
 
        i = 0;
-       netdev_for_each_mc_addr(list, netdev) {
+       netdev_for_each_mc_addr(ha, netdev) {
                if (i == mc_count)
                        break;
-               memcpy(mc_addr[i++], list->dmi_addr, ETH_ALEN);
+               memcpy(mc_addr[i++], ha->addr, ETH_ALEN);
        }
 
        for (i = 0; i < enic->mc_count; i++) {
@@ -922,6 +995,213 @@ static void enic_tx_timeout(struct net_device *netdev)
        schedule_work(&enic->reset);
 }
 
+static int enic_vnic_dev_deinit(struct enic *enic)
+{
+       int err;
+
+       spin_lock(&enic->devcmd_lock);
+       err = vnic_dev_deinit(enic->vdev);
+       spin_unlock(&enic->devcmd_lock);
+
+       return err;
+}
+
+static int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp)
+{
+       int err;
+
+       spin_lock(&enic->devcmd_lock);
+       err = vnic_dev_init_prov(enic->vdev,
+               (u8 *)vp, vic_provinfo_size(vp));
+       spin_unlock(&enic->devcmd_lock);
+
+       return err;
+}
+
+static int enic_dev_init_done(struct enic *enic, int *done, int *error)
+{
+       int err;
+
+       spin_lock(&enic->devcmd_lock);
+       err = vnic_dev_init_done(enic->vdev, done, error);
+       spin_unlock(&enic->devcmd_lock);
+
+       return err;
+}
+
+static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
+       char *name, u8 *instance_uuid, u8 *host_uuid)
+{
+       struct vic_provinfo *vp;
+       u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
+       unsigned short *uuid;
+       char uuid_str[38];
+       static char *uuid_fmt = "%04X%04X-%04X-%04X-%04X-%04X%04X%04X";
+       int err;
+
+       if (!name)
+               return -EINVAL;
+
+       if (!is_valid_ether_addr(mac))
+               return -EADDRNOTAVAIL;
+
+       vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE);
+       if (!vp)
+               return -ENOMEM;
+
+       vic_provinfo_add_tlv(vp,
+               VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
+               strlen(name) + 1, name);
+
+       vic_provinfo_add_tlv(vp,
+               VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
+               ETH_ALEN, mac);
+
+       if (instance_uuid) {
+               uuid = (unsigned short *)instance_uuid;
+               sprintf(uuid_str, uuid_fmt,
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7]);
+               vic_provinfo_add_tlv(vp,
+                       VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
+                       sizeof(uuid_str), uuid_str);
+       }
+
+       if (host_uuid) {
+               uuid = (unsigned short *)host_uuid;
+               sprintf(uuid_str, uuid_fmt,
+                       uuid[0], uuid[1], uuid[2], uuid[3],
+                       uuid[4], uuid[5], uuid[6], uuid[7]);
+               vic_provinfo_add_tlv(vp,
+                       VIC_LINUX_PROV_TLV_HOST_UUID_STR,
+                       sizeof(uuid_str), uuid_str);
+       }
+
+       err = enic_vnic_dev_deinit(enic);
+       if (err)
+               goto err_out;
+
+       memset(&enic->pp, 0, sizeof(enic->pp));
+
+       err = enic_dev_init_prov(enic, vp);
+       if (err)
+               goto err_out;
+
+       enic->pp.request = request;
+       memcpy(enic->pp.name, name, PORT_PROFILE_MAX);
+       if (instance_uuid)
+               memcpy(enic->pp.instance_uuid,
+                       instance_uuid, PORT_UUID_MAX);
+       if (host_uuid)
+               memcpy(enic->pp.host_uuid,
+                       host_uuid, PORT_UUID_MAX);
+
+err_out:
+       vic_provinfo_free(vp);
+
+       return err;
+}
+
+static int enic_unset_port_profile(struct enic *enic)
+{
+       memset(&enic->pp, 0, sizeof(enic->pp));
+       return enic_vnic_dev_deinit(enic);
+}
+
+static int enic_set_vf_port(struct net_device *netdev, int vf,
+       struct nlattr *port[])
+{
+       struct enic *enic = netdev_priv(netdev);
+       char *name = NULL;
+       u8 *instance_uuid = NULL;
+       u8 *host_uuid = NULL;
+       u8 request = PORT_REQUEST_DISASSOCIATE;
+
+       /* don't support VFs, yet */
+       if (vf != PORT_SELF_VF)
+               return -EOPNOTSUPP;
+
+       if (port[IFLA_PORT_REQUEST])
+               request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+
+       switch (request) {
+       case PORT_REQUEST_ASSOCIATE:
+
+               if (port[IFLA_PORT_PROFILE])
+                       name = nla_data(port[IFLA_PORT_PROFILE]);
+
+               if (port[IFLA_PORT_INSTANCE_UUID])
+                       instance_uuid =
+                               nla_data(port[IFLA_PORT_INSTANCE_UUID]);
+
+               if (port[IFLA_PORT_HOST_UUID])
+                       host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]);
+
+               return enic_set_port_profile(enic, request,
+                       netdev->dev_addr, name,
+                       instance_uuid, host_uuid);
+
+       case PORT_REQUEST_DISASSOCIATE:
+
+               return enic_unset_port_profile(enic);
+
+       default:
+               break;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int enic_get_vf_port(struct net_device *netdev, int vf,
+       struct sk_buff *skb)
+{
+       struct enic *enic = netdev_priv(netdev);
+       int err, error, done;
+       u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
+
+       /* don't support VFs, yet */
+       if (vf != PORT_SELF_VF)
+               return -EOPNOTSUPP;
+
+       err = enic_dev_init_done(enic, &done, &error);
+
+       if (err)
+               return err;
+
+       switch (error) {
+       case ERR_SUCCESS:
+               if (!done)
+                       response = PORT_PROFILE_RESPONSE_INPROGRESS;
+               break;
+       case ERR_EINVAL:
+               response = PORT_PROFILE_RESPONSE_INVALID;
+               break;
+       case ERR_EBADSTATE:
+               response = PORT_PROFILE_RESPONSE_BADSTATE;
+               break;
+       case ERR_ENOMEM:
+               response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
+               break;
+       default:
+               response = PORT_PROFILE_RESPONSE_ERROR;
+               break;
+       }
+
+       NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
+       NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
+       NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
+               enic->pp.name);
+       NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
+               enic->pp.instance_uuid);
+       NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
+               enic->pp.host_uuid);
+
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
 static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
 {
        struct enic *enic = vnic_dev_priv(rq->vdev);
@@ -1440,9 +1720,7 @@ static int enic_open(struct net_device *netdev)
        for (i = 0; i < enic->rq_count; i++)
                vnic_rq_enable(&enic->rq[i]);
 
-       spin_lock(&enic->devcmd_lock);
-       enic_add_station_addr(enic);
-       spin_unlock(&enic->devcmd_lock);
+       enic_dev_add_station_addr(enic);
        enic_set_multicast_list(netdev);
 
        netif_wake_queue(netdev);
@@ -1489,6 +1767,8 @@ static int enic_stop(struct net_device *netdev)
        netif_carrier_off(netdev);
        netif_tx_disable(netdev);
 
+       enic_dev_del_station_addr(enic);
+
        for (i = 0; i < enic->wq_count; i++) {
                err = vnic_wq_disable(&enic->wq[i]);
                if (err)
@@ -1774,14 +2054,34 @@ static void enic_clear_intr_mode(struct enic *enic)
        vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
 }
 
+static const struct net_device_ops enic_netdev_dynamic_ops = {
+       .ndo_open               = enic_open,
+       .ndo_stop               = enic_stop,
+       .ndo_start_xmit         = enic_hard_start_xmit,
+       .ndo_get_stats          = enic_get_stats,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_multicast_list = enic_set_multicast_list,
+       .ndo_set_mac_address    = enic_set_mac_address_dynamic,
+       .ndo_change_mtu         = enic_change_mtu,
+       .ndo_vlan_rx_register   = enic_vlan_rx_register,
+       .ndo_vlan_rx_add_vid    = enic_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = enic_vlan_rx_kill_vid,
+       .ndo_tx_timeout         = enic_tx_timeout,
+       .ndo_set_vf_port        = enic_set_vf_port,
+       .ndo_get_vf_port        = enic_get_vf_port,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = enic_poll_controller,
+#endif
+};
+
 static const struct net_device_ops enic_netdev_ops = {
        .ndo_open               = enic_open,
        .ndo_stop               = enic_stop,
        .ndo_start_xmit         = enic_hard_start_xmit,
        .ndo_get_stats          = enic_get_stats,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_set_multicast_list = enic_set_multicast_list,
+       .ndo_set_mac_address    = enic_set_mac_address,
        .ndo_change_mtu         = enic_change_mtu,
        .ndo_vlan_rx_register   = enic_vlan_rx_register,
        .ndo_vlan_rx_add_vid    = enic_vlan_rx_add_vid,
@@ -2010,11 +2310,13 @@ static int __devinit enic_probe(struct pci_dev *pdev,
 
        netif_carrier_off(netdev);
 
-       err = vnic_dev_init(enic->vdev, 0);
-       if (err) {
-               printk(KERN_ERR PFX
-                       "vNIC dev init failed, aborting.\n");
-               goto err_out_dev_close;
+       if (!enic_is_dynamic(enic)) {
+               err = vnic_dev_init(enic->vdev, 0);
+               if (err) {
+                       printk(KERN_ERR PFX
+                               "vNIC dev init failed, aborting.\n");
+                       goto err_out_dev_close;
+               }
        }
 
        err = enic_dev_init(enic);
@@ -2054,12 +2356,15 @@ static int __devinit enic_probe(struct pci_dev *pdev,
        enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
        enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
 
-       netdev->netdev_ops = &enic_netdev_ops;
+       if (enic_is_dynamic(enic))
+               netdev->netdev_ops = &enic_netdev_dynamic_ops;
+       else
+               netdev->netdev_ops = &enic_netdev_ops;
+
        netdev->watchdog_timeo = 2 * HZ;
        netdev->ethtool_ops = &enic_ethtool_ops;
 
-       netdev->features |= NETIF_F_HW_VLAN_TX |
-               NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+       netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
        if (ENIC_SETTING(enic, TXCSUM))
                netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
        if (ENIC_SETTING(enic, TSO))
index 02839bf0fe8bde44a215ff558a0a0669aca1a399..9b18840cba969aa0a3162a79298c4b1713926c11 100644 (file)
@@ -103,11 +103,6 @@ int enic_get_vnic_config(struct enic *enic)
        return 0;
 }
 
-void enic_add_station_addr(struct enic *enic)
-{
-       vnic_dev_add_addr(enic->vdev, enic->mac_addr);
-}
-
 void enic_add_multicast_addr(struct enic *enic, u8 *addr)
 {
        vnic_dev_add_addr(enic->vdev, addr);
index abc19741ab02c3a23f675fe591e1322b609f2327..494664f7fcccec916e865d7c7e612efd8481d766 100644 (file)
@@ -131,7 +131,6 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq,
 struct enic;
 
 int enic_get_vnic_config(struct enic *);
-void enic_add_station_addr(struct enic *enic);
 void enic_add_multicast_addr(struct enic *enic, u8 *addr);
 void enic_del_multicast_addr(struct enic *enic, u8 *addr);
 void enic_add_vlan(struct enic *enic, u16 vlanid);
index cf22de71014e2ef5729928766d085ea0b1aa1d56..2b3e16db5c82f2a75763f128854b06a3d2447d24 100644 (file)
@@ -530,7 +530,7 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
                printk(KERN_ERR "Can't set packet filter\n");
 }
 
-void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
+int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
 {
        u64 a0 = 0, a1 = 0;
        int wait = 1000;
@@ -543,9 +543,11 @@ void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
        err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
        if (err)
                printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err);
+
+       return err;
 }
 
-void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
+int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
 {
        u64 a0 = 0, a1 = 0;
        int wait = 1000;
@@ -558,6 +560,8 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
        err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
        if (err)
                printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err);
+
+       return err;
 }
 
 int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr)
@@ -574,22 +578,18 @@ int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr)
        return err;
 }
 
-int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
+int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
+       void *notify_addr, dma_addr_t notify_pa, u16 intr)
 {
        u64 a0, a1;
        int wait = 1000;
        int r;
 
-       if (!vdev->notify) {
-               vdev->notify = pci_alloc_consistent(vdev->pdev,
-                       sizeof(struct vnic_devcmd_notify),
-                       &vdev->notify_pa);
-               if (!vdev->notify)
-                       return -ENOMEM;
-               memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify));
-       }
+       memset(notify_addr, 0, sizeof(struct vnic_devcmd_notify));
+       vdev->notify = notify_addr;
+       vdev->notify_pa = notify_pa;
 
-       a0 = vdev->notify_pa;
+       a0 = (u64)notify_pa;
        a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL;
        a1 += sizeof(struct vnic_devcmd_notify);
 
@@ -598,7 +598,27 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
        return r;
 }
 
-void vnic_dev_notify_unset(struct vnic_dev *vdev)
+int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
+{
+       void *notify_addr;
+       dma_addr_t notify_pa;
+
+       if (vdev->notify || vdev->notify_pa) {
+               printk(KERN_ERR "notify block %p still allocated",
+                       vdev->notify);
+               return -EINVAL;
+       }
+
+       notify_addr = pci_alloc_consistent(vdev->pdev,
+                       sizeof(struct vnic_devcmd_notify),
+                       &notify_pa);
+       if (!notify_addr)
+               return -ENOMEM;
+
+       return vnic_dev_notify_setcmd(vdev, notify_addr, notify_pa, intr);
+}
+
+void vnic_dev_notify_unsetcmd(struct vnic_dev *vdev)
 {
        u64 a0, a1;
        int wait = 1000;
@@ -608,9 +628,23 @@ void vnic_dev_notify_unset(struct vnic_dev *vdev)
        a1 += sizeof(struct vnic_devcmd_notify);
 
        vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+       vdev->notify = NULL;
+       vdev->notify_pa = 0;
        vdev->notify_sz = 0;
 }
 
+void vnic_dev_notify_unset(struct vnic_dev *vdev)
+{
+       if (vdev->notify) {
+               pci_free_consistent(vdev->pdev,
+                       sizeof(struct vnic_devcmd_notify),
+                       vdev->notify,
+                       vdev->notify_pa);
+       }
+
+       vnic_dev_notify_unsetcmd(vdev);
+}
+
 static int vnic_dev_notify_ready(struct vnic_dev *vdev)
 {
        u32 *words;
@@ -652,6 +686,56 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg)
        return r;
 }
 
+int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err)
+{
+       u64 a0 = 0, a1 = 0;
+       int wait = 1000;
+       int ret;
+
+       *done = 0;
+
+       ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait);
+       if (ret)
+               return ret;
+
+       *done = (a0 == 0);
+
+       *err = (a0 == 0) ? a1 : 0;
+
+       return 0;
+}
+
+int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len)
+{
+       u64 a0, a1 = len;
+       int wait = 1000;
+       u64 prov_pa;
+       void *prov_buf;
+       int ret;
+
+       prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa);
+       if (!prov_buf)
+               return -ENOMEM;
+
+       memcpy(prov_buf, buf, len);
+
+       a0 = prov_pa;
+
+       ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait);
+
+       pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa);
+
+       return ret;
+}
+
+int vnic_dev_deinit(struct vnic_dev *vdev)
+{
+       u64 a0 = 0, a1 = 0;
+       int wait = 1000;
+
+       return vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait);
+}
+
 int vnic_dev_link_status(struct vnic_dev *vdev)
 {
        if (vdev->linkstatus)
index fc5e3eb35a5eac21dfc83275ea67c026c32108bb..caccce36957b4695a0126d2df6050cadb3271249 100644 (file)
@@ -103,11 +103,14 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
 int vnic_dev_hang_notify(struct vnic_dev *vdev);
 void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
        int broadcast, int promisc, int allmulti);
-void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
-void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
+int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
+int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
 int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
 int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr);
+int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
+       void *notify_addr, dma_addr_t notify_pa, u16 intr);
 int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
+void vnic_dev_notify_unsetcmd(struct vnic_dev *vdev);
 void vnic_dev_notify_unset(struct vnic_dev *vdev);
 int vnic_dev_link_status(struct vnic_dev *vdev);
 u32 vnic_dev_port_speed(struct vnic_dev *vdev);
@@ -121,6 +124,9 @@ int vnic_dev_disable(struct vnic_dev *vdev);
 int vnic_dev_open(struct vnic_dev *vdev, int arg);
 int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
 int vnic_dev_init(struct vnic_dev *vdev, int arg);
+int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err);
+int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
+int vnic_dev_deinit(struct vnic_dev *vdev);
 int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
 int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
 void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
index e186efaf9da1fc0c5d552fdb90aac7885b553a86..cc580cfec41dd8baae417347d7604380623179a0 100644 (file)
@@ -168,10 +168,10 @@ int vnic_rq_disable(struct vnic_rq *rq)
        iowrite32(0, &rq->ctrl->enable);
 
        /* Wait for HW to ACK disable request */
-       for (wait = 0; wait < 100; wait++) {
+       for (wait = 0; wait < 1000; wait++) {
                if (!(ioread32(&rq->ctrl->running)))
                        return 0;
-               udelay(1);
+               udelay(10);
        }
 
        printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index);
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c
new file mode 100644 (file)
index 0000000..d769772
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include "vnic_vic.h"
+
+struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type)
+{
+       struct vic_provinfo *vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
+
+       if (!vp || !oui)
+               return NULL;
+
+       memcpy(vp->oui, oui, sizeof(vp->oui));
+       vp->type = type;
+       vp->length = htonl(sizeof(vp->num_tlvs));
+
+       return vp;
+}
+
+void vic_provinfo_free(struct vic_provinfo *vp)
+{
+       kfree(vp);
+}
+
+int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
+       void *value)
+{
+       struct vic_provinfo_tlv *tlv;
+
+       if (!vp || !value)
+               return -EINVAL;
+
+       if (ntohl(vp->length) + sizeof(*tlv) + length >
+               VIC_PROVINFO_MAX_TLV_DATA)
+               return -ENOMEM;
+
+       tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv +
+               ntohl(vp->length) - sizeof(vp->num_tlvs));
+
+       tlv->type = htons(type);
+       tlv->length = htons(length);
+       memcpy(tlv->value, value, length);
+
+       vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
+       vp->length = htonl(ntohl(vp->length) + sizeof(*tlv) + length);
+
+       return 0;
+}
+
+size_t vic_provinfo_size(struct vic_provinfo *vp)
+{
+       return vp ?  ntohl(vp->length) + sizeof(*vp) - sizeof(vp->num_tlvs) : 0;
+}
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
new file mode 100644 (file)
index 0000000..085c2a2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 Cisco Systems, Inc.  All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_VIC_H_
+#define _VNIC_VIC_H_
+
+/* Note: All integer fields in NETWORK byte order */
+
+/* Note: String field lengths include null char */
+
+#define VIC_PROVINFO_CISCO_OUI         { 0x00, 0x00, 0x0c }
+#define VIC_PROVINFO_LINUX_TYPE                0x2
+
+enum vic_linux_prov_tlv_type {
+       VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR = 0,
+       VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR = 1,                 /* u8[6] */
+       VIC_LINUX_PROV_TLV_CLIENT_NAME_STR = 2,
+       VIC_LINUX_PROV_TLV_HOST_UUID_STR = 8,
+       VIC_LINUX_PROV_TLV_CLIENT_UUID_STR = 9,
+};
+
+struct vic_provinfo {
+       u8 oui[3];              /* OUI of data provider */
+       u8 type;                /* provider-specific type */
+       u32 length;             /* length of data below */
+       u32 num_tlvs;           /* number of tlvs */
+       struct vic_provinfo_tlv {
+               u16 type;
+               u16 length;
+               u8 value[0];
+       } tlv[0];
+} __attribute__ ((packed));
+
+#define VIC_PROVINFO_MAX_DATA          1385
+#define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
+       sizeof(struct vic_provinfo))
+
+struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type);
+void vic_provinfo_free(struct vic_provinfo *vp);
+int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
+       void *value);
+size_t vic_provinfo_size(struct vic_provinfo *vp);
+
+#endif /* _VNIC_VIC_H_ */
index d5f984357f5cb2437a3a48172e75bcaf93f77db1..1378afbdfe67b150ee172f6216f4af13fbd5c2ae 100644 (file)
@@ -161,10 +161,10 @@ int vnic_wq_disable(struct vnic_wq *wq)
        iowrite32(0, &wq->ctrl->enable);
 
        /* Wait for HW to ACK disable request */
-       for (wait = 0; wait < 100; wait++) {
+       for (wait = 0; wait < 1000; wait++) {
                if (!(ioread32(&wq->ctrl->running)))
                        return 0;
-               udelay(1);
+               udelay(10);
        }
 
        printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index);
index 7a567201e8295f8c17763c2f350e96f3b8495a0c..6838dfc9ef23a4549c69144c7d87db589e1c7928 100644 (file)
@@ -652,7 +652,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
                if ((inl(ioaddr + MIICtrl) & MII_WRITEOP) == 0)
                        break;
        }
-       return;
 }
 
 
@@ -840,7 +839,6 @@ static void epic_restart(struct net_device *dev)
                   " interrupt %4.4x.\n",
                   dev->name, (int)inl(ioaddr + COMMAND), (int)inl(ioaddr + GENCTL),
                   (int)inl(ioaddr + INTSTAT));
-       return;
 }
 
 static void check_media(struct net_device *dev)
@@ -908,7 +906,7 @@ static void epic_tx_timeout(struct net_device *dev)
                outl(TxQueued, dev->base_addr + COMMAND);
        }
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        ep->stats.tx_errors++;
        if (!ep->tx_full)
                netif_wake_queue(dev);
@@ -958,7 +956,6 @@ static void epic_init_ring(struct net_device *dev)
                        (i+1)*sizeof(struct epic_tx_desc);
        }
        ep->tx_ring[i-1].next = ep->tx_ring_dma;
-       return;
 }
 
 static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -1006,7 +1003,6 @@ static netdev_tx_t epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Trigger an immediate transmit demand. */
        outl(TxQueued, dev->base_addr + COMMAND);
 
-       dev->trans_start = jiffies;
        if (debug > 4)
                printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
                           "flag %2.2x Tx status %8.8x.\n",
@@ -1399,12 +1395,12 @@ static void set_rx_mode(struct net_device *dev)
                outl(0x0004, ioaddr + RxCtrl);
                return;
        } else {                                        /* Never executed, for now. */
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        unsigned int bit_nr =
-                               ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f;
+                               ether_crc_le(ETH_ALEN, ha->addr) & 0x3f;
                        mc_filter[bit_nr >> 3] |= (1 << bit_nr);
                }
        }
@@ -1414,7 +1410,6 @@ static void set_rx_mode(struct net_device *dev)
                        outw(((u16 *)mc_filter)[i], ioaddr + MC0 + i*4);
                memcpy(ep->mc_filter, mc_filter, sizeof(mc_filter));
        }
-       return;
 }
 
 static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
index b34a2ddeef4c810b37dca41faad2ed4cc12955b9..dda2c7944da9a45872d55f626503d15c67c67641 100644 (file)
@@ -288,7 +288,7 @@ static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        return eql_s_master_cfg(dev, ifr->ifr_data);
                default:
                        return -EOPNOTSUPP;
-       };
+       }
 }
 
 /* queue->lock must be held */
index 5569f2ffb62cbc2814df1012e11f5ff7e1995727..0ba5e7b9058441046a2bfbcd5e6e1d02a85a71e0 100644 (file)
@@ -319,8 +319,6 @@ static void es_reset_8390(struct net_device *dev)
        ei_status.txing = 0;
        outb(0x01, ioaddr + ES_RESET_PORT);
        if (ei_debug > 1) printk("reset done\n");
-
-       return;
 }
 
 /*
index d4e24f08b3ba3bb0c51d925109cd0ffc88964b1c..874973f558e92ee1b7ddc4fba185aecdc49f127a 100644 (file)
@@ -1027,7 +1027,7 @@ static void eth16i_timeout(struct net_device *dev)
        inw(ioaddr + TX_STATUS_REG),  (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
                       "IRQ conflict" : "network cable problem");
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 
        /* Let's dump all registers */
        if(eth16i_debug > 0) {
@@ -1047,7 +1047,7 @@ static void eth16i_timeout(struct net_device *dev)
        }
        dev->stats.tx_errors++;
        eth16i_reset(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
        netif_wake_queue(dev);
 }
@@ -1109,7 +1109,6 @@ static netdev_tx_t eth16i_tx(struct sk_buff *skb, struct net_device *dev)
                outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
                lp->tx_queue = 0;
                lp->tx_queue_len = 0;
-               dev->trans_start = jiffies;
                lp->tx_started = 1;
                netif_wake_queue(dev);
        }
index a8d92503226e3d00a9e68ade94e97a2b892ec1cc..14cbde5cf68e52546d0b2f4c0e42f26fa95b89f5 100644 (file)
@@ -756,7 +756,7 @@ static void ethoc_set_multicast_list(struct net_device *dev)
 {
        struct ethoc *priv = netdev_priv(dev);
        u32 mode = ethoc_read(priv, MODER);
-       struct dev_mc_list *mc;
+       struct netdev_hw_addr *ha;
        u32 hash[2] = { 0, 0 };
 
        /* set loopback mode if requested */
@@ -784,8 +784,8 @@ static void ethoc_set_multicast_list(struct net_device *dev)
                hash[0] = 0xffffffff;
                hash[1] = 0xffffffff;
        } else {
-               netdev_for_each_mc_addr(mc, dev) {
-                       u32 crc = ether_crc(ETH_ALEN, mc->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       u32 crc = ether_crc(ETH_ALEN, ha->addr);
                        int bit = (crc >> 26) & 0x3f;
                        hash[bit >> 5] |= 1 << (bit & 0x1f);
                }
@@ -851,7 +851,6 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
 
-       dev->trans_start = jiffies;
        spin_unlock_irq(&priv->lock);
 out:
        dev_kfree_skb(skb);
@@ -1040,7 +1039,6 @@ static int ethoc_probe(struct platform_device *pdev)
        netdev->features |= 0;
 
        /* setup NAPI */
-       memset(&priv->napi, 0, sizeof(priv->napi));
        netif_napi_add(netdev, &priv->napi, ethoc_poll, 64);
 
        spin_lock_init(&priv->rx_lock);
index 91e59f3a9d6dae11b7deaf1c82f83dc21678a892..380d0614a89a329355c5377e1d2d04a5c208e275 100644 (file)
@@ -757,7 +757,7 @@ static void ewrk3_timeout(struct net_device *dev)
                 */
                ENABLE_IRQs;
 
-               dev->trans_start = jiffies;
+               dev->trans_start = jiffies; /* prevent tx timeout */
                netif_wake_queue(dev);
        }
 }
@@ -862,7 +862,6 @@ static netdev_tx_t ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irq (&lp->hw_lock);
 
        dev->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
 
        /* Check for free resources: stop Tx queue if there are none */
@@ -1169,7 +1168,7 @@ static void set_multicast_list(struct net_device *dev)
 static void SetMulticastFilter(struct net_device *dev)
 {
        struct ewrk3_private *lp = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        u_long iobase = dev->base_addr;
        int i;
        char *addrs, bit, byte;
@@ -1213,8 +1212,8 @@ static void SetMulticastFilter(struct net_device *dev)
                }
 
                /* Update table */
-               netdev_for_each_mc_addr(dmi, dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       addrs = ha->addr;
                        if ((*addrs & 0x01) == 1) {     /* multicast address? */
                                crc = ether_crc_le(ETH_ALEN, addrs);
                                hashcode = crc & ((1 << 9) - 1);        /* hashcode is 9 LSb of CRC */
@@ -1370,8 +1369,6 @@ static void __init EthwrkSignature(char *name, char *eeprom_image)
                name[EWRK3_STRLEN] = '\0';
        } else
                name[0] = '\0';
-
-       return;
 }
 
 /*
@@ -1776,8 +1773,7 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                break;
        case EWRK3_SET_MCA:     /* Set a multicast address */
                if (capable(CAP_NET_ADMIN)) {
-                       if (ioc->len > 1024)
-                       {
+                       if (ioc->len > HASH_TABLE_LEN) {
                                status = -EINVAL;
                                break;
                        }
index d11ae5197f01533f20cf141f023d1516b2b37765..15f4f8d3d46d9e24396f783d79a027f97d90c246 100644 (file)
@@ -1233,7 +1233,7 @@ static void fealnx_tx_timeout(struct net_device *dev)
 
        spin_unlock_irqrestore(&np->lock, flags);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        np->stats.tx_errors++;
        netif_wake_queue(dev); /* or .._start_.. ?? */
 }
@@ -1374,7 +1374,6 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        ++np->really_tx_count;
        iowrite32(0, np->mem + TXPDR);
-       dev->trans_start = jiffies;
 
        spin_unlock_irqrestore(&np->lock, flags);
        return NETDEV_TX_OK;
@@ -1791,12 +1790,12 @@ static void __set_rx_mode(struct net_device *dev)
                memset(mc_filter, 0xff, sizeof(mc_filter));
                rx_mode = CR_W_AB | CR_W_AM;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        unsigned int bit;
-                       bit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F;
+                       bit = (ether_crc(ETH_ALEN, ha->addr) >> 26) ^ 0x3F;
                        mc_filter[bit >> 5] |= (1 << bit);
                }
                rx_mode = CR_W_AB | CR_W_AM;
index 9b4e8f797a7ad76d7ae8c36b8efe5d08a94f530d..42d9ac9ba3958aa3b4b6a7210bb96cb51aa3dd52 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
+#include <linux/phy.h>
 
 #include <asm/cacheflush.h>
 
@@ -61,7 +62,6 @@
  * Define the fixed address of the FEC hardware.
  */
 #if defined(CONFIG_M5272)
-#define HAVE_mii_link_interrupt
 
 static unsigned char   fec_mac_default[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -86,23 +86,6 @@ static unsigned char fec_mac_default[] = {
 #endif
 #endif /* CONFIG_M5272 */
 
-/* Forward declarations of some structures to support different PHYs */
-
-typedef struct {
-       uint mii_data;
-       void (*funct)(uint mii_reg, struct net_device *dev);
-} phy_cmd_t;
-
-typedef struct {
-       uint id;
-       char *name;
-
-       const phy_cmd_t *config;
-       const phy_cmd_t *startup;
-       const phy_cmd_t *ack_int;
-       const phy_cmd_t *shutdown;
-} phy_info_t;
-
 /* The number of Tx and Rx buffers.  These are allocated from the page
  * pool.  The code may assume these are power of two, so it it best
  * to keep them that size.
@@ -189,29 +172,21 @@ struct fec_enet_private {
        uint    tx_full;
        /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
        spinlock_t hw_lock;
-       /* hold while accessing the mii_list_t() elements */
-       spinlock_t mii_lock;
-
-       uint    phy_id;
-       uint    phy_id_done;
-       uint    phy_status;
-       uint    phy_speed;
-       phy_info_t const        *phy;
-       struct work_struct phy_task;
 
-       uint    sequence_done;
-       uint    mii_phy_task_queued;
+       struct  platform_device *pdev;
 
-       uint    phy_addr;
+       int     opened;
 
+       /* Phylib and MDIO interface */
+       struct  mii_bus *mii_bus;
+       struct  phy_device *phy_dev;
+       int     mii_timeout;
+       uint    phy_speed;
        int     index;
-       int     opened;
        int     link;
-       int     old_link;
        int     full_duplex;
 };
 
-static void fec_enet_mii(struct net_device *dev);
 static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
 static void fec_enet_tx(struct net_device *dev);
 static void fec_enet_rx(struct net_device *dev);
@@ -219,67 +194,20 @@ static int fec_enet_close(struct net_device *dev);
 static void fec_restart(struct net_device *dev, int duplex);
 static void fec_stop(struct net_device *dev);
 
+/* FEC MII MMFR bits definition */
+#define FEC_MMFR_ST            (1 << 30)
+#define FEC_MMFR_OP_READ       (2 << 28)
+#define FEC_MMFR_OP_WRITE      (1 << 28)
+#define FEC_MMFR_PA(v)         ((v & 0x1f) << 23)
+#define FEC_MMFR_RA(v)         ((v & 0x1f) << 18)
+#define FEC_MMFR_TA            (2 << 16)
+#define FEC_MMFR_DATA(v)       (v & 0xffff)
 
-/* MII processing.  We keep this as simple as possible.  Requests are
- * placed on the list (if there is room).  When the request is finished
- * by the MII, an optional function may be called.
- */
-typedef struct mii_list {
-       uint    mii_regval;
-       void    (*mii_func)(uint val, struct net_device *dev);
-       struct  mii_list *mii_next;
-} mii_list_t;
-
-#define                NMII    20
-static mii_list_t      mii_cmds[NMII];
-static mii_list_t      *mii_free;
-static mii_list_t      *mii_head;
-static mii_list_t      *mii_tail;
-
-static int     mii_queue(struct net_device *dev, int request,
-                               void (*func)(uint, struct net_device *));
-
-/* Make MII read/write commands for the FEC */
-#define mk_mii_read(REG)       (0x60020000 | ((REG & 0x1f) << 18))
-#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \
-                                               (VAL & 0xffff))
-#define mk_mii_end     0
+#define FEC_MII_TIMEOUT                10000
 
 /* Transmitter timeout */
 #define TX_TIMEOUT (2 * HZ)
 
-/* Register definitions for the PHY */
-
-#define MII_REG_CR          0  /* Control Register                         */
-#define MII_REG_SR          1  /* Status Register                          */
-#define MII_REG_PHYIR1      2  /* PHY Identification Register 1            */
-#define MII_REG_PHYIR2      3  /* PHY Identification Register 2            */
-#define MII_REG_ANAR        4  /* A-N Advertisement Register               */
-#define MII_REG_ANLPAR      5  /* A-N Link Partner Ability Register        */
-#define MII_REG_ANER        6  /* A-N Expansion Register                   */
-#define MII_REG_ANNPTR      7  /* A-N Next Page Transmit Register          */
-#define MII_REG_ANLPRNPR    8  /* A-N Link Partner Received Next Page Reg. */
-
-/* values for phy_status */
-
-#define PHY_CONF_ANE   0x0001  /* 1 auto-negotiation enabled */
-#define PHY_CONF_LOOP  0x0002  /* 1 loopback mode enabled */
-#define PHY_CONF_SPMASK        0x00f0  /* mask for speed */
-#define PHY_CONF_10HDX 0x0010  /* 10 Mbit half duplex supported */
-#define PHY_CONF_10FDX 0x0020  /* 10 Mbit full duplex supported */
-#define PHY_CONF_100HDX        0x0040  /* 100 Mbit half duplex supported */
-#define PHY_CONF_100FDX        0x0080  /* 100 Mbit full duplex supported */
-
-#define PHY_STAT_LINK  0x0100  /* 1 up - 0 down */
-#define PHY_STAT_FAULT 0x0200  /* 1 remote fault */
-#define PHY_STAT_ANC   0x0400  /* 1 auto-negotiation complete  */
-#define PHY_STAT_SPMASK        0xf000  /* mask for speed */
-#define PHY_STAT_10HDX 0x1000  /* 10 Mbit half duplex selected */
-#define PHY_STAT_10FDX 0x2000  /* 10 Mbit full duplex selected */
-#define PHY_STAT_100HDX        0x4000  /* 100 Mbit half duplex selected */
-#define PHY_STAT_100FDX        0x8000  /* 100 Mbit full duplex selected */
-
-
 static int
 fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -347,8 +275,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        | BD_ENET_TX_LAST | BD_ENET_TX_TC);
        bdp->cbd_sc = status;
 
-       dev->trans_start = jiffies;
-
        /* Trigger transmission start */
        writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
@@ -406,12 +332,6 @@ fec_enet_interrupt(int irq, void * dev_id)
                        ret = IRQ_HANDLED;
                        fec_enet_tx(dev);
                }
-
-               if (int_events & FEC_ENET_MII) {
-                       ret = IRQ_HANDLED;
-                       fec_enet_mii(dev);
-               }
-
        } while (int_events);
 
        return ret;
@@ -607,827 +527,311 @@ rx_processing_done:
        spin_unlock(&fep->hw_lock);
 }
 
-/* called from interrupt context */
-static void
-fec_enet_mii(struct net_device *dev)
-{
-       struct  fec_enet_private *fep;
-       mii_list_t      *mip;
-
-       fep = netdev_priv(dev);
-       spin_lock(&fep->mii_lock);
-
-       if ((mip = mii_head) == NULL) {
-               printk("MII and no head!\n");
-               goto unlock;
-       }
-
-       if (mip->mii_func != NULL)
-               (*(mip->mii_func))(readl(fep->hwp + FEC_MII_DATA), dev);
-
-       mii_head = mip->mii_next;
-       mip->mii_next = mii_free;
-       mii_free = mip;
-
-       if ((mip = mii_head) != NULL)
-               writel(mip->mii_regval, fep->hwp + FEC_MII_DATA);
-
-unlock:
-       spin_unlock(&fep->mii_lock);
-}
-
-static int
-mii_queue_unlocked(struct net_device *dev, int regval,
-               void (*func)(uint, struct net_device *))
+/* ------------------------------------------------------------------------- */
+#ifdef CONFIG_M5272
+static void __inline__ fec_get_mac(struct net_device *dev)
 {
-       struct fec_enet_private *fep;
-       mii_list_t      *mip;
-       int             retval;
-
-       /* Add PHY address to register command */
-       fep = netdev_priv(dev);
+       struct fec_enet_private *fep = netdev_priv(dev);
+       unsigned char *iap, tmpaddr[ETH_ALEN];
 
-       regval |= fep->phy_addr << 23;
-       retval = 0;
-
-       if ((mip = mii_free) != NULL) {
-               mii_free = mip->mii_next;
-               mip->mii_regval = regval;
-               mip->mii_func = func;
-               mip->mii_next = NULL;
-               if (mii_head) {
-                       mii_tail->mii_next = mip;
-                       mii_tail = mip;
-               } else {
-                       mii_head = mii_tail = mip;
-                       writel(regval, fep->hwp + FEC_MII_DATA);
-               }
+       if (FEC_FLASHMAC) {
+               /*
+                * Get MAC address from FLASH.
+                * If it is all 1's or 0's, use the default.
+                */
+               iap = (unsigned char *)FEC_FLASHMAC;
+               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+                   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+                       iap = fec_mac_default;
+               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+                   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+                       iap = fec_mac_default;
        } else {
-               retval = 1;
+               *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW);
+               *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
+               iap = &tmpaddr[0];
        }
 
-       return retval;
-}
-
-static int
-mii_queue(struct net_device *dev, int regval,
-               void (*func)(uint, struct net_device *))
-{
-       struct fec_enet_private *fep;
-       unsigned long   flags;
-       int             retval;
-       fep = netdev_priv(dev);
-       spin_lock_irqsave(&fep->mii_lock, flags);
-       retval = mii_queue_unlocked(dev, regval, func);
-       spin_unlock_irqrestore(&fep->mii_lock, flags);
-       return retval;
-}
-
-static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
-{
-       if(!c)
-               return;
+       memcpy(dev->dev_addr, iap, ETH_ALEN);
 
-       for (; c->mii_data != mk_mii_end; c++)
-               mii_queue(dev, c->mii_data, c->funct);
+       /* Adjust MAC if using default MAC address */
+       if (iap == fec_mac_default)
+                dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
 }
+#endif
 
-static void mii_parse_sr(uint mii_reg, struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
-
-       status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
-
-       if (mii_reg & 0x0004)
-               status |= PHY_STAT_LINK;
-       if (mii_reg & 0x0010)
-               status |= PHY_STAT_FAULT;
-       if (mii_reg & 0x0020)
-               status |= PHY_STAT_ANC;
-       *s = status;
-}
+/* ------------------------------------------------------------------------- */
 
-static void mii_parse_cr(uint mii_reg, struct net_device *dev)
+/*
+ * Phy section
+ */
+static void fec_enet_adjust_link(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
-
-       status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP);
-
-       if (mii_reg & 0x1000)
-               status |= PHY_CONF_ANE;
-       if (mii_reg & 0x4000)
-               status |= PHY_CONF_LOOP;
-       *s = status;
-}
+       struct phy_device *phy_dev = fep->phy_dev;
+       unsigned long flags;
 
-static void mii_parse_anar(uint mii_reg, struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
-
-       status = *s & ~(PHY_CONF_SPMASK);
-
-       if (mii_reg & 0x0020)
-               status |= PHY_CONF_10HDX;
-       if (mii_reg & 0x0040)
-               status |= PHY_CONF_10FDX;
-       if (mii_reg & 0x0080)
-               status |= PHY_CONF_100HDX;
-       if (mii_reg & 0x00100)
-               status |= PHY_CONF_100FDX;
-       *s = status;
-}
+       int status_change = 0;
 
-/* ------------------------------------------------------------------------- */
-/* The Level one LXT970 is used by many boards                              */
+       spin_lock_irqsave(&fep->hw_lock, flags);
 
-#define MII_LXT970_MIRROR    16  /* Mirror register           */
-#define MII_LXT970_IER       17  /* Interrupt Enable Register */
-#define MII_LXT970_ISR       18  /* Interrupt Status Register */
-#define MII_LXT970_CONFIG    19  /* Configuration Register    */
-#define MII_LXT970_CSR       20  /* Chip Status Register      */
+       /* Prevent a state halted on mii error */
+       if (fep->mii_timeout && phy_dev->state == PHY_HALTED) {
+               phy_dev->state = PHY_RESUMING;
+               goto spin_unlock;
+       }
 
-static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
+       /* Duplex link change */
+       if (phy_dev->link) {
+               if (fep->full_duplex != phy_dev->duplex) {
+                       fec_restart(dev, phy_dev->duplex);
+                       status_change = 1;
+               }
+       }
 
-       status = *s & ~(PHY_STAT_SPMASK);
-       if (mii_reg & 0x0800) {
-               if (mii_reg & 0x1000)
-                       status |= PHY_STAT_100FDX;
-               else
-                       status |= PHY_STAT_100HDX;
-       } else {
-               if (mii_reg & 0x1000)
-                       status |= PHY_STAT_10FDX;
+       /* Link on or off change */
+       if (phy_dev->link != fep->link) {
+               fep->link = phy_dev->link;
+               if (phy_dev->link)
+                       fec_restart(dev, phy_dev->duplex);
                else
-                       status |= PHY_STAT_10HDX;
+                       fec_stop(dev);
+               status_change = 1;
        }
-       *s = status;
-}
 
-static phy_cmd_t const phy_cmd_lxt970_config[] = {
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */
-               { mk_mii_write(MII_LXT970_IER, 0x0002), NULL },
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_lxt970_ack_int[] = {
-               /* read SR and ISR to acknowledge */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_read(MII_LXT970_ISR), NULL },
-
-               /* find out the current status */
-               { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */
-               { mk_mii_write(MII_LXT970_IER, 0x0000), NULL },
-               { mk_mii_end, }
-       };
-static phy_info_t const phy_info_lxt970 = {
-       .id = 0x07810000,
-       .name = "LXT970",
-       .config = phy_cmd_lxt970_config,
-       .startup = phy_cmd_lxt970_startup,
-       .ack_int = phy_cmd_lxt970_ack_int,
-       .shutdown = phy_cmd_lxt970_shutdown
-};
-
-/* ------------------------------------------------------------------------- */
-/* The Level one LXT971 is used on some of my custom boards                  */
-
-/* register definitions for the 971 */
+spin_unlock:
+       spin_unlock_irqrestore(&fep->hw_lock, flags);
 
-#define MII_LXT971_PCR       16  /* Port Control Register     */
-#define MII_LXT971_SR2       17  /* Status Register 2         */
-#define MII_LXT971_IER       18  /* Interrupt Enable Register */
-#define MII_LXT971_ISR       19  /* Interrupt Status Register */
-#define MII_LXT971_LCR       20  /* LED Control Register      */
-#define MII_LXT971_TCR       30  /* Transmit Control Register */
+       if (status_change)
+               phy_print_status(phy_dev);
+}
 
 /*
- * I had some nice ideas of running the MDIO faster...
- * The 971 should support 8MHz and I tried it, but things acted really
- * weird, so 2.5 MHz ought to be enough for anyone...
+ * NOTE: a MII transaction is during around 25 us, so polling it...
  */
-
-static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
+static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
+       struct fec_enet_private *fep = bus->priv;
+       int timeout = FEC_MII_TIMEOUT;
 
-       status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
+       fep->mii_timeout = 0;
 
-       if (mii_reg & 0x0400) {
-               fep->link = 1;
-               status |= PHY_STAT_LINK;
-       } else {
-               fep->link = 0;
-       }
-       if (mii_reg & 0x0080)
-               status |= PHY_STAT_ANC;
-       if (mii_reg & 0x4000) {
-               if (mii_reg & 0x0200)
-                       status |= PHY_STAT_100FDX;
-               else
-                       status |= PHY_STAT_100HDX;
-       } else {
-               if (mii_reg & 0x0200)
-                       status |= PHY_STAT_10FDX;
-               else
-                       status |= PHY_STAT_10HDX;
+       /* clear MII end of transfer bit*/
+       writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+
+       /* start a read op */
+       writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+               FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
+               FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
+
+       /* wait for end of transfer */
+       while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
+               cpu_relax();
+               if (timeout-- < 0) {
+                       fep->mii_timeout = 1;
+                       printk(KERN_ERR "FEC: MDIO read timeout\n");
+                       return -ETIMEDOUT;
+               }
        }
-       if (mii_reg & 0x0008)
-               status |= PHY_STAT_FAULT;
 
-       *s = status;
+       /* return value */
+       return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
 }
 
-static phy_cmd_t const phy_cmd_lxt971_config[] = {
-               /* limit to 10MBit because my prototype board
-                * doesn't work with 100. */
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_lxt971_startup[] = {  /* enable interrupts */
-               { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL },
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */
-               /* Somehow does the 971 tell me that the link is down
-                * the first read after power-up.
-                * read here to get a valid value in ack_int */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_lxt971_ack_int[] = {
-               /* acknowledge the int before reading status ! */
-               { mk_mii_read(MII_LXT971_ISR), NULL },
-               /* find out the current status */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */
-               { mk_mii_write(MII_LXT971_IER, 0x0000), NULL },
-               { mk_mii_end, }
-       };
-static phy_info_t const phy_info_lxt971 = {
-       .id = 0x0001378e,
-       .name = "LXT971",
-       .config = phy_cmd_lxt971_config,
-       .startup = phy_cmd_lxt971_startup,
-       .ack_int = phy_cmd_lxt971_ack_int,
-       .shutdown = phy_cmd_lxt971_shutdown
-};
-
-/* ------------------------------------------------------------------------- */
-/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
-
-/* register definitions */
-
-#define MII_QS6612_MCR       17  /* Mode Control Register      */
-#define MII_QS6612_FTR       27  /* Factory Test Register      */
-#define MII_QS6612_MCO       28  /* Misc. Control Register     */
-#define MII_QS6612_ISR       29  /* Interrupt Source Register  */
-#define MII_QS6612_IMR       30  /* Interrupt Mask Register    */
-#define MII_QS6612_PCR       31  /* 100BaseTx PHY Control Reg. */
-
-static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
+static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+                          u16 value)
 {
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
-
-       status = *s & ~(PHY_STAT_SPMASK);
+       struct fec_enet_private *fep = bus->priv;
+       int timeout = FEC_MII_TIMEOUT;
 
-       switch((mii_reg >> 2) & 7) {
-       case 1: status |= PHY_STAT_10HDX; break;
-       case 2: status |= PHY_STAT_100HDX; break;
-       case 5: status |= PHY_STAT_10FDX; break;
-       case 6: status |= PHY_STAT_100FDX; break;
-}
-
-       *s = status;
-}
+       fep->mii_timeout = 0;
 
-static phy_cmd_t const phy_cmd_qs6612_config[] = {
-               /* The PHY powers up isolated on the RPX,
-                * so send a command to allow operation.
-                */
-               { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },
-
-               /* parse cr and anar to get some info */
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_qs6612_startup[] = {  /* enable interrupts */
-               { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL },
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_qs6612_ack_int[] = {
-               /* we need to read ISR, SR and ANER to acknowledge */
-               { mk_mii_read(MII_QS6612_ISR), NULL },
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_read(MII_REG_ANER), NULL },
-
-               /* read pcr to get info */
-               { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */
-               { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL },
-               { mk_mii_end, }
-       };
-static phy_info_t const phy_info_qs6612 = {
-       .id = 0x00181440,
-       .name = "QS6612",
-       .config = phy_cmd_qs6612_config,
-       .startup = phy_cmd_qs6612_startup,
-       .ack_int = phy_cmd_qs6612_ack_int,
-       .shutdown = phy_cmd_qs6612_shutdown
-};
-
-/* ------------------------------------------------------------------------- */
-/* AMD AM79C874 phy                                                          */
+       /* clear MII end of transfer bit*/
+       writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
 
-/* register definitions for the 874 */
+       /* start a read op */
+       writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+               FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
+               FEC_MMFR_TA | FEC_MMFR_DATA(value),
+               fep->hwp + FEC_MII_DATA);
+
+       /* wait for end of transfer */
+       while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
+               cpu_relax();
+               if (timeout-- < 0) {
+                       fep->mii_timeout = 1;
+                       printk(KERN_ERR "FEC: MDIO write timeout\n");
+                       return -ETIMEDOUT;
+               }
+       }
 
-#define MII_AM79C874_MFR       16  /* Miscellaneous Feature Register */
-#define MII_AM79C874_ICSR      17  /* Interrupt/Status Register      */
-#define MII_AM79C874_DR        18  /* Diagnostic Register            */
-#define MII_AM79C874_PMLR      19  /* Power and Loopback Register    */
-#define MII_AM79C874_MCR       21  /* ModeControl Register           */
-#define MII_AM79C874_DC        23  /* Disconnect Counter             */
-#define MII_AM79C874_REC       24  /* Recieve Error Counter          */
+       return 0;
+}
 
-static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
+static int fec_enet_mdio_reset(struct mii_bus *bus)
 {
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-       uint status;
-
-       status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
-
-       if (mii_reg & 0x0080)
-               status |= PHY_STAT_ANC;
-       if (mii_reg & 0x0400)
-               status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX);
-       else
-               status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);
-
-       *s = status;
+       return 0;
 }
 
-static phy_cmd_t const phy_cmd_am79c874_config[] = {
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_am79c874_startup[] = {  /* enable interrupts */
-               { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
-               /* find out the current status */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr },
-               /* we only need to read ISR to acknowledge */
-               { mk_mii_read(MII_AM79C874_ICSR), NULL },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */
-               { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL },
-               { mk_mii_end, }
-       };
-static phy_info_t const phy_info_am79c874 = {
-       .id = 0x00022561,
-       .name = "AM79C874",
-       .config = phy_cmd_am79c874_config,
-       .startup = phy_cmd_am79c874_startup,
-       .ack_int = phy_cmd_am79c874_ack_int,
-       .shutdown = phy_cmd_am79c874_shutdown
-};
-
-
-/* ------------------------------------------------------------------------- */
-/* Kendin KS8721BL phy                                                       */
-
-/* register definitions for the 8721 */
-
-#define MII_KS8721BL_RXERCR    21
-#define MII_KS8721BL_ICSR      27
-#define        MII_KS8721BL_PHYCR      31
-
-static phy_cmd_t const phy_cmd_ks8721bl_config[] = {
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_ks8721bl_startup[] = {  /* enable interrupts */
-               { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
-               /* find out the current status */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               /* we only need to read ISR to acknowledge */
-               { mk_mii_read(MII_KS8721BL_ICSR), NULL },
-               { mk_mii_end, }
-       };
-static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */
-               { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL },
-               { mk_mii_end, }
-       };
-static phy_info_t const phy_info_ks8721bl = {
-       .id = 0x00022161,
-       .name = "KS8721BL",
-       .config = phy_cmd_ks8721bl_config,
-       .startup = phy_cmd_ks8721bl_startup,
-       .ack_int = phy_cmd_ks8721bl_ack_int,
-       .shutdown = phy_cmd_ks8721bl_shutdown
-};
-
-/* ------------------------------------------------------------------------- */
-/* register definitions for the DP83848 */
-
-#define MII_DP8384X_PHYSTST    16  /* PHY Status Register */
-
-static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
+static int fec_enet_mii_probe(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
-
-       *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
-
-       /* Link up */
-       if (mii_reg & 0x0001) {
-               fep->link = 1;
-               *s |= PHY_STAT_LINK;
-       } else
-               fep->link = 0;
-       /* Status of link */
-       if (mii_reg & 0x0010)   /* Autonegotioation complete */
-               *s |= PHY_STAT_ANC;
-       if (mii_reg & 0x0002) {   /* 10MBps? */
-               if (mii_reg & 0x0004)   /* Full Duplex? */
-                       *s |= PHY_STAT_10FDX;
-               else
-                       *s |= PHY_STAT_10HDX;
-       } else {                  /* 100 Mbps? */
-               if (mii_reg & 0x0004)   /* Full Duplex? */
-                       *s |= PHY_STAT_100FDX;
-               else
-                       *s |= PHY_STAT_100HDX;
-       }
-       if (mii_reg & 0x0008)
-               *s |= PHY_STAT_FAULT;
-}
+       struct phy_device *phy_dev = NULL;
+       int phy_addr;
 
-static phy_info_t phy_info_dp83848= {
-       0x020005c9,
-       "DP83848",
-
-       (const phy_cmd_t []) {  /* config */
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 },
-               { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* startup - enable interrupts */
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */
-               { mk_mii_end, }
-       },
-       (const phy_cmd_t []) {  /* shutdown */
-               { mk_mii_end, }
-       },
-};
+       /* find the first phy */
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+               if (fep->mii_bus->phy_map[phy_addr]) {
+                       phy_dev = fep->mii_bus->phy_map[phy_addr];
+                       break;
+               }
+       }
 
-static phy_info_t phy_info_lan8700 = {
-       0x0007C0C,
-       "LAN8700",
-       (const phy_cmd_t []) { /* config */
-               { mk_mii_read(MII_REG_CR), mii_parse_cr },
-               { mk_mii_read(MII_REG_ANAR), mii_parse_anar },
-               { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* startup */
-               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
-               { mk_mii_read(MII_REG_SR), mii_parse_sr },
-               { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* act_int */
-               { mk_mii_end, }
-       },
-       (const phy_cmd_t []) { /* shutdown */
-               { mk_mii_end, }
-       },
-};
-/* ------------------------------------------------------------------------- */
+       if (!phy_dev) {
+               printk(KERN_ERR "%s: no PHY found\n", dev->name);
+               return -ENODEV;
+       }
 
-static phy_info_t const * const phy_info[] = {
-       &phy_info_lxt970,
-       &phy_info_lxt971,
-       &phy_info_qs6612,
-       &phy_info_am79c874,
-       &phy_info_ks8721bl,
-       &phy_info_dp83848,
-       &phy_info_lan8700,
-       NULL
-};
+       /* attach the mac to the phy */
+       phy_dev = phy_connect(dev, dev_name(&phy_dev->dev),
+                            &fec_enet_adjust_link, 0,
+                            PHY_INTERFACE_MODE_MII);
+       if (IS_ERR(phy_dev)) {
+               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+               return PTR_ERR(phy_dev);
+       }
 
-/* ------------------------------------------------------------------------- */
-#ifdef HAVE_mii_link_interrupt
-static irqreturn_t
-mii_link_interrupt(int irq, void * dev_id);
+       /* mask with MAC supported features */
+       phy_dev->supported &= PHY_BASIC_FEATURES;
+       phy_dev->advertising = phy_dev->supported;
 
-/*
- *     This is specific to the MII interrupt setup of the M5272EVB.
- */
-static void __inline__ fec_request_mii_intr(struct net_device *dev)
-{
-       if (request_irq(66, mii_link_interrupt, IRQF_DISABLED, "fec(MII)", dev) != 0)
-               printk("FEC: Could not allocate fec(MII) IRQ(66)!\n");
-}
+       fep->phy_dev = phy_dev;
+       fep->link = 0;
+       fep->full_duplex = 0;
 
-static void __inline__ fec_disable_phy_intr(struct net_device *dev)
-{
-       free_irq(66, dev);
+       return 0;
 }
-#endif
 
-#ifdef CONFIG_M5272
-static void __inline__ fec_get_mac(struct net_device *dev)
+static int fec_enet_mii_init(struct platform_device *pdev)
 {
+       struct net_device *dev = platform_get_drvdata(pdev);
        struct fec_enet_private *fep = netdev_priv(dev);
-       unsigned char *iap, tmpaddr[ETH_ALEN];
+       int err = -ENXIO, i;
 
-       if (FEC_FLASHMAC) {
-               /*
-                * Get MAC address from FLASH.
-                * If it is all 1's or 0's, use the default.
-                */
-               iap = (unsigned char *)FEC_FLASHMAC;
-               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
-                   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
-                       iap = fec_mac_default;
-               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
-                   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
-                       iap = fec_mac_default;
-       } else {
-               *((unsigned long *) &tmpaddr[0]) = readl(fep->hwp + FEC_ADDR_LOW);
-               *((unsigned short *) &tmpaddr[4]) = (readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
-               iap = &tmpaddr[0];
-       }
+       fep->mii_timeout = 0;
 
-       memcpy(dev->dev_addr, iap, ETH_ALEN);
-
-       /* Adjust MAC if using default MAC address */
-       if (iap == fec_mac_default)
-                dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
-}
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-static void mii_display_status(struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile uint *s = &(fep->phy_status);
+       /*
+        * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
+        */
+       fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
+       writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 
-       if (!fep->link && !fep->old_link) {
-               /* Link is still down - don't print anything */
-               return;
+       fep->mii_bus = mdiobus_alloc();
+       if (fep->mii_bus == NULL) {
+               err = -ENOMEM;
+               goto err_out;
        }
 
-       printk("%s: status: ", dev->name);
-
-       if (!fep->link) {
-               printk("link down");
-       } else {
-               printk("link up");
-
-               switch(*s & PHY_STAT_SPMASK) {
-               case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;
-               case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;
-               case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;
-               case PHY_STAT_10HDX: printk(", 10MBit Half Duplex"); break;
-               default:
-                       printk(", Unknown speed/duplex");
-               }
-
-               if (*s & PHY_STAT_ANC)
-                       printk(", auto-negotiation complete");
+       fep->mii_bus->name = "fec_enet_mii_bus";
+       fep->mii_bus->read = fec_enet_mdio_read;
+       fep->mii_bus->write = fec_enet_mdio_write;
+       fep->mii_bus->reset = fec_enet_mdio_reset;
+       snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id);
+       fep->mii_bus->priv = fep;
+       fep->mii_bus->parent = &pdev->dev;
+
+       fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (!fep->mii_bus->irq) {
+               err = -ENOMEM;
+               goto err_out_free_mdiobus;
        }
 
-       if (*s & PHY_STAT_FAULT)
-               printk(", remote fault");
-
-       printk(".\n");
-}
-
-static void mii_display_config(struct work_struct *work)
-{
-       struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
-       struct net_device *dev = fep->netdev;
-       uint status = fep->phy_status;
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               fep->mii_bus->irq[i] = PHY_POLL;
 
-       /*
-       ** When we get here, phy_task is already removed from
-       ** the workqueue.  It is thus safe to allow to reuse it.
-       */
-       fep->mii_phy_task_queued = 0;
-       printk("%s: config: auto-negotiation ", dev->name);
-
-       if (status & PHY_CONF_ANE)
-               printk("on");
-       else
-               printk("off");
+       platform_set_drvdata(dev, fep->mii_bus);
 
-       if (status & PHY_CONF_100FDX)
-               printk(", 100FDX");
-       if (status & PHY_CONF_100HDX)
-               printk(", 100HDX");
-       if (status & PHY_CONF_10FDX)
-               printk(", 10FDX");
-       if (status & PHY_CONF_10HDX)
-               printk(", 10HDX");
-       if (!(status & PHY_CONF_SPMASK))
-               printk(", No speed/duplex selected?");
+       if (mdiobus_register(fep->mii_bus))
+               goto err_out_free_mdio_irq;
 
-       if (status & PHY_CONF_LOOP)
-               printk(", loopback enabled");
+       if (fec_enet_mii_probe(dev) != 0)
+               goto err_out_unregister_bus;
 
-       printk(".\n");
+       return 0;
 
-       fep->sequence_done = 1;
+err_out_unregister_bus:
+       mdiobus_unregister(fep->mii_bus);
+err_out_free_mdio_irq:
+       kfree(fep->mii_bus->irq);
+err_out_free_mdiobus:
+       mdiobus_free(fep->mii_bus);
+err_out:
+       return err;
 }
 
-static void mii_relink(struct work_struct *work)
+static void fec_enet_mii_remove(struct fec_enet_private *fep)
 {
-       struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
-       struct net_device *dev = fep->netdev;
-       int duplex;
-
-       /*
-       ** When we get here, phy_task is already removed from
-       ** the workqueue.  It is thus safe to allow to reuse it.
-       */
-       fep->mii_phy_task_queued = 0;
-       fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
-       mii_display_status(dev);
-       fep->old_link = fep->link;
-
-       if (fep->link) {
-               duplex = 0;
-               if (fep->phy_status
-                   & (PHY_STAT_100FDX | PHY_STAT_10FDX))
-                       duplex = 1;
-               fec_restart(dev, duplex);
-       } else
-               fec_stop(dev);
+       if (fep->phy_dev)
+               phy_disconnect(fep->phy_dev);
+       mdiobus_unregister(fep->mii_bus);
+       kfree(fep->mii_bus->irq);
+       mdiobus_free(fep->mii_bus);
 }
 
-/* mii_queue_relink is called in interrupt context from mii_link_interrupt */
-static void mii_queue_relink(uint mii_reg, struct net_device *dev)
+static int fec_enet_get_settings(struct net_device *dev,
+                                 struct ethtool_cmd *cmd)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
+       struct phy_device *phydev = fep->phy_dev;
 
-       /*
-        * We cannot queue phy_task twice in the workqueue.  It
-        * would cause an endless loop in the workqueue.
-        * Fortunately, if the last mii_relink entry has not yet been
-        * executed now, it will do the job for the current interrupt,
-        * which is just what we want.
-        */
-       if (fep->mii_phy_task_queued)
-               return;
+       if (!phydev)
+               return -ENODEV;
 
-       fep->mii_phy_task_queued = 1;
-       INIT_WORK(&fep->phy_task, mii_relink);
-       schedule_work(&fep->phy_task);
+       return phy_ethtool_gset(phydev, cmd);
 }
 
-/* mii_queue_config is called in interrupt context from fec_enet_mii */
-static void mii_queue_config(uint mii_reg, struct net_device *dev)
+static int fec_enet_set_settings(struct net_device *dev,
+                                struct ethtool_cmd *cmd)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
+       struct phy_device *phydev = fep->phy_dev;
 
-       if (fep->mii_phy_task_queued)
-               return;
+       if (!phydev)
+               return -ENODEV;
 
-       fep->mii_phy_task_queued = 1;
-       INIT_WORK(&fep->phy_task, mii_display_config);
-       schedule_work(&fep->phy_task);
+       return phy_ethtool_sset(phydev, cmd);
 }
 
-phy_cmd_t const phy_cmd_relink[] = {
-       { mk_mii_read(MII_REG_CR), mii_queue_relink },
-       { mk_mii_end, }
-       };
-phy_cmd_t const phy_cmd_config[] = {
-       { mk_mii_read(MII_REG_CR), mii_queue_config },
-       { mk_mii_end, }
-       };
-
-/* Read remainder of PHY ID. */
-static void
-mii_discover_phy3(uint mii_reg, struct net_device *dev)
+static void fec_enet_get_drvinfo(struct net_device *dev,
+                                struct ethtool_drvinfo *info)
 {
-       struct fec_enet_private *fep;
-       int i;
-
-       fep = netdev_priv(dev);
-       fep->phy_id |= (mii_reg & 0xffff);
-       printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id);
-
-       for(i = 0; phy_info[i]; i++) {
-               if(phy_info[i]->id == (fep->phy_id >> 4))
-                       break;
-       }
-
-       if (phy_info[i])
-               printk(" -- %s\n", phy_info[i]->name);
-       else
-               printk(" -- unknown PHY!\n");
+       struct fec_enet_private *fep = netdev_priv(dev);
 
-       fep->phy = phy_info[i];
-       fep->phy_id_done = 1;
+       strcpy(info->driver, fep->pdev->dev.driver->name);
+       strcpy(info->version, "Revision: 1.0");
+       strcpy(info->bus_info, dev_name(&dev->dev));
 }
 
-/* Scan all of the MII PHY addresses looking for someone to respond
- * with a valid ID.  This usually happens quickly.
- */
-static void
-mii_discover_phy(uint mii_reg, struct net_device *dev)
-{
-       struct fec_enet_private *fep;
-       uint phytype;
-
-       fep = netdev_priv(dev);
-
-       if (fep->phy_addr < 32) {
-               if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {
-
-                       /* Got first part of ID, now get remainder */
-                       fep->phy_id = phytype << 16;
-                       mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR2),
-                                                       mii_discover_phy3);
-               } else {
-                       fep->phy_addr++;
-                       mii_queue_unlocked(dev, mk_mii_read(MII_REG_PHYIR1),
-                                                       mii_discover_phy);
-               }
-       } else {
-               printk("FEC: No PHY device found.\n");
-               /* Disable external MII interface */
-               writel(0, fep->hwp + FEC_MII_SPEED);
-               fep->phy_speed = 0;
-#ifdef HAVE_mii_link_interrupt
-               fec_disable_phy_intr(dev);
-#endif
-       }
-}
+static struct ethtool_ops fec_enet_ethtool_ops = {
+       .get_settings           = fec_enet_get_settings,
+       .set_settings           = fec_enet_set_settings,
+       .get_drvinfo            = fec_enet_get_drvinfo,
+       .get_link               = ethtool_op_get_link,
+};
 
-/* This interrupt occurs when the PHY detects a link change */
-#ifdef HAVE_mii_link_interrupt
-static irqreturn_t
-mii_link_interrupt(int irq, void * dev_id)
+static int fec_enet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       struct  net_device *dev = dev_id;
        struct fec_enet_private *fep = netdev_priv(dev);
+       struct phy_device *phydev = fep->phy_dev;
+
+       if (!netif_running(dev))
+               return -EINVAL;
 
-       mii_do_cmd(dev, fep->phy->ack_int);
-       mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
+       if (!phydev)
+               return -ENODEV;
 
-       return IRQ_HANDLED;
+       return phy_mii_ioctl(phydev, if_mii(rq), cmd);
 }
-#endif
 
 static void fec_enet_free_buffers(struct net_device *dev)
 {
@@ -1509,35 +913,8 @@ fec_enet_open(struct net_device *dev)
        if (ret)
                return ret;
 
-       fep->sequence_done = 0;
-       fep->link = 0;
-
-       fec_restart(dev, 1);
-
-       if (fep->phy) {
-               mii_do_cmd(dev, fep->phy->ack_int);
-               mii_do_cmd(dev, fep->phy->config);
-               mii_do_cmd(dev, phy_cmd_config);  /* display configuration */
-
-               /* Poll until the PHY tells us its configuration
-                * (not link state).
-                * Request is initiated by mii_do_cmd above, but answer
-                * comes by interrupt.
-                * This should take about 25 usec per register at 2.5 MHz,
-                * and we read approximately 5 registers.
-                */
-               while(!fep->sequence_done)
-                       schedule();
-
-               mii_do_cmd(dev, fep->phy->startup);
-       }
-
-       /* Set the initial link state to true. A lot of hardware
-        * based on this device does not implement a PHY interrupt,
-        * so we are never notified of link change.
-        */
-       fep->link = 1;
-
+       /* schedule a link state check */
+       phy_start(fep->phy_dev);
        netif_start_queue(dev);
        fep->opened = 1;
        return 0;
@@ -1550,6 +927,7 @@ fec_enet_close(struct net_device *dev)
 
        /* Don't know what to do yet. */
        fep->opened = 0;
+       phy_stop(fep->phy_dev);
        netif_stop_queue(dev);
        fec_stop(dev);
 
@@ -1574,7 +952,7 @@ fec_enet_close(struct net_device *dev)
 static void set_multicast_list(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned int i, bit, data, crc, tmp;
        unsigned char hash;
 
@@ -1604,16 +982,16 @@ static void set_multicast_list(struct net_device *dev)
        writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
        writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
 
-       netdev_for_each_mc_addr(dmi, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                /* Only support group multicast for now */
-               if (!(dmi->dmi_addr[0] & 1))
+               if (!(ha->addr[0] & 1))
                        continue;
 
                /* calculate crc32 value of mac address */
                crc = 0xffffffff;
 
-               for (i = 0; i < dmi->dmi_addrlen; i++) {
-                       data = dmi->dmi_addr[i];
+               for (i = 0; i < dev->addr_len; i++) {
+                       data = ha->addr[i];
                        for (bit = 0; bit < 8; bit++, data >>= 1) {
                                crc = (crc >> 1) ^
                                (((crc ^ data) & 1) ? CRC32_POLY : 0);
@@ -1666,6 +1044,7 @@ static const struct net_device_ops fec_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_tx_timeout         = fec_timeout,
        .ndo_set_mac_address    = fec_set_mac_address,
+       .ndo_do_ioctl           = fec_enet_ioctl,
 };
 
  /*
@@ -1689,7 +1068,6 @@ static int fec_enet_init(struct net_device *dev, int index)
        }
 
        spin_lock_init(&fep->hw_lock);
-       spin_lock_init(&fep->mii_lock);
 
        fep->index = index;
        fep->hwp = (void __iomem *)dev->base_addr;
@@ -1716,20 +1094,10 @@ static int fec_enet_init(struct net_device *dev, int index)
        fep->rx_bd_base = cbd_base;
        fep->tx_bd_base = cbd_base + RX_RING_SIZE;
 
-#ifdef HAVE_mii_link_interrupt
-       fec_request_mii_intr(dev);
-#endif
        /* The FEC Ethernet specific entries in the device structure */
        dev->watchdog_timeo = TX_TIMEOUT;
        dev->netdev_ops = &fec_netdev_ops;
-
-       for (i=0; i<NMII-1; i++)
-               mii_cmds[i].mii_next = &mii_cmds[i+1];
-       mii_free = mii_cmds;
-
-       /* Set MII speed to 2.5 MHz */
-       fep->phy_speed = ((((clk_get_rate(fep->clk) / 2 + 4999999)
-                                       / 2500000) / 2) & 0x3F) << 1;
+       dev->ethtool_ops = &fec_enet_ethtool_ops;
 
        /* Initialize the receive buffer descriptors. */
        bdp = fep->rx_bd_base;
@@ -1760,13 +1128,6 @@ static int fec_enet_init(struct net_device *dev, int index)
 
        fec_restart(dev, 0);
 
-       /* Queue up command to detect the PHY and initialize the
-        * remainder of the interface.
-        */
-       fep->phy_id_done = 0;
-       fep->phy_addr = 0;
-       mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
-
        return 0;
 }
 
@@ -1835,8 +1196,7 @@ fec_restart(struct net_device *dev, int duplex)
        writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
        /* Enable interrupts we wish to service */
-       writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII,
-                       fep->hwp + FEC_IMASK);
+       writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK);
 }
 
 static void
@@ -1859,7 +1219,6 @@ fec_stop(struct net_device *dev)
        /* Clear outstanding MII command interrupts. */
        writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
 
-       writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
        writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
 }
 
@@ -1891,6 +1250,7 @@ fec_probe(struct platform_device *pdev)
        memset(fep, 0, sizeof(*fep));
 
        ndev->base_addr = (unsigned long)ioremap(r->start, resource_size(r));
+       fep->pdev = pdev;
 
        if (!ndev->base_addr) {
                ret = -ENOMEM;
@@ -1926,13 +1286,24 @@ fec_probe(struct platform_device *pdev)
        if (ret)
                goto failed_init;
 
+       ret = fec_enet_mii_init(pdev);
+       if (ret)
+               goto failed_mii_init;
+
        ret = register_netdev(ndev);
        if (ret)
                goto failed_register;
 
+       printk(KERN_INFO "%s: Freescale FEC PHY driver [%s] "
+               "(mii_bus:phy_addr=%s, irq=%d)\n", ndev->name,
+               fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev),
+               fep->phy_dev->irq);
+
        return 0;
 
 failed_register:
+       fec_enet_mii_remove(fep);
+failed_mii_init:
 failed_init:
        clk_disable(fep->clk);
        clk_put(fep->clk);
@@ -1959,6 +1330,7 @@ fec_drv_remove(struct platform_device *pdev)
        platform_set_drvdata(pdev, NULL);
 
        fec_stop(ndev);
+       fec_enet_mii_remove(fep);
        clk_disable(fep->clk);
        clk_put(fep->clk);
        iounmap((void __iomem *)ndev->base_addr);
index 4a43e56b739496fddaf8daba5202f2f20831271d..221f440c10f4b59c49232283dae0fbbd48920856 100644 (file)
@@ -327,7 +327,6 @@ static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       dev->trans_start = jiffies;
 
        bd = (struct bcom_fec_bd *)
                bcom_prepare_next_buffer(priv->tx_dmatsk);
@@ -436,7 +435,6 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id)
                                 DMA_FROM_DEVICE);
                length = status & BCOM_FEC_RX_BD_LEN_MASK;
                skb_put(rskb, length - 4);      /* length without CRC32 */
-               rskb->dev = dev;
                rskb->protocol = eth_type_trans(rskb, dev);
                netif_rx(rskb);
 
@@ -576,12 +574,12 @@ static void mpc52xx_fec_set_multicast_list(struct net_device *dev)
                        out_be32(&fec->gaddr2, 0xffffffff);
                } else {
                        u32 crc;
-                       struct dev_mc_list *dmi;
+                       struct netdev_hw_addr *ha;
                        u32 gaddr1 = 0x00000000;
                        u32 gaddr2 = 0x00000000;
 
-                       netdev_for_each_mc_addr(dmi, dev) {
-                               crc = ether_crc_le(6, dmi->dmi_addr) >> 26;
+                       netdev_for_each_mc_addr(ha, dev) {
+                               crc = ether_crc_le(6, ha->addr) >> 26;
                                if (crc >= 32)
                                        gaddr1 |= 1 << (crc-32);
                                else
index 5c98f7c22425ee0c0209205219ea53075c9577cc..268ea4d566d732b1fd0705898d82dd854eb8be8f 100644 (file)
@@ -1104,20 +1104,16 @@ static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask)
 
 static void nv_napi_enable(struct net_device *dev)
 {
-#ifdef CONFIG_FORCEDETH_NAPI
        struct fe_priv *np = get_nvpriv(dev);
 
        napi_enable(&np->napi);
-#endif
 }
 
 static void nv_napi_disable(struct net_device *dev)
 {
-#ifdef CONFIG_FORCEDETH_NAPI
        struct fe_priv *np = get_nvpriv(dev);
 
        napi_disable(&np->napi);
-#endif
 }
 
 #define MII_READ       (-1)
@@ -1810,7 +1806,6 @@ static int nv_alloc_rx_optimized(struct net_device *dev)
 }
 
 /* If rx bufs are exhausted called after 50ms to attempt to refresh */
-#ifdef CONFIG_FORCEDETH_NAPI
 static void nv_do_rx_refill(unsigned long data)
 {
        struct net_device *dev = (struct net_device *) data;
@@ -1819,41 +1814,6 @@ static void nv_do_rx_refill(unsigned long data)
        /* Just reschedule NAPI rx processing */
        napi_schedule(&np->napi);
 }
-#else
-static void nv_do_rx_refill(unsigned long data)
-{
-       struct net_device *dev = (struct net_device *) data;
-       struct fe_priv *np = netdev_priv(dev);
-       int retcode;
-
-       if (!using_multi_irqs(dev)) {
-               if (np->msi_flags & NV_MSI_X_ENABLED)
-                       disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
-               else
-                       disable_irq(np->pci_dev->irq);
-       } else {
-               disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
-       }
-       if (!nv_optimized(np))
-               retcode = nv_alloc_rx(dev);
-       else
-               retcode = nv_alloc_rx_optimized(dev);
-       if (retcode) {
-               spin_lock_irq(&np->lock);
-               if (!np->in_shutdown)
-                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-               spin_unlock_irq(&np->lock);
-       }
-       if (!using_multi_irqs(dev)) {
-               if (np->msi_flags & NV_MSI_X_ENABLED)
-                       enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
-               else
-                       enable_irq(np->pci_dev->irq);
-       } else {
-               enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
-       }
-}
-#endif
 
 static void nv_init_rx(struct net_device *dev)
 {
@@ -2148,7 +2108,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int i;
        u32 offset = 0;
        u32 bcnt;
-       u32 size = skb->len-skb->data_len;
+       u32 size = skb_headlen(skb);
        u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
        u32 empty_slots;
        struct ring_desc* put_tx;
@@ -2254,7 +2214,6 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dprintk("\n");
        }
 
-       dev->trans_start = jiffies;
        writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
        return NETDEV_TX_OK;
 }
@@ -2269,7 +2228,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
        unsigned int i;
        u32 offset = 0;
        u32 bcnt;
-       u32 size = skb->len-skb->data_len;
+       u32 size = skb_headlen(skb);
        u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
        u32 empty_slots;
        struct ring_desc_ex* put_tx;
@@ -2409,7 +2368,6 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                dprintk("\n");
        }
 
-       dev->trans_start = jiffies;
        writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
        return NETDEV_TX_OK;
 }
@@ -2816,11 +2774,7 @@ static int nv_rx_process(struct net_device *dev, int limit)
                skb->protocol = eth_type_trans(skb, dev);
                dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
                                        dev->name, len, skb->protocol);
-#ifdef CONFIG_FORCEDETH_NAPI
-               netif_receive_skb(skb);
-#else
-               netif_rx(skb);
-#endif
+               napi_gro_receive(&np->napi, skb);
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += len;
 next_pkt:
@@ -2909,27 +2863,14 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit)
                                dev->name, len, skb->protocol);
 
                        if (likely(!np->vlangrp)) {
-#ifdef CONFIG_FORCEDETH_NAPI
-                               netif_receive_skb(skb);
-#else
-                               netif_rx(skb);
-#endif
+                               napi_gro_receive(&np->napi, skb);
                        } else {
                                vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
                                if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
-#ifdef CONFIG_FORCEDETH_NAPI
-                                       vlan_hwaccel_receive_skb(skb, np->vlangrp,
-                                                                vlanflags & NV_RX3_VLAN_TAG_MASK);
-#else
-                                       vlan_hwaccel_rx(skb, np->vlangrp,
-                                                       vlanflags & NV_RX3_VLAN_TAG_MASK);
-#endif
+                                       vlan_gro_receive(&np->napi, np->vlangrp,
+                                                        vlanflags & NV_RX3_VLAN_TAG_MASK, skb);
                                } else {
-#ifdef CONFIG_FORCEDETH_NAPI
-                                       netif_receive_skb(skb);
-#else
-                                       netif_rx(skb);
-#endif
+                                       napi_gro_receive(&np->napi, skb);
                                }
                        }
 
@@ -3104,12 +3045,14 @@ static void nv_set_multicast(struct net_device *dev)
                        if (dev->flags & IFF_ALLMULTI) {
                                alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0;
                        } else {
-                               struct dev_mc_list *walk;
+                               struct netdev_hw_addr *ha;
 
-                               netdev_for_each_mc_addr(walk, dev) {
+                               netdev_for_each_mc_addr(ha, dev) {
+                                       unsigned char *addr = ha->addr;
                                        u32 a, b;
-                                       a = le32_to_cpu(*(__le32 *) walk->dmi_addr);
-                                       b = le16_to_cpu(*(__le16 *) (&walk->dmi_addr[4]));
+
+                                       a = le32_to_cpu(*(__le32 *) addr);
+                                       b = le16_to_cpu(*(__le16 *) (&addr[4]));
                                        alwaysOn[0] &= a;
                                        alwaysOff[0] &= ~a;
                                        alwaysOn[1] &= b;
@@ -3494,10 +3437,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-#ifndef CONFIG_FORCEDETH_NAPI
-       int total_work = 0;
-       int loop_count = 0;
-#endif
 
        dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);
 
@@ -3514,7 +3453,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
 
        nv_msi_workaround(np);
 
-#ifdef CONFIG_FORCEDETH_NAPI
        if (napi_schedule_prep(&np->napi)) {
                /*
                 * Disable further irq's (msix not enabled with napi)
@@ -3523,65 +3461,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                __napi_schedule(&np->napi);
        }
 
-#else
-       do
-       {
-               int work = 0;
-               if ((work = nv_rx_process(dev, RX_WORK_PER_LOOP))) {
-                       if (unlikely(nv_alloc_rx(dev))) {
-                               spin_lock(&np->lock);
-                               if (!np->in_shutdown)
-                                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-                               spin_unlock(&np->lock);
-                       }
-               }
-
-               spin_lock(&np->lock);
-               work += nv_tx_done(dev, TX_WORK_PER_LOOP);
-               spin_unlock(&np->lock);
-
-               if (!work)
-                       break;
-
-               total_work += work;
-
-               loop_count++;
-       }
-       while (loop_count < max_interrupt_work);
-
-       if (nv_change_interrupt_mode(dev, total_work)) {
-               /* setup new irq mask */
-               writel(np->irqmask, base + NvRegIrqMask);
-       }
-
-       if (unlikely(np->events & NVREG_IRQ_LINK)) {
-               spin_lock(&np->lock);
-               nv_link_irq(dev);
-               spin_unlock(&np->lock);
-       }
-       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
-               spin_lock(&np->lock);
-               nv_linkchange(dev);
-               spin_unlock(&np->lock);
-               np->link_timeout = jiffies + LINK_TIMEOUT;
-       }
-       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
-               spin_lock(&np->lock);
-               /* disable interrupts on the nic */
-               if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                       writel(0, base + NvRegIrqMask);
-               else
-                       writel(np->irqmask, base + NvRegIrqMask);
-               pci_push(base);
-
-               if (!np->in_shutdown) {
-                       np->nic_poll_irq = np->irqmask;
-                       np->recover_error = 1;
-                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-               }
-               spin_unlock(&np->lock);
-       }
-#endif
        dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
 
        return IRQ_HANDLED;
@@ -3597,10 +3476,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-#ifndef CONFIG_FORCEDETH_NAPI
-       int total_work = 0;
-       int loop_count = 0;
-#endif
 
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
 
@@ -3617,7 +3492,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
 
        nv_msi_workaround(np);
 
-#ifdef CONFIG_FORCEDETH_NAPI
        if (napi_schedule_prep(&np->napi)) {
                /*
                 * Disable further irq's (msix not enabled with napi)
@@ -3625,66 +3499,6 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
                writel(0, base + NvRegIrqMask);
                __napi_schedule(&np->napi);
        }
-#else
-       do
-       {
-               int work = 0;
-               if ((work = nv_rx_process_optimized(dev, RX_WORK_PER_LOOP))) {
-                       if (unlikely(nv_alloc_rx_optimized(dev))) {
-                               spin_lock(&np->lock);
-                               if (!np->in_shutdown)
-                                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-                               spin_unlock(&np->lock);
-                       }
-               }
-
-               spin_lock(&np->lock);
-               work += nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
-               spin_unlock(&np->lock);
-
-               if (!work)
-                       break;
-
-               total_work += work;
-
-               loop_count++;
-       }
-       while (loop_count < max_interrupt_work);
-
-       if (nv_change_interrupt_mode(dev, total_work)) {
-               /* setup new irq mask */
-               writel(np->irqmask, base + NvRegIrqMask);
-       }
-
-       if (unlikely(np->events & NVREG_IRQ_LINK)) {
-               spin_lock(&np->lock);
-               nv_link_irq(dev);
-               spin_unlock(&np->lock);
-       }
-       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
-               spin_lock(&np->lock);
-               nv_linkchange(dev);
-               spin_unlock(&np->lock);
-               np->link_timeout = jiffies + LINK_TIMEOUT;
-       }
-       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
-               spin_lock(&np->lock);
-               /* disable interrupts on the nic */
-               if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                       writel(0, base + NvRegIrqMask);
-               else
-                       writel(np->irqmask, base + NvRegIrqMask);
-               pci_push(base);
-
-               if (!np->in_shutdown) {
-                       np->nic_poll_irq = np->irqmask;
-                       np->recover_error = 1;
-                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-               }
-               spin_unlock(&np->lock);
-       }
-
-#endif
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
 
        return IRQ_HANDLED;
@@ -3733,7 +3547,6 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
        return IRQ_RETVAL(i);
 }
 
-#ifdef CONFIG_FORCEDETH_NAPI
 static int nv_napi_poll(struct napi_struct *napi, int budget)
 {
        struct fe_priv *np = container_of(napi, struct fe_priv, napi);
@@ -3741,23 +3554,27 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
        u8 __iomem *base = get_hwbase(dev);
        unsigned long flags;
        int retcode;
-       int tx_work, rx_work;
+       int rx_count, tx_work=0, rx_work=0;
 
-       if (!nv_optimized(np)) {
-               spin_lock_irqsave(&np->lock, flags);
-               tx_work = nv_tx_done(dev, np->tx_ring_size);
-               spin_unlock_irqrestore(&np->lock, flags);
+       do {
+               if (!nv_optimized(np)) {
+                       spin_lock_irqsave(&np->lock, flags);
+                       tx_work += nv_tx_done(dev, np->tx_ring_size);
+                       spin_unlock_irqrestore(&np->lock, flags);
 
-               rx_work = nv_rx_process(dev, budget);
-               retcode = nv_alloc_rx(dev);
-       } else {
-               spin_lock_irqsave(&np->lock, flags);
-               tx_work = nv_tx_done_optimized(dev, np->tx_ring_size);
-               spin_unlock_irqrestore(&np->lock, flags);
+                       rx_count = nv_rx_process(dev, budget - rx_work);
+                       retcode = nv_alloc_rx(dev);
+               } else {
+                       spin_lock_irqsave(&np->lock, flags);
+                       tx_work += nv_tx_done_optimized(dev, np->tx_ring_size);
+                       spin_unlock_irqrestore(&np->lock, flags);
 
-               rx_work = nv_rx_process_optimized(dev, budget);
-               retcode = nv_alloc_rx_optimized(dev);
-       }
+                       rx_count = nv_rx_process_optimized(dev,
+                           budget - rx_work);
+                       retcode = nv_alloc_rx_optimized(dev);
+               }
+       } while (retcode == 0 &&
+                rx_count > 0 && (rx_work += rx_count) < budget);
 
        if (retcode) {
                spin_lock_irqsave(&np->lock, flags);
@@ -3800,7 +3617,6 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
        }
        return rx_work;
 }
-#endif
 
 static irqreturn_t nv_nic_irq_rx(int foo, void *data)
 {
@@ -5706,6 +5522,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
                dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
                dev->features |= NETIF_F_TSO;
+               dev->features |= NETIF_F_GRO;
        }
 
        np->vlanctl_bits = 0;
@@ -5758,9 +5575,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        else
                dev->netdev_ops = &nv_netdev_ops_optimized;
 
-#ifdef CONFIG_FORCEDETH_NAPI
        netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
-#endif
        SET_ETHTOOL_OPS(dev, &ops);
        dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
 
@@ -5863,7 +5678,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                /* msix has had reported issues when modifying irqmask
                   as in the case of napi, therefore, disable for now
                */
-#ifndef CONFIG_FORCEDETH_NAPI
+#if 0
                np->msi_flags |= NV_MSI_X_CAPABLE;
 #endif
        }
index 0770e2f6da6bb28ec73e33d8aa8c57e178e757e0..0fb0fefcb7874f5ba159be21a73db0fb3d710523 100644 (file)
@@ -674,8 +674,6 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                skb->data, skb->len, DMA_TO_DEVICE));
        CBDW_DATLEN(bdp, skb->len);
 
-       dev->trans_start = jiffies;
-
        /*
         * If this was the last BD in the ring, start at the beginning again.
         */
index 0a973e71876b591e2fc371e90dd1a8437ced969d..714da967fa19bde3162c5be324bd48fcd19e926f 100644 (file)
@@ -231,12 +231,12 @@ static void set_multicast_finish(struct net_device *dev)
 
 static void set_multicast_list(struct net_device *dev)
 {
-       struct dev_mc_list *pmc;
+       struct netdev_hw_addr *ha;
 
        if ((dev->flags & IFF_PROMISC) == 0) {
                set_multicast_start(dev);
-               netdev_for_each_mc_addr(pmc, dev)
-                       set_multicast_one(dev, pmc->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       set_multicast_one(dev, ha->addr);
                set_multicast_finish(dev);
        } else
                set_promiscuous_mode(dev);
index ec81f50d59196aac31d58fcc6146a9a44e72f01b..7eff92ef01da4de9e28857cfbe0a5c69f4789b41 100644 (file)
@@ -232,12 +232,12 @@ static void set_multicast_finish(struct net_device *dev)
 
 static void set_multicast_list(struct net_device *dev)
 {
-       struct dev_mc_list *pmc;
+       struct netdev_hw_addr *ha;
 
        if ((dev->flags & IFF_PROMISC) == 0) {
                set_multicast_start(dev);
-               netdev_for_each_mc_addr(pmc, dev)
-                       set_multicast_one(dev, pmc->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       set_multicast_one(dev, ha->addr);
                set_multicast_finish(dev);
        } else
                set_promiscuous_mode(dev);
index 34d3da751eb4001bc8925848de903cc7ce4a9270..7f0591e43cd992feac439dbdd83bbb7a9ae17d42 100644 (file)
@@ -223,12 +223,12 @@ static void set_multicast_finish(struct net_device *dev)
 
 static void set_multicast_list(struct net_device *dev)
 {
-       struct dev_mc_list *pmc;
+       struct netdev_hw_addr *ha;
 
        if ((dev->flags & IFF_PROMISC) == 0) {
                set_multicast_start(dev);
-               netdev_for_each_mc_addr(pmc, dev)
-                       set_multicast_one(dev, pmc->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       set_multicast_one(dev, ha->addr);
                set_multicast_finish(dev);
        } else
                set_promiscuous_mode(dev);
index 3acac5f930c8f7d3fd8563d46d046df94725673d..ff028f59b9306c086f03df626e5cecf31d131a22 100644 (file)
@@ -277,15 +277,17 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
        int tbiaddr = -1;
        const u32 *addrp;
        u64 addr = 0, size = 0;
-       int err = 0;
+       int err;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
        new_bus = mdiobus_alloc();
-       if (NULL == new_bus)
+       if (!new_bus) {
+               err = -ENOMEM;
                goto err_free_priv;
+       }
 
        new_bus->name = "Freescale PowerQUICC MII Bus",
        new_bus->read = &fsl_pq_mdio_read,
index 5d3763fb3472c4247933dec887767643728b693b..c6791cd4ee0537503a70f4cbd2d0a005725c863d 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/in.h>
+#include <linux/net_tstamp.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -377,6 +378,13 @@ static void gfar_init_mac(struct net_device *ndev)
                rctrl |= RCTRL_PADDING(priv->padding);
        }
 
+       /* Insert receive time stamps into padding alignment bytes */
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) {
+               rctrl &= ~RCTRL_PAL_MASK;
+               rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE | RCTRL_PADDING(8);
+               priv->padding = 8;
+       }
+
        /* keep vlan related bits if it's enabled */
        if (priv->vlgrp) {
                rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
@@ -501,7 +509,8 @@ void unlock_tx_qs(struct gfar_private *priv)
 /* Returns 1 if incoming frames use an FCB */
 static inline int gfar_uses_fcb(struct gfar_private *priv)
 {
-       return priv->vlgrp || priv->rx_csum_enable;
+       return priv->vlgrp || priv->rx_csum_enable ||
+               (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
 }
 
 static void free_tx_pointers(struct gfar_private *priv)
@@ -738,7 +747,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
                        FSL_GIANFAR_DEV_HAS_CSUM |
                        FSL_GIANFAR_DEV_HAS_VLAN |
                        FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
-                       FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+                       FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
+                       FSL_GIANFAR_DEV_HAS_TIMER;
 
        ctype = of_get_property(np, "phy-connection-type", NULL);
 
@@ -768,6 +778,48 @@ err_grp_init:
        return err;
 }
 
+static int gfar_hwtstamp_ioctl(struct net_device *netdev,
+                       struct ifreq *ifr, int cmd)
+{
+       struct hwtstamp_config config;
+       struct gfar_private *priv = netdev_priv(netdev);
+
+       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       /* reserved for future extensions */
+       if (config.flags)
+               return -EINVAL;
+
+       switch (config.tx_type) {
+       case HWTSTAMP_TX_OFF:
+               priv->hwts_tx_en = 0;
+               break;
+       case HWTSTAMP_TX_ON:
+               if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
+                       return -ERANGE;
+               priv->hwts_tx_en = 1;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       switch (config.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               priv->hwts_rx_en = 0;
+               break;
+       default:
+               if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
+                       return -ERANGE;
+               priv->hwts_rx_en = 1;
+               config.rx_filter = HWTSTAMP_FILTER_ALL;
+               break;
+       }
+
+       return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+               -EFAULT : 0;
+}
+
 /* Ioctl MII Interface */
 static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -776,6 +828,9 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        if (!netif_running(dev))
                return -EINVAL;
 
+       if (cmd == SIOCSHWTSTAMP)
+               return gfar_hwtstamp_ioctl(dev, rq, cmd);
+
        if (!priv->phydev)
                return -ENODEV;
 
@@ -978,7 +1033,8 @@ static int gfar_probe(struct of_device *ofdev,
        else
                priv->padding = 0;
 
-       if (dev->features & NETIF_F_IP_CSUM)
+       if (dev->features & NETIF_F_IP_CSUM ||
+                       priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
                dev->hard_header_len += GMAC_FCB_LEN;
 
        /* Program the isrg regs only if number of grps > 1 */
@@ -1288,21 +1344,9 @@ static struct dev_pm_ops gfar_pm_ops = {
 
 #define GFAR_PM_OPS (&gfar_pm_ops)
 
-static int gfar_legacy_suspend(struct of_device *ofdev, pm_message_t state)
-{
-       return gfar_suspend(&ofdev->dev);
-}
-
-static int gfar_legacy_resume(struct of_device *ofdev)
-{
-       return gfar_resume(&ofdev->dev);
-}
-
 #else
 
 #define GFAR_PM_OPS NULL
-#define gfar_legacy_suspend NULL
-#define gfar_legacy_resume NULL
 
 #endif
 
@@ -1683,7 +1727,7 @@ void gfar_start(struct net_device *dev)
                gfar_write(&regs->imask, IMASK_DEFAULT);
        }
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 void gfar_configure_coalescing(struct gfar_private *priv,
@@ -1923,23 +1967,29 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct netdev_queue *txq;
        struct gfar __iomem *regs = NULL;
        struct txfcb *fcb = NULL;
-       struct txbd8 *txbdp, *txbdp_start, *base;
+       struct txbd8 *txbdp, *txbdp_start, *base, *txbdp_tstamp = NULL;
        u32 lstatus;
-       int i, rq = 0;
+       int i, rq = 0, do_tstamp = 0;
        u32 bufaddr;
        unsigned long flags;
-       unsigned int nr_frags, length;
-
+       unsigned int nr_frags, nr_txbds, length;
+       union skb_shared_tx *shtx;
 
        rq = skb->queue_mapping;
        tx_queue = priv->tx_queue[rq];
        txq = netdev_get_tx_queue(dev, rq);
        base = tx_queue->tx_bd_base;
        regs = tx_queue->grp->regs;
+       shtx = skb_tx(skb);
+
+       /* check if time stamp should be generated */
+       if (unlikely(shtx->hardware && priv->hwts_tx_en))
+               do_tstamp = 1;
 
        /* make space for additional header when fcb is needed */
        if (((skb->ip_summed == CHECKSUM_PARTIAL) ||
-                       (priv->vlgrp && vlan_tx_tag_present(skb))) &&
+                       (priv->vlgrp && vlan_tx_tag_present(skb)) ||
+                       unlikely(do_tstamp)) &&
                        (skb_headroom(skb) < GMAC_FCB_LEN)) {
                struct sk_buff *skb_new;
 
@@ -1956,8 +2006,14 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* total number of fragments in the SKB */
        nr_frags = skb_shinfo(skb)->nr_frags;
 
+       /* calculate the required number of TxBDs for this skb */
+       if (unlikely(do_tstamp))
+               nr_txbds = nr_frags + 2;
+       else
+               nr_txbds = nr_frags + 1;
+
        /* check if there is space to queue this packet */
-       if ((nr_frags+1) > tx_queue->num_txbdfree) {
+       if (nr_txbds > tx_queue->num_txbdfree) {
                /* no space, stop the queue */
                netif_tx_stop_queue(txq);
                dev->stats.tx_fifo_errors++;
@@ -1969,9 +2025,19 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        txq->tx_packets ++;
 
        txbdp = txbdp_start = tx_queue->cur_tx;
+       lstatus = txbdp->lstatus;
+
+       /* Time stamp insertion requires one additional TxBD */
+       if (unlikely(do_tstamp))
+               txbdp_tstamp = txbdp = next_txbd(txbdp, base,
+                               tx_queue->tx_ring_size);
 
        if (nr_frags == 0) {
-               lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
+               if (unlikely(do_tstamp))
+                       txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_LAST |
+                                       TXBD_INTERRUPT);
+               else
+                       lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
        } else {
                /* Place the fragment addresses and lengths into the TxBDs */
                for (i = 0; i < nr_frags; i++) {
@@ -2017,11 +2083,32 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                gfar_tx_vlan(skb, fcb);
        }
 
-       /* setup the TxBD length and buffer pointer for the first BD */
+       /* Setup tx hardware time stamping if requested */
+       if (unlikely(do_tstamp)) {
+               shtx->in_progress = 1;
+               if (fcb == NULL)
+                       fcb = gfar_add_fcb(skb);
+               fcb->ptp = 1;
+               lstatus |= BD_LFLAG(TXBD_TOE);
+       }
+
        txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
                        skb_headlen(skb), DMA_TO_DEVICE);
 
-       lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
+       /*
+        * If time stamping is requested one additional TxBD must be set up. The
+        * first TxBD points to the FCB and must have a data length of
+        * GMAC_FCB_LEN. The second TxBD points to the actual frame data with
+        * the full frame length.
+        */
+       if (unlikely(do_tstamp)) {
+               txbdp_tstamp->bufPtr = txbdp_start->bufPtr + GMAC_FCB_LEN;
+               txbdp_tstamp->lstatus |= BD_LFLAG(TXBD_READY) |
+                               (skb_headlen(skb) - GMAC_FCB_LEN);
+               lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | GMAC_FCB_LEN;
+       } else {
+               lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
+       }
 
        /*
         * We can work in parallel with gfar_clean_tx_ring(), except
@@ -2061,9 +2148,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_queue->cur_tx = next_txbd(txbdp, base, tx_queue->tx_ring_size);
 
        /* reduce TxBD free count */
-       tx_queue->num_txbdfree -= (nr_frags + 1);
-
-       dev->trans_start = jiffies;
+       tx_queue->num_txbdfree -= (nr_txbds);
 
        /* If the next BD still needs to be cleaned up, then the bds
           are full.  We need to tell the kernel to stop sending us stuff. */
@@ -2251,16 +2336,18 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        struct net_device *dev = tx_queue->dev;
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar_priv_rx_q *rx_queue = NULL;
-       struct txbd8 *bdp;
+       struct txbd8 *bdp, *next = NULL;
        struct txbd8 *lbdp = NULL;
        struct txbd8 *base = tx_queue->tx_bd_base;
        struct sk_buff *skb;
        int skb_dirtytx;
        int tx_ring_size = tx_queue->tx_ring_size;
-       int frags = 0;
+       int frags = 0, nr_txbds = 0;
        int i;
        int howmany = 0;
        u32 lstatus;
+       size_t buflen;
+       union skb_shared_tx *shtx;
 
        rx_queue = priv->rx_queue[tx_queue->qindex];
        bdp = tx_queue->dirty_tx;
@@ -2270,7 +2357,18 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                unsigned long flags;
 
                frags = skb_shinfo(skb)->nr_frags;
-               lbdp = skip_txbd(bdp, frags, base, tx_ring_size);
+
+               /*
+                * When time stamping, one additional TxBD must be freed.
+                * Also, we need to dma_unmap_single() the TxPAL.
+                */
+               shtx = skb_tx(skb);
+               if (unlikely(shtx->in_progress))
+                       nr_txbds = frags + 2;
+               else
+                       nr_txbds = frags + 1;
+
+               lbdp = skip_txbd(bdp, nr_txbds - 1, base, tx_ring_size);
 
                lstatus = lbdp->lstatus;
 
@@ -2279,10 +2377,24 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
                                (lstatus & BD_LENGTH_MASK))
                        break;
 
-               dma_unmap_single(&priv->ofdev->dev,
-                               bdp->bufPtr,
-                               bdp->length,
-                               DMA_TO_DEVICE);
+               if (unlikely(shtx->in_progress)) {
+                       next = next_txbd(bdp, base, tx_ring_size);
+                       buflen = next->length + GMAC_FCB_LEN;
+               } else
+                       buflen = bdp->length;
+
+               dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
+                               buflen, DMA_TO_DEVICE);
+
+               if (unlikely(shtx->in_progress)) {
+                       struct skb_shared_hwtstamps shhwtstamps;
+                       u64 *ns = (u64*) (((u32)skb->data + 0x10) & ~0x7);
+                       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+                       shhwtstamps.hwtstamp = ns_to_ktime(*ns);
+                       skb_tstamp_tx(skb, &shhwtstamps);
+                       bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
+                       bdp = next;
+               }
 
                bdp->lstatus &= BD_LFLAG(TXBD_WRAP);
                bdp = next_txbd(bdp, base, tx_ring_size);
@@ -2314,7 +2426,7 @@ static int gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
 
                howmany++;
                spin_lock_irqsave(&tx_queue->txlock, flags);
-               tx_queue->num_txbdfree += frags + 1;
+               tx_queue->num_txbdfree += nr_txbds;
                spin_unlock_irqrestore(&tx_queue->txlock, flags);
        }
 
@@ -2470,6 +2582,17 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
                skb_pull(skb, amount_pull);
        }
 
+       /* Get receive timestamp from the skb */
+       if (priv->hwts_rx_en) {
+               struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+               u64 *ns = (u64 *) skb->data;
+               memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+               shhwtstamps->hwtstamp = ns_to_ktime(*ns);
+       }
+
+       if (priv->padding)
+               skb_pull(skb, priv->padding);
+
        if (priv->rx_csum_enable)
                gfar_rx_checksum(skb, fcb);
 
@@ -2506,8 +2629,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
        bdp = rx_queue->cur_rx;
        base = rx_queue->rx_bd_base;
 
-       amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
-               priv->padding;
+       amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0);
 
        while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
                struct sk_buff *newskb;
@@ -2794,7 +2916,7 @@ static void adjust_link(struct net_device *dev)
  * whenever dev->flags is changed */
 static void gfar_set_multi(struct net_device *dev)
 {
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 tempval;
@@ -2867,17 +2989,14 @@ static void gfar_set_multi(struct net_device *dev)
                        return;
 
                /* Parse the list, and set the appropriate bits */
-               netdev_for_each_mc_addr(mc_ptr, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        if (idx < em_num) {
-                               gfar_set_mac_for_addr(dev, idx,
-                                               mc_ptr->dmi_addr);
+                               gfar_set_mac_for_addr(dev, idx, ha->addr);
                                idx++;
                        } else
-                               gfar_set_hash_for_addr(dev, mc_ptr->dmi_addr);
+                               gfar_set_hash_for_addr(dev, ha->addr);
                }
        }
-
-       return;
 }
 
 
@@ -2918,8 +3037,6 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
        tempval = gfar_read(priv->hash_regs[whichreg]);
        tempval |= value;
        gfar_write(priv->hash_regs[whichreg], tempval);
-
-       return;
 }
 
 
@@ -3055,8 +3172,6 @@ static struct of_platform_driver gfar_driver = {
 
        .probe = gfar_probe,
        .remove = gfar_remove,
-       .suspend = gfar_legacy_suspend,
-       .resume = gfar_legacy_resume,
        .driver.pm = GFAR_PM_OPS,
 };
 
index 17d25e714236f305908670efc53fc0c6ace07a08..ac4a92e08c09b67b304d3084bffd9a494c80afb5 100644 (file)
@@ -262,6 +262,7 @@ extern const char gfar_driver_version[];
 
 #define next_bd(bdp, base, ring_size) skip_bd(bdp, 1, base, ring_size)
 
+#define RCTRL_TS_ENABLE        0x01000000
 #define RCTRL_PAL_MASK         0x001f0000
 #define RCTRL_VLEX             0x00002000
 #define RCTRL_FILREN           0x00001000
@@ -539,7 +540,7 @@ struct txbd8
 
 struct txfcb {
        u8      flags;
-       u8      reserved;
+       u8      ptp;    /* Flag to enable tx timestamping */
        u8      l4os;   /* Level 4 Header Offset */
        u8      l3os;   /* Level 3 Header Offset */
        u16     phcs;   /* Pseudo-header Checksum */
@@ -885,6 +886,7 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET       0x00000100
 #define FSL_GIANFAR_DEV_HAS_BD_STASHING                0x00000200
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING       0x00000400
+#define FSL_GIANFAR_DEV_HAS_TIMER              0x00000800
 
 #if (MAXGROUPS == 2)
 #define DEFAULT_MAPPING        0xAA
@@ -1100,6 +1102,10 @@ struct gfar_private {
 
        /* Network Statistics */
        struct gfar_extra_stats extra_stats;
+
+       /* HW time stamping enabled flag */
+       int hwts_rx_en;
+       int hwts_tx_en;
 };
 
 extern unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
index 3a90430de918bc1b1a1de8bd05e0d0f5f11bda6e..fd491e409488e0ea0b8947c36f24f4810b012c03 100644 (file)
@@ -895,7 +895,6 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
                                else
                                        skb->ip_summed = CHECKSUM_NONE;
 
-                               skb->dev = dev;
                                skb->protocol = eth_type_trans(skb, dev);
                                dev->stats.rx_packets++;
                                netif_receive_skb(skb);
@@ -990,7 +989,7 @@ static u32 greth_hash_get_index(__u8 *addr)
 
 static void greth_set_hash_filter(struct net_device *dev)
 {
-       struct dev_mc_list *curr;
+       struct netdev_hw_addr *ha;
        struct greth_private *greth = netdev_priv(dev);
        struct greth_regs *regs = (struct greth_regs *) greth->regs;
        u32 mc_filter[2];
@@ -998,8 +997,8 @@ static void greth_set_hash_filter(struct net_device *dev)
 
        mc_filter[0] = mc_filter[1] = 0;
 
-       netdev_for_each_mc_addr(curr, dev) {
-               bitnr = greth_hash_get_index(curr->dmi_addr);
+       netdev_for_each_mc_addr(ha, dev) {
+               bitnr = greth_hash_get_index(ha->addr);
                mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
        }
 
index 5d6f138795925dc2fecf2e729a918b01d6d7e8e1..61f2b1cfcd46317ada1a0a6333d900810b28d9e0 100644 (file)
@@ -859,7 +859,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
        for (i = 10000; i >= 0; i--)
                if ((readw(ioaddr + MII_Status) & 1) == 0)
                        break;
-       return;
 }
 
 
@@ -1225,8 +1224,6 @@ static void hamachi_init_ring(struct net_device *dev)
        }
        /* Mark the last entry of the ring */
        hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing);
-
-       return;
 }
 
 
@@ -1857,12 +1854,12 @@ static void set_rx_mode(struct net_device *dev)
                /* Too many to match, or accept all multicasts. */
                writew(0x000B, ioaddr + AddrMode);
        } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                int i = 0;
 
-               netdev_for_each_mc_addr(mclist, dev) {
-                       writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8);
-                       writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]),
+               netdev_for_each_mc_addr(ha, dev) {
+                       writel(*(u32 *)(ha->addr), ioaddr + 0x100 + i*8);
+                       writel(0x20000 | (*(u16 *)&ha->addr[4]),
                                   ioaddr + 0x104 + i*8);
                        i++;
                }
index 0cab992b3d1abcd5bd5686c3109bb4a9f88c7784..3e25f10cabd60e9c93bc0898d23dfe1bf5f0351a 100644 (file)
@@ -429,7 +429,7 @@ static int ser12_open(struct net_device *dev)
                return -EINVAL;
        }
        if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
-               printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", 
+               printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy\n",
                       dev->base_addr);
                return -EACCES;
        }
index f3a96b8439110856b1446ab32876161205226ec9..9f64c8637208c4b8395743ef8385dc57b9e7605a 100644 (file)
@@ -1629,7 +1629,6 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb)
        skb->protocol = ax25_type_trans(skb, scc->dev);
        
        netif_rx(skb);
-       return;
 }
 
 /* ----> transmit frame <---- */
index efdbcad63c67d2f3a4d20774cdd52623002391dd..82bffc3cabdf92327fddcc3c5a81d53199a245e4 100644 (file)
@@ -351,7 +351,6 @@ hpp_reset_8390(struct net_device *dev)
                printk("%s: hp_reset_8390() did not complete.\n", dev->name);
 
        if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-       return;
 }
 
 /* The programmed-I/O version of reading the 4 byte 8390 specific header.
@@ -422,7 +421,6 @@ hpp_io_block_output(struct net_device *dev, int count,
        int ioaddr = dev->base_addr - NIC_OFFSET;
        outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
        outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
-       return;
 }
 
 static void
@@ -436,8 +434,6 @@ hpp_mem_block_output(struct net_device *dev, int count,
        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
        memcpy_toio(ei_status.mem, buf, (count + 3) & ~3);
        outw(option_reg, ioaddr + HPP_OPTION);
-
-       return;
 }
 
 
index 5c4d78c1ff42ae87db44d8dd5f72c32b9a6867e4..86ececd3c6582d17f7d0ffe0d3a19eeb5d85cfb0 100644 (file)
@@ -240,7 +240,6 @@ hp_reset_8390(struct net_device *dev)
                printk("%s: hp_reset_8390() did not complete.\n", dev->name);
 
        if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
-       return;
 }
 
 static void
@@ -360,7 +359,6 @@ hp_block_output(struct net_device *dev, int count,
                           dev->name, (start_page << 8) + count, addr);
        }
        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
-       return;
 }
 
 /* This function resets the ethercard if something screws up. */
@@ -371,7 +369,6 @@ hp_init_card(struct net_device *dev)
        NS8390p_init(dev, 0);
        outb_p(irqmap[irq&0x0f] | HP_RUN,
                   dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
-       return;
 }
 
 #ifdef MODULE
index 4daad8cd56ea885af08391c9c0cef4481e7ad416..68e5ac8832ad0b8a1678fb50e38d996fbd684524 100644 (file)
@@ -1102,7 +1102,7 @@ static int hp100_open(struct net_device *dev)
                return -EAGAIN;
        }
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_start_queue(dev);
 
        lp->lan_type = hp100_sense_lan(dev);
@@ -1510,7 +1510,7 @@ static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
                printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);
 #endif
                /* not waited long enough since last tx? */
-               if (time_before(jiffies, dev->trans_start + HZ))
+               if (time_before(jiffies, dev_trans_start(dev) + HZ))
                        goto drop;
 
                if (hp100_check_lan(dev))
@@ -1547,7 +1547,6 @@ static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
                        }
                }
 
-               dev->trans_start = jiffies;
                goto drop;
        }
 
@@ -1585,7 +1584,6 @@ static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
        /* Update statistics */
        lp->stats.tx_packets++;
        lp->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
 
        return NETDEV_TX_OK;
 
@@ -1663,7 +1661,7 @@ static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
                printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i);
 #endif
                /* not waited long enough since last failed tx try? */
-               if (time_before(jiffies, dev->trans_start + HZ)) {
+               if (time_before(jiffies, dev_trans_start(dev) + HZ)) {
 #ifdef HP100_DEBUG
                        printk("hp100: %s: trans_start timing problem\n",
                               dev->name);
@@ -1701,7 +1699,6 @@ static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
                                mdelay(1);
                        }
                }
-               dev->trans_start = jiffies;
                goto drop;
        }
 
@@ -1745,7 +1742,6 @@ static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
 
        lp->stats.tx_packets++;
        lp->stats.tx_bytes += skb->len;
-       dev->trans_start = jiffies;
        hp100_ints_on();
        spin_unlock_irqrestore(&lp->lock, flags);
 
@@ -2099,15 +2095,15 @@ static void hp100_set_multicast_list(struct net_device *dev)
                } else {
                        int i, idx;
                        u_char *addrs;
-                       struct dev_mc_list *dmi;
+                       struct netdev_hw_addr *ha;
 
                        memset(&lp->hash_bytes, 0x00, 8);
 #ifdef HP100_DEBUG
                        printk("hp100: %s: computing hash filter - mc_count = %i\n",
                               dev->name, netdev_mc_count(dev));
 #endif
-                       netdev_for_each_mc_addr(dmi, dev) {
-                               addrs = dmi->dmi_addr;
+                       netdev_for_each_mc_addr(ha, dev) {
+                               addrs = ha->addr;
                                if ((*addrs & 0x01) == 0x01) {  /* multicast address? */
 #ifdef HP100_DEBUG
                                        printk("hp100: %s: multicast = %pM, ",
index dd873cc41c2b718262c053642593c5461134f458..2484e9e6c1edd0f7dd06026d4111b6dadab7ea12 100644 (file)
@@ -389,18 +389,19 @@ static void emac_hash_mc(struct emac_instance *dev)
        const int regs = EMAC_XAHT_REGS(dev);
        u32 *gaht_base = emac_gaht_base(dev);
        u32 gaht_temp[regs];
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int i;
 
        DBG(dev, "hash_mc %d" NL, netdev_mc_count(dev->ndev));
 
        memset(gaht_temp, 0, sizeof (gaht_temp));
 
-       netdev_for_each_mc_addr(dmi, dev->ndev) {
+       netdev_for_each_mc_addr(ha, dev->ndev) {
                int slot, reg, mask;
-               DBG2(dev, "mc %pM" NL, dmi->dmi_addr);
+               DBG2(dev, "mc %pM" NL, ha->addr);
 
-               slot = EMAC_XAHT_CRC_TO_SLOT(dev, ether_crc(ETH_ALEN, dmi->dmi_addr));
+               slot = EMAC_XAHT_CRC_TO_SLOT(dev,
+                                            ether_crc(ETH_ALEN, ha->addr));
                reg = EMAC_XAHT_SLOT_TO_REG(dev, slot);
                mask = EMAC_XAHT_SLOT_TO_MASK(dev, slot);
 
@@ -1177,7 +1178,7 @@ static int emac_open(struct net_device *ndev)
                netif_carrier_on(dev->ndev);
 
        /* Required for Pause packet support in EMAC */
-       dev_mc_add(ndev, default_mcast_addr, sizeof(default_mcast_addr), 1);
+       dev_mc_add_global(ndev, default_mcast_addr);
 
        emac_configure(dev);
        mal_poll_add(dev->mal, &dev->commac);
@@ -1700,7 +1701,6 @@ static int emac_poll_rx(void *param, int budget)
 
                skb_put(skb, len);
        push_packet:
-               skb->dev = dev->ndev;
                skb->protocol = eth_type_trans(skb, dev->ndev);
                emac_rx_csum(dev, skb, ctrl);
 
index 7d6cf3340c113041216fbca52ea23a3c9514d8c3..294ccfb427cf13475603a7194a03df6b8cbdc619 100644 (file)
@@ -384,7 +384,7 @@ static void InitBoard(struct net_device *dev)
        int camcnt;
        camentry_t cams[16];
        u32 cammask;
-       struct dev_mc_list *mcptr;
+       struct netdev_hw_addr *ha;
        u16 rcrval;
 
        /* reset the SONIC */
@@ -419,8 +419,8 @@ static void InitBoard(struct net_device *dev)
        /* start putting the multicast addresses into the CAM list.  Stop if
           it is full. */
 
-       netdev_for_each_mc_addr(mcptr, dev) {
-               putcam(cams, &camcnt, mcptr->dmi_addr);
+       netdev_for_each_mc_addr(ha, dev) {
+               putcam(cams, &camcnt, ha->addr);
                if (camcnt == 16)
                        break;
        }
@@ -478,7 +478,7 @@ static void InitBoard(struct net_device *dev)
        /* if still multicast addresses left or ALLMULTI is set, set the multicast
           enable bit */
 
-       if ((dev->flags & IFF_ALLMULTI) || (mcptr != NULL))
+       if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > camcnt)
                rcrval |= RCREG_AMC;
 
        /* promiscous mode ? */
index cd508a8ee25b3f9a5a81b568e5a733e68e4d961e..7acb3edc47ef88ba62a2de614213a85518b98274 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/pm.h>
 #include <linux/ethtool.h>
 #include <linux/proc_fs.h>
 #include <linux/in.h>
@@ -199,7 +200,7 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
                return -1;
        }
 
-       pool->skbuff = kmalloc(sizeof(void*) * pool->size, GFP_KERNEL);
+       pool->skbuff = kcalloc(pool->size, sizeof(void *), GFP_KERNEL);
 
        if(!pool->skbuff) {
                kfree(pool->dma_addr);
@@ -210,7 +211,6 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool)
                return -1;
        }
 
-       memset(pool->skbuff, 0, sizeof(void*) * pool->size);
        memset(pool->dma_addr, 0, sizeof(dma_addr_t) * pool->size);
 
        for(i = 0; i < pool->size; ++i) {
@@ -957,7 +957,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb,
        } else {
                tx_packets++;
                tx_bytes += skb->len;
-               netdev->trans_start = jiffies;
+               netdev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
        }
 
        if (!used_bounce)
@@ -1073,7 +1073,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                        ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc);
                }
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                /* clear the filter table & disable filtering */
                lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                           IbmVethMcastEnableRecv |
@@ -1084,10 +1084,10 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                        ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc);
                }
                /* add the addresses to the filter table */
-               netdev_for_each_mc_addr(mclist, netdev) {
+               netdev_for_each_mc_addr(ha, netdev) {
                        // add the multicast address to the filter table
                        unsigned long mcast_addr = 0;
-                       memcpy(((char *)&mcast_addr)+2, mclist->dmi_addr, 6);
+                       memcpy(((char *)&mcast_addr)+2, ha->addr, 6);
                        lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                                   IbmVethMcastAddFilter,
                                                   mcast_addr);
@@ -1421,7 +1421,6 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
                if (!entry)
                        ibmveth_error_printk("Cannot create adapter proc entry");
        }
-       return;
 }
 
 static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
@@ -1589,6 +1588,12 @@ static struct kobj_type ktype_veth_pool = {
        .default_attrs  = veth_pool_attrs,
 };
 
+static int ibmveth_resume(struct device *dev)
+{
+       struct net_device *netdev = dev_get_drvdata(dev);
+       ibmveth_interrupt(netdev->irq, netdev);
+       return 0;
+}
 
 static struct vio_device_id ibmveth_device_table[] __devinitdata= {
        { "network", "IBM,l-lan"},
@@ -1596,6 +1601,10 @@ static struct vio_device_id ibmveth_device_table[] __devinitdata= {
 };
 MODULE_DEVICE_TABLE(vio, ibmveth_device_table);
 
+static struct dev_pm_ops ibmveth_pm_ops = {
+       .resume = ibmveth_resume
+};
+
 static struct vio_driver ibmveth_driver = {
        .id_table       = ibmveth_device_table,
        .probe          = ibmveth_probe,
@@ -1604,6 +1613,7 @@ static struct vio_driver ibmveth_driver = {
        .driver         = {
                .name   = ibmveth_driver_name,
                .owner  = THIS_MODULE,
+               .pm = &ibmveth_pm_ops,
        }
 };
 
index f4081c0a2d9c1bd8c2f4b9609b6a7d0bfd6996ca..ab9f675c5b8b8b86473d07b60b3ad933523b3ab5 100644 (file)
@@ -182,7 +182,6 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
 
-       dev->trans_start = jiffies;
        skb_queue_tail(&dp->rq, skb);
        if (!dp->tasklet_pending) {
                dp->tasklet_pending = 1;
index 4a32bed77c719acab24f459e2a4f57b3600a777e..86438b59fa214e9f2f5c4c62f71b23f48c1e88d8 100644 (file)
@@ -104,6 +104,12 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
        case E1000_DEV_ID_82580_COPPER_DUAL:
                mac->type = e1000_82580;
                break;
+       case E1000_DEV_ID_I350_COPPER:
+       case E1000_DEV_ID_I350_FIBER:
+       case E1000_DEV_ID_I350_SERDES:
+       case E1000_DEV_ID_I350_SGMII:
+               mac->type = e1000_i350;
+               break;
        default:
                return -E1000_ERR_MAC_INIT;
                break;
@@ -153,8 +159,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
        if (mac->type == e1000_82580)
                mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
+       if (mac->type == e1000_i350)
+               mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
        /* reset */
-       if (mac->type == e1000_82580)
+       if (mac->type >= e1000_82580)
                mac->ops.reset_hw = igb_reset_hw_82580;
        else
                mac->ops.reset_hw = igb_reset_hw_82575;
@@ -225,7 +233,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                phy->ops.reset              = igb_phy_hw_reset_sgmii_82575;
                phy->ops.read_reg           = igb_read_phy_reg_sgmii_82575;
                phy->ops.write_reg          = igb_write_phy_reg_sgmii_82575;
-       } else if (hw->mac.type == e1000_82580) {
+       } else if (hw->mac.type >= e1000_82580) {
                phy->ops.reset              = igb_phy_hw_reset;
                phy->ops.read_reg           = igb_read_phy_reg_82580;
                phy->ops.write_reg          = igb_write_phy_reg_82580;
@@ -261,6 +269,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                phy->ops.set_d3_lplu_state  = igb_set_d3_lplu_state;
                break;
        case I82580_I_PHY_ID:
+       case I350_I_PHY_ID:
                phy->type                   = e1000_phy_82580;
                phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;
                phy->ops.get_cable_length   = igb_get_cable_length_82580;
@@ -1205,8 +1214,6 @@ void igb_power_down_phy_copper_82575(struct e1000_hw *hw)
        /* If the management interface is not enabled, then power down */
        if (!(igb_enable_mng_pass_thru(hw) || igb_check_reset_block(hw)))
                igb_power_down_phy_copper(hw);
-
-       return;
 }
 
 /**
@@ -1445,7 +1452,6 @@ void igb_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
  **/
 static s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
 {
-       u32 mdicnfg = 0;
        s32 ret_val;
 
 
@@ -1453,15 +1459,6 @@ static s32 igb_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
        if (ret_val)
                goto out;
 
-       /*
-        * We config the phy address in MDICNFG register now. Same bits
-        * as before. The values in MDIC can be written but will be
-        * ignored. This allows us to call the old function after
-        * configuring the PHY address in the new register
-        */
-       mdicnfg = (hw->phy.addr << E1000_MDIC_PHY_SHIFT);
-       wr32(E1000_MDICNFG, mdicnfg);
-
        ret_val = igb_read_phy_reg_mdic(hw, offset, data);
 
        hw->phy.ops.release(hw);
@@ -1480,7 +1477,6 @@ out:
  **/
 static s32 igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data)
 {
-       u32 mdicnfg = 0;
        s32 ret_val;
 
 
@@ -1488,15 +1484,6 @@ static s32 igb_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data)
        if (ret_val)
                goto out;
 
-       /*
-        * We config the phy address in MDICNFG register now. Same bits
-        * as before. The values in MDIC can be written but will be
-        * ignored. This allows us to call the old function after
-        * configuring the PHY address in the new register
-        */
-       mdicnfg = (hw->phy.addr << E1000_MDIC_PHY_SHIFT);
-       wr32(E1000_MDICNFG, mdicnfg);
-
        ret_val = igb_write_phy_reg_mdic(hw, offset, data);
 
        hw->phy.ops.release(hw);
index fbe1c99c193c09434a72ee35a84d10f09731bd24..cbd1e1259e4d4c8ec43faf3ee1b1e9bcb5c947ac 100644 (file)
@@ -38,9 +38,10 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
                                      (ID_LED_DEF1_DEF2 <<  4) | \
                                      (ID_LED_OFF1_ON2))
 
-#define E1000_RAR_ENTRIES_82575   16
-#define E1000_RAR_ENTRIES_82576   24
-#define E1000_RAR_ENTRIES_82580   24
+#define E1000_RAR_ENTRIES_82575        16
+#define E1000_RAR_ENTRIES_82576        24
+#define E1000_RAR_ENTRIES_82580        24
+#define E1000_RAR_ENTRIES_I350         32
 
 #define E1000_SW_SYNCH_MB              0x00000100
 #define E1000_STAT_DEV_RST_SET         0x00100000
@@ -52,6 +53,7 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
 #define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
 #define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
 #define E1000_SRRCTL_DROP_EN                            0x80000000
+#define E1000_SRRCTL_TIMESTAMP                          0x40000000
 
 #define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
 #define E1000_MRQC_ENABLE_VMDQ              0x00000003
@@ -108,6 +110,7 @@ union e1000_adv_rx_desc {
 #define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
 #define E1000_RXDADV_HDRBUFLEN_SHIFT     5
 #define E1000_RXDADV_STAT_TS             0x10000 /* Pkt was time stamped */
+#define E1000_RXDADV_STAT_TSIP           0x08000 /* timestamp in packet */
 
 /* Transmit Descriptor - Advanced */
 union e1000_adv_tx_desc {
index fe6cf1b696c783b7ce754fca7530f7cdaea618be..24d9be64342ff91d75119c149618194a9e1485ae 100644 (file)
 #define IGP_LED3_MODE           0x07000000
 
 /* PCI/PCI-X/PCI-EX Config space */
-#define PCIE_LINK_STATUS             0x12
 #define PCIE_DEVICE_CONTROL2         0x28
-
-#define PCIE_LINK_WIDTH_MASK         0x3F0
-#define PCIE_LINK_WIDTH_SHIFT        4
 #define PCIE_DEVICE_CONTROL2_16ms    0x0005
 
 #define PHY_REVISION_MASK      0xFFFFFFF0
 #define M88E1111_I_PHY_ID    0x01410CC0
 #define IGP03E1000_E_PHY_ID  0x02A80390
 #define I82580_I_PHY_ID      0x015403A0
+#define I350_I_PHY_ID        0x015403B0
 #define M88_VENDOR           0x0141
 
 /* M88E1000 Specific Registers */
index 82a533f5192a545e5d6d631b2cc671e0bb042a5b..cb8db78b1a05ba4f241cab3c98c617213e1d3b16 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/netdevice.h>
 
 #include "e1000_regs.h"
 #include "e1000_defines.h"
@@ -53,6 +54,10 @@ struct e1000_hw;
 #define E1000_DEV_ID_82580_SERDES             0x1510
 #define E1000_DEV_ID_82580_SGMII              0x1511
 #define E1000_DEV_ID_82580_COPPER_DUAL        0x1516
+#define E1000_DEV_ID_I350_COPPER              0x1521
+#define E1000_DEV_ID_I350_FIBER               0x1522
+#define E1000_DEV_ID_I350_SERDES              0x1523
+#define E1000_DEV_ID_I350_SGMII               0x1524
 
 #define E1000_REVISION_2 2
 #define E1000_REVISION_4 4
@@ -72,6 +77,7 @@ enum e1000_mac_type {
        e1000_82575,
        e1000_82576,
        e1000_82580,
+       e1000_i350,
        e1000_num_macs  /* List is 1-based, so subtract 1 for true count. */
 };
 
@@ -502,14 +508,11 @@ struct e1000_hw {
        u8  revision_id;
 };
 
-#ifdef DEBUG
-extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
+extern struct net_device *igb_get_hw_dev(struct e1000_hw *hw);
 #define hw_dbg(format, arg...) \
-       printk(KERN_DEBUG "%s: " format, igb_get_hw_dev_name(hw), ##arg)
-#else
-#define hw_dbg(format, arg...)
-#endif
-#endif
+       netdev_dbg(igb_get_hw_dev(hw), format, ##arg)
+
 /* These functions must be implemented by drivers */
 s32  igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
 s32  igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+#endif /* _E1000_HW_H_ */
index be8d010e40213a7b51616fad0e320464a43c751a..90c5e01e9235875ba6b954e31ab3a52cbcee9fb1 100644 (file)
@@ -53,17 +53,30 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw)
        u16 pcie_link_status;
 
        bus->type = e1000_bus_type_pci_express;
-       bus->speed = e1000_bus_speed_2500;
 
        ret_val = igb_read_pcie_cap_reg(hw,
-                                         PCIE_LINK_STATUS,
-                                         &pcie_link_status);
-       if (ret_val)
+                                       PCI_EXP_LNKSTA,
+                                       &pcie_link_status);
+       if (ret_val) {
                bus->width = e1000_bus_width_unknown;
-       else
+               bus->speed = e1000_bus_speed_unknown;
+       } else {
+               switch (pcie_link_status & PCI_EXP_LNKSTA_CLS) {
+               case PCI_EXP_LNKSTA_CLS_2_5GB:
+                       bus->speed = e1000_bus_speed_2500;
+                       break;
+               case PCI_EXP_LNKSTA_CLS_5_0GB:
+                       bus->speed = e1000_bus_speed_5000;
+                       break;
+               default:
+                       bus->speed = e1000_bus_speed_unknown;
+                       break;
+               }
+
                bus->width = (enum e1000_bus_width)((pcie_link_status &
-                                                    PCIE_LINK_WIDTH_MASK) >>
-                                                    PCIE_LINK_WIDTH_SHIFT);
+                                                    PCI_EXP_LNKSTA_NLW) >>
+                                                    PCI_EXP_LNKSTA_NLW_SHIFT);
+       }
 
        reg = rd32(E1000_STATUS);
        bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT;
index 3b772b822a5dcc61548c8bc98297c8bd9c47efb6..6e63d9a7fc75808baac188b1719f3d0223ad3303 100644 (file)
@@ -107,6 +107,7 @@ struct vf_data_storage {
 #define MAXIMUM_ETHERNET_VLAN_SIZE 1522
 
 /* Supported Rx Buffer Sizes */
+#define IGB_RXBUFFER_64    64     /* Used for packet split */
 #define IGB_RXBUFFER_128   128    /* Used for packet split */
 #define IGB_RXBUFFER_1024  1024
 #define IGB_RXBUFFER_2048  2048
@@ -140,8 +141,10 @@ struct igb_buffer {
                        unsigned long time_stamp;
                        u16 length;
                        u16 next_to_watch;
-                       u16 mapped_as_page;
+                       unsigned int bytecount;
                        u16 gso_segs;
+                       union skb_shared_tx shtx;
+                       u8 mapped_as_page;
                };
                /* RX */
                struct {
@@ -185,7 +188,7 @@ struct igb_q_vector {
 struct igb_ring {
        struct igb_q_vector *q_vector; /* backlink to q_vector */
        struct net_device *netdev;     /* back pointer to net_device */
-       struct pci_dev *pdev;          /* pci device for dma mapping */
+       struct device *dev;            /* device pointer for dma mapping */
        dma_addr_t dma;                /* phys address of the ring */
        void *desc;                    /* descriptor ring memory */
        unsigned int size;             /* length of desc. ring in bytes */
@@ -323,6 +326,7 @@ struct igb_adapter {
 
 #define IGB_82576_TSYNC_SHIFT 19
 #define IGB_82580_TSYNC_SHIFT 24
+#define IGB_TS_HDR_LEN        16
 enum e1000_state_t {
        __IGB_TESTING,
        __IGB_RESETTING,
@@ -336,7 +340,6 @@ enum igb_boards {
 extern char igb_driver_name[];
 extern char igb_driver_version[];
 
-extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
 extern int igb_up(struct igb_adapter *);
 extern void igb_down(struct igb_adapter *);
 extern void igb_reinit_locked(struct igb_adapter *);
index 743038490104bbc51b054e2600a71132fbfb86e4..f2ebf927e4bc0d2b6ab21285f9c54ebd0937829f 100644 (file)
@@ -902,6 +902,49 @@ struct igb_reg_test {
 #define TABLE64_TEST_LO        5
 #define TABLE64_TEST_HI        6
 
+/* i350 reg test */
+static struct igb_reg_test reg_test_i350[] = {
+       { E1000_FCAL,      0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_FCAH,      0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+       { E1000_FCT,       0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF },
+       { E1000_VET,       0x100, 1,  PATTERN_TEST, 0xFFFF0000, 0xFFFF0000 },
+       { E1000_RDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_RDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { E1000_RDBAL(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_RDBAH(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RDLEN(4),  0x40,  4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       /* RDH is read-only for i350, only test RDT. */
+       { E1000_RDT(0),    0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_RDT(4),    0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_FCRTH,     0x100, 1,  PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 },
+       { E1000_FCTTV,     0x100, 1,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_TIPG,      0x100, 1,  PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF },
+       { E1000_TDBAL(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_TDBAH(0),  0x100, 4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_TDLEN(0),  0x100, 4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { E1000_TDBAL(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF },
+       { E1000_TDBAH(4),  0x40,  4,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_TDLEN(4),  0x40,  4,  PATTERN_TEST, 0x000FFF80, 0x000FFFFF },
+       { E1000_TDT(0),    0x100, 4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_TDT(4),    0x40,  4,  PATTERN_TEST, 0x0000FFFF, 0x0000FFFF },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0x003FFFFB },
+       { E1000_RCTL,      0x100, 1,  SET_READ_TEST, 0x04CFB0FE, 0xFFFFFFFF },
+       { E1000_TCTL,      0x100, 1,  SET_READ_TEST, 0xFFFFFFFF, 0x00000000 },
+       { E1000_RA,        0, 16, TABLE64_TEST_LO,
+                                               0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RA,        0, 16, TABLE64_TEST_HI,
+                                               0xC3FFFFFF, 0xFFFFFFFF },
+       { E1000_RA2,       0, 16, TABLE64_TEST_LO,
+                                               0xFFFFFFFF, 0xFFFFFFFF },
+       { E1000_RA2,       0, 16, TABLE64_TEST_HI,
+                                               0xC3FFFFFF, 0xFFFFFFFF },
+       { E1000_MTA,       0, 128, TABLE32_TEST,
+                                               0xFFFFFFFF, 0xFFFFFFFF },
+       { 0, 0, 0, 0 }
+};
+
 /* 82580 reg test */
 static struct igb_reg_test reg_test_82580[] = {
        { E1000_FCAL,      0x100, 1,  PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF },
@@ -1077,6 +1120,10 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
        u32 i, toggle;
 
        switch (adapter->hw.mac.type) {
+       case e1000_i350:
+               test = reg_test_i350;
+               toggle = 0x7FEFF3FF;
+               break;
        case e1000_82580:
                test = reg_test_82580;
                toggle = 0x7FEFF3FF;
@@ -1238,6 +1285,9 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data)
        case e1000_82580:
                ics_mask = 0x77DCFED5;
                break;
+       case e1000_i350:
+               ics_mask = 0x77DCFED5;
+               break;
        default:
                ics_mask = 0x7FFFFFFF;
                break;
@@ -1344,7 +1394,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
 
        /* Setup Tx descriptor ring and Tx buffers */
        tx_ring->count = IGB_DEFAULT_TXD;
-       tx_ring->pdev = adapter->pdev;
+       tx_ring->dev = &adapter->pdev->dev;
        tx_ring->netdev = adapter->netdev;
        tx_ring->reg_idx = adapter->vfs_allocated_count;
 
@@ -1358,7 +1408,7 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
 
        /* Setup Rx descriptor ring and Rx buffers */
        rx_ring->count = IGB_DEFAULT_RXD;
-       rx_ring->pdev = adapter->pdev;
+       rx_ring->dev = &adapter->pdev->dev;
        rx_ring->netdev = adapter->netdev;
        rx_ring->rx_buffer_len = IGB_RXBUFFER_2048;
        rx_ring->reg_idx = adapter->vfs_allocated_count;
@@ -1554,10 +1604,10 @@ static int igb_clean_test_rings(struct igb_ring *rx_ring,
                buffer_info = &rx_ring->buffer_info[rx_ntc];
 
                /* unmap rx buffer, will be remapped by alloc_rx_buffers */
-               pci_unmap_single(rx_ring->pdev,
+               dma_unmap_single(rx_ring->dev,
                                 buffer_info->dma,
                                 rx_ring->rx_buffer_len,
-                                PCI_DMA_FROMDEVICE);
+                                DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                /* verify contents of skb */
index c9baa2aa98cd640268924ef2ef891afbdd29ba33..3881918f5382c4e1305e4c5127bfbb2180bb85cd 100644 (file)
@@ -62,6 +62,10 @@ static const struct e1000_info *igb_info_tbl[] = {
 };
 
 static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = {
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_COPPER), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_FIBER), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SERDES), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_I350_SGMII), board_82575 },
        { 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 },
@@ -197,6 +201,336 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+struct igb_reg_info {
+       u32 ofs;
+       char *name;
+};
+
+static const struct igb_reg_info igb_reg_info_tbl[] = {
+
+       /* General Registers */
+       {E1000_CTRL, "CTRL"},
+       {E1000_STATUS, "STATUS"},
+       {E1000_CTRL_EXT, "CTRL_EXT"},
+
+       /* Interrupt Registers */
+       {E1000_ICR, "ICR"},
+
+       /* RX Registers */
+       {E1000_RCTL, "RCTL"},
+       {E1000_RDLEN(0), "RDLEN"},
+       {E1000_RDH(0), "RDH"},
+       {E1000_RDT(0), "RDT"},
+       {E1000_RXDCTL(0), "RXDCTL"},
+       {E1000_RDBAL(0), "RDBAL"},
+       {E1000_RDBAH(0), "RDBAH"},
+
+       /* TX Registers */
+       {E1000_TCTL, "TCTL"},
+       {E1000_TDBAL(0), "TDBAL"},
+       {E1000_TDBAH(0), "TDBAH"},
+       {E1000_TDLEN(0), "TDLEN"},
+       {E1000_TDH(0), "TDH"},
+       {E1000_TDT(0), "TDT"},
+       {E1000_TXDCTL(0), "TXDCTL"},
+       {E1000_TDFH, "TDFH"},
+       {E1000_TDFT, "TDFT"},
+       {E1000_TDFHS, "TDFHS"},
+       {E1000_TDFPC, "TDFPC"},
+
+       /* List Terminator */
+       {}
+};
+
+/*
+ * igb_regdump - register printout routine
+ */
+static void igb_regdump(struct e1000_hw *hw, struct igb_reg_info *reginfo)
+{
+       int n = 0;
+       char rname[16];
+       u32 regs[8];
+
+       switch (reginfo->ofs) {
+       case E1000_RDLEN(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDLEN(n));
+               break;
+       case E1000_RDH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDH(n));
+               break;
+       case E1000_RDT(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDT(n));
+               break;
+       case E1000_RXDCTL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RXDCTL(n));
+               break;
+       case E1000_RDBAL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDBAL(n));
+               break;
+       case E1000_RDBAH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDBAH(n));
+               break;
+       case E1000_TDBAL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_RDBAL(n));
+               break;
+       case E1000_TDBAH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDBAH(n));
+               break;
+       case E1000_TDLEN(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDLEN(n));
+               break;
+       case E1000_TDH(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDH(n));
+               break;
+       case E1000_TDT(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TDT(n));
+               break;
+       case E1000_TXDCTL(0):
+               for (n = 0; n < 4; n++)
+                       regs[n] = rd32(E1000_TXDCTL(n));
+               break;
+       default:
+               printk(KERN_INFO "%-15s %08x\n",
+                       reginfo->name, rd32(reginfo->ofs));
+               return;
+       }
+
+       snprintf(rname, 16, "%s%s", reginfo->name, "[0-3]");
+       printk(KERN_INFO "%-15s ", rname);
+       for (n = 0; n < 4; n++)
+               printk(KERN_CONT "%08x ", regs[n]);
+       printk(KERN_CONT "\n");
+}
+
+/*
+ * igb_dump - Print registers, tx-rings and rx-rings
+ */
+static void igb_dump(struct igb_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_hw *hw = &adapter->hw;
+       struct igb_reg_info *reginfo;
+       int n = 0;
+       struct igb_ring *tx_ring;
+       union e1000_adv_tx_desc *tx_desc;
+       struct my_u0 { u64 a; u64 b; } *u0;
+       struct igb_buffer *buffer_info;
+       struct igb_ring *rx_ring;
+       union e1000_adv_rx_desc *rx_desc;
+       u32 staterr;
+       int i = 0;
+
+       if (!netif_msg_hw(adapter))
+               return;
+
+       /* Print netdevice Info */
+       if (netdev) {
+               dev_info(&adapter->pdev->dev, "Net device Info\n");
+               printk(KERN_INFO "Device Name     state            "
+                       "trans_start      last_rx\n");
+               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
+               netdev->name,
+               netdev->state,
+               netdev->trans_start,
+               netdev->last_rx);
+       }
+
+       /* Print Registers */
+       dev_info(&adapter->pdev->dev, "Register Dump\n");
+       printk(KERN_INFO " Register Name   Value\n");
+       for (reginfo = (struct igb_reg_info *)igb_reg_info_tbl;
+            reginfo->name; reginfo++) {
+               igb_regdump(hw, reginfo);
+       }
+
+       /* Print TX Ring Summary */
+       if (!netdev || !netif_running(netdev))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ]"
+               " leng ntw timestamp\n");
+       for (n = 0; n < adapter->num_tx_queues; n++) {
+               tx_ring = adapter->tx_ring[n];
+               buffer_info = &tx_ring->buffer_info[tx_ring->next_to_clean];
+               printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
+                          n, tx_ring->next_to_use, tx_ring->next_to_clean,
+                          (u64)buffer_info->dma,
+                          buffer_info->length,
+                          buffer_info->next_to_watch,
+                          (u64)buffer_info->time_stamp);
+       }
+
+       /* Print TX Rings */
+       if (!netif_msg_tx_done(adapter))
+               goto rx_ring_summary;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+
+       /* Transmit Descriptor Formats
+        *
+        * Advanced Transmit Descriptor
+        *   +--------------------------------------------------------------+
+        * 0 |         Buffer Address [63:0]                                |
+        *   +--------------------------------------------------------------+
+        * 8 | PAYLEN  | PORTS  |CC|IDX | STA | DCMD  |DTYP|MAC|RSV| DTALEN |
+        *   +--------------------------------------------------------------+
+        *   63      46 45    40 39 38 36 35 32 31   24             15       0
+        */
+
+       for (n = 0; n < adapter->num_tx_queues; n++) {
+               tx_ring = adapter->tx_ring[n];
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "T [desc]     [address 63:0  ] "
+                       "[PlPOCIStDDM Ln] [bi->dma       ] "
+                       "leng  ntw timestamp        bi->skb\n");
+
+               for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+                       tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
+                       buffer_info = &tx_ring->buffer_info[i];
+                       u0 = (struct my_u0 *)tx_desc;
+                       printk(KERN_INFO "T [0x%03X]    %016llX %016llX %016llX"
+                               " %04X  %3X %016llX %p", i,
+                               le64_to_cpu(u0->a),
+                               le64_to_cpu(u0->b),
+                               (u64)buffer_info->dma,
+                               buffer_info->length,
+                               buffer_info->next_to_watch,
+                               (u64)buffer_info->time_stamp,
+                               buffer_info->skb);
+                       if (i == tx_ring->next_to_use &&
+                               i == tx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC/U\n");
+                       else if (i == tx_ring->next_to_use)
+                               printk(KERN_CONT " NTU\n");
+                       else if (i == tx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC\n");
+                       else
+                               printk(KERN_CONT "\n");
+
+                       if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+                               print_hex_dump(KERN_INFO, "",
+                                       DUMP_PREFIX_ADDRESS,
+                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       buffer_info->length, true);
+               }
+       }
+
+       /* Print RX Rings Summary */
+rx_ring_summary:
+       dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               printk(KERN_INFO " %5d %5X %5X\n", n,
+                          rx_ring->next_to_use, rx_ring->next_to_clean);
+       }
+
+       /* Print RX Rings */
+       if (!netif_msg_rx_status(adapter))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+
+       /* Advanced Receive Descriptor (Read) Format
+        *    63                                           1        0
+        *    +-----------------------------------------------------+
+        *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+        *    +----------------------------------------------+------+
+        *  8 |       Header Buffer Address [63:1]           |  DD  |
+        *    +-----------------------------------------------------+
+        *
+        *
+        * Advanced Receive Descriptor (Write-Back) Format
+        *
+        *   63       48 47    32 31  30      21 20 17 16   4 3     0
+        *   +------------------------------------------------------+
+        * 0 | Packet     IP     |SPH| HDR_LEN   | RSV|Packet|  RSS |
+        *   | Checksum   Ident  |   |           |    | Type | Type |
+        *   +------------------------------------------------------+
+        * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+        *   +------------------------------------------------------+
+        *   63       48 47    32 31            20 19               0
+        */
+
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "R  [desc]      [ PktBuf     A0] "
+                       "[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+                       "<-- Adv Rx Read format\n");
+               printk(KERN_INFO "RWB[desc]      [PcsmIpSHl PtRs] "
+                       "[vl er S cks ln] ---------------- [bi->skb] "
+                       "<-- Adv Rx Write-Back format\n");
+
+               for (i = 0; i < rx_ring->count; i++) {
+                       buffer_info = &rx_ring->buffer_info[i];
+                       rx_desc = E1000_RX_DESC_ADV(*rx_ring, i);
+                       u0 = (struct my_u0 *)rx_desc;
+                       staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+                       if (staterr & E1000_RXD_STAT_DD) {
+                               /* Descriptor Done */
+                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
+                                       "%016llX ---------------- %p", i,
+                                       le64_to_cpu(u0->a),
+                                       le64_to_cpu(u0->b),
+                                       buffer_info->skb);
+                       } else {
+                               printk(KERN_INFO "R  [0x%03X]     %016llX "
+                                       "%016llX %016llX %p", i,
+                                       le64_to_cpu(u0->a),
+                                       le64_to_cpu(u0->b),
+                                       (u64)buffer_info->dma,
+                                       buffer_info->skb);
+
+                               if (netif_msg_pktdata(adapter)) {
+                                       print_hex_dump(KERN_INFO, "",
+                                               DUMP_PREFIX_ADDRESS,
+                                               16, 1,
+                                               phys_to_virt(buffer_info->dma),
+                                               rx_ring->rx_buffer_len, true);
+                                       if (rx_ring->rx_buffer_len
+                                               < IGB_RXBUFFER_1024)
+                                               print_hex_dump(KERN_INFO, "",
+                                                 DUMP_PREFIX_ADDRESS,
+                                                 16, 1,
+                                                 phys_to_virt(
+                                                   buffer_info->page_dma +
+                                                   buffer_info->page_offset),
+                                                 PAGE_SIZE/2, true);
+                               }
+                       }
+
+                       if (i == rx_ring->next_to_use)
+                               printk(KERN_CONT " NTU\n");
+                       else if (i == rx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC\n");
+                       else
+                               printk(KERN_CONT "\n");
+
+               }
+       }
+
+exit:
+       return;
+}
+
+
 /**
  * igb_read_clock - read raw cycle counter (to be used by time counter)
  */
@@ -223,41 +557,15 @@ static cycle_t igb_read_clock(const struct cyclecounter *tc)
        return stamp;
 }
 
-#ifdef DEBUG
 /**
- * igb_get_hw_dev_name - return device name string
+ * igb_get_hw_dev - return device
  * used by hardware layer to print debugging information
  **/
-char *igb_get_hw_dev_name(struct e1000_hw *hw)
+struct net_device *igb_get_hw_dev(struct e1000_hw *hw)
 {
        struct igb_adapter *adapter = hw->back;
-       return adapter->netdev->name;
-}
-
-/**
- * igb_get_time_str - format current NIC and system time as string
- */
-static char *igb_get_time_str(struct igb_adapter *adapter,
-                             char buffer[160])
-{
-       cycle_t hw = adapter->cycles.read(&adapter->cycles);
-       struct timespec nic = ns_to_timespec(timecounter_read(&adapter->clock));
-       struct timespec sys;
-       struct timespec delta;
-       getnstimeofday(&sys);
-
-       delta = timespec_sub(nic, sys);
-
-       sprintf(buffer,
-               "HW %llu, NIC %ld.%09lus, SYS %ld.%09lus, NIC-SYS %lds + %09luns",
-               hw,
-               (long)nic.tv_sec, nic.tv_nsec,
-               (long)sys.tv_sec, sys.tv_nsec,
-               (long)delta.tv_sec, delta.tv_nsec);
-
-       return buffer;
+       return adapter->netdev;
 }
-#endif
 
 /**
  * igb_init_module - Driver Registration Routine
@@ -328,6 +636,7 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
                }
        case e1000_82575:
        case e1000_82580:
+       case e1000_i350:
        default:
                for (; i < adapter->num_rx_queues; i++)
                        adapter->rx_ring[i]->reg_idx = rbase_offset + i;
@@ -371,7 +680,7 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
                        goto err;
                ring->count = adapter->tx_ring_count;
                ring->queue_index = i;
-               ring->pdev = adapter->pdev;
+               ring->dev = &adapter->pdev->dev;
                ring->netdev = adapter->netdev;
                /* For 82575, context index must be unique per ring. */
                if (adapter->hw.mac.type == e1000_82575)
@@ -385,7 +694,7 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
                        goto err;
                ring->count = adapter->rx_ring_count;
                ring->queue_index = i;
-               ring->pdev = adapter->pdev;
+               ring->dev = &adapter->pdev->dev;
                ring->netdev = adapter->netdev;
                ring->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
                ring->flags = IGB_RING_FLAG_RX_CSUM; /* enable rx checksum */
@@ -471,6 +780,7 @@ static void igb_assign_vector(struct igb_q_vector *q_vector, int msix_vector)
                q_vector->eims_value = 1 << msix_vector;
                break;
        case e1000_82580:
+       case e1000_i350:
                /* 82580 uses the same table-based approach as 82576 but has fewer
                   entries as a result we carry over for queues greater than 4. */
                if (rx_queue > IGB_N0_QUEUE) {
@@ -551,6 +861,7 @@ static void igb_configure_msix(struct igb_adapter *adapter)
 
        case e1000_82576:
        case e1000_82580:
+       case e1000_i350:
                /* Turn on MSI-X capability first, or our settings
                 * won't stick.  And it will take days to debug. */
                wr32(E1000_GPIE, E1000_GPIE_MSIX_MODE |
@@ -743,7 +1054,6 @@ msi_only:
 out:
        /* Notify the stack of the (possibly) reduced Tx Queue count. */
        adapter->netdev->real_num_tx_queues = adapter->num_tx_queues;
-       return;
 }
 
 /**
@@ -1253,6 +1563,7 @@ void igb_reset(struct igb_adapter *adapter)
         * To take effect CTRL.RST is required.
         */
        switch (mac->type) {
+       case e1000_i350:
        case e1000_82580:
                pba = rd32(E1000_RXPBS);
                pba = igb_rxpbs_adjust_82580(pba);
@@ -1416,15 +1727,15 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                return err;
 
        pci_using_dac = 0;
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
        if (!err) {
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
                if (!err)
                        pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+                       err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
                        if (err) {
                                dev_err(&pdev->dev, "No usable DMA "
                                        "configuration, aborting\n");
@@ -1656,6 +1967,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
        dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n",
                 netdev->name,
                 ((hw->bus.speed == e1000_bus_speed_2500) ? "2.5Gb/s" :
+                 (hw->bus.speed == e1000_bus_speed_5000) ? "5.0Gb/s" :
                                                            "unknown"),
                 ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
                  (hw->bus.width == e1000_bus_width_pcie_x2) ? "Width x2" :
@@ -1826,6 +2138,7 @@ static void igb_init_hw_timer(struct igb_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
 
        switch (hw->mac.type) {
+       case e1000_i350:
        case e1000_82580:
                memset(&adapter->cycles, 0, sizeof(adapter->cycles));
                adapter->cycles.read = igb_read_clock;
@@ -2096,7 +2409,7 @@ static int igb_close(struct net_device *netdev)
  **/
 int igb_setup_tx_resources(struct igb_ring *tx_ring)
 {
-       struct pci_dev *pdev = tx_ring->pdev;
+       struct device *dev = tx_ring->dev;
        int size;
 
        size = sizeof(struct igb_buffer) * tx_ring->count;
@@ -2109,9 +2422,10 @@ int igb_setup_tx_resources(struct igb_ring *tx_ring)
        tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
 
-       tx_ring->desc = pci_alloc_consistent(pdev,
-                                            tx_ring->size,
-                                            &tx_ring->dma);
+       tx_ring->desc = dma_alloc_coherent(dev,
+                                          tx_ring->size,
+                                          &tx_ring->dma,
+                                          GFP_KERNEL);
 
        if (!tx_ring->desc)
                goto err;
@@ -2122,7 +2436,7 @@ int igb_setup_tx_resources(struct igb_ring *tx_ring)
 
 err:
        vfree(tx_ring->buffer_info);
-       dev_err(&pdev->dev,
+       dev_err(dev,
                "Unable to allocate memory for the transmit descriptor ring\n");
        return -ENOMEM;
 }
@@ -2246,7 +2560,7 @@ static void igb_configure_tx(struct igb_adapter *adapter)
  **/
 int igb_setup_rx_resources(struct igb_ring *rx_ring)
 {
-       struct pci_dev *pdev = rx_ring->pdev;
+       struct device *dev = rx_ring->dev;
        int size, desc_len;
 
        size = sizeof(struct igb_buffer) * rx_ring->count;
@@ -2261,8 +2575,10 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
        rx_ring->size = rx_ring->count * desc_len;
        rx_ring->size = ALIGN(rx_ring->size, 4096);
 
-       rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
-                                            &rx_ring->dma);
+       rx_ring->desc = dma_alloc_coherent(dev,
+                                          rx_ring->size,
+                                          &rx_ring->dma,
+                                          GFP_KERNEL);
 
        if (!rx_ring->desc)
                goto err;
@@ -2275,8 +2591,8 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
 err:
        vfree(rx_ring->buffer_info);
        rx_ring->buffer_info = NULL;
-       dev_err(&pdev->dev, "Unable to allocate memory for "
-               "the receive descriptor ring\n");
+       dev_err(dev, "Unable to allocate memory for the receive descriptor"
+               " ring\n");
        return -ENOMEM;
 }
 
@@ -2339,6 +2655,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
        if (adapter->vfs_allocated_count) {
                /* 82575 and 82576 supports 2 RSS queues for VMDq */
                switch (hw->mac.type) {
+               case e1000_i350:
                case e1000_82580:
                        num_rx_queues = 1;
                        shift = 0;
@@ -2590,6 +2907,8 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
                         E1000_SRRCTL_BSIZEPKT_SHIFT;
                srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
        }
+       if (hw->mac.type == e1000_82580)
+               srrctl |= E1000_SRRCTL_TIMESTAMP;
        /* Only set Drop Enable if we are supporting multiple queues */
        if (adapter->vfs_allocated_count || adapter->num_rx_queues > 1)
                srrctl |= E1000_SRRCTL_DROP_EN;
@@ -2649,8 +2968,8 @@ void igb_free_tx_resources(struct igb_ring *tx_ring)
        if (!tx_ring->desc)
                return;
 
-       pci_free_consistent(tx_ring->pdev, tx_ring->size,
-                           tx_ring->desc, tx_ring->dma);
+       dma_free_coherent(tx_ring->dev, tx_ring->size,
+                         tx_ring->desc, tx_ring->dma);
 
        tx_ring->desc = NULL;
 }
@@ -2674,15 +2993,15 @@ void igb_unmap_and_free_tx_resource(struct igb_ring *tx_ring,
 {
        if (buffer_info->dma) {
                if (buffer_info->mapped_as_page)
-                       pci_unmap_page(tx_ring->pdev,
+                       dma_unmap_page(tx_ring->dev,
                                        buffer_info->dma,
                                        buffer_info->length,
-                                       PCI_DMA_TODEVICE);
+                                       DMA_TO_DEVICE);
                else
-                       pci_unmap_single(tx_ring->pdev,
+                       dma_unmap_single(tx_ring->dev,
                                        buffer_info->dma,
                                        buffer_info->length,
-                                       PCI_DMA_TODEVICE);
+                                       DMA_TO_DEVICE);
                buffer_info->dma = 0;
        }
        if (buffer_info->skb) {
@@ -2753,8 +3072,8 @@ void igb_free_rx_resources(struct igb_ring *rx_ring)
        if (!rx_ring->desc)
                return;
 
-       pci_free_consistent(rx_ring->pdev, rx_ring->size,
-                           rx_ring->desc, rx_ring->dma);
+       dma_free_coherent(rx_ring->dev, rx_ring->size,
+                         rx_ring->desc, rx_ring->dma);
 
        rx_ring->desc = NULL;
 }
@@ -2790,10 +3109,10 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
        for (i = 0; i < rx_ring->count; i++) {
                buffer_info = &rx_ring->buffer_info[i];
                if (buffer_info->dma) {
-                       pci_unmap_single(rx_ring->pdev,
+                       dma_unmap_single(rx_ring->dev,
                                         buffer_info->dma,
                                         rx_ring->rx_buffer_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        buffer_info->dma = 0;
                }
 
@@ -2802,10 +3121,10 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring)
                        buffer_info->skb = NULL;
                }
                if (buffer_info->page_dma) {
-                       pci_unmap_page(rx_ring->pdev,
+                       dma_unmap_page(rx_ring->dev,
                                       buffer_info->page_dma,
                                       PAGE_SIZE / 2,
-                                      PCI_DMA_FROMDEVICE);
+                                      DMA_FROM_DEVICE);
                        buffer_info->page_dma = 0;
                }
                if (buffer_info->page) {
@@ -2876,7 +3195,7 @@ static int igb_write_mc_addr_list(struct net_device *netdev)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u8  *mta_list;
        int i;
 
@@ -2893,8 +3212,8 @@ static int igb_write_mc_addr_list(struct net_device *netdev)
 
        /* The shared function expects a packed array of only addresses. */
        i = 0;
-       netdev_for_each_mc_addr(mc_ptr, netdev)
-               memcpy(mta_list + (i++ * ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
+       netdev_for_each_mc_addr(ha, netdev)
+               memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
 
        igb_update_mc_addr_list(hw, mta_list, i);
        kfree(mta_list);
@@ -3397,8 +3716,6 @@ set_itr_now:
                q_vector->itr_val = new_itr;
                q_vector->set_itr = 1;
        }
-
-       return;
 }
 
 #define IGB_TX_FLAGS_CSUM              0x00000001
@@ -3493,7 +3810,7 @@ static inline bool igb_tx_csum_adv(struct igb_ring *tx_ring,
                                   struct sk_buff *skb, u32 tx_flags)
 {
        struct e1000_adv_tx_context_desc *context_desc;
-       struct pci_dev *pdev = tx_ring->pdev;
+       struct device *dev = tx_ring->dev;
        struct igb_buffer *buffer_info;
        u32 info = 0, tu_cmd = 0;
        unsigned int i;
@@ -3544,7 +3861,7 @@ static inline bool igb_tx_csum_adv(struct igb_ring *tx_ring,
                                break;
                        default:
                                if (unlikely(net_ratelimit()))
-                                       dev_warn(&pdev->dev,
+                                       dev_warn(dev,
                                            "partial checksum but proto=%x!\n",
                                            skb->protocol);
                                break;
@@ -3578,59 +3895,61 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb,
                                 unsigned int first)
 {
        struct igb_buffer *buffer_info;
-       struct pci_dev *pdev = tx_ring->pdev;
-       unsigned int len = skb_headlen(skb);
+       struct device *dev = tx_ring->dev;
+       unsigned int hlen = skb_headlen(skb);
        unsigned int count = 0, i;
        unsigned int f;
+       u16 gso_segs = skb_shinfo(skb)->gso_segs ?: 1;
 
        i = tx_ring->next_to_use;
 
        buffer_info = &tx_ring->buffer_info[i];
-       BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
-       buffer_info->length = len;
+       BUG_ON(hlen >= IGB_MAX_DATA_PER_TXD);
+       buffer_info->length = hlen;
        /* set time_stamp *before* dma to help avoid a possible race */
        buffer_info->time_stamp = jiffies;
        buffer_info->next_to_watch = i;
-       buffer_info->dma = pci_map_single(pdev, skb->data, len,
-                                         PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(pdev, buffer_info->dma))
+       buffer_info->dma = dma_map_single(dev, skb->data, hlen,
+                                         DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, buffer_info->dma))
                goto dma_error;
 
        for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
-               struct skb_frag_struct *frag;
+               struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[f];
+               unsigned int len = frag->size;
 
                count++;
                i++;
                if (i == tx_ring->count)
                        i = 0;
 
-               frag = &skb_shinfo(skb)->frags[f];
-               len = frag->size;
-
                buffer_info = &tx_ring->buffer_info[i];
                BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
                buffer_info->length = len;
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
                buffer_info->mapped_as_page = true;
-               buffer_info->dma = pci_map_page(pdev,
+               buffer_info->dma = dma_map_page(dev,
                                                frag->page,
                                                frag->page_offset,
                                                len,
-                                               PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma))
+                                               DMA_TO_DEVICE);
+               if (dma_mapping_error(dev, buffer_info->dma))
                        goto dma_error;
 
        }
 
        tx_ring->buffer_info[i].skb = skb;
-       tx_ring->buffer_info[i].gso_segs = skb_shinfo(skb)->gso_segs ?: 1;
+       tx_ring->buffer_info[i].shtx = skb_shinfo(skb)->tx_flags;
+       /* multiply data chunks by size of headers */
+       tx_ring->buffer_info[i].bytecount = ((gso_segs - 1) * hlen) + skb->len;
+       tx_ring->buffer_info[i].gso_segs = gso_segs;
        tx_ring->buffer_info[first].next_to_watch = i;
 
        return ++count;
 
 dma_error:
-       dev_err(&pdev->dev, "TX DMA map failed\n");
+       dev_err(dev, "TX DMA map failed\n");
 
        /* clear timestamp and dma mappings for failed buffer_info mapping */
        buffer_info->dma = 0;
@@ -3868,6 +4187,8 @@ static void igb_reset_task(struct work_struct *work)
        struct igb_adapter *adapter;
        adapter = container_of(work, struct igb_adapter, reset_task);
 
+       igb_dump(adapter);
+       netdev_err(adapter->netdev, "Reset adapter\n");
        igb_reinit_locked(adapter);
 }
 
@@ -3920,6 +4241,9 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
         * i.e. RXBUFFER_2048 --> size-4096 slab
         */
 
+       if (adapter->hw.mac.type == e1000_82580)
+               max_frame += IGB_TS_HDR_LEN;
+
        if (max_frame <= IGB_RXBUFFER_1024)
                rx_buffer_len = IGB_RXBUFFER_1024;
        else if (max_frame <= MAXIMUM_ETHERNET_VLAN_SIZE)
@@ -3927,6 +4251,14 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
        else
                rx_buffer_len = IGB_RXBUFFER_128;
 
+       if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN + IGB_TS_HDR_LEN) ||
+            (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE + IGB_TS_HDR_LEN))
+               rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE + IGB_TS_HDR_LEN;
+
+       if ((adapter->hw.mac.type == e1000_82580) &&
+           (rx_buffer_len == IGB_RXBUFFER_128))
+               rx_buffer_len += IGB_RXBUFFER_64;
+
        if (netif_running(netdev))
                igb_down(adapter);
 
@@ -4955,22 +5287,21 @@ static void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
 /**
  * igb_tx_hwtstamp - utility function which checks for TX time stamp
  * @q_vector: pointer to q_vector containing needed info
- * @skb: packet that was just sent
+ * @buffer: pointer to igb_buffer structure
  *
  * If we were asked to do hardware stamping and such a time stamp is
  * available, then it must have been for this skb here because we only
  * allow only one such packet into the queue.
  */
-static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb)
+static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct igb_buffer *buffer_info)
 {
        struct igb_adapter *adapter = q_vector->adapter;
-       union skb_shared_tx *shtx = skb_tx(skb);
        struct e1000_hw *hw = &adapter->hw;
        struct skb_shared_hwtstamps shhwtstamps;
        u64 regval;
 
        /* if skb does not support hw timestamp or TX stamp not valid exit */
-       if (likely(!shtx->hardware) ||
+       if (likely(!buffer_info->shtx.hardware) ||
            !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
                return;
 
@@ -4978,7 +5309,7 @@ static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb)
        regval |= (u64)rd32(E1000_TXSTMPH) << 32;
 
        igb_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
-       skb_tstamp_tx(skb, &shhwtstamps);
+       skb_tstamp_tx(buffer_info->skb, &shhwtstamps);
 }
 
 /**
@@ -4993,7 +5324,6 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
        struct net_device *netdev = tx_ring->netdev;
        struct e1000_hw *hw = &adapter->hw;
        struct igb_buffer *buffer_info;
-       struct sk_buff *skb;
        union e1000_adv_tx_desc *tx_desc, *eop_desc;
        unsigned int total_bytes = 0, total_packets = 0;
        unsigned int i, eop, count = 0;
@@ -5009,19 +5339,12 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
                        tx_desc = E1000_TX_DESC_ADV(*tx_ring, i);
                        buffer_info = &tx_ring->buffer_info[i];
                        cleaned = (i == eop);
-                       skb = buffer_info->skb;
 
-                       if (skb) {
-                               unsigned int segs, bytecount;
+                       if (buffer_info->skb) {
+                               total_bytes += buffer_info->bytecount;
                                /* gso_segs is currently only valid for tcp */
-                               segs = buffer_info->gso_segs;
-                               /* multiply data chunks by size of headers */
-                               bytecount = ((segs - 1) * skb_headlen(skb)) +
-                                           skb->len;
-                               total_packets += segs;
-                               total_bytes += bytecount;
-
-                               igb_tx_hwtstamp(q_vector, skb);
+                               total_packets += buffer_info->gso_segs;
+                               igb_tx_hwtstamp(q_vector, buffer_info);
                        }
 
                        igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
@@ -5061,7 +5384,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
                    !(rd32(E1000_STATUS) & E1000_STATUS_TXOFF)) {
 
                        /* detected Tx unit hang */
-                       dev_err(&tx_ring->pdev->dev,
+                       dev_err(tx_ring->dev,
                                "Detected Tx Unit Hang\n"
                                "  Tx Queue             <%d>\n"
                                "  TDH                  <%x>\n"
@@ -5140,10 +5463,10 @@ static inline void igb_rx_checksum_adv(struct igb_ring *ring,
        if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS))
                skb->ip_summed = CHECKSUM_UNNECESSARY;
 
-       dev_dbg(&ring->pdev->dev, "cksum success: bits %08X\n", status_err);
+       dev_dbg(ring->dev, "cksum success: bits %08X\n", status_err);
 }
 
-static inline void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
+static void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
                                    struct sk_buff *skb)
 {
        struct igb_adapter *adapter = q_vector->adapter;
@@ -5161,13 +5484,18 @@ static inline void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
         * If nothing went wrong, then it should have a skb_shared_tx that we
         * can turn into a skb_shared_hwtstamps.
         */
-       if (likely(!(staterr & E1000_RXDADV_STAT_TS)))
-               return;
-       if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
-               return;
+       if (staterr & E1000_RXDADV_STAT_TSIP) {
+               u32 *stamp = (u32 *)skb->data;
+               regval = le32_to_cpu(*(stamp + 2));
+               regval |= (u64)le32_to_cpu(*(stamp + 3)) << 32;
+               skb_pull(skb, IGB_TS_HDR_LEN);
+       } else {
+               if(!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
+                       return;
 
-       regval = rd32(E1000_RXSTMPL);
-       regval |= (u64)rd32(E1000_RXSTMPH) << 32;
+               regval = rd32(E1000_RXSTMPL);
+               regval |= (u64)rd32(E1000_RXSTMPH) << 32;
+       }
 
        igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
 }
@@ -5190,7 +5518,7 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
 {
        struct igb_ring *rx_ring = q_vector->rx_ring;
        struct net_device *netdev = rx_ring->netdev;
-       struct pci_dev *pdev = rx_ring->pdev;
+       struct device *dev = rx_ring->dev;
        union e1000_adv_rx_desc *rx_desc , *next_rxd;
        struct igb_buffer *buffer_info , *next_buffer;
        struct sk_buff *skb;
@@ -5230,9 +5558,9 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
                cleaned_count++;
 
                if (buffer_info->dma) {
-                       pci_unmap_single(pdev, buffer_info->dma,
+                       dma_unmap_single(dev, buffer_info->dma,
                                         rx_ring->rx_buffer_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        buffer_info->dma = 0;
                        if (rx_ring->rx_buffer_len >= IGB_RXBUFFER_1024) {
                                skb_put(skb, length);
@@ -5242,11 +5570,11 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
                }
 
                if (length) {
-                       pci_unmap_page(pdev, buffer_info->page_dma,
-                                      PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+                       dma_unmap_page(dev, buffer_info->page_dma,
+                                      PAGE_SIZE / 2, DMA_FROM_DEVICE);
                        buffer_info->page_dma = 0;
 
-                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++,
+                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
                                                buffer_info->page,
                                                buffer_info->page_offset,
                                                length);
@@ -5275,7 +5603,8 @@ send_up:
                        goto next_desc;
                }
 
-               igb_rx_hwtstamp(q_vector, staterr, skb);
+               if (staterr & (E1000_RXDADV_STAT_TSIP | E1000_RXDADV_STAT_TS))
+                       igb_rx_hwtstamp(q_vector, staterr, skb);
                total_bytes += skb->len;
                total_packets++;
 
@@ -5350,12 +5679,12 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
                                buffer_info->page_offset ^= PAGE_SIZE / 2;
                        }
                        buffer_info->page_dma =
-                               pci_map_page(rx_ring->pdev, buffer_info->page,
+                               dma_map_page(rx_ring->dev, buffer_info->page,
                                             buffer_info->page_offset,
                                             PAGE_SIZE / 2,
-                                            PCI_DMA_FROMDEVICE);
-                       if (pci_dma_mapping_error(rx_ring->pdev,
-                                                 buffer_info->page_dma)) {
+                                            DMA_FROM_DEVICE);
+                       if (dma_mapping_error(rx_ring->dev,
+                                             buffer_info->page_dma)) {
                                buffer_info->page_dma = 0;
                                rx_ring->rx_stats.alloc_failed++;
                                goto no_buffers;
@@ -5373,12 +5702,12 @@ void igb_alloc_rx_buffers_adv(struct igb_ring *rx_ring, int cleaned_count)
                        buffer_info->skb = skb;
                }
                if (!buffer_info->dma) {
-                       buffer_info->dma = pci_map_single(rx_ring->pdev,
+                       buffer_info->dma = dma_map_single(rx_ring->dev,
                                                          skb->data,
                                                          bufsz,
-                                                         PCI_DMA_FROMDEVICE);
-                       if (pci_dma_mapping_error(rx_ring->pdev,
-                                                 buffer_info->dma)) {
+                                                         DMA_FROM_DEVICE);
+                       if (dma_mapping_error(rx_ring->dev,
+                                             buffer_info->dma)) {
                                buffer_info->dma = 0;
                                rx_ring->rx_stats.alloc_failed++;
                                goto no_buffers;
@@ -5555,6 +5884,16 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
                return 0;
        }
 
+       /*
+        * Per-packet timestamping only works if all packets are
+        * timestamped, so enable timestamping in all packets as
+        * long as one rx filter was configured.
+        */
+       if ((hw->mac.type == e1000_82580) && tsync_rx_ctl) {
+               tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
+       }
+
        /* enable/disable TX */
        regval = rd32(E1000_TSYNCTXCTL);
        regval &= ~E1000_TSYNCTXCTL_ENABLED;
@@ -6131,19 +6470,25 @@ static void igb_vmm_control(struct igb_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        u32 reg;
 
-       /* replication is not supported for 82575 */
-       if (hw->mac.type == e1000_82575)
+       switch (hw->mac.type) {
+       case e1000_82575:
+       default:
+               /* replication is not supported for 82575 */
                return;
-
-       /* enable replication vlan tag stripping */
-       reg = rd32(E1000_RPLOLR);
-       reg |= E1000_RPLOLR_STRVLAN;
-       wr32(E1000_RPLOLR, reg);
-
-       /* notify HW that the MAC is adding vlan tags */
-       reg = rd32(E1000_DTXCTL);
-       reg |= E1000_DTXCTL_VLAN_ADDED;
-       wr32(E1000_DTXCTL, reg);
+       case e1000_82576:
+               /* notify HW that the MAC is adding vlan tags */
+               reg = rd32(E1000_DTXCTL);
+               reg |= E1000_DTXCTL_VLAN_ADDED;
+               wr32(E1000_DTXCTL, reg);
+       case e1000_82580:
+               /* enable replication vlan tag stripping */
+               reg = rd32(E1000_RPLOLR);
+               reg |= E1000_RPLOLR_STRVLAN;
+               wr32(E1000_RPLOLR, reg);
+       case e1000_i350:
+               /* none of the above registers are supported by i350 */
+               break;
+       }
 
        if (adapter->vfs_allocated_count) {
                igb_vmdq_set_loopback_pf(hw, true);
index 8afff07ff5591de68b0acc58e340424b83b92cca..103b3aa1afc2297d862005d25b48dc42af9607e8 100644 (file)
@@ -390,8 +390,6 @@ static void igbvf_get_wol(struct net_device *netdev,
 {
        wol->supported = 0;
        wol->wolopts = 0;
-
-       return;
 }
 
 static int igbvf_set_wol(struct net_device *netdev,
index f16e981812a9b5c7d112cad20228e2204263f22c..5e2b2a8c56c6f81ade223d30f9e3bf0705ed3f6e 100644 (file)
@@ -165,10 +165,10 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
                                buffer_info->page_offset ^= PAGE_SIZE / 2;
                        }
                        buffer_info->page_dma =
-                               pci_map_page(pdev, buffer_info->page,
+                               dma_map_page(&pdev->dev, buffer_info->page,
                                             buffer_info->page_offset,
                                             PAGE_SIZE / 2,
-                                            PCI_DMA_FROMDEVICE);
+                                            DMA_FROM_DEVICE);
                }
 
                if (!buffer_info->skb) {
@@ -179,9 +179,9 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
                        }
 
                        buffer_info->skb = skb;
-                       buffer_info->dma = pci_map_single(pdev, skb->data,
+                       buffer_info->dma = dma_map_single(&pdev->dev, skb->data,
                                                          bufsz,
-                                                         PCI_DMA_FROMDEVICE);
+                                                         DMA_FROM_DEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
                 * each write-back erases this info. */
@@ -269,28 +269,28 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
                prefetch(skb->data - NET_IP_ALIGN);
                buffer_info->skb = NULL;
                if (!adapter->rx_ps_hdr_size) {
-                       pci_unmap_single(pdev, buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, buffer_info->dma,
                                         adapter->rx_buffer_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        buffer_info->dma = 0;
                        skb_put(skb, length);
                        goto send_up;
                }
 
                if (!skb_shinfo(skb)->nr_frags) {
-                       pci_unmap_single(pdev, buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, buffer_info->dma,
                                         adapter->rx_ps_hdr_size,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        skb_put(skb, hlen);
                }
 
                if (length) {
-                       pci_unmap_page(pdev, buffer_info->page_dma,
+                       dma_unmap_page(&pdev->dev, buffer_info->page_dma,
                                       PAGE_SIZE / 2,
-                                      PCI_DMA_FROMDEVICE);
+                                      DMA_FROM_DEVICE);
                        buffer_info->page_dma = 0;
 
-                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags++,
+                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
                                           buffer_info->page,
                                           buffer_info->page_offset,
                                           length);
@@ -370,15 +370,15 @@ static void igbvf_put_txbuf(struct igbvf_adapter *adapter,
 {
        if (buffer_info->dma) {
                if (buffer_info->mapped_as_page)
-                       pci_unmap_page(adapter->pdev,
+                       dma_unmap_page(&adapter->pdev->dev,
                                       buffer_info->dma,
                                       buffer_info->length,
-                                      PCI_DMA_TODEVICE);
+                                      DMA_TO_DEVICE);
                else
-                       pci_unmap_single(adapter->pdev,
+                       dma_unmap_single(&adapter->pdev->dev,
                                         buffer_info->dma,
                                         buffer_info->length,
-                                        PCI_DMA_TODEVICE);
+                                        DMA_TO_DEVICE);
                buffer_info->dma = 0;
        }
        if (buffer_info->skb) {
@@ -439,8 +439,8 @@ int igbvf_setup_tx_resources(struct igbvf_adapter *adapter,
        tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
 
-       tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
-                                            &tx_ring->dma);
+       tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+                                          &tx_ring->dma, GFP_KERNEL);
 
        if (!tx_ring->desc)
                goto err;
@@ -481,8 +481,8 @@ int igbvf_setup_rx_resources(struct igbvf_adapter *adapter,
        rx_ring->size = rx_ring->count * desc_len;
        rx_ring->size = ALIGN(rx_ring->size, 4096);
 
-       rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
-                                            &rx_ring->dma);
+       rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+                                          &rx_ring->dma, GFP_KERNEL);
 
        if (!rx_ring->desc)
                goto err;
@@ -550,7 +550,8 @@ void igbvf_free_tx_resources(struct igbvf_ring *tx_ring)
        vfree(tx_ring->buffer_info);
        tx_ring->buffer_info = NULL;
 
-       pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+       dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+                         tx_ring->dma);
 
        tx_ring->desc = NULL;
 }
@@ -575,13 +576,13 @@ static void igbvf_clean_rx_ring(struct igbvf_ring *rx_ring)
                buffer_info = &rx_ring->buffer_info[i];
                if (buffer_info->dma) {
                        if (adapter->rx_ps_hdr_size){
-                               pci_unmap_single(pdev, buffer_info->dma,
+                               dma_unmap_single(&pdev->dev, buffer_info->dma,
                                                 adapter->rx_ps_hdr_size,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        } else {
-                               pci_unmap_single(pdev, buffer_info->dma,
+                               dma_unmap_single(&pdev->dev, buffer_info->dma,
                                                 adapter->rx_buffer_len,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        }
                        buffer_info->dma = 0;
                }
@@ -593,9 +594,10 @@ static void igbvf_clean_rx_ring(struct igbvf_ring *rx_ring)
 
                if (buffer_info->page) {
                        if (buffer_info->page_dma)
-                               pci_unmap_page(pdev, buffer_info->page_dma,
+                               dma_unmap_page(&pdev->dev,
+                                              buffer_info->page_dma,
                                               PAGE_SIZE / 2,
-                                              PCI_DMA_FROMDEVICE);
+                                              DMA_FROM_DEVICE);
                        put_page(buffer_info->page);
                        buffer_info->page = NULL;
                        buffer_info->page_dma = 0;
@@ -1399,7 +1401,7 @@ static void igbvf_set_multi(struct net_device *netdev)
 {
        struct igbvf_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u8  *mta_list = NULL;
        int i;
 
@@ -1414,8 +1416,8 @@ static void igbvf_set_multi(struct net_device *netdev)
 
        /* prepare a packed array of only addresses. */
        i = 0;
-       netdev_for_each_mc_addr(mc_ptr, netdev)
-               memcpy(mta_list + (i++ * ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
+       netdev_for_each_mc_addr(ha, netdev)
+               memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
 
        hw->mac.ops.update_mc_addr_list(hw, mta_list, i, 0, 0);
        kfree(mta_list);
@@ -2105,9 +2107,9 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
        buffer_info->time_stamp = jiffies;
        buffer_info->next_to_watch = i;
        buffer_info->mapped_as_page = false;
-       buffer_info->dma = pci_map_single(pdev, skb->data, len,
-                                         PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(pdev, buffer_info->dma))
+       buffer_info->dma = dma_map_single(&pdev->dev, skb->data, len,
+                                         DMA_TO_DEVICE);
+       if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                goto dma_error;
 
 
@@ -2128,12 +2130,12 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter,
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
                buffer_info->mapped_as_page = true;
-               buffer_info->dma = pci_map_page(pdev,
+               buffer_info->dma = dma_map_page(&pdev->dev,
                                                frag->page,
                                                frag->page_offset,
                                                len,
-                                               PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma))
+                                               DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                        goto dma_error;
        }
 
@@ -2645,16 +2647,16 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
                return err;
 
        pci_using_dac = 0;
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
        if (!err) {
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+               err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
                if (!err)
                        pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = pci_set_consistent_dma_mask(pdev,
-                                                         DMA_BIT_MASK(32));
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
                        if (err) {
                                dev_err(&pdev->dev, "No usable DMA "
                                        "configuration, aborting\n");
index 8f6197d647c0433a227dd74f4057df0cc9905fbf..e3b5e949060136a619bee08d429a1a7e10c4ef2e 100644 (file)
@@ -1503,7 +1503,6 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        BARRIER();
 
-       dev->trans_start = jiffies;
        ip->tx_skbs[produce] = skb;                     /* Remember skb */
        produce = (produce + 1) & 127;
        ip->tx_pi = produce;
@@ -1665,7 +1664,7 @@ static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 static void ioc3_set_multicast_list(struct net_device *dev)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        struct ioc3_private *ip = netdev_priv(dev);
        struct ioc3 *ioc3 = ip->regs;
        u64 ehar = 0;
@@ -1689,8 +1688,8 @@ static void ioc3_set_multicast_list(struct net_device *dev)
                        ip->ehar_h = 0xffffffff;
                        ip->ehar_l = 0xffffffff;
                } else {
-                       netdev_for_each_mc_addr(dmi, dev) {
-                               char *addr = dmi->dmi_addr;
+                       netdev_for_each_mc_addr(ha, dev) {
+                               char *addr = ha->addr;
 
                                if (!(*addr & 1))
                                        continue;
index 639bf9fb027974b65b0376a5a2a188f3171dec26..72e3d2da9e9fd3174bea52c1d9feaf57e0423316 100644 (file)
@@ -570,7 +570,7 @@ static int ipg_config_autoneg(struct net_device *dev)
 static void ipg_nic_set_multicast_list(struct net_device *dev)
 {
        void __iomem *ioaddr = ipg_ioaddr(dev);
-       struct dev_mc_list *mc_list_ptr;
+       struct netdev_hw_addr *ha;
        unsigned int hashindex;
        u32 hashtable[2];
        u8 receivemode;
@@ -609,9 +609,9 @@ static void ipg_nic_set_multicast_list(struct net_device *dev)
        hashtable[1] = 0x00000000;
 
        /* Cycle through all multicast addresses to filter. */
-       netdev_for_each_mc_addr(mc_list_ptr, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                /* Calculate CRC result for each multicast address. */
-               hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
+               hashindex = crc32_le(0xffffffff, ha->addr,
                                     ETH_ALEN);
 
                /* Use only the least significant 6 bits. */
@@ -1548,8 +1548,6 @@ static void ipg_reset_after_host_error(struct work_struct *work)
                container_of(work, struct ipg_nic_private, task.work);
        struct net_device *dev = sp->dev;
 
-       IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL));
-
        /*
         * Acknowledge HostError interrupt by resetting
         * IPG DMA and HOST.
@@ -1826,9 +1824,6 @@ static int ipg_nic_stop(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount);
-       IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount);
-       IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount);
        IPG_DUMPTFDLIST(dev);
 
        do {
index dfc2541bb55628dc4c0c934958834cdc980a646b..6ce027355fcf721932336aee3fce299f4fe7f716 100644 (file)
@@ -29,7 +29,7 @@
 /* GMII based PHY IDs */
 #define                NS                              0x2000
 #define                MARVELL                         0x0141
-#define                ICPLUS_PHY              0x243
+#define                ICPLUS_PHY                      0x243
 
 /* NIC Physical Layer Device MII register fields. */
 #define         MII_PHY_SELECTOR_IEEE8023       0x0001
@@ -96,31 +96,31 @@ enum ipg_regs {
 };
 
 /* Ethernet MIB statistic register offsets. */
-#define        IPG_OCTETRCVOK          0xA8
+#define        IPG_OCTETRCVOK                  0xA8
 #define        IPG_MCSTOCTETRCVDOK             0xAC
 #define        IPG_BCSTOCTETRCVOK              0xB0
 #define        IPG_FRAMESRCVDOK                0xB4
 #define        IPG_MCSTFRAMESRCVDOK            0xB8
 #define        IPG_BCSTFRAMESRCVDOK            0xBE
 #define        IPG_MACCONTROLFRAMESRCVD        0xC6
-#define        IPG_FRAMETOOLONGERRRORS 0xC8
-#define        IPG_INRANGELENGTHERRORS 0xCA
-#define        IPG_FRAMECHECKSEQERRORS 0xCC
-#define        IPG_FRAMESLOSTRXERRORS  0xCE
-#define        IPG_OCTETXMTOK          0xD0
+#define        IPG_FRAMETOOLONGERRRORS         0xC8
+#define        IPG_INRANGELENGTHERRORS         0xCA
+#define        IPG_FRAMECHECKSEQERRORS         0xCC
+#define        IPG_FRAMESLOSTRXERRORS          0xCE
+#define        IPG_OCTETXMTOK                  0xD0
 #define        IPG_MCSTOCTETXMTOK              0xD4
 #define        IPG_BCSTOCTETXMTOK              0xD8
 #define        IPG_FRAMESXMTDOK                0xDC
 #define        IPG_MCSTFRAMESXMTDOK            0xE0
-#define        IPG_FRAMESWDEFERREDXMT  0xE4
+#define        IPG_FRAMESWDEFERREDXMT          0xE4
 #define        IPG_LATECOLLISIONS              0xE8
 #define        IPG_MULTICOLFRAMES              0xEC
 #define        IPG_SINGLECOLFRAMES             0xF0
 #define        IPG_BCSTFRAMESXMTDOK            0xF6
-#define        IPG_CARRIERSENSEERRORS  0xF8
+#define        IPG_CARRIERSENSEERRORS          0xF8
 #define        IPG_MACCONTROLFRAMESXMTDOK      0xFA
-#define        IPG_FRAMESABORTXSCOLLS  0xFC
-#define        IPG_FRAMESWEXDEFERRAL   0xFE
+#define        IPG_FRAMESABORTXSCOLLS          0xFC
+#define        IPG_FRAMESWEXDEFERRAL           0xFE
 
 /* RMON statistic register offsets. */
 #define        IPG_ETHERSTATSCOLLISIONS                        0x100
@@ -134,8 +134,8 @@ enum ipg_regs {
 #define        IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT     0x120
 #define        IPG_ETHERSTATSCRCALIGNERRORS                    0x124
 #define        IPG_ETHERSTATSUNDERSIZEPKTS                     0x128
-#define        IPG_ETHERSTATSFRAGMENTS                 0x12C
-#define        IPG_ETHERSTATSJABBERS                   0x130
+#define        IPG_ETHERSTATSFRAGMENTS                         0x12C
+#define        IPG_ETHERSTATSJABBERS                           0x130
 #define        IPG_ETHERSTATSOCTETS                            0x134
 #define        IPG_ETHERSTATSPKTS                              0x138
 #define        IPG_ETHERSTATSPKTS64OCTESTS                     0x13C
@@ -154,10 +154,10 @@ enum ipg_regs {
 #define        IPG_ETHERSTATSDROPEVENTS                        0xCE
 
 /* Serial EEPROM offsets */
-#define        IPG_EEPROM_CONFIGPARAM  0x00
+#define        IPG_EEPROM_CONFIGPARAM          0x00
 #define        IPG_EEPROM_ASICCTRL             0x01
 #define        IPG_EEPROM_SUBSYSTEMVENDORID    0x02
-#define        IPG_EEPROM_SUBSYSTEMID  0x03
+#define        IPG_EEPROM_SUBSYSTEMID          0x03
 #define        IPG_EEPROM_STATIONADDRESS0      0x10
 #define        IPG_EEPROM_STATIONADDRESS1      0x11
 #define        IPG_EEPROM_STATIONADDRESS2      0x12
@@ -168,16 +168,16 @@ enum ipg_regs {
 
 /* IOBaseAddress */
 #define         IPG_PIB_RSVD_MASK              0xFFFFFE01
-#define         IPG_PIB_IOBASEADDRESS  0xFFFFFF00
-#define         IPG_PIB_IOBASEADDRIND  0x00000001
+#define         IPG_PIB_IOBASEADDRESS          0xFFFFFF00
+#define         IPG_PIB_IOBASEADDRIND          0x00000001
 
 /* MemBaseAddress */
 #define         IPG_PMB_RSVD_MASK              0xFFFFFE07
-#define         IPG_PMB_MEMBASEADDRIND 0x00000001
+#define         IPG_PMB_MEMBASEADDRIND         0x00000001
 #define         IPG_PMB_MEMMAPTYPE             0x00000006
 #define         IPG_PMB_MEMMAPTYPE0            0x00000002
 #define         IPG_PMB_MEMMAPTYPE1            0x00000004
-#define         IPG_PMB_MEMBASEADDRESS 0xFFFFFE00
+#define         IPG_PMB_MEMBASEADDRESS         0xFFFFFE00
 
 /* ConfigStatus */
 #define IPG_CS_RSVD_MASK                0xFFB0
@@ -196,20 +196,20 @@ enum ipg_regs {
 
 /* TFDList, TFC */
 #define        IPG_TFC_RSVD_MASK                       0x0000FFFF9FFFFFFF
-#define        IPG_TFC_FRAMEID                 0x000000000000FFFF
+#define        IPG_TFC_FRAMEID                         0x000000000000FFFF
 #define        IPG_TFC_WORDALIGN                       0x0000000000030000
 #define        IPG_TFC_WORDALIGNTODWORD                0x0000000000000000
-#define        IPG_TFC_WORDALIGNTOWORD         0x0000000000020000
+#define        IPG_TFC_WORDALIGNTOWORD                 0x0000000000020000
 #define        IPG_TFC_WORDALIGNDISABLED               0x0000000000030000
 #define        IPG_TFC_TCPCHECKSUMENABLE               0x0000000000040000
 #define        IPG_TFC_UDPCHECKSUMENABLE               0x0000000000080000
 #define        IPG_TFC_IPCHECKSUMENABLE                0x0000000000100000
 #define        IPG_TFC_FCSAPPENDDISABLE                0x0000000000200000
 #define        IPG_TFC_TXINDICATE                      0x0000000000400000
-#define        IPG_TFC_TXDMAINDICATE           0x0000000000800000
+#define        IPG_TFC_TXDMAINDICATE                   0x0000000000800000
 #define        IPG_TFC_FRAGCOUNT                       0x000000000F000000
-#define        IPG_TFC_VLANTAGINSERT           0x0000000010000000
-#define        IPG_TFC_TFDDONE                 0x0000000080000000
+#define        IPG_TFC_VLANTAGINSERT                   0x0000000010000000
+#define        IPG_TFC_TFDDONE                         0x0000000080000000
 #define        IPG_TFC_VID                             0x00000FFF00000000
 #define        IPG_TFC_CFI                             0x0000100000000000
 #define        IPG_TFC_USERPRIORITY                    0x0000E00000000000
@@ -217,35 +217,35 @@ enum ipg_regs {
 /* TFDList, FragInfo */
 #define        IPG_TFI_RSVD_MASK                       0xFFFF00FFFFFFFFFF
 #define        IPG_TFI_FRAGADDR                        0x000000FFFFFFFFFF
-#define        IPG_TFI_FRAGLEN                 0xFFFF000000000000LL
+#define        IPG_TFI_FRAGLEN                         0xFFFF000000000000LL
 
 /* RFD data structure masks. */
 
 /* RFDList, RFS */
 #define        IPG_RFS_RSVD_MASK                       0x0000FFFFFFFFFFFF
 #define        IPG_RFS_RXFRAMELEN                      0x000000000000FFFF
-#define        IPG_RFS_RXFIFOOVERRUN           0x0000000000010000
+#define        IPG_RFS_RXFIFOOVERRUN                   0x0000000000010000
 #define        IPG_RFS_RXRUNTFRAME                     0x0000000000020000
 #define        IPG_RFS_RXALIGNMENTERROR                0x0000000000040000
 #define        IPG_RFS_RXFCSERROR                      0x0000000000080000
 #define        IPG_RFS_RXOVERSIZEDFRAME                0x0000000000100000
-#define        IPG_RFS_RXLENGTHERROR           0x0000000000200000
+#define        IPG_RFS_RXLENGTHERROR                   0x0000000000200000
 #define        IPG_RFS_VLANDETECTED                    0x0000000000400000
 #define        IPG_RFS_TCPDETECTED                     0x0000000000800000
 #define        IPG_RFS_TCPERROR                        0x0000000001000000
 #define        IPG_RFS_UDPDETECTED                     0x0000000002000000
 #define        IPG_RFS_UDPERROR                        0x0000000004000000
 #define        IPG_RFS_IPDETECTED                      0x0000000008000000
-#define        IPG_RFS_IPERROR                 0x0000000010000000
+#define        IPG_RFS_IPERROR                         0x0000000010000000
 #define        IPG_RFS_FRAMESTART                      0x0000000020000000
 #define        IPG_RFS_FRAMEEND                        0x0000000040000000
-#define        IPG_RFS_RFDDONE                 0x0000000080000000
+#define        IPG_RFS_RFDDONE                         0x0000000080000000
 #define        IPG_RFS_TCI                             0x0000FFFF00000000
 
 /* RFDList, FragInfo */
 #define        IPG_RFI_RSVD_MASK                       0xFFFF00FFFFFFFFFF
 #define        IPG_RFI_FRAGADDR                        0x000000FFFFFFFFFF
-#define        IPG_RFI_FRAGLEN                 0xFFFF000000000000LL
+#define        IPG_RFI_FRAGLEN                         0xFFFF000000000000LL
 
 /* I/O Register masks. */
 
@@ -254,37 +254,37 @@ enum ipg_regs {
 
 /* Statistics Mask */
 #define        IPG_SM_ALL                                      0x0FFFFFFF
-#define        IPG_SM_OCTETRCVOK_FRAMESRCVDOK          0x00000001
-#define        IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002
-#define        IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004
+#define        IPG_SM_OCTETRCVOK_FRAMESRCVDOK                  0x00000001
+#define        IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK         0x00000002
+#define        IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK         0x00000004
 #define        IPG_SM_RXJUMBOFRAMES                            0x00000008
 #define        IPG_SM_TCPCHECKSUMERRORS                        0x00000010
-#define        IPG_SM_IPCHECKSUMERRORS                 0x00000020
+#define        IPG_SM_IPCHECKSUMERRORS                         0x00000020
 #define        IPG_SM_UDPCHECKSUMERRORS                        0x00000040
 #define        IPG_SM_MACCONTROLFRAMESRCVD                     0x00000080
 #define        IPG_SM_FRAMESTOOLONGERRORS                      0x00000100
 #define        IPG_SM_INRANGELENGTHERRORS                      0x00000200
 #define        IPG_SM_FRAMECHECKSEQERRORS                      0x00000400
 #define        IPG_SM_FRAMESLOSTRXERRORS                       0x00000800
-#define        IPG_SM_OCTETXMTOK_FRAMESXMTOK           0x00001000
-#define        IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK  0x00002000
-#define        IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK  0x00004000
+#define        IPG_SM_OCTETXMTOK_FRAMESXMTOK                   0x00001000
+#define        IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK          0x00002000
+#define        IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK          0x00004000
 #define        IPG_SM_FRAMESWDEFERREDXMT                       0x00008000
-#define        IPG_SM_LATECOLLISIONS                   0x00010000
-#define        IPG_SM_MULTICOLFRAMES                   0x00020000
-#define        IPG_SM_SINGLECOLFRAMES                  0x00040000
+#define        IPG_SM_LATECOLLISIONS                           0x00010000
+#define        IPG_SM_MULTICOLFRAMES                           0x00020000
+#define        IPG_SM_SINGLECOLFRAMES                          0x00040000
 #define        IPG_SM_TXJUMBOFRAMES                            0x00080000
 #define        IPG_SM_CARRIERSENSEERRORS                       0x00100000
 #define        IPG_SM_MACCONTROLFRAMESXMTD                     0x00200000
 #define        IPG_SM_FRAMESABORTXSCOLLS                       0x00400000
-#define        IPG_SM_FRAMESWEXDEFERAL                 0x00800000
+#define        IPG_SM_FRAMESWEXDEFERAL                         0x00800000
 
 /* Countdown */
 #define        IPG_CD_RSVD_MASK                0x0700FFFF
 #define        IPG_CD_COUNT                    0x0000FFFF
-#define        IPG_CD_COUNTDOWNSPEED   0x01000000
+#define        IPG_CD_COUNTDOWNSPEED           0x01000000
 #define        IPG_CD_COUNTDOWNMODE            0x02000000
-#define        IPG_CD_COUNTINTENABLED  0x04000000
+#define        IPG_CD_COUNTINTENABLED          0x04000000
 
 /* TxDMABurstThresh */
 #define IPG_TB_RSVD_MASK                0xFF
@@ -653,15 +653,28 @@ enum ipg_regs {
  * Miscellaneous macros.
  */
 
-/* Marco for printing debug statements. */
+/* Macros for printing debug statements. */
 #ifdef IPG_DEBUG
-#  define IPG_DEBUG_MSG(args...)
-#  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args)
+#  define IPG_DEBUG_MSG(fmt, args...)                  \
+do {                                                   \
+       if (0)                                          \
+               printk(KERN_DEBUG "IPG: " fmt, ##args); \
+} while (0)
+#  define IPG_DDEBUG_MSG(fmt, args...)                 \
+       printk(KERN_DEBUG "IPG: " fmt, ##args)
 #  define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
 #  define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
 #else
-#  define IPG_DEBUG_MSG(args...)
-#  define IPG_DDEBUG_MSG(args...)
+#  define IPG_DEBUG_MSG(fmt, args...)                  \
+do {                                                   \
+       if (0)                                          \
+               printk(KERN_DEBUG "IPG: " fmt, ##args); \
+} while (0)
+#  define IPG_DDEBUG_MSG(fmt, args...)                 \
+do {                                                   \
+       if (0)                                          \
+               printk(KERN_DEBUG "IPG: " fmt, ##args); \
+} while (0)
 #  define IPG_DUMPRFDLIST(args)
 #  define IPG_DUMPTFDLIST(args)
 #endif
index af10e97345ced34a19c86bc3d28b39e7fdb37fcb..25bb2a015e18e6a470ace112909010c29b5420c1 100644 (file)
@@ -397,5 +397,11 @@ config MCS_FIR
          To compile it as a module, choose M here: the module will be called
          mcs7780.
 
+config SH_IRDA
+       tristate "SuperH IrDA driver"
+       depends on IRDA && ARCH_SHMOBILE
+       help
+         Say Y here if your want to enable SuperH IrDA devices.
+
 endmenu
 
index e030d47e27932a44e0472238ab54016bea0b32d5..dfc64537f62f939f537fe012382d562978348c6c 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_VIA_FIR)         += via-ircc.o
 obj-$(CONFIG_PXA_FICP)         += pxaficp_ir.o
 obj-$(CONFIG_MCS_FIR)          += mcs7780.o
 obj-$(CONFIG_AU1000_FIR)       += au1k_ir.o
+obj-$(CONFIG_SH_IRDA)          += sh_irda.o
 # SIR drivers
 obj-$(CONFIG_IRTTY_SIR)                += irtty-sir.o  sir-dev.o
 obj-$(CONFIG_BFIN_SIR)         += bfin_sir.o
index 28992c815cba14282dc17a999ca32c8a6fd450c9..a3cb109006a5c24f0e1405ce73e8923b0daf3663 100644 (file)
@@ -753,18 +753,18 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self)
                        if(OldMessageCount > ((self->LineStatus+1) & 0x07))
                        {
                                self->rcvFramesOverflow = TRUE; 
-                               IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __func__);
+                               IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ********\n", __func__);
                        }
                                                
                        if (ali_ircc_dma_receive_complete(self))
                        {
-                               IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __func__);
+                               IRDA_DEBUG(1, "%s(), ******* receive complete ********\n", __func__);
                                
                                self->ier = IER_EOM;                            
                        }
                        else
                        {
-                               IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __func__);
+                               IRDA_DEBUG(1, "%s(), ******* Not receive complete ********\n", __func__);
                                
                                self->ier = IER_EOM | IER_TIMER;                                                                
                        }       
@@ -777,7 +777,7 @@ static irqreturn_t ali_ircc_fir_interrupt(struct ali_ircc_cb *self)
                if(OldMessageCount > ((self->LineStatus+1) & 0x07))
                {
                        self->rcvFramesOverflow = TRUE; 
-                       IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __func__);
+                       IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE *******\n", __func__);
                }
                /* Disable Timer */
                switch_bank(iobase, BANK1);
@@ -942,7 +942,7 @@ static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self)
                        // benjamin 2000/11/10 06:32PM
                        if (self->io.speed > 115200)
                        {
-                               IRDA_DEBUG(2, "%s(), ali_ircc_change_speed from UART_LSR_TEMT \n", __func__ );
+                               IRDA_DEBUG(2, "%s(), ali_ircc_change_speed from UART_LSR_TEMT\n", __func__ );
                                        
                                self->ier = IER_EOM;
                                // SetCOMInterrupts(self, TRUE);                                                        
@@ -970,7 +970,7 @@ static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
        
        IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __func__ );
        
-       IRDA_DEBUG(2, "%s(), setting speed = %d \n", __func__ , baud);
+       IRDA_DEBUG(2, "%s(), setting speed = %d\n", __func__ , baud);
        
        /* This function *must* be called with irq off and spin-lock.
         * - Jean II */
@@ -1500,7 +1500,7 @@ static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb,
                        diff = self->now.tv_usec - self->stamp.tv_usec;
                        /* self->stamp is set from ali_ircc_dma_receive_complete() */
                                                        
-                       IRDA_DEBUG(1, "%s(), ******* diff = %d ******* \n", __func__ , diff);
+                       IRDA_DEBUG(1, "%s(), ******* diff = %d *******\n", __func__ , diff);
                        
                        if (diff < 0) 
                                diff += 1000000;
@@ -1641,7 +1641,7 @@ static void ali_ircc_dma_xmit(struct ali_ircc_cb *self)
        tmp = inb(iobase+FIR_LCR_B);
        tmp &= ~0x20; // Disable SIP
        outb(((unsigned char)(tmp & 0x3f) | LCR_B_TX_MODE) & ~LCR_B_BW, iobase+FIR_LCR_B);
-       IRDA_DEBUG(1, "%s(), ******* Change to TX mode: FIR_LCR_B = 0x%x ******* \n", __func__ , inb(iobase+FIR_LCR_B));
+       IRDA_DEBUG(1, "%s(), *** Change to TX mode: FIR_LCR_B = 0x%x ***\n", __func__ , inb(iobase+FIR_LCR_B));
        
        outb(0, iobase+FIR_LSR);
                        
@@ -1768,7 +1768,7 @@ static int ali_ircc_dma_receive(struct ali_ircc_cb *self)
        //switch_bank(iobase, BANK0);
        tmp = inb(iobase+FIR_LCR_B);
        outb((unsigned char)(tmp &0x3f) | LCR_B_RX_MODE | LCR_B_BW , iobase + FIR_LCR_B); // 2000/12/1 05:16PM
-       IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x *** \n", __func__ , inb(iobase+FIR_LCR_B));
+       IRDA_DEBUG(1, "%s(), *** Change To RX mode: FIR_LCR_B = 0x%x ***\n", __func__ , inb(iobase+FIR_LCR_B));
                        
        /* Set Rx Threshold */
        switch_bank(iobase, BANK1);
@@ -1840,7 +1840,7 @@ static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
                /* Check for errors */
                if ((status & 0xd8) || self->rcvFramesOverflow || (len==0))             
                {
-                       IRDA_DEBUG(0,"%s(), ************* RX Errors ************ \n", __func__ );
+                       IRDA_DEBUG(0,"%s(), ************* RX Errors ************\n", __func__ );
                        
                        /* Skip frame */
                        self->netdev->stats.rx_errors++;
@@ -1850,29 +1850,29 @@ static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
                        if (status & LSR_FIFO_UR) 
                        {
                                self->netdev->stats.rx_frame_errors++;
-                               IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************ \n", __func__ );
+                               IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************\n", __func__ );
                        }       
                        if (status & LSR_FRAME_ERROR)
                        {
                                self->netdev->stats.rx_frame_errors++;
-                               IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************ \n", __func__ );
+                               IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************\n", __func__ );
                        }
                                                        
                        if (status & LSR_CRC_ERROR) 
                        {
                                self->netdev->stats.rx_crc_errors++;
-                               IRDA_DEBUG(0,"%s(), ************* CRC Errors ************ \n", __func__ );
+                               IRDA_DEBUG(0,"%s(), ************* CRC Errors ************\n", __func__ );
                        }
                        
                        if(self->rcvFramesOverflow)
                        {
                                self->netdev->stats.rx_frame_errors++;
-                               IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************ \n", __func__ );
+                               IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************\n", __func__ );
                        }
                        if(len == 0)
                        {
                                self->netdev->stats.rx_frame_errors++;
-                               IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 ********* \n", __func__ );
+                               IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 *********\n", __func__ );
                        }
                }        
                else 
@@ -1884,7 +1884,7 @@ static int  ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
                                val = inb(iobase+FIR_BSR);      
                                if ((val& BSR_FIFO_NOT_EMPTY)== 0x80) 
                                {
-                                       IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************ \n", __func__ );
+                                       IRDA_DEBUG(0, "%s(), ************* BSR_FIFO_NOT_EMPTY ************\n", __func__ );
                                        
                                        /* Put this entry back in fifo */
                                        st_fifo->head--;
index b5cbd39d068558b6ee5c7ac544e1350889427751..a3d696a9456a10a9d4f659cc70ad1982f2a7e58d 100644 (file)
@@ -546,7 +546,6 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
        aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
index b7e6625ca75e35a34b1f2907ed040de0eb0591ce..48bd5ec9f29b34edafeeda78d08fafba543376e5 100644 (file)
@@ -1002,8 +1002,6 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
 
   toshoboe_checkstuck (self);
 
-  dev->trans_start = jiffies;
-
  /* Check if we need to change the speed */
   /* But not now. Wait after transmission if mtt not required */
   speed=irda_get_next_speed(skb);
index 2c9b3af16612b9324d97202123fedaa16cede085..4441fa3389c265248ae45fa8f2adee625c30a7e1 100644 (file)
@@ -839,7 +839,7 @@ static void irda_usb_receive(struct urb *urb)
                        /* Usually precursor to a hot-unplug on OHCI. */
                default:
                        self->netdev->stats.rx_errors++;
-                       IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __func__, urb->status, urb->transfer_flags);
+                       IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X\n", __func__, urb->status, urb->transfer_flags);
                        break;
                }
                /* If we received an error, we don't want to resubmit the
index c0e0bb9401d3a1eb40ef19e907446af05074fa3b..5b1036ac38d7ba1a14a54394ad19f9f29b0397f4 100644 (file)
@@ -434,8 +434,6 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
 
        mcs->netdev->stats.rx_packets++;
        mcs->netdev->stats.rx_bytes += new_len;
-
-       return;
 }
 
 /* Unwrap received packets at FIR speed.  A 32 bit crc_ccitt checksum is
@@ -487,8 +485,6 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
 
        mcs->netdev->stats.rx_packets++;
        mcs->netdev->stats.rx_bytes += new_len;
-
-       return;
 }
 
 
index 1a54f6bb68c5066612af0125c358abcf9285ccdc..c192c31e4c5c3792a2113afac14b28ca8748c1c0 100644 (file)
@@ -556,7 +556,6 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        dev_kfree_skb(skb);
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
index 1dcdce0631aa9439815047628ed30547072f2dc3..da2705061a60fd2bac8c4ff60d2328995c46fb46 100644 (file)
@@ -715,8 +715,6 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
                Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_TXE;
        }
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
new file mode 100644 (file)
index 0000000..9a828b0
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ * SuperH IrDA Driver
+ *
+ * Copyright (C) 2010 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on sh_sir.c
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * 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.
+ */
+
+/*
+ * CAUTION
+ *
+ * This driver is very simple.
+ * So, it doesn't have below support now
+ *  - MIR/FIR support
+ *  - DMA transfer support
+ *  - FIFO mode support
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#define DRIVER_NAME "sh_irda"
+
+#if defined(CONFIG_ARCH_SH7367) || defined(CONFIG_ARCH_SH7377)
+#define __IRDARAM_LEN  0x13FF
+#else
+#define __IRDARAM_LEN  0x1039
+#endif
+
+#define IRTMR          0x1F00 /* Transfer mode */
+#define IRCFR          0x1F02 /* Configuration */
+#define IRCTR          0x1F04 /* IR control */
+#define IRTFLR         0x1F20 /* Transmit frame length */
+#define IRTCTR         0x1F22 /* Transmit control */
+#define IRRFLR         0x1F40 /* Receive frame length */
+#define IRRCTR         0x1F42 /* Receive control */
+#define SIRISR         0x1F60 /* SIR-UART mode interrupt source */
+#define SIRIMR         0x1F62 /* SIR-UART mode interrupt mask */
+#define SIRICR         0x1F64 /* SIR-UART mode interrupt clear */
+#define SIRBCR         0x1F68 /* SIR-UART mode baud rate count */
+#define MFIRISR                0x1F70 /* MIR/FIR mode interrupt source */
+#define MFIRIMR                0x1F72 /* MIR/FIR mode interrupt mask */
+#define MFIRICR                0x1F74 /* MIR/FIR mode interrupt clear */
+#define CRCCTR         0x1F80 /* CRC engine control */
+#define CRCIR          0x1F86 /* CRC engine input data */
+#define CRCCR          0x1F8A /* CRC engine calculation */
+#define CRCOR          0x1F8E /* CRC engine output data */
+#define FIFOCP         0x1FC0 /* FIFO current pointer */
+#define FIFOFP         0x1FC2 /* FIFO follow pointer */
+#define FIFORSMSK      0x1FC4 /* FIFO receive status mask */
+#define FIFORSOR       0x1FC6 /* FIFO receive status OR */
+#define FIFOSEL                0x1FC8 /* FIFO select */
+#define FIFORS         0x1FCA /* FIFO receive status */
+#define FIFORFL                0x1FCC /* FIFO receive frame length */
+#define FIFORAMCP      0x1FCE /* FIFO RAM current pointer */
+#define FIFORAMFP      0x1FD0 /* FIFO RAM follow pointer */
+#define BIFCTL         0x1FD2 /* BUS interface control */
+#define IRDARAM                0x0000 /* IrDA buffer RAM */
+#define IRDARAM_LEN    __IRDARAM_LEN /* - 8/16/32 (read-only for 32) */
+
+/* IRTMR */
+#define TMD_MASK       (0x3 << 14) /* Transfer Mode */
+#define TMD_SIR                (0x0 << 14)
+#define TMD_MIR                (0x3 << 14)
+#define TMD_FIR                (0x2 << 14)
+
+#define FIFORIM                (1 << 8) /* FIFO receive interrupt mask */
+#define MIM            (1 << 4) /* MIR/FIR Interrupt Mask */
+#define SIM            (1 << 0) /* SIR Interrupt Mask */
+#define xIM_MASK       (FIFORIM | MIM | SIM)
+
+/* IRCFR */
+#define RTO_SHIFT      8 /* shift for Receive Timeout */
+#define RTO            (0x3 << RTO_SHIFT)
+
+/* IRTCTR */
+#define ARMOD          (1 << 15) /* Auto-Receive Mode */
+#define TE             (1 <<  0) /* Transmit Enable */
+
+/* IRRFLR */
+#define RFL_MASK       (0x1FFF) /* mask for Receive Frame Length */
+
+/* IRRCTR */
+#define RE             (1 <<  0) /* Receive Enable */
+
+/*
+ * SIRISR,  SIRIMR,  SIRICR,
+ * MFIRISR, MFIRIMR, MFIRICR
+ */
+#define FRE            (1 << 15) /* Frame Receive End */
+#define TROV           (1 << 11) /* Transfer Area Overflow */
+#define xIR_9          (1 << 9)
+#define TOT            xIR_9     /* for SIR     Timeout */
+#define ABTD           xIR_9     /* for MIR/FIR Abort Detection */
+#define xIR_8          (1 << 8)
+#define FER            xIR_8     /* for SIR     Framing Error */
+#define CRCER          xIR_8     /* for MIR/FIR CRC error */
+#define FTE            (1 << 7)  /* Frame Transmit End */
+#define xIR_MASK       (FRE | TROV | xIR_9 | xIR_8 | FTE)
+
+/* SIRBCR */
+#define BRC_MASK       (0x3F) /* mask for Baud Rate Count */
+
+/* CRCCTR */
+#define CRC_RST                (1 << 15) /* CRC Engine Reset */
+#define CRC_CT_MASK    0x0FFF    /* mask for CRC Engine Input Data Count */
+
+/* CRCIR */
+#define CRC_IN_MASK    0x0FFF    /* mask for CRC Engine Input Data */
+
+/************************************************************************
+
+
+                       enum / structure
+
+
+************************************************************************/
+enum sh_irda_mode {
+       SH_IRDA_NONE = 0,
+       SH_IRDA_SIR,
+       SH_IRDA_MIR,
+       SH_IRDA_FIR,
+};
+
+struct sh_irda_self;
+struct sh_irda_xir_func {
+       int (*xir_fre)  (struct sh_irda_self *self);
+       int (*xir_trov) (struct sh_irda_self *self);
+       int (*xir_9)    (struct sh_irda_self *self);
+       int (*xir_8)    (struct sh_irda_self *self);
+       int (*xir_fte)  (struct sh_irda_self *self);
+};
+
+struct sh_irda_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;
+
+       enum sh_irda_mode       mode;
+       spinlock_t              lock;
+
+       struct sh_irda_xir_func *xir_func;
+};
+
+/************************************************************************
+
+
+                       common function
+
+
+************************************************************************/
+static void sh_irda_write(struct sh_irda_self *self, u32 offset, u16 data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&self->lock, flags);
+       iowrite16(data, self->membase + offset);
+       spin_unlock_irqrestore(&self->lock, flags);
+}
+
+static u16 sh_irda_read(struct sh_irda_self *self, u32 offset)
+{
+       unsigned long flags;
+       u16 ret;
+
+       spin_lock_irqsave(&self->lock, flags);
+       ret = ioread16(self->membase + offset);
+       spin_unlock_irqrestore(&self->lock, flags);
+
+       return ret;
+}
+
+static void sh_irda_update_bits(struct sh_irda_self *self, u32 offset,
+                              u16 mask, u16 data)
+{
+       unsigned long flags;
+       u16 old, new;
+
+       spin_lock_irqsave(&self->lock, flags);
+       old = ioread16(self->membase + offset);
+       new = (old & ~mask) | data;
+       if (old != new)
+               iowrite16(data, self->membase + offset);
+       spin_unlock_irqrestore(&self->lock, flags);
+}
+
+/************************************************************************
+
+
+                       mode function
+
+
+************************************************************************/
+/*=====================================
+ *
+ *             common
+ *
+ *=====================================*/
+static void sh_irda_rcv_ctrl(struct sh_irda_self *self, int enable)
+{
+       struct device *dev = &self->ndev->dev;
+
+       sh_irda_update_bits(self, IRRCTR, RE, enable ? RE : 0);
+       dev_dbg(dev, "recv %s\n", enable ? "enable" : "disable");
+}
+
+static int sh_irda_set_timeout(struct sh_irda_self *self, int interval)
+{
+       struct device *dev = &self->ndev->dev;
+
+       if (SH_IRDA_SIR != self->mode)
+               interval = 0;
+
+       if (interval < 0 || interval > 2) {
+               dev_err(dev, "unsupported timeout interval\n");
+               return -EINVAL;
+       }
+
+       sh_irda_update_bits(self, IRCFR, RTO, interval << RTO_SHIFT);
+       return 0;
+}
+
+static int sh_irda_set_baudrate(struct sh_irda_self *self, int baudrate)
+{
+       struct device *dev = &self->ndev->dev;
+       u16 val;
+
+       if (baudrate < 0)
+               return 0;
+
+       if (SH_IRDA_SIR != self->mode) {
+               dev_err(dev, "it is not SIR mode\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Baud rate (bits/s) =
+        *   (48 MHz / 26) / (baud rate counter value + 1) x 16
+        */
+       val = (48000000 / 26 / 16 / baudrate) - 1;
+       dev_dbg(dev, "baudrate = %d,  val = 0x%02x\n", baudrate, val);
+
+       sh_irda_update_bits(self, SIRBCR, BRC_MASK, val);
+
+       return 0;
+}
+
+static int xir_get_rcv_length(struct sh_irda_self *self)
+{
+       return RFL_MASK & sh_irda_read(self, IRRFLR);
+}
+
+/*=====================================
+ *
+ *             NONE MODE
+ *
+ *=====================================*/
+static int xir_fre(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       dev_err(dev, "none mode: frame recv\n");
+       return 0;
+}
+
+static int xir_trov(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       dev_err(dev, "none mode: buffer ram over\n");
+       return 0;
+}
+
+static int xir_9(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       dev_err(dev, "none mode: time over\n");
+       return 0;
+}
+
+static int xir_8(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       dev_err(dev, "none mode: framing error\n");
+       return 0;
+}
+
+static int xir_fte(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       dev_err(dev, "none mode: frame transmit end\n");
+       return 0;
+}
+
+static struct sh_irda_xir_func xir_func = {
+       .xir_fre        = xir_fre,
+       .xir_trov       = xir_trov,
+       .xir_9          = xir_9,
+       .xir_8          = xir_8,
+       .xir_fte        = xir_fte,
+};
+
+/*=====================================
+ *
+ *             MIR/FIR MODE
+ *
+ * MIR/FIR are not supported now
+ *=====================================*/
+static struct sh_irda_xir_func mfir_func = {
+       .xir_fre        = xir_fre,
+       .xir_trov       = xir_trov,
+       .xir_9          = xir_9,
+       .xir_8          = xir_8,
+       .xir_fte        = xir_fte,
+};
+
+/*=====================================
+ *
+ *             SIR MODE
+ *
+ *=====================================*/
+static int sir_fre(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       u16 data16;
+       u8  *data = (u8 *)&data16;
+       int len = xir_get_rcv_length(self);
+       int i, j;
+
+       if (len > IRDARAM_LEN)
+               len = IRDARAM_LEN;
+
+       dev_dbg(dev, "frame recv length = %d\n", len);
+
+       for (i = 0; i < len; i++) {
+               j = i % 2;
+               if (!j)
+                       data16 = sh_irda_read(self, IRDARAM + i);
+
+               async_unwrap_char(self->ndev, &self->ndev->stats,
+                                 &self->rx_buff, data[j]);
+       }
+       self->ndev->last_rx = jiffies;
+
+       sh_irda_rcv_ctrl(self, 1);
+
+       return 0;
+}
+
+static int sir_trov(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+
+       dev_err(dev, "buffer ram over\n");
+       sh_irda_rcv_ctrl(self, 1);
+       return 0;
+}
+
+static int sir_tot(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+
+       dev_err(dev, "time over\n");
+       sh_irda_set_baudrate(self, 9600);
+       sh_irda_rcv_ctrl(self, 1);
+       return 0;
+}
+
+static int sir_fer(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+
+       dev_err(dev, "framing error\n");
+       sh_irda_rcv_ctrl(self, 1);
+       return 0;
+}
+
+static int sir_fte(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+
+       dev_dbg(dev, "frame transmit end\n");
+       netif_wake_queue(self->ndev);
+
+       return 0;
+}
+
+static struct sh_irda_xir_func sir_func = {
+       .xir_fre        = sir_fre,
+       .xir_trov       = sir_trov,
+       .xir_9          = sir_tot,
+       .xir_8          = sir_fer,
+       .xir_fte        = sir_fte,
+};
+
+static void sh_irda_set_mode(struct sh_irda_self *self, enum sh_irda_mode mode)
+{
+       struct device *dev = &self->ndev->dev;
+       struct sh_irda_xir_func *func;
+       const char *name;
+       u16 data;
+
+       switch (mode) {
+       case SH_IRDA_SIR:
+               name    = "SIR";
+               data    = TMD_SIR;
+               func    = &sir_func;
+               break;
+       case SH_IRDA_MIR:
+               name    = "MIR";
+               data    = TMD_MIR;
+               func    = &mfir_func;
+               break;
+       case SH_IRDA_FIR:
+               name    = "FIR";
+               data    = TMD_FIR;
+               func    = &mfir_func;
+               break;
+       default:
+               name = "NONE";
+               data = 0;
+               func = &xir_func;
+               break;
+       }
+
+       self->mode = mode;
+       self->xir_func = func;
+       sh_irda_update_bits(self, IRTMR, TMD_MASK, data);
+
+       dev_dbg(dev, "switch to %s mode", name);
+}
+
+/************************************************************************
+
+
+                       irq function
+
+
+************************************************************************/
+static void sh_irda_set_irq_mask(struct sh_irda_self *self)
+{
+       u16 tmr_hole;
+       u16 xir_reg;
+
+       /* set all mask */
+       sh_irda_update_bits(self, IRTMR,   xIM_MASK, xIM_MASK);
+       sh_irda_update_bits(self, SIRIMR,  xIR_MASK, xIR_MASK);
+       sh_irda_update_bits(self, MFIRIMR, xIR_MASK, xIR_MASK);
+
+       /* clear irq */
+       sh_irda_update_bits(self, SIRICR,  xIR_MASK, xIR_MASK);
+       sh_irda_update_bits(self, MFIRICR, xIR_MASK, xIR_MASK);
+
+       switch (self->mode) {
+       case SH_IRDA_SIR:
+               tmr_hole        = SIM;
+               xir_reg         = SIRIMR;
+               break;
+       case SH_IRDA_MIR:
+       case SH_IRDA_FIR:
+               tmr_hole        = MIM;
+               xir_reg         = MFIRIMR;
+               break;
+       default:
+               tmr_hole        = 0;
+               xir_reg         = 0;
+               break;
+       }
+
+       /* open mask */
+       if (xir_reg) {
+               sh_irda_update_bits(self, IRTMR, tmr_hole, 0);
+               sh_irda_update_bits(self, xir_reg, xIR_MASK, 0);
+       }
+}
+
+static irqreturn_t sh_irda_irq(int irq, void *dev_id)
+{
+       struct sh_irda_self *self = dev_id;
+       struct sh_irda_xir_func *func = self->xir_func;
+       u16 isr = sh_irda_read(self, SIRISR);
+
+       /* clear irq */
+       sh_irda_write(self, SIRICR, isr);
+
+       if (isr & FRE)
+               func->xir_fre(self);
+       if (isr & TROV)
+               func->xir_trov(self);
+       if (isr & xIR_9)
+               func->xir_9(self);
+       if (isr & xIR_8)
+               func->xir_8(self);
+       if (isr & FTE)
+               func->xir_fte(self);
+
+       return IRQ_HANDLED;
+}
+
+/************************************************************************
+
+
+                       CRC function
+
+
+************************************************************************/
+static void sh_irda_crc_reset(struct sh_irda_self *self)
+{
+       sh_irda_write(self, CRCCTR, CRC_RST);
+}
+
+static void sh_irda_crc_add(struct sh_irda_self *self, u16 data)
+{
+       sh_irda_write(self, CRCIR, data & CRC_IN_MASK);
+}
+
+static u16 sh_irda_crc_cnt(struct sh_irda_self *self)
+{
+       return CRC_CT_MASK & sh_irda_read(self, CRCCTR);
+}
+
+static u16 sh_irda_crc_out(struct sh_irda_self *self)
+{
+       return sh_irda_read(self, CRCOR);
+}
+
+static int sh_irda_crc_init(struct sh_irda_self *self)
+{
+       struct device *dev = &self->ndev->dev;
+       int ret = -EIO;
+       u16 val;
+
+       sh_irda_crc_reset(self);
+
+       sh_irda_crc_add(self, 0xCC);
+       sh_irda_crc_add(self, 0xF5);
+       sh_irda_crc_add(self, 0xF1);
+       sh_irda_crc_add(self, 0xA7);
+
+       val = sh_irda_crc_cnt(self);
+       if (4 != val) {
+               dev_err(dev, "CRC count error %x\n", val);
+               goto crc_init_out;
+       }
+
+       val = sh_irda_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_irda_crc_reset(self);
+       return ret;
+}
+
+/************************************************************************
+
+
+                       iobuf function
+
+
+************************************************************************/
+static void sh_irda_remove_iobuf(struct sh_irda_self *self)
+{
+       kfree(self->rx_buff.head);
+
+       self->tx_buff.head = NULL;
+       self->tx_buff.data = NULL;
+       self->rx_buff.head = NULL;
+       self->rx_buff.data = NULL;
+}
+
+static int sh_irda_init_iobuf(struct sh_irda_self *self, int rxsize, int txsize)
+{
+       if (self->rx_buff.head ||
+           self->tx_buff.head) {
+               dev_err(&self->ndev->dev, "iobuff has already existed.");
+               return -EINVAL;
+       }
+
+       /* rx_buff */
+       self->rx_buff.head = kmalloc(rxsize, GFP_KERNEL);
+       if (!self->rx_buff.head)
+               return -ENOMEM;
+
+       self->rx_buff.truesize  = rxsize;
+       self->rx_buff.in_frame  = FALSE;
+       self->rx_buff.state     = OUTSIDE_FRAME;
+       self->rx_buff.data      = self->rx_buff.head;
+
+       /* tx_buff */
+       self->tx_buff.head      = self->membase + IRDARAM;
+       self->tx_buff.truesize  = IRDARAM_LEN;
+
+       return 0;
+}
+
+/************************************************************************
+
+
+                       net_device_ops function
+
+
+************************************************************************/
+static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+       struct sh_irda_self *self = netdev_priv(ndev);
+       struct device *dev = &self->ndev->dev;
+       int speed = irda_get_next_speed(skb);
+       int ret;
+
+       dev_dbg(dev, "hard xmit\n");
+
+       netif_stop_queue(ndev);
+       sh_irda_rcv_ctrl(self, 0);
+
+       ret = sh_irda_set_baudrate(self, speed);
+       if (ret < 0)
+               return ret;
+
+       self->tx_buff.len = 0;
+       if (skb->len) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&self->lock, flags);
+               self->tx_buff.len = async_wrap_skb(skb,
+                                                  self->tx_buff.head,
+                                                  self->tx_buff.truesize);
+               spin_unlock_irqrestore(&self->lock, flags);
+
+               if (self->tx_buff.len > self->tx_buff.truesize)
+                       self->tx_buff.len = self->tx_buff.truesize;
+
+               sh_irda_write(self, IRTFLR, self->tx_buff.len);
+               sh_irda_write(self, IRTCTR, ARMOD | TE);
+       }
+
+       dev_kfree_skb(skb);
+
+       return 0;
+}
+
+static int sh_irda_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_irda_stats(struct net_device *ndev)
+{
+       struct sh_irda_self *self = netdev_priv(ndev);
+
+       return &self->ndev->stats;
+}
+
+static int sh_irda_open(struct net_device *ndev)
+{
+       struct sh_irda_self *self = netdev_priv(ndev);
+       int err;
+
+       clk_enable(self->clk);
+       err = sh_irda_crc_init(self);
+       if (err)
+               goto open_err;
+
+       sh_irda_set_mode(self, SH_IRDA_SIR);
+       sh_irda_set_timeout(self, 2);
+       sh_irda_set_baudrate(self, 9600);
+
+       self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
+       if (!self->irlap) {
+               err = -ENODEV;
+               goto open_err;
+       }
+
+       netif_start_queue(ndev);
+       sh_irda_rcv_ctrl(self, 1);
+       sh_irda_set_irq_mask(self);
+
+       dev_info(&ndev->dev, "opened\n");
+
+       return 0;
+
+open_err:
+       clk_disable(self->clk);
+
+       return err;
+}
+
+static int sh_irda_stop(struct net_device *ndev)
+{
+       struct sh_irda_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_irda_ndo = {
+       .ndo_open               = sh_irda_open,
+       .ndo_stop               = sh_irda_stop,
+       .ndo_start_xmit         = sh_irda_hard_xmit,
+       .ndo_do_ioctl           = sh_irda_ioctl,
+       .ndo_get_stats          = sh_irda_stats,
+};
+
+/************************************************************************
+
+
+                       platform_driver function
+
+
+************************************************************************/
+static int __devinit sh_irda_probe(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+       struct sh_irda_self *self;
+       struct resource *res;
+       char clk_name[8];
+       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;
+
+       self = netdev_priv(ndev);
+       self->membase = ioremap_nocache(res->start, resource_size(res));
+       if (!self->membase) {
+               err = -ENXIO;
+               dev_err(&pdev->dev, "Unable to ioremap.\n");
+               goto err_mem_1;
+       }
+
+       err = sh_irda_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_irda_ndo;
+       ndev->irq               = irq;
+
+       self->ndev                      = ndev;
+       self->qos.baud_rate.bits        &= IR_9600; /* FIXME */
+       self->qos.min_turn_time.bits    = 1; /* 10 ms or more */
+       spin_lock_init(&self->lock);
+
+       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_irda_irq, IRQF_DISABLED, "sh_irda", self)) {
+               dev_warn(&pdev->dev, "Unable to attach sh_irda 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_irda_remove_iobuf(self);
+err_mem_2:
+       iounmap(self->membase);
+err_mem_1:
+       free_netdev(ndev);
+exit:
+       return err;
+}
+
+static int __devexit sh_irda_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct sh_irda_self *self = netdev_priv(ndev);
+
+       if (!self)
+               return 0;
+
+       unregister_netdev(ndev);
+       clk_put(self->clk);
+       sh_irda_remove_iobuf(self);
+       iounmap(self->membase);
+       free_netdev(ndev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver sh_irda_driver = {
+       .probe   = sh_irda_probe,
+       .remove  = __devexit_p(sh_irda_remove),
+       .driver  = {
+               .name = DRIVER_NAME,
+       },
+};
+
+static int __init sh_irda_init(void)
+{
+       return platform_driver_register(&sh_irda_driver);
+}
+
+static void __exit sh_irda_exit(void)
+{
+       platform_driver_unregister(&sh_irda_driver);
+}
+
+module_init(sh_irda_init);
+module_exit(sh_irda_exit);
+
+MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
+MODULE_DESCRIPTION("SuperH IrDA driver");
+MODULE_LICENSE("GPL");
index 0745581c4b5ec873d7ba06e9e817f93d7dd0e16d..5c5f99d50341d5e981225d14fa3951fd59a3b596 100644 (file)
@@ -646,8 +646,10 @@ static int sh_sir_open(struct net_device *ndev)
        sh_sir_set_baudrate(self, 9600);
 
        self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME);
-       if (!self->irlap)
+       if (!self->irlap) {
+               err = -ENODEV;
                goto open_err;
+       }
 
        /*
         * Now enable the interrupt then start the queue
@@ -707,7 +709,6 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
        struct sh_sir_self *self;
        struct resource *res;
        char clk_name[8];
-       void __iomem *base;
        unsigned int irq;
        int err = -ENOMEM;
 
@@ -722,14 +723,14 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
        if (!ndev)
                goto exit;
 
-       base = ioremap_nocache(res->start, resource_size(res));
-       if (!base) {
+       self = netdev_priv(ndev);
+       self->membase = ioremap_nocache(res->start, resource_size(res));
+       if (!self->membase) {
                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;
@@ -746,7 +747,6 @@ static int __devinit sh_sir_probe(struct platform_device *pdev)
        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 */
index de91cd14016be75de37513939d018d8b35df806e..1b051dab7b298a761a5d9e4f2ff38af16f062238 100644 (file)
@@ -655,7 +655,6 @@ static netdev_tx_t sirdev_hard_xmit(struct sk_buff *skb,
 
        if (likely(actual > 0)) {
                dev->tx_skb = skb;
-               ndev->trans_start = jiffies;
                dev->tx_buff.data += actual;
                dev->tx_buff.len -= actual;
        }
index 6af84d88cd03c960237927ee71752a06c087de60..d67e48418e55c3a5fa085231c7fe462e491703d7 100644 (file)
@@ -868,7 +868,7 @@ static void smsc_ircc_timeout(struct net_device *dev)
        spin_lock_irqsave(&self->lock, flags);
        smsc_ircc_sir_start(self);
        smsc_ircc_change_speed(self, self->io.speed);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
        spin_unlock_irqrestore(&self->lock, flags);
 }
@@ -2822,7 +2822,6 @@ static void __init preconfigure_ali_port(struct pci_dev *dev,
        tmpbyte |= mask;
        pci_write_config_byte(dev, reg, tmpbyte);
        IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port);
-       return;
 }
 
 static int __init preconfigure_through_ali(struct pci_dev *dev,
index d9d1db03fa2d97638824ddf35e792350b484e326..5a84822b5a43ed0dcefc9622723753490d961733 100644 (file)
@@ -774,7 +774,7 @@ static void SetBaudRate(__u16 iobase, __u32 rate)
                        break;
                default:
                        break;
-               };
+               }
        } else if (IsMIROn(iobase)) {
                value = 0;      // will automatically be fixed in 1.152M
        } else if (IsFIROn(iobase)) {
index 209d4bcfaced6d7e4288c3d5d90927b4493d7e1d..c3d07382b7fa48c84846be41a7c30c0596af2b90 100644 (file)
@@ -1037,7 +1037,6 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb,
                wmb();
                outw(0, iobase+VLSI_PIO_PROMPT);
        }
-       ndev->trans_start = jiffies;
 
        if (ring_put(r) == NULL) {
                netif_stop_queue(ndev);
@@ -1742,7 +1741,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
        vlsi_irda_dev_t *idev;
 
        if (!ndev) {
-               IRDA_ERROR("%s - %s: no netdevice \n",
+               IRDA_ERROR("%s - %s: no netdevice\n",
                           __func__, pci_name(pdev));
                return 0;
        }
@@ -1781,7 +1780,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
        vlsi_irda_dev_t *idev;
 
        if (!ndev) {
-               IRDA_ERROR("%s - %s: no netdevice \n",
+               IRDA_ERROR("%s - %s: no netdevice\n",
                           __func__, pci_name(pdev));
                return 0;
        }
index cb0cb758be64a23e5eae893b296bc2d642451975..1f9c3f08d1a3c0f35f6318daa2d5c992fc9025b3 100644 (file)
@@ -515,7 +515,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
                /* Check for empty frame */
                if (!skb->len) {
                        w83977af_change_speed(self, speed); 
-                       dev->trans_start = jiffies;
                        dev_kfree_skb(skb);
                        return NETDEV_TX_OK;
                } else
@@ -549,7 +548,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb,
                switch_bank(iobase, SET0);
                outb(ICR_ETXTHI, iobase+ICR);
        }
-       dev->trans_start = jiffies;
        dev_kfree_skb(skb);
 
        /* Restore set register */
index 773c59c8969162fac202202b854e6e77a6c43a67..ba1de5973fb2083fe669027d551ea98d427bf350 100644 (file)
@@ -962,15 +962,15 @@ static void veth_set_multicast_list(struct net_device *dev)
                        (netdev_mc_count(dev) > VETH_MAX_MCAST)) {
                port->promiscuous = 1;
        } else {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
 
                port->promiscuous = 0;
 
                /* Update table */
                port->num_mcast = 0;
 
-               netdev_for_each_mc_addr(dmi, dev) {
-                       u8 *addr = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       u8 *addr = ha->addr;
                        u64 xaddr = 0;
 
                        if (addr[0] & 0x01) {/* multicast address? */
index 92d2e71d0c8b7e96843cc959ffcb965d53c7374f..521c0c732998e94b61e0176b5cd6c5abd9bf9518 100644 (file)
@@ -78,9 +78,13 @@ struct ixgb_adapter;
 #define PFX "ixgb: "
 
 #ifdef _DEBUG_DRIVER_
-#define IXGB_DBG(args...) printk(KERN_DEBUG PFX args)
+#define IXGB_DBG(fmt, args...) printk(KERN_DEBUG PFX fmt, ##args)
 #else
-#define IXGB_DBG(args...)
+#define IXGB_DBG(fmt, args...)                         \
+do {                                                   \
+       if (0)                                          \
+               printk(KERN_DEBUG PFX fmt, ##args);     \
+} while (0)
 #endif
 
 /* TX/RX descriptor defines */
index 89ffa7264a12aac3682d26a4e80b55982654f77f..813993f9c65c920f338c6b46cfab8d62ecd2ef6b 100644 (file)
@@ -26,6 +26,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "ixgb_hw.h"
 #include "ixgb_ee.h"
 /* Local prototypes */
@@ -56,7 +58,6 @@ ixgb_raise_clock(struct ixgb_hw *hw,
        *eecd_reg = *eecd_reg | IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, *eecd_reg);
        udelay(50);
-       return;
 }
 
 /******************************************************************************
@@ -75,7 +76,6 @@ ixgb_lower_clock(struct ixgb_hw *hw,
        *eecd_reg = *eecd_reg & ~IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, *eecd_reg);
        udelay(50);
-       return;
 }
 
 /******************************************************************************
@@ -125,7 +125,6 @@ ixgb_shift_out_bits(struct ixgb_hw *hw,
        /* We leave the "DI" bit set to "0" when we leave this routine. */
        eecd_reg &= ~IXGB_EECD_DI;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
-       return;
 }
 
 /******************************************************************************
@@ -190,7 +189,6 @@ ixgb_setup_eeprom(struct ixgb_hw *hw)
        /*  Set CS  */
        eecd_reg |= IXGB_EECD_CS;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
-       return;
 }
 
 /******************************************************************************
@@ -224,7 +222,6 @@ ixgb_standby_eeprom(struct ixgb_hw *hw)
        eecd_reg &= ~IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
        udelay(50);
-       return;
 }
 
 /******************************************************************************
@@ -248,7 +245,6 @@ ixgb_clock_eeprom(struct ixgb_hw *hw)
        eecd_reg &= ~IXGB_EECD_SK;
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
        udelay(50);
-       return;
 }
 
 /******************************************************************************
@@ -268,7 +264,6 @@ ixgb_cleanup_eeprom(struct ixgb_hw *hw)
        IXGB_WRITE_REG(hw, EECD, eecd_reg);
 
        ixgb_clock_eeprom(hw);
-       return;
 }
 
 /******************************************************************************
@@ -357,7 +352,6 @@ ixgb_update_eeprom_checksum(struct ixgb_hw *hw)
        checksum = (u16) EEPROM_SUM - checksum;
 
        ixgb_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum);
-       return;
 }
 
 /******************************************************************************
@@ -412,8 +406,6 @@ ixgb_write_eeprom(struct ixgb_hw *hw, u16 offset, u16 data)
 
        /* clear the init_ctrl_reg_1 to signify that the cache is invalidated */
        ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
-
-       return;
 }
 
 /******************************************************************************
@@ -467,11 +459,11 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
        u16 checksum = 0;
        struct ixgb_ee_map_type *ee_map;
 
-       DEBUGFUNC("ixgb_get_eeprom_data");
+       ENTER();
 
        ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
-       DEBUGOUT("ixgb_ee: Reading eeprom data\n");
+       pr_debug("Reading eeprom data\n");
        for (i = 0; i < IXGB_EEPROM_SIZE ; i++) {
                u16 ee_data;
                ee_data = ixgb_read_eeprom(hw, i);
@@ -480,7 +472,7 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
        }
 
        if (checksum != (u16) EEPROM_SUM) {
-               DEBUGOUT("ixgb_ee: Checksum invalid.\n");
+               pr_debug("Checksum invalid\n");
                /* clear the init_ctrl_reg_1 to signify that the cache is
                 * invalidated */
                ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
@@ -489,7 +481,7 @@ ixgb_get_eeprom_data(struct ixgb_hw *hw)
 
        if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
                 != cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
-               DEBUGOUT("ixgb_ee: Signature invalid.\n");
+               pr_debug("Signature invalid\n");
                return(false);
        }
 
@@ -555,13 +547,13 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw,
        int i;
        struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
-       DEBUGFUNC("ixgb_get_ee_mac_addr");
+       ENTER();
 
        if (ixgb_check_and_get_eeprom_data(hw) == true) {
                for (i = 0; i < IXGB_ETH_LENGTH_OF_ADDRESS; i++) {
                        mac_addr[i] = ee_map->mac_addr[i];
-                       DEBUGOUT2("mac(%d) = %.2X\n", i, mac_addr[i]);
                }
+               pr_debug("eeprom mac address = %pM\n", mac_addr);
        }
 }
 
index ff67a84e68026daf7d72aa36faf3cb68dcd1508c..397acabccab6c2a43ad8e18cc6f8775d1f0a6429 100644 (file)
  * Shared functions for accessing and configuring the adapter
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "ixgb_hw.h"
 #include "ixgb_ids.h"
 
+#include <linux/etherdevice.h>
+
 /*  Local function prototypes */
 
 static u32 ixgb_hash_mc_addr(struct ixgb_hw *hw, u8 * mc_addr);
@@ -120,13 +124,13 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
        u32 ctrl_reg;
        u32 icr_reg;
 
-       DEBUGFUNC("ixgb_adapter_stop");
+       ENTER();
 
        /* If we are stopped or resetting exit gracefully and wait to be
         * started again before accessing the hardware.
         */
        if (hw->adapter_stopped) {
-               DEBUGOUT("Exiting because the adapter is already stopped!!!\n");
+               pr_debug("Exiting because the adapter is already stopped!!!\n");
                return false;
        }
 
@@ -136,7 +140,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
        hw->adapter_stopped = true;
 
        /* Clear interrupt mask to stop board from generating interrupts */
-       DEBUGOUT("Masking off all interrupts\n");
+       pr_debug("Masking off all interrupts\n");
        IXGB_WRITE_REG(hw, IMC, 0xFFFFFFFF);
 
        /* Disable the Transmit and Receive units.  Then delay to allow
@@ -152,12 +156,12 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
         * the current PCI configuration.  The global reset bit is self-
         * clearing, and should clear within a microsecond.
         */
-       DEBUGOUT("Issuing a global reset to MAC\n");
+       pr_debug("Issuing a global reset to MAC\n");
 
        ctrl_reg = ixgb_mac_reset(hw);
 
        /* Clear interrupt mask to stop board from generating interrupts */
-       DEBUGOUT("Masking off all interrupts\n");
+       pr_debug("Masking off all interrupts\n");
        IXGB_WRITE_REG(hw, IMC, 0xffffffff);
 
        /* Clear any pending interrupt events. */
@@ -183,7 +187,7 @@ ixgb_identify_xpak_vendor(struct ixgb_hw *hw)
        u16 vendor_name[5];
        ixgb_xpak_vendor xpak_vendor;
 
-       DEBUGFUNC("ixgb_identify_xpak_vendor");
+       ENTER();
 
        /* Read the first few bytes of the vendor string from the XPAK NVR
         * registers.  These are standard XENPAK/XPAK registers, so all XPAK
@@ -222,12 +226,12 @@ ixgb_identify_phy(struct ixgb_hw *hw)
        ixgb_phy_type phy_type;
        ixgb_xpak_vendor xpak_vendor;
 
-       DEBUGFUNC("ixgb_identify_phy");
+       ENTER();
 
        /* Infer the transceiver/phy type from the device id */
        switch (hw->device_id) {
        case IXGB_DEVICE_ID_82597EX:
-               DEBUGOUT("Identified TXN17401 optics\n");
+               pr_debug("Identified TXN17401 optics\n");
                phy_type = ixgb_phy_type_txn17401;
                break;
 
@@ -237,30 +241,30 @@ ixgb_identify_phy(struct ixgb_hw *hw)
                 * type of optics. */
                xpak_vendor = ixgb_identify_xpak_vendor(hw);
                if (xpak_vendor == ixgb_xpak_vendor_intel) {
-                       DEBUGOUT("Identified TXN17201 optics\n");
+                       pr_debug("Identified TXN17201 optics\n");
                        phy_type = ixgb_phy_type_txn17201;
                } else {
-                       DEBUGOUT("Identified G6005 optics\n");
+                       pr_debug("Identified G6005 optics\n");
                        phy_type = ixgb_phy_type_g6005;
                }
                break;
        case IXGB_DEVICE_ID_82597EX_LR:
-               DEBUGOUT("Identified G6104 optics\n");
+               pr_debug("Identified G6104 optics\n");
                phy_type = ixgb_phy_type_g6104;
                break;
        case IXGB_DEVICE_ID_82597EX_CX4:
-               DEBUGOUT("Identified CX4\n");
+               pr_debug("Identified CX4\n");
                xpak_vendor = ixgb_identify_xpak_vendor(hw);
                if (xpak_vendor == ixgb_xpak_vendor_intel) {
-                       DEBUGOUT("Identified TXN17201 optics\n");
+                       pr_debug("Identified TXN17201 optics\n");
                        phy_type = ixgb_phy_type_txn17201;
                } else {
-                       DEBUGOUT("Identified G6005 optics\n");
+                       pr_debug("Identified G6005 optics\n");
                        phy_type = ixgb_phy_type_g6005;
                }
                break;
        default:
-               DEBUGOUT("Unknown physical layer module\n");
+               pr_debug("Unknown physical layer module\n");
                phy_type = ixgb_phy_type_unknown;
                break;
        }
@@ -296,18 +300,18 @@ ixgb_init_hw(struct ixgb_hw *hw)
        u32 ctrl_reg;
        bool status;
 
-       DEBUGFUNC("ixgb_init_hw");
+       ENTER();
 
        /* Issue a global reset to the MAC.  This will reset the chip's
         * transmit, receive, DMA, and link units.  It will not effect
         * the current PCI configuration.  The global reset bit is self-
         * clearing, and should clear within a microsecond.
         */
-       DEBUGOUT("Issuing a global reset to MAC\n");
+       pr_debug("Issuing a global reset to MAC\n");
 
        ctrl_reg = ixgb_mac_reset(hw);
 
-       DEBUGOUT("Issuing an EE reset to MAC\n");
+       pr_debug("Issuing an EE reset to MAC\n");
 #ifdef HP_ZX1
        /* Workaround for 82597EX reset errata */
        IXGB_WRITE_REG_IO(hw, CTRL1, IXGB_CTRL1_EE_RST);
@@ -335,7 +339,7 @@ ixgb_init_hw(struct ixgb_hw *hw)
         * If it is not valid, we fail hardware init.
         */
        if (!mac_addr_valid(hw->curr_mac_addr)) {
-               DEBUGOUT("MAC address invalid after ixgb_init_rx_addrs\n");
+               pr_debug("MAC address invalid after ixgb_init_rx_addrs\n");
                return(false);
        }
 
@@ -346,7 +350,7 @@ ixgb_init_hw(struct ixgb_hw *hw)
        ixgb_get_bus_info(hw);
 
        /* Zero out the Multicast HASH table */
-       DEBUGOUT("Zeroing the MTA\n");
+       pr_debug("Zeroing the MTA\n");
        for (i = 0; i < IXGB_MC_TBL_SIZE; i++)
                IXGB_WRITE_REG_ARRAY(hw, MTA, i, 0);
 
@@ -379,7 +383,7 @@ ixgb_init_rx_addrs(struct ixgb_hw *hw)
 {
        u32 i;
 
-       DEBUGFUNC("ixgb_init_rx_addrs");
+       ENTER();
 
        /*
         * If the current mac address is valid, assume it is a software override
@@ -391,35 +395,24 @@ ixgb_init_rx_addrs(struct ixgb_hw *hw)
                /* Get the MAC address from the eeprom for later reference */
                ixgb_get_ee_mac_addr(hw, hw->curr_mac_addr);
 
-               DEBUGOUT3(" Keeping Permanent MAC Addr =%.2X %.2X %.2X ",
-                         hw->curr_mac_addr[0],
-                         hw->curr_mac_addr[1], hw->curr_mac_addr[2]);
-               DEBUGOUT3("%.2X %.2X %.2X\n",
-                         hw->curr_mac_addr[3],
-                         hw->curr_mac_addr[4], hw->curr_mac_addr[5]);
+               pr_debug("Keeping Permanent MAC Addr = %pM\n",
+                        hw->curr_mac_addr);
        } else {
 
                /* Setup the receive address. */
-               DEBUGOUT("Overriding MAC Address in RAR[0]\n");
-               DEBUGOUT3(" New MAC Addr =%.2X %.2X %.2X ",
-                         hw->curr_mac_addr[0],
-                         hw->curr_mac_addr[1], hw->curr_mac_addr[2]);
-               DEBUGOUT3("%.2X %.2X %.2X\n",
-                         hw->curr_mac_addr[3],
-                         hw->curr_mac_addr[4], hw->curr_mac_addr[5]);
+               pr_debug("Overriding MAC Address in RAR[0]\n");
+               pr_debug("New MAC Addr = %pM\n", hw->curr_mac_addr);
 
                ixgb_rar_set(hw, hw->curr_mac_addr, 0);
        }
 
        /* Zero out the other 15 receive addresses. */
-       DEBUGOUT("Clearing RAR[1-15]\n");
+       pr_debug("Clearing RAR[1-15]\n");
        for (i = 1; i < IXGB_RAR_ENTRIES; i++) {
                /* Write high reg first to disable the AV bit first */
                IXGB_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
                IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
        }
-
-       return;
 }
 
 /******************************************************************************
@@ -444,65 +437,50 @@ ixgb_mc_addr_list_update(struct ixgb_hw *hw,
        u32 hash_value;
        u32 i;
        u32 rar_used_count = 1;         /* RAR[0] is used for our MAC address */
+       u8 *mca;
 
-       DEBUGFUNC("ixgb_mc_addr_list_update");
+       ENTER();
 
        /* Set the new number of MC addresses that we are being requested to use. */
        hw->num_mc_addrs = mc_addr_count;
 
        /* Clear RAR[1-15] */
-       DEBUGOUT(" Clearing RAR[1-15]\n");
+       pr_debug("Clearing RAR[1-15]\n");
        for (i = rar_used_count; i < IXGB_RAR_ENTRIES; i++) {
                IXGB_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
                IXGB_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
        }
 
        /* Clear the MTA */
-       DEBUGOUT(" Clearing MTA\n");
+       pr_debug("Clearing MTA\n");
        for (i = 0; i < IXGB_MC_TBL_SIZE; i++)
                IXGB_WRITE_REG_ARRAY(hw, MTA, i, 0);
 
        /* Add the new addresses */
+       mca = mc_addr_list;
        for (i = 0; i < mc_addr_count; i++) {
-               DEBUGOUT(" Adding the multicast addresses:\n");
-               DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
-                         mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad)],
-                         mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad) +
-                                      1],
-                         mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad) +
-                                      2],
-                         mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad) +
-                                      3],
-                         mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad) +
-                                      4],
-                         mc_addr_list[i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad) +
-                                      5]);
+               pr_debug("Adding the multicast addresses:\n");
+               pr_debug("MC Addr #%d = %pM\n", i, mca);
 
                /* Place this multicast address in the RAR if there is room, *
                 * else put it in the MTA
                 */
                if (rar_used_count < IXGB_RAR_ENTRIES) {
-                       ixgb_rar_set(hw,
-                                    mc_addr_list +
-                                    (i * (IXGB_ETH_LENGTH_OF_ADDRESS + pad)),
-                                    rar_used_count);
-                       DEBUGOUT1("Added a multicast address to RAR[%d]\n", i);
+                       ixgb_rar_set(hw, mca, rar_used_count);
+                       pr_debug("Added a multicast address to RAR[%d]\n", i);
                        rar_used_count++;
                } else {
-                       hash_value = ixgb_hash_mc_addr(hw,
-                                                      mc_addr_list +
-                                                      (i *
-                                                       (IXGB_ETH_LENGTH_OF_ADDRESS
-                                                        + pad)));
+                       hash_value = ixgb_hash_mc_addr(hw, mca);
 
-                       DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+                       pr_debug("Hash value = 0x%03X\n", hash_value);
 
                        ixgb_mta_set(hw, hash_value);
                }
+
+               mca += IXGB_ETH_LENGTH_OF_ADDRESS + pad;
        }
 
-       DEBUGOUT("MC Update Complete\n");
-       return;
+       pr_debug("MC Update Complete\n");
 }
 
 /******************************************************************************
@@ -520,7 +498,7 @@ ixgb_hash_mc_addr(struct ixgb_hw *hw,
 {
        u32 hash_value = 0;
 
-       DEBUGFUNC("ixgb_hash_mc_addr");
+       ENTER();
 
        /* The portion of the address that is used for the hash table is
         * determined by the mc_filter_type setting.
@@ -547,7 +525,7 @@ ixgb_hash_mc_addr(struct ixgb_hw *hw,
                break;
        default:
                /* Invalid mc_filter_type, what should we do? */
-               DEBUGOUT("MC filter type param set incorrectly\n");
+               pr_debug("MC filter type param set incorrectly\n");
                ASSERT(0);
                break;
        }
@@ -585,8 +563,6 @@ ixgb_mta_set(struct ixgb_hw *hw,
        mta_reg |= (1 << hash_bit);
 
        IXGB_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta_reg);
-
-       return;
 }
 
 /******************************************************************************
@@ -603,7 +579,7 @@ ixgb_rar_set(struct ixgb_hw *hw,
 {
        u32 rar_low, rar_high;
 
-       DEBUGFUNC("ixgb_rar_set");
+       ENTER();
 
        /* HW expects these in little endian so we reverse the byte order
         * from network order (big endian) to little endian
@@ -619,7 +595,6 @@ ixgb_rar_set(struct ixgb_hw *hw,
 
        IXGB_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
        IXGB_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
-       return;
 }
 
 /******************************************************************************
@@ -635,7 +610,6 @@ ixgb_write_vfta(struct ixgb_hw *hw,
                 u32 value)
 {
        IXGB_WRITE_REG_ARRAY(hw, VFTA, offset, value);
-       return;
 }
 
 /******************************************************************************
@@ -650,7 +624,6 @@ ixgb_clear_vfta(struct ixgb_hw *hw)
 
        for (offset = 0; offset < IXGB_VLAN_FILTER_TBL_SIZE; offset++)
                IXGB_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
-       return;
 }
 
 /******************************************************************************
@@ -666,7 +639,7 @@ ixgb_setup_fc(struct ixgb_hw *hw)
        u32 pap_reg = 0;   /* by default, assume no pause time */
        bool status = true;
 
-       DEBUGFUNC("ixgb_setup_fc");
+       ENTER();
 
        /* Get the current control reg 0 settings */
        ctrl_reg = IXGB_READ_REG(hw, CTRL0);
@@ -710,7 +683,7 @@ ixgb_setup_fc(struct ixgb_hw *hw)
                break;
        default:
                /* We should never get here.  The value should be 0-3. */
-               DEBUGOUT("Flow control param set incorrectly\n");
+               pr_debug("Flow control param set incorrectly\n");
                ASSERT(0);
                break;
        }
@@ -940,7 +913,7 @@ ixgb_check_for_link(struct ixgb_hw *hw)
        u32 status_reg;
        u32 xpcss_reg;
 
-       DEBUGFUNC("ixgb_check_for_link");
+       ENTER();
 
        xpcss_reg = IXGB_READ_REG(hw, XPCSS);
        status_reg = IXGB_READ_REG(hw, STATUS);
@@ -950,7 +923,7 @@ ixgb_check_for_link(struct ixgb_hw *hw)
                hw->link_up = true;
        } else if (!(xpcss_reg & IXGB_XPCSS_ALIGN_STATUS) &&
                   (status_reg & IXGB_STATUS_LU)) {
-               DEBUGOUT("XPCSS Not Aligned while Status:LU is set.\n");
+               pr_debug("XPCSS Not Aligned while Status:LU is set\n");
                hw->link_up = ixgb_link_reset(hw);
        } else {
                /*
@@ -981,8 +954,7 @@ bool ixgb_check_for_bad_link(struct ixgb_hw *hw)
                newRFC = IXGB_READ_REG(hw, RFC);
                if ((hw->lastLFC + 250 < newLFC)
                    || (hw->lastRFC + 250 < newRFC)) {
-                       DEBUGOUT
-                           ("BAD LINK! too many LFC/RFC since last check\n");
+                       pr_debug("BAD LINK! too many LFC/RFC since last check\n");
                        bad_link_returncode = true;
                }
                hw->lastLFC = newLFC;
@@ -1002,11 +974,11 @@ ixgb_clear_hw_cntrs(struct ixgb_hw *hw)
 {
        volatile u32 temp_reg;
 
-       DEBUGFUNC("ixgb_clear_hw_cntrs");
+       ENTER();
 
        /* if we are stopped or resetting exit gracefully */
        if (hw->adapter_stopped) {
-               DEBUGOUT("Exiting because the adapter is stopped!!!\n");
+               pr_debug("Exiting because the adapter is stopped!!!\n");
                return;
        }
 
@@ -1070,7 +1042,6 @@ ixgb_clear_hw_cntrs(struct ixgb_hw *hw)
        temp_reg = IXGB_READ_REG(hw, XOFFRXC);
        temp_reg = IXGB_READ_REG(hw, XOFFTXC);
        temp_reg = IXGB_READ_REG(hw, RJC);
-       return;
 }
 
 /******************************************************************************
@@ -1086,7 +1057,6 @@ ixgb_led_on(struct ixgb_hw *hw)
        /* To turn on the LED, clear software-definable pin 0 (SDP0). */
        ctrl0_reg &= ~IXGB_CTRL0_SDP0;
        IXGB_WRITE_REG(hw, CTRL0, ctrl0_reg);
-       return;
 }
 
 /******************************************************************************
@@ -1102,7 +1072,6 @@ ixgb_led_off(struct ixgb_hw *hw)
        /* To turn off the LED, set software-definable pin 0 (SDP0). */
        ctrl0_reg |= IXGB_CTRL0_SDP0;
        IXGB_WRITE_REG(hw, CTRL0, ctrl0_reg);
-       return;
 }
 
 /******************************************************************************
@@ -1142,8 +1111,6 @@ ixgb_get_bus_info(struct ixgb_hw *hw)
 
        hw->bus.width = (status_reg & IXGB_STATUS_BUS64) ?
                ixgb_bus_width_64 : ixgb_bus_width_32;
-
-       return;
 }
 
 /******************************************************************************
@@ -1156,26 +1123,21 @@ static bool
 mac_addr_valid(u8 *mac_addr)
 {
        bool is_valid = true;
-       DEBUGFUNC("mac_addr_valid");
+       ENTER();
 
        /* Make sure it is not a multicast address */
-       if (IS_MULTICAST(mac_addr)) {
-               DEBUGOUT("MAC address is multicast\n");
+       if (is_multicast_ether_addr(mac_addr)) {
+               pr_debug("MAC address is multicast\n");
                is_valid = false;
        }
        /* Not a broadcast address */
-       else if (IS_BROADCAST(mac_addr)) {
-               DEBUGOUT("MAC address is broadcast\n");
+       else if (is_broadcast_ether_addr(mac_addr)) {
+               pr_debug("MAC address is broadcast\n");
                is_valid = false;
        }
        /* Reject the zero address */
-       else if (mac_addr[0] == 0 &&
-                        mac_addr[1] == 0 &&
-                        mac_addr[2] == 0 &&
-                        mac_addr[3] == 0 &&
-                        mac_addr[4] == 0 &&
-                        mac_addr[5] == 0) {
-               DEBUGOUT("MAC address is all zeros\n");
+       else if (is_zero_ether_addr(mac_addr)) {
+               pr_debug("MAC address is all zeros\n");
                is_valid = false;
        }
        return (is_valid);
@@ -1235,8 +1197,6 @@ ixgb_optics_reset(struct ixgb_hw *hw)
                                             IXGB_PHY_ADDRESS,
                                             MDIO_MMD_PMAPMD);
        }
-
-       return;
 }
 
 /******************************************************************************
@@ -1297,6 +1257,4 @@ ixgb_optics_reset_bcm(struct ixgb_hw *hw)
 
        /* SerDes needs extra delay */
        msleep(IXGB_SUN_PHY_RESET_DELAY);
-
-       return;
 }
index af6ca3aab5adc5d16a96d2aa57a96b27074bdeff..873d32b89fba9a47e14e52fe578584488d363447 100644 (file)
@@ -636,18 +636,6 @@ struct ixgb_flash_buffer {
        u8 filler3[0xAAAA];
 };
 
-/*
- * This is a little-endian specific check.
- */
-#define IS_MULTICAST(Address) \
-    (bool)(((u8 *)(Address))[0] & ((u8)0x01))
-
-/*
- * Check whether an address is broadcast.
- */
-#define IS_BROADCAST(Address)               \
-    ((((u8 *)(Address))[0] == ((u8)0xff)) && (((u8 *)(Address))[1] == ((u8)0xff)))
-
 /* Flow control parameters */
 struct ixgb_fc {
        u32 high_water; /* Flow Control High-water          */
index c9fef65cb98be5e17e02ad656d0e92d62d89cd5e..c6b75c83100c91b782221bf3e7ae6f813ef43da5 100644 (file)
@@ -26,6 +26,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "ixgb.h"
 
 char ixgb_driver_name[] = "ixgb";
@@ -146,10 +148,8 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 static int __init
 ixgb_init_module(void)
 {
-       printk(KERN_INFO "%s - version %s\n",
-              ixgb_driver_string, ixgb_driver_version);
-
-       printk(KERN_INFO "%s\n", ixgb_copyright);
+       pr_info("%s - version %s\n", ixgb_driver_string, ixgb_driver_version);
+       pr_info("%s\n", ixgb_copyright);
 
        return pci_register_driver(&ixgb_driver);
 }
@@ -368,17 +368,22 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                return err;
 
-       if (!(err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) &&
-           !(err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)))) {
-               pci_using_dac = 1;
+       pci_using_dac = 0;
+       err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+       if (!err) {
+               err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+               if (!err)
+                       pci_using_dac = 1;
        } else {
-               if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) ||
-                   (err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))) {
-                       printk(KERN_ERR
-                        "ixgb: No usable DMA configuration, aborting\n");
-                       goto err_dma_mask;
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               if (err) {
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
+                       if (err) {
+                               pr_err("No usable DMA configuration, aborting\n");
+                               goto err_dma_mask;
+                       }
                }
-               pci_using_dac = 0;
        }
 
        err = pci_request_regions(pdev, ixgb_driver_name);
@@ -674,7 +679,8 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
        txdr->size = txdr->count * sizeof(struct ixgb_tx_desc);
        txdr->size = ALIGN(txdr->size, 4096);
 
-       txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+       txdr->desc = dma_alloc_coherent(&pdev->dev, txdr->size, &txdr->dma,
+                                       GFP_KERNEL);
        if (!txdr->desc) {
                vfree(txdr->buffer_info);
                netif_err(adapter, probe, adapter->netdev,
@@ -763,7 +769,8 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
        rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc);
        rxdr->size = ALIGN(rxdr->size, 4096);
 
-       rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+       rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,
+                                       GFP_KERNEL);
 
        if (!rxdr->desc) {
                vfree(rxdr->buffer_info);
@@ -884,8 +891,8 @@ ixgb_free_tx_resources(struct ixgb_adapter *adapter)
        vfree(adapter->tx_ring.buffer_info);
        adapter->tx_ring.buffer_info = NULL;
 
-       pci_free_consistent(pdev, adapter->tx_ring.size,
-                           adapter->tx_ring.desc, adapter->tx_ring.dma);
+       dma_free_coherent(&pdev->dev, adapter->tx_ring.size,
+                         adapter->tx_ring.desc, adapter->tx_ring.dma);
 
        adapter->tx_ring.desc = NULL;
 }
@@ -896,12 +903,11 @@ ixgb_unmap_and_free_tx_resource(struct ixgb_adapter *adapter,
 {
        if (buffer_info->dma) {
                if (buffer_info->mapped_as_page)
-                       pci_unmap_page(adapter->pdev, buffer_info->dma,
-                                      buffer_info->length, PCI_DMA_TODEVICE);
+                       dma_unmap_page(&adapter->pdev->dev, buffer_info->dma,
+                                      buffer_info->length, DMA_TO_DEVICE);
                else
-                       pci_unmap_single(adapter->pdev, buffer_info->dma,
-                                        buffer_info->length,
-                                        PCI_DMA_TODEVICE);
+                       dma_unmap_single(&adapter->pdev->dev, buffer_info->dma,
+                                        buffer_info->length, DMA_TO_DEVICE);
                buffer_info->dma = 0;
        }
 
@@ -967,7 +973,8 @@ ixgb_free_rx_resources(struct ixgb_adapter *adapter)
        vfree(rx_ring->buffer_info);
        rx_ring->buffer_info = NULL;
 
-       pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+       dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+                         rx_ring->dma);
 
        rx_ring->desc = NULL;
 }
@@ -991,10 +998,10 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter)
        for (i = 0; i < rx_ring->count; i++) {
                buffer_info = &rx_ring->buffer_info[i];
                if (buffer_info->dma) {
-                       pci_unmap_single(pdev,
+                       dma_unmap_single(&pdev->dev,
                                         buffer_info->dma,
                                         buffer_info->length,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        buffer_info->dma = 0;
                        buffer_info->length = 0;
                }
@@ -1058,7 +1065,7 @@ ixgb_set_multi(struct net_device *netdev)
 {
        struct ixgb_adapter *adapter = netdev_priv(netdev);
        struct ixgb_hw *hw = &adapter->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u32 rctl;
        int i;
 
@@ -1089,9 +1096,9 @@ ixgb_set_multi(struct net_device *netdev)
                IXGB_WRITE_REG(hw, RCTL, rctl);
 
                i = 0;
-               netdev_for_each_mc_addr(mc_ptr, netdev)
+               netdev_for_each_mc_addr(ha, netdev)
                        memcpy(&mta[i++ * IXGB_ETH_LENGTH_OF_ADDRESS],
-                              mc_ptr->dmi_addr, IXGB_ETH_LENGTH_OF_ADDRESS);
+                              ha->addr, IXGB_ETH_LENGTH_OF_ADDRESS);
 
                ixgb_mc_addr_list_update(hw, mta, netdev_mc_count(netdev), 0);
        }
@@ -1118,15 +1125,14 @@ ixgb_watchdog(unsigned long data)
 
        if (adapter->hw.link_up) {
                if (!netif_carrier_ok(netdev)) {
-                       printk(KERN_INFO "ixgb: %s NIC Link is Up 10 Gbps "
-                              "Full Duplex, Flow Control: %s\n",
-                              netdev->name,
-                              (adapter->hw.fc.type == ixgb_fc_full) ?
-                               "RX/TX" :
-                               ((adapter->hw.fc.type == ixgb_fc_rx_pause) ?
-                                "RX" :
-                                ((adapter->hw.fc.type == ixgb_fc_tx_pause) ?
-                                 "TX" : "None")));
+                       netdev_info(netdev,
+                                   "NIC Link is Up 10 Gbps Full Duplex, Flow Control: %s\n",
+                                   (adapter->hw.fc.type == ixgb_fc_full) ?
+                                   "RX/TX" :
+                                   (adapter->hw.fc.type == ixgb_fc_rx_pause) ?
+                                    "RX" :
+                                   (adapter->hw.fc.type == ixgb_fc_tx_pause) ?
+                                   "TX" : "None");
                        adapter->link_speed = 10000;
                        adapter->link_duplex = FULL_DUPLEX;
                        netif_carrier_on(netdev);
@@ -1135,8 +1141,7 @@ ixgb_watchdog(unsigned long data)
                if (netif_carrier_ok(netdev)) {
                        adapter->link_speed = 0;
                        adapter->link_duplex = 0;
-                       printk(KERN_INFO "ixgb: %s NIC Link is Down\n",
-                              netdev->name);
+                       netdev_info(netdev, "NIC Link is Down\n");
                        netif_carrier_off(netdev);
                }
        }
@@ -1303,9 +1308,10 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                WARN_ON(buffer_info->dma != 0);
                buffer_info->time_stamp = jiffies;
                buffer_info->mapped_as_page = false;
-               buffer_info->dma = pci_map_single(pdev, skb->data + offset,
-                                                 size, PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, buffer_info->dma))
+               buffer_info->dma = dma_map_single(&pdev->dev,
+                                                 skb->data + offset,
+                                                 size, DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                        goto dma_error;
                buffer_info->next_to_watch = 0;
 
@@ -1344,10 +1350,9 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                        buffer_info->time_stamp = jiffies;
                        buffer_info->mapped_as_page = true;
                        buffer_info->dma =
-                               pci_map_page(pdev, frag->page,
-                                            offset, size,
-                                            PCI_DMA_TODEVICE);
-                       if (pci_dma_mapping_error(pdev, buffer_info->dma))
+                               dma_map_page(&pdev->dev, frag->page,
+                                            offset, size, DMA_TO_DEVICE);
+                       if (dma_mapping_error(&pdev->dev, buffer_info->dma))
                                goto dma_error;
                        buffer_info->next_to_watch = 0;
 
@@ -1916,6 +1921,31 @@ ixgb_rx_checksum(struct ixgb_adapter *adapter,
        }
 }
 
+/*
+ * this should improve performance for small packets with large amounts
+ * of reassembly being done in the stack
+ */
+static void ixgb_check_copybreak(struct net_device *netdev,
+                                struct ixgb_buffer *buffer_info,
+                                u32 length, struct sk_buff **skb)
+{
+       struct sk_buff *new_skb;
+
+       if (length > copybreak)
+               return;
+
+       new_skb = netdev_alloc_skb_ip_align(netdev, length);
+       if (!new_skb)
+               return;
+
+       skb_copy_to_linear_data_offset(new_skb, -NET_IP_ALIGN,
+                                      (*skb)->data - NET_IP_ALIGN,
+                                      length + NET_IP_ALIGN);
+       /* save the skb in buffer_info as good */
+       buffer_info->skb = *skb;
+       *skb = new_skb;
+}
+
 /**
  * ixgb_clean_rx_irq - Send received data up the network stack,
  * @adapter: board private structure
@@ -1952,11 +1982,14 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do)
 
                prefetch(skb->data - NET_IP_ALIGN);
 
-               if (++i == rx_ring->count) i = 0;
+               if (++i == rx_ring->count)
+                       i = 0;
                next_rxd = IXGB_RX_DESC(*rx_ring, i);
                prefetch(next_rxd);
 
-               if ((j = i + 1) == rx_ring->count) j = 0;
+               j = i + 1;
+               if (j == rx_ring->count)
+                       j = 0;
                next2_buffer = &rx_ring->buffer_info[j];
                prefetch(next2_buffer);
 
@@ -1965,10 +1998,10 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do)
                cleaned = true;
                cleaned_count++;
 
-               pci_unmap_single(pdev,
+               dma_unmap_single(&pdev->dev,
                                 buffer_info->dma,
                                 buffer_info->length,
-                                PCI_DMA_FROMDEVICE);
+                                DMA_FROM_DEVICE);
                buffer_info->dma = 0;
 
                length = le16_to_cpu(rx_desc->length);
@@ -1992,25 +2025,7 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do)
                        goto rxdesc_done;
                }
 
-               /* code added for copybreak, this should improve
-                * performance for small packets with large amounts
-                * of reassembly being done in the stack */
-               if (length < copybreak) {
-                       struct sk_buff *new_skb =
-                           netdev_alloc_skb_ip_align(netdev, length);
-                       if (new_skb) {
-                               skb_copy_to_linear_data_offset(new_skb,
-                                                              -NET_IP_ALIGN,
-                                                              (skb->data -
-                                                               NET_IP_ALIGN),
-                                                              (length +
-                                                               NET_IP_ALIGN));
-                               /* save the skb in buffer_info as good */
-                               buffer_info->skb = skb;
-                               skb = new_skb;
-                       }
-               }
-               /* end copybreak code */
+               ixgb_check_copybreak(netdev, buffer_info, length, &skb);
 
                /* Good Receive */
                skb_put(skb, length);
@@ -2091,10 +2106,10 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter, int cleaned_count)
                buffer_info->skb = skb;
                buffer_info->length = adapter->rx_buffer_len;
 map_skb:
-               buffer_info->dma = pci_map_single(pdev,
+               buffer_info->dma = dma_map_single(&pdev->dev,
                                                  skb->data,
                                                  adapter->rx_buffer_len,
-                                                 PCI_DMA_FROMDEVICE);
+                                                 DMA_FROM_DEVICE);
 
                rx_desc = IXGB_RX_DESC(*rx_ring, i);
                rx_desc->buff_addr = cpu_to_le64(buffer_info->dma);
@@ -2322,7 +2337,7 @@ static void ixgb_io_resume(struct pci_dev *pdev)
 
        if (netif_running(netdev)) {
                if (ixgb_up(adapter)) {
-                       printk ("ixgb: can't bring device back up after reset\n");
+                       pr_err("can't bring device back up after reset\n");
                        return;
                }
        }
index 371a6be4d965b5a5cf0a852a9af8d71c0c614e7c..e361185920ef692aa0e89870bc58507339f9431e 100644 (file)
 
 #undef ASSERT
 #define ASSERT(x)      BUG_ON(!(x))
-#define MSGOUT(S, A, B)        printk(KERN_DEBUG S "\n", A, B)
-
-#ifdef DBG
-#define DEBUGOUT(S)            printk(KERN_DEBUG S "\n")
-#define DEBUGOUT1(S, A...)     printk(KERN_DEBUG S "\n", A)
-#else
-#define DEBUGOUT(S)
-#define DEBUGOUT1(S, A...)
-#endif
-
-#define DEBUGFUNC(F) DEBUGOUT(F)
-#define DEBUGOUT2 DEBUGOUT1
-#define DEBUGOUT3 DEBUGOUT2
-#define DEBUGOUT7 DEBUGOUT3
+
+#define ENTER() pr_debug("%s\n", __func__);
 
 #define IXGB_WRITE_REG(a, reg, value) ( \
        writel((value), ((a)->hw_addr + IXGB_##reg)))
index af35e1ddadd6d7f50faac9adf712628206d2c0e3..88a08f05624128fb2ffbd148e9036fd8437e4f63 100644 (file)
@@ -26,6 +26,8 @@
 
 *******************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include "ixgb.h"
 
 /* This is the only thing that needs to be changed to adjust the
@@ -209,16 +211,16 @@ ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt)
        case enable_option:
                switch (*value) {
                case OPTION_ENABLED:
-                       printk(KERN_INFO "%s Enabled\n", opt->name);
+                       pr_info("%s Enabled\n", opt->name);
                        return 0;
                case OPTION_DISABLED:
-                       printk(KERN_INFO "%s Disabled\n", opt->name);
+                       pr_info("%s Disabled\n", opt->name);
                        return 0;
                }
                break;
        case range_option:
                if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
-                       printk(KERN_INFO "%s set to %i\n", opt->name, *value);
+                       pr_info("%s set to %i\n", opt->name, *value);
                        return 0;
                }
                break;
@@ -230,7 +232,7 @@ ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt)
                        ent = &opt->arg.l.p[i];
                        if (*value == ent->i) {
                                if (ent->str[0] != '\0')
-                                       printk(KERN_INFO "%s\n", ent->str);
+                                       pr_info("%s\n", ent->str);
                                return 0;
                        }
                }
@@ -240,8 +242,7 @@ ixgb_validate_option(unsigned int *value, const struct ixgb_option *opt)
                BUG();
        }
 
-       printk(KERN_INFO "Invalid %s specified (%i) %s\n",
-                  opt->name, *value, opt->err);
+       pr_info("Invalid %s specified (%i) %s\n", opt->name, *value, opt->err);
        *value = opt->def;
        return -1;
 }
@@ -261,9 +262,8 @@ ixgb_check_options(struct ixgb_adapter *adapter)
 {
        int bd = adapter->bd_number;
        if (bd >= IXGB_MAX_NIC) {
-               printk(KERN_NOTICE
-                          "Warning: no configuration for board #%i\n", bd);
-               printk(KERN_NOTICE "Using defaults for all values\n");
+               pr_notice("Warning: no configuration for board #%i\n", bd);
+               pr_notice("Using defaults for all values\n");
        }
 
        { /* Transmit Descriptor Count */
@@ -363,8 +363,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
                        adapter->hw.fc.high_water = opt.def;
                }
                if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) )
-                       printk(KERN_INFO
-                               "Ignoring RxFCHighThresh when no RxFC\n");
+                       pr_info("Ignoring RxFCHighThresh when no RxFC\n");
        }
        { /* Receive Flow Control Low Threshold */
                const struct ixgb_option opt = {
@@ -383,8 +382,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
                        adapter->hw.fc.low_water = opt.def;
                }
                if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) )
-                       printk(KERN_INFO
-                               "Ignoring RxFCLowThresh when no RxFC\n");
+                       pr_info("Ignoring RxFCLowThresh when no RxFC\n");
        }
        { /* Flow Control Pause Time Request*/
                const struct ixgb_option opt = {
@@ -404,17 +402,14 @@ ixgb_check_options(struct ixgb_adapter *adapter)
                        adapter->hw.fc.pause_time = opt.def;
                }
                if (!(adapter->hw.fc.type & ixgb_fc_tx_pause) )
-                       printk(KERN_INFO
-                               "Ignoring FCReqTimeout when no RxFC\n");
+                       pr_info("Ignoring FCReqTimeout when no RxFC\n");
        }
        /* high low and spacing check for rx flow control thresholds */
        if (adapter->hw.fc.type & ixgb_fc_tx_pause) {
                /* high must be greater than low */
                if (adapter->hw.fc.high_water < (adapter->hw.fc.low_water + 8)) {
                        /* set defaults */
-                       printk(KERN_INFO
-                               "RxFCHighThresh must be >= (RxFCLowThresh + 8), "
-                               "Using Defaults\n");
+                       pr_info("RxFCHighThresh must be >= (RxFCLowThresh + 8), Using Defaults\n");
                        adapter->hw.fc.high_water = DEFAULT_FCRTH;
                        adapter->hw.fc.low_water  = DEFAULT_FCRTL;
                }
index 79c35ae3718c96186898452e286d59d5e0482814..d0ea3d6dea95f6f26b2fe3f9534c8b445c810cc6 100644 (file)
@@ -111,7 +111,10 @@ struct vf_data_storage {
        u16 default_vf_vlan_id;
        u16 vlans_enabled;
        bool clear_to_send;
+       bool pf_set_mac;
        int rar;
+       u16 pf_vlan; /* When set, guest VLAN config not allowed. */
+       u16 pf_qos;
 };
 
 /* wrapper around a pointer to a socket buffer,
index 35a06b47587bd2bf57a376bf4f95ee65a7c93c0e..f2b7ff44215b52b3f9608d6593d22792273727f5 100644 (file)
@@ -42,9 +42,9 @@ static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw,
                                              ixgbe_link_speed *speed,
                                              bool *autoneg);
 static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
-                                               ixgbe_link_speed speed,
-                                               bool autoneg,
-                                               bool autoneg_wait_to_complete);
+                                         ixgbe_link_speed speed,
+                                         bool autoneg,
+                                         bool autoneg_wait_to_complete);
 static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
                                        u8 *eeprom_data);
 
@@ -1221,7 +1221,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
 
 static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
        .init_params            = &ixgbe_init_eeprom_params_generic,
-       .read                   = &ixgbe_read_eeprom_generic,
+       .read                   = &ixgbe_read_eerd_generic,
        .validate_checksum      = &ixgbe_validate_eeprom_checksum_generic,
        .update_checksum        = &ixgbe_update_eeprom_checksum_generic,
 };
index 12fc0e7ba2ca3bbf10034fa8e906bc34bb06a689..e9706eb8e4ff58fdb805e12094438a3e14437bb9 100644 (file)
@@ -133,27 +133,6 @@ setup_sfp_out:
        return ret_val;
 }
 
-/**
- *  ixgbe_get_pcie_msix_count_82599 - Gets MSI-X vector count
- *  @hw: pointer to hardware structure
- *
- *  Read PCIe configuration space, and get the MSI-X vector count from
- *  the capabilities table.
- **/
-static u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw)
-{
-       struct ixgbe_adapter *adapter = hw->back;
-       u16 msix_count;
-       pci_read_config_word(adapter->pdev, IXGBE_PCIE_MSIX_82599_CAPS,
-                            &msix_count);
-       msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK;
-
-       /* MSI-X count is zero-based in HW, so increment to give proper value */
-       msix_count++;
-
-       return msix_count;
-}
-
 static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
 {
        struct ixgbe_mac_info *mac = &hw->mac;
@@ -165,7 +144,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
        mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES;
        mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES;
-       mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82599(hw);
+       mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
 
        return 0;
 }
@@ -642,6 +621,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
        s32 i, j;
        bool link_up = false;
        u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       struct ixgbe_adapter *adapter = hw->back;
 
        hw_dbg(hw, "ixgbe_setup_mac_link_smartspeed.\n");
 
@@ -726,63 +706,13 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
                                            autoneg_wait_to_complete);
 
 out:
+       if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
+               netif_info(adapter, hw, adapter->netdev, "Smartspeed has"
+                       " downgraded the link speed from the maximum"
+                       " advertised\n");
        return status;
 }
 
-/**
- *  ixgbe_check_mac_link_82599 - Determine link and speed status
- *  @hw: pointer to hardware structure
- *  @speed: pointer to link speed
- *  @link_up: true when link is up
- *  @link_up_wait_to_complete: bool used to wait for link up or not
- *
- *  Reads the links register to determine if link is up and the current speed
- **/
-static s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw,
-                                      ixgbe_link_speed *speed,
-                                      bool *link_up,
-                                      bool link_up_wait_to_complete)
-{
-       u32 links_reg;
-       u32 i;
-
-       links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
-       if (link_up_wait_to_complete) {
-               for (i = 0; i < IXGBE_LINK_UP_TIME; i++) {
-                       if (links_reg & IXGBE_LINKS_UP) {
-                               *link_up = true;
-                               break;
-                       } else {
-                               *link_up = false;
-                       }
-                       msleep(100);
-                       links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
-               }
-       } else {
-               if (links_reg & IXGBE_LINKS_UP)
-                       *link_up = true;
-               else
-                       *link_up = false;
-       }
-
-       if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
-           IXGBE_LINKS_SPEED_10G_82599)
-               *speed = IXGBE_LINK_SPEED_10GB_FULL;
-       else if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
-                IXGBE_LINKS_SPEED_1G_82599)
-               *speed = IXGBE_LINK_SPEED_1GB_FULL;
-       else
-               *speed = IXGBE_LINK_SPEED_100_FULL;
-
-       /* if link is down, zero out the current_mode */
-       if (*link_up == false) {
-               hw->fc.current_mode = ixgbe_fc_none;
-               hw->fc.fc_was_autonegged = false;
-       }
-
-       return 0;
-}
-
 /**
  *  ixgbe_setup_mac_link_82599 - Set MAC link speed
  *  @hw: pointer to hardware structure
@@ -1044,243 +974,6 @@ reset_hw_out:
        return status;
 }
 
-/**
- *  ixgbe_clear_vmdq_82599 - Disassociate a VMDq pool index from a rx address
- *  @hw: pointer to hardware struct
- *  @rar: receive address register index to disassociate
- *  @vmdq: VMDq pool index to remove from the rar
- **/
-static s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
-{
-       u32 mpsar_lo, mpsar_hi;
-       u32 rar_entries = hw->mac.num_rar_entries;
-
-       if (rar < rar_entries) {
-               mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
-               mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
-
-               if (!mpsar_lo && !mpsar_hi)
-                       goto done;
-
-               if (vmdq == IXGBE_CLEAR_VMDQ_ALL) {
-                       if (mpsar_lo) {
-                               IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), 0);
-                               mpsar_lo = 0;
-                       }
-                       if (mpsar_hi) {
-                               IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), 0);
-                               mpsar_hi = 0;
-                       }
-               } else if (vmdq < 32) {
-                       mpsar_lo &= ~(1 << vmdq);
-                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar_lo);
-               } else {
-                       mpsar_hi &= ~(1 << (vmdq - 32));
-                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar_hi);
-               }
-
-               /* was that the last pool using this rar? */
-               if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0)
-                       hw->mac.ops.clear_rar(hw, rar);
-       } else {
-               hw_dbg(hw, "RAR index %d is out of range.\n", rar);
-       }
-
-done:
-       return 0;
-}
-
-/**
- *  ixgbe_set_vmdq_82599 - Associate a VMDq pool index with a rx address
- *  @hw: pointer to hardware struct
- *  @rar: receive address register index to associate with a VMDq index
- *  @vmdq: VMDq pool index
- **/
-static s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
-{
-       u32 mpsar;
-       u32 rar_entries = hw->mac.num_rar_entries;
-
-       if (rar < rar_entries) {
-               if (vmdq < 32) {
-                       mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
-                       mpsar |= 1 << vmdq;
-                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar);
-               } else {
-                       mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
-                       mpsar |= 1 << (vmdq - 32);
-                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar);
-               }
-       } else {
-               hw_dbg(hw, "RAR index %d is out of range.\n", rar);
-       }
-       return 0;
-}
-
-/**
- *  ixgbe_set_vfta_82599 - Set VLAN filter table
- *  @hw: pointer to hardware structure
- *  @vlan: VLAN id to write to VLAN filter
- *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
- *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
- *
- *  Turn on/off specified VLAN in the VLAN filter table.
- **/
-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;
-
-       /*
-        * this is a 2 part operation - first the VFTA, then the
-        * VLVF and VLVFB if vind is set
-        */
-
-       /* Part 1
-        * The VFTA is a bitstring made up of 128 32-bit registers
-        * that enable the particular VLAN id, much like the MTA:
-        *    bits[11-5]: which register
-        *    bits[4-0]:  which bit in the register
-        */
-       regindex = (vlan >> 5) & 0x7F;
-       bitindex = vlan & 0x1F;
-       bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
-       if (vlan_on)
-               bits |= (1 << bitindex);
-       else
-               bits &= ~(1 << bitindex);
-       IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits);
-
-
-       /* Part 2
-        * 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
-        */
-       vt_ctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
-       if (!(vt_ctl & IXGBE_VT_CTL_VT_ENABLE))
-               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(vlvf_index * 2));
-                       bits |= (1 << vind);
-                       IXGBE_WRITE_REG(hw,
-                                       IXGBE_VLVFB(vlvf_index * 2), bits);
-               } 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);
-               }
-       } 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(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(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;
-}
-
-/**
- *  ixgbe_clear_vfta_82599 - Clear VLAN filter table
- *  @hw: pointer to hardware structure
- *
- *  Clears the VLAN filer table, and the VMDq index associated with the filter
- **/
-static s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw)
-{
-       u32 offset;
-
-       for (offset = 0; offset < hw->mac.vft_size; offset++)
-               IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
-
-       for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) {
-               IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_VLVFB((offset * 2) + 1), 0);
-       }
-
-       return 0;
-}
-
-/**
- *  ixgbe_init_uta_tables_82599 - Initialize the Unicast Table Array
- *  @hw: pointer to hardware structure
- **/
-static s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw)
-{
-       int i;
-       hw_dbg(hw, " Clearing UTA\n");
-
-       for (i = 0; i < 128; i++)
-               IXGBE_WRITE_REG(hw, IXGBE_UTA(i), 0);
-
-       return 0;
-}
-
 /**
  *  ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables.
  *  @hw: pointer to hardware structure
@@ -1303,7 +996,7 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw)
        }
        if (i >= IXGBE_FDIRCMD_CMD_POLL) {
                hw_dbg(hw ,"Flow Director previous command isn't complete, "
-                      "aborting table re-initialization. \n");
+                      "aborting table re-initialization.\n");
                return IXGBE_ERR_FDIR_REINIT_FAILED;
        }
 
@@ -2462,10 +2155,14 @@ sfp_check:
                goto out;
 
        switch (hw->phy.type) {
-       case ixgbe_phy_tw_tyco:
-       case ixgbe_phy_tw_unknown:
+       case ixgbe_phy_sfp_passive_tyco:
+       case ixgbe_phy_sfp_passive_unknown:
                physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
                break;
+       case ixgbe_phy_sfp_ftl_active:
+       case ixgbe_phy_sfp_active_unknown:
+               physical_layer = IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA;
+               break;
        case ixgbe_phy_sfp_avago:
        case ixgbe_phy_sfp_ftl:
        case ixgbe_phy_sfp_intel:
@@ -2544,75 +2241,6 @@ static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps)
        return 0;
 }
 
-/**
- *  ixgbe_get_san_mac_addr_offset_82599 - SAN MAC address offset for 82599
- *  @hw: pointer to hardware structure
- *  @san_mac_offset: SAN MAC address offset
- *
- *  This function will read the EEPROM location for the SAN MAC address
- *  pointer, and returns the value at that location.  This is used in both
- *  get and set mac_addr routines.
- **/
-static s32 ixgbe_get_san_mac_addr_offset_82599(struct ixgbe_hw *hw,
-                                               u16 *san_mac_offset)
-{
-       /*
-        * First read the EEPROM pointer to see if the MAC addresses are
-        * available.
-        */
-       hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, san_mac_offset);
-
-       return 0;
-}
-
-/**
- *  ixgbe_get_san_mac_addr_82599 - SAN MAC address retrieval for 82599
- *  @hw: pointer to hardware structure
- *  @san_mac_addr: SAN MAC address
- *
- *  Reads the SAN MAC address from the EEPROM, if it's available.  This is
- *  per-port, so set_lan_id() must be called before reading the addresses.
- *  set_lan_id() is called by identify_sfp(), but this cannot be relied
- *  upon for non-SFP connections, so we must call it here.
- **/
-static s32 ixgbe_get_san_mac_addr_82599(struct ixgbe_hw *hw, u8 *san_mac_addr)
-{
-       u16 san_mac_data, san_mac_offset;
-       u8 i;
-
-       /*
-        * First read the EEPROM pointer to see if the MAC addresses are
-        * available.  If they're not, no point in calling set_lan_id() here.
-        */
-       ixgbe_get_san_mac_addr_offset_82599(hw, &san_mac_offset);
-
-       if ((san_mac_offset == 0) || (san_mac_offset == 0xFFFF)) {
-               /*
-                * No addresses available in this EEPROM.  It's not an
-                * error though, so just wipe the local address and return.
-                */
-               for (i = 0; i < 6; i++)
-                       san_mac_addr[i] = 0xFF;
-
-               goto san_mac_addr_out;
-       }
-
-       /* make sure we know which port we need to program */
-       hw->mac.ops.set_lan_id(hw);
-       /* apply the port offset to the address offset */
-       (hw->bus.func) ? (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT1_OFFSET) :
-                        (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT0_OFFSET);
-       for (i = 0; i < 3; i++) {
-               hw->eeprom.ops.read(hw, san_mac_offset, &san_mac_data);
-               san_mac_addr[i * 2] = (u8)(san_mac_data);
-               san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8);
-               san_mac_offset++;
-       }
-
-san_mac_addr_out:
-       return 0;
-}
-
 /**
  *  ixgbe_verify_fw_version_82599 - verify fw version for 82599
  *  @hw: pointer to hardware structure
@@ -2715,7 +2343,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
        .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82599,
        .enable_rx_dma          = &ixgbe_enable_rx_dma_82599,
        .get_mac_addr           = &ixgbe_get_mac_addr_generic,
-       .get_san_mac_addr       = &ixgbe_get_san_mac_addr_82599,
+       .get_san_mac_addr       = &ixgbe_get_san_mac_addr_generic,
        .get_device_caps        = &ixgbe_get_device_caps_82599,
        .get_wwn_prefix         = &ixgbe_get_wwn_prefix_82599,
        .stop_adapter           = &ixgbe_stop_adapter_generic,
@@ -2724,7 +2352,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
        .read_analog_reg8       = &ixgbe_read_analog_reg8_82599,
        .write_analog_reg8      = &ixgbe_write_analog_reg8_82599,
        .setup_link             = &ixgbe_setup_mac_link_82599,
-       .check_link             = &ixgbe_check_mac_link_82599,
+       .check_link             = &ixgbe_check_mac_link_generic,
        .get_link_capabilities  = &ixgbe_get_link_capabilities_82599,
        .led_on                 = &ixgbe_led_on_generic,
        .led_off                = &ixgbe_led_off_generic,
@@ -2732,23 +2360,23 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
        .blink_led_stop         = &ixgbe_blink_led_stop_generic,
        .set_rar                = &ixgbe_set_rar_generic,
        .clear_rar              = &ixgbe_clear_rar_generic,
-       .set_vmdq               = &ixgbe_set_vmdq_82599,
-       .clear_vmdq             = &ixgbe_clear_vmdq_82599,
+       .set_vmdq               = &ixgbe_set_vmdq_generic,
+       .clear_vmdq             = &ixgbe_clear_vmdq_generic,
        .init_rx_addrs          = &ixgbe_init_rx_addrs_generic,
        .update_uc_addr_list    = &ixgbe_update_uc_addr_list_generic,
        .update_mc_addr_list    = &ixgbe_update_mc_addr_list_generic,
        .enable_mc              = &ixgbe_enable_mc_generic,
        .disable_mc             = &ixgbe_disable_mc_generic,
-       .clear_vfta             = &ixgbe_clear_vfta_82599,
-       .set_vfta               = &ixgbe_set_vfta_82599,
-       .fc_enable               = &ixgbe_fc_enable_generic,
-       .init_uta_tables        = &ixgbe_init_uta_tables_82599,
+       .clear_vfta             = &ixgbe_clear_vfta_generic,
+       .set_vfta               = &ixgbe_set_vfta_generic,
+       .fc_enable              = &ixgbe_fc_enable_generic,
+       .init_uta_tables        = &ixgbe_init_uta_tables_generic,
        .setup_sfp              = &ixgbe_setup_sfp_modules_82599,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
        .init_params            = &ixgbe_init_eeprom_params_generic,
-       .read                   = &ixgbe_read_eeprom_generic,
+       .read                   = &ixgbe_read_eerd_generic,
        .write                  = &ixgbe_write_eeprom_generic,
        .validate_checksum      = &ixgbe_validate_eeprom_checksum_generic,
        .update_checksum        = &ixgbe_update_eeprom_checksum_generic,
@@ -2757,7 +2385,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
 static struct ixgbe_phy_operations phy_ops_82599 = {
        .identify               = &ixgbe_identify_phy_82599,
        .identify_sfp           = &ixgbe_identify_sfp_module_generic,
-       .init                   = &ixgbe_init_phy_ops_82599,
+       .init                               = &ixgbe_init_phy_ops_82599,
        .reset                  = &ixgbe_reset_phy_generic,
        .read_reg               = &ixgbe_read_phy_reg_generic,
        .write_reg              = &ixgbe_write_phy_reg_generic,
index eb49020903c12a019335d9ef27ca421721d35166..1159d9138f0577c84643ba3db8b263d995cd683a 100644 (file)
@@ -34,7 +34,6 @@
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
-static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw);
 static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw);
 static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw);
 static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw);
@@ -595,14 +594,14 @@ out:
 }
 
 /**
- *  ixgbe_read_eeprom_generic - Read EEPROM word using EERD
+ *  ixgbe_read_eerd_generic - Read EEPROM word using EERD
  *  @hw: pointer to hardware structure
  *  @offset: offset of  word in the EEPROM to read
  *  @data: word read from the EEPROM
  *
  *  Reads a 16 bit word from the EEPROM using the EERD register.
  **/
-s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
+s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
 {
        u32 eerd;
        s32 status;
@@ -614,15 +613,15 @@ s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
                goto out;
        }
 
-       eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) +
-              IXGBE_EEPROM_READ_REG_START;
+       eerd = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) +
+              IXGBE_EEPROM_RW_REG_START;
 
        IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
-       status = ixgbe_poll_eeprom_eerd_done(hw);
+       status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ);
 
        if (status == 0)
                *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
-                        IXGBE_EEPROM_READ_REG_DATA);
+                        IXGBE_EEPROM_RW_REG_DATA);
        else
                hw_dbg(hw, "Eeprom read timed out\n");
 
@@ -631,20 +630,26 @@ out:
 }
 
 /**
- *  ixgbe_poll_eeprom_eerd_done - Poll EERD status
+ *  ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status
  *  @hw: pointer to hardware structure
+ *  @ee_reg: EEPROM flag for polling
  *
- *  Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ *  Polls the status bit (bit 1) of the EERD or EEWR to determine when the
+ *  read or write is done respectively.
  **/
-static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw)
+s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
 {
        u32 i;
        u32 reg;
        s32 status = IXGBE_ERR_EEPROM;
 
-       for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) {
-               reg = IXGBE_READ_REG(hw, IXGBE_EERD);
-               if (reg & IXGBE_EEPROM_READ_REG_DONE) {
+       for (i = 0; i < IXGBE_EERD_EEWR_ATTEMPTS; i++) {
+               if (ee_reg == IXGBE_NVM_POLL_READ)
+                       reg = IXGBE_READ_REG(hw, IXGBE_EERD);
+               else
+                       reg = IXGBE_READ_REG(hw, IXGBE_EEWR);
+
+               if (reg & IXGBE_EEPROM_RW_REG_DONE) {
                        status = 0;
                        break;
                }
@@ -1392,14 +1397,17 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
                        fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
                        fctrl |= IXGBE_FCTRL_UPE;
                        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+                       hw->addr_ctrl.uc_set_promisc = true;
                }
        } else {
                /* only disable if set by overflow, not by user */
-               if (old_promisc_setting && !hw->addr_ctrl.user_set_promisc) {
+               if ((old_promisc_setting && hw->addr_ctrl.uc_set_promisc) &&
+                  !(hw->addr_ctrl.user_set_promisc)) {
                        hw_dbg(hw, " Leaving address overflow promisc mode\n");
                        fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
                        fctrl &= ~IXGBE_FCTRL_UPE;
                        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+                       hw->addr_ctrl.uc_set_promisc = false;
                }
        }
 
@@ -1484,26 +1492,24 @@ static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr)
 /**
  *  ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses
  *  @hw: pointer to hardware structure
- *  @mc_addr_list: the list of new multicast addresses
- *  @mc_addr_count: number of addresses
- *  @next: iterator function to walk the multicast address list
+ *  @netdev: pointer to net device structure
  *
  *  The given list replaces any existing list. Clears the MC addrs from receive
  *  address registers and the multicast table. Uses unused receive address
  *  registers for the first multicast addresses, and hashes the rest into the
  *  multicast table.
  **/
-s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
-                                      u32 mc_addr_count, ixgbe_mc_addr_itr next)
+s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw,
+                                     struct net_device *netdev)
 {
+       struct netdev_hw_addr *ha;
        u32 i;
-       u32 vmdq;
 
        /*
         * Set the new number of MC addresses that we are being requested to
         * use.
         */
-       hw->addr_ctrl.num_mc_addrs = mc_addr_count;
+       hw->addr_ctrl.num_mc_addrs = netdev_mc_count(netdev);
        hw->addr_ctrl.mta_in_use = 0;
 
        /* Clear the MTA */
@@ -1512,9 +1518,9 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
                IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
 
        /* Add the new addresses */
-       for (i = 0; i < mc_addr_count; i++) {
+       netdev_for_each_mc_addr(ha, netdev) {
                hw_dbg(hw, " Adding the multicast addresses:\n");
-               ixgbe_set_mta(hw, next(hw, &mc_addr_list, &vmdq));
+               ixgbe_set_mta(hw, ha->addr);
        }
 
        /* Enable mta */
@@ -2254,3 +2260,490 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index)
 
        return 0;
 }
+
+/**
+ *  ixgbe_get_san_mac_addr_offset - Get SAN MAC address offset from the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @san_mac_offset: SAN MAC address offset
+ *
+ *  This function will read the EEPROM location for the SAN MAC address
+ *  pointer, and returns the value at that location.  This is used in both
+ *  get and set mac_addr routines.
+ **/
+static s32 ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw,
+                                        u16 *san_mac_offset)
+{
+       /*
+        * First read the EEPROM pointer to see if the MAC addresses are
+        * available.
+        */
+       hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, san_mac_offset);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_get_san_mac_addr_generic - SAN MAC address retrieval from the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @san_mac_addr: SAN MAC address
+ *
+ *  Reads the SAN MAC address from the EEPROM, if it's available.  This is
+ *  per-port, so set_lan_id() must be called before reading the addresses.
+ *  set_lan_id() is called by identify_sfp(), but this cannot be relied
+ *  upon for non-SFP connections, so we must call it here.
+ **/
+s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr)
+{
+       u16 san_mac_data, san_mac_offset;
+       u8 i;
+
+       /*
+        * First read the EEPROM pointer to see if the MAC addresses are
+        * available.  If they're not, no point in calling set_lan_id() here.
+        */
+       ixgbe_get_san_mac_addr_offset(hw, &san_mac_offset);
+
+       if ((san_mac_offset == 0) || (san_mac_offset == 0xFFFF)) {
+               /*
+                * No addresses available in this EEPROM.  It's not an
+                * error though, so just wipe the local address and return.
+                */
+               for (i = 0; i < 6; i++)
+                       san_mac_addr[i] = 0xFF;
+
+               goto san_mac_addr_out;
+       }
+
+       /* make sure we know which port we need to program */
+       hw->mac.ops.set_lan_id(hw);
+       /* apply the port offset to the address offset */
+       (hw->bus.func) ? (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT1_OFFSET) :
+                        (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT0_OFFSET);
+       for (i = 0; i < 3; i++) {
+               hw->eeprom.ops.read(hw, san_mac_offset, &san_mac_data);
+               san_mac_addr[i * 2] = (u8)(san_mac_data);
+               san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8);
+               san_mac_offset++;
+       }
+
+san_mac_addr_out:
+       return 0;
+}
+
+/**
+ *  ixgbe_get_pcie_msix_count_generic - Gets MSI-X vector count
+ *  @hw: pointer to hardware structure
+ *
+ *  Read PCIe configuration space, and get the MSI-X vector count from
+ *  the capabilities table.
+ **/
+u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       u16 msix_count;
+       pci_read_config_word(adapter->pdev, IXGBE_PCIE_MSIX_82599_CAPS,
+                            &msix_count);
+       msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK;
+
+       /* MSI-X count is zero-based in HW, so increment to give proper value */
+       msix_count++;
+
+       return msix_count;
+}
+
+/**
+ *  ixgbe_clear_vmdq_generic - Disassociate a VMDq pool index from a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to disassociate
+ *  @vmdq: VMDq pool index to remove from the rar
+ **/
+s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+{
+       u32 mpsar_lo, mpsar_hi;
+       u32 rar_entries = hw->mac.num_rar_entries;
+
+       if (rar < rar_entries) {
+               mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
+               mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
+
+               if (!mpsar_lo && !mpsar_hi)
+                       goto done;
+
+               if (vmdq == IXGBE_CLEAR_VMDQ_ALL) {
+                       if (mpsar_lo) {
+                               IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), 0);
+                               mpsar_lo = 0;
+                       }
+                       if (mpsar_hi) {
+                               IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), 0);
+                               mpsar_hi = 0;
+                       }
+               } else if (vmdq < 32) {
+                       mpsar_lo &= ~(1 << vmdq);
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar_lo);
+               } else {
+                       mpsar_hi &= ~(1 << (vmdq - 32));
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar_hi);
+               }
+
+               /* was that the last pool using this rar? */
+               if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0)
+                       hw->mac.ops.clear_rar(hw, rar);
+       } else {
+               hw_dbg(hw, "RAR index %d is out of range.\n", rar);
+       }
+
+done:
+       return 0;
+}
+
+/**
+ *  ixgbe_set_vmdq_generic - Associate a VMDq pool index with a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to associate with a VMDq index
+ *  @vmdq: VMDq pool index
+ **/
+s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+{
+       u32 mpsar;
+       u32 rar_entries = hw->mac.num_rar_entries;
+
+       if (rar < rar_entries) {
+               if (vmdq < 32) {
+                       mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
+                       mpsar |= 1 << vmdq;
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar);
+               } else {
+                       mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
+                       mpsar |= 1 << (vmdq - 32);
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar);
+               }
+       } else {
+               hw_dbg(hw, "RAR index %d is out of range.\n", rar);
+       }
+       return 0;
+}
+
+/**
+ *  ixgbe_init_uta_tables_generic - Initialize the Unicast Table Array
+ *  @hw: pointer to hardware structure
+ **/
+s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw)
+{
+       int i;
+
+
+       for (i = 0; i < 128; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_UTA(i), 0);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_find_vlvf_slot - find the vlanid or the first empty slot
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *
+ *  return the VLVF index where this VLAN id should be placed
+ *
+ **/
+s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
+{
+       u32 bits = 0;
+       u32 first_empty_slot = 0;
+       s32 regindex;
+
+       /* short cut the special case */
+       if (vlan == 0)
+               return 0;
+
+       /*
+         * Search for the vlan id in the VLVF entries. Save off the first empty
+         * slot found along the way
+         */
+       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;
+       }
+
+       /*
+         * If regindex is less than IXGBE_VLVF_ENTRIES, then we found the vlan
+         * in the VLVF. Else use the first empty VLVF register for this
+         * vlan id.
+         */
+       if (regindex >= IXGBE_VLVF_ENTRIES) {
+               if (first_empty_slot)
+                       regindex = first_empty_slot;
+               else {
+                       hw_dbg(hw, "No space in VLVF.\n");
+                       regindex = IXGBE_ERR_NO_SPACE;
+               }
+       }
+
+       return regindex;
+}
+
+/**
+ *  ixgbe_set_vfta_generic - Set VLAN filter table
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
+ *
+ *  Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+                           bool vlan_on)
+{
+       s32 regindex;
+       u32 bitindex;
+       u32 vfta;
+       u32 bits;
+       u32 vt;
+       u32 targetbit;
+       bool vfta_changed = false;
+
+       if (vlan > 4095)
+               return IXGBE_ERR_PARAM;
+
+       /*
+        * this is a 2 part operation - first the VFTA, then the
+        * VLVF and VLVFB if VT Mode is set
+        * We don't write the VFTA until we know the VLVF part succeeded.
+        */
+
+       /* Part 1
+        * The VFTA is a bitstring made up of 128 32-bit registers
+        * that enable the particular VLAN id, much like the MTA:
+        *    bits[11-5]: which register
+        *    bits[4-0]:  which bit in the register
+        */
+       regindex = (vlan >> 5) & 0x7F;
+       bitindex = vlan & 0x1F;
+       targetbit = (1 << bitindex);
+       vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
+
+       if (vlan_on) {
+               if (!(vfta & targetbit)) {
+                       vfta |= targetbit;
+                       vfta_changed = true;
+               }
+       } else {
+               if ((vfta & targetbit)) {
+                       vfta &= ~targetbit;
+                       vfta_changed = true;
+               }
+       }
+
+       /* Part 2
+        * 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
+        */
+       vt = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
+       if (vt & IXGBE_VT_CTL_VT_ENABLE) {
+               s32 vlvf_index;
+
+               vlvf_index = ixgbe_find_vlvf_slot(hw, vlan);
+               if (vlvf_index < 0)
+                       return vlvf_index;
+
+               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 {
+                               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(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 there are still bits set in the VLVFB registers
+                * for the VLAN ID indicated we need to see if the
+                * caller is requesting that we clear the VFTA entry bit.
+                * If the caller has requested that we clear the VFTA
+                * entry bit but there are still pools/VFs using this VLAN
+                * ID entry then ignore the request.  We're not worried
+                * about the case where we're turning the VFTA VLAN ID
+                * entry bit on, only when requested to turn it off as
+                * there may be multiple pools and/or VFs using the
+                * VLAN ID entry.  In that case we cannot clear the
+                * VFTA bit until all pools/VFs using that VLAN ID have also
+                * been cleared.  This will be indicated by "bits" being
+                * zero.
+                */
+               if (bits) {
+                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index),
+                                       (IXGBE_VLVF_VIEN | vlan));
+                       if (!vlan_on) {
+                               /* someone wants to clear the vfta entry
+                                * but some pools/VFs are still using it.
+                                * Ignore it. */
+                               vfta_changed = false;
+                       }
+               }
+               else
+                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
+       }
+
+       if (vfta_changed)
+               IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), vfta);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_clear_vfta_generic - Clear VLAN filter table
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw)
+{
+       u32 offset;
+
+       for (offset = 0; offset < hw->mac.vft_size; offset++)
+               IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+
+       for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) {
+               IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset*2), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVFB((offset*2)+1), 0);
+       }
+
+       return 0;
+}
+
+/**
+ *  ixgbe_check_mac_link_generic - Determine link and speed status
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @link_up: true when link is up
+ *  @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ *  Reads the links register to determine if link is up and the current speed
+ **/
+s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+                               bool *link_up, bool link_up_wait_to_complete)
+{
+       u32 links_reg;
+       u32 i;
+
+       links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+       if (link_up_wait_to_complete) {
+               for (i = 0; i < IXGBE_LINK_UP_TIME; i++) {
+                       if (links_reg & IXGBE_LINKS_UP) {
+                               *link_up = true;
+                               break;
+                       } else {
+                               *link_up = false;
+                       }
+                       msleep(100);
+                       links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+               }
+       } else {
+               if (links_reg & IXGBE_LINKS_UP)
+                       *link_up = true;
+               else
+                       *link_up = false;
+       }
+
+       if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
+           IXGBE_LINKS_SPEED_10G_82599)
+               *speed = IXGBE_LINK_SPEED_10GB_FULL;
+       else if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
+                IXGBE_LINKS_SPEED_1G_82599)
+               *speed = IXGBE_LINK_SPEED_1GB_FULL;
+       else
+               *speed = IXGBE_LINK_SPEED_100_FULL;
+
+       /* if link is down, zero out the current_mode */
+       if (*link_up == false) {
+               hw->fc.current_mode = ixgbe_fc_none;
+               hw->fc.fc_was_autonegged = false;
+       }
+
+       return 0;
+}
+
+/**
+ *  ixgbe_get_wwn_prefix_generic - Get alternative WWNN/WWPN prefix from
+ *  the EEPROM
+ *  @hw: pointer to hardware structure
+ *  @wwnn_prefix: the alternative WWNN prefix
+ *  @wwpn_prefix: the alternative WWPN prefix
+ *
+ *  This function will read the EEPROM from the alternative SAN MAC address
+ *  block to check the support for the alternative WWNN/WWPN prefix support.
+ **/
+s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix,
+                                 u16 *wwpn_prefix)
+{
+       u16 offset, caps;
+       u16 alt_san_mac_blk_offset;
+
+       /* clear output first */
+       *wwnn_prefix = 0xFFFF;
+       *wwpn_prefix = 0xFFFF;
+
+       /* check if alternative SAN MAC is supported */
+       hw->eeprom.ops.read(hw, IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR,
+                           &alt_san_mac_blk_offset);
+
+       if ((alt_san_mac_blk_offset == 0) ||
+           (alt_san_mac_blk_offset == 0xFFFF))
+               goto wwn_prefix_out;
+
+       /* check capability in alternative san mac address block */
+       offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET;
+       hw->eeprom.ops.read(hw, offset, &caps);
+       if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN))
+               goto wwn_prefix_out;
+
+       /* get the corresponding prefix for WWNN/WWPN */
+       offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET;
+       hw->eeprom.ops.read(hw, offset, wwnn_prefix);
+
+       offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET;
+       hw->eeprom.ops.read(hw, offset, wwpn_prefix);
+
+wwn_prefix_out:
+       return 0;
+}
index 13606d4809c90b8050b9087a2deb51dc0f43d7a6..3080afb12bdfef2641170bfe0269dc8210b82772 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "ixgbe_type.h"
 
+u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw);
 s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw);
@@ -45,20 +46,20 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index);
 
 s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw);
 s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
-s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
 s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
                                        u16 *data);
 s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
                                            u16 *checksum_val);
 s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw);
+s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
 
 s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
                           u32 enable_addr);
 s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index);
 s32 ixgbe_init_rx_addrs_generic(struct ixgbe_hw *hw);
-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_mc_addr_list_generic(struct ixgbe_hw *hw,
+                                     struct net_device *netdev);
 s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw,
                                      struct net_device *netdev);
 s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
@@ -71,9 +72,16 @@ s32 ixgbe_validate_mac_addr(u8 *mac_addr);
 s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
 void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
 s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
-
-s32 ixgbe_read_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 *val);
-s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val);
+s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr);
+s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
+s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
+s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw);
+s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan,
+                           u32 vind, bool vlan_on);
+s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw);
+s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw,
+                                 ixgbe_link_speed *speed,
+                                 bool *link_up, bool link_up_wait_to_complete);
 
 s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index);
 s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
index dd4883f642be0c8d411ba631d92b80de499f12d4..71da325dfa800bc73a17df67cfa3a3c2af3037cd 100644 (file)
@@ -488,7 +488,6 @@ static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
        if (adapter->temp_dcb_cfg.pfc_mode_enable !=
                adapter->dcb_cfg.pfc_mode_enable)
                adapter->dcb_set_bitmap |= BIT_PFC;
-       return;
 }
 
 /**
index 8f461d5cee7775da632822317da4151ac02a2ff4..c50a7541ffecf763fb0050de183f4db98f43b1b7 100644 (file)
@@ -212,8 +212,8 @@ static int ixgbe_get_settings(struct net_device *netdev,
                ecmd->port = PORT_FIBRE;
                break;
        case ixgbe_phy_nl:
-       case ixgbe_phy_tw_tyco:
-       case ixgbe_phy_tw_unknown:
+       case ixgbe_phy_sfp_passive_tyco:
+       case ixgbe_phy_sfp_passive_unknown:
        case ixgbe_phy_sfp_ftl:
        case ixgbe_phy_sfp_avago:
        case ixgbe_phy_sfp_intel:
@@ -365,7 +365,7 @@ static int ixgbe_set_pauseparam(struct net_device *netdev,
        else
                fc.disable_fc_autoneg = false;
 
-       if (pause->rx_pause && pause->tx_pause)
+       if ((pause->rx_pause && pause->tx_pause) || pause->autoneg)
                fc.requested_mode = ixgbe_fc_full;
        else if (pause->rx_pause && !pause->tx_pause)
                fc.requested_mode = ixgbe_fc_rx_pause;
@@ -1458,8 +1458,8 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
                        struct ixgbe_tx_buffer *buf =
                                        &(tx_ring->tx_buffer_info[i]);
                        if (buf->dma)
-                               pci_unmap_single(pdev, buf->dma, buf->length,
-                                                PCI_DMA_TODEVICE);
+                               dma_unmap_single(&pdev->dev, buf->dma,
+                                                buf->length, DMA_TO_DEVICE);
                        if (buf->skb)
                                dev_kfree_skb(buf->skb);
                }
@@ -1470,22 +1470,22 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
                        struct ixgbe_rx_buffer *buf =
                                        &(rx_ring->rx_buffer_info[i]);
                        if (buf->dma)
-                               pci_unmap_single(pdev, buf->dma,
+                               dma_unmap_single(&pdev->dev, buf->dma,
                                                 IXGBE_RXBUFFER_2048,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                        if (buf->skb)
                                dev_kfree_skb(buf->skb);
                }
        }
 
        if (tx_ring->desc) {
-               pci_free_consistent(pdev, tx_ring->size, tx_ring->desc,
-                                   tx_ring->dma);
+               dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+                                 tx_ring->dma);
                tx_ring->desc = NULL;
        }
        if (rx_ring->desc) {
-               pci_free_consistent(pdev, rx_ring->size, rx_ring->desc,
-                                   rx_ring->dma);
+               dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+                                 rx_ring->dma);
                rx_ring->desc = NULL;
        }
 
@@ -1493,8 +1493,6 @@ static void ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
        tx_ring->tx_buffer_info = NULL;
        kfree(rx_ring->rx_buffer_info);
        rx_ring->rx_buffer_info = NULL;
-
-       return;
 }
 
 static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
@@ -1520,8 +1518,9 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
 
        tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
-       if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
-                                                  &tx_ring->dma))) {
+       tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+                                          &tx_ring->dma, GFP_KERNEL);
+       if (!(tx_ring->desc)) {
                ret_val = 2;
                goto err_nomem;
        }
@@ -1563,8 +1562,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
                tx_ring->tx_buffer_info[i].skb = skb;
                tx_ring->tx_buffer_info[i].length = skb->len;
                tx_ring->tx_buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, skb->len,
-                                      PCI_DMA_TODEVICE);
+                       dma_map_single(&pdev->dev, skb->data, skb->len,
+                                      DMA_TO_DEVICE);
                desc->read.buffer_addr =
                                    cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
                desc->read.cmd_type_len = cpu_to_le32(skb->len);
@@ -1593,8 +1592,9 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
 
        rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
        rx_ring->size = ALIGN(rx_ring->size, 4096);
-       if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
-                                                  &rx_ring->dma))) {
+       rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+                                          &rx_ring->dma, GFP_KERNEL);
+       if (!(rx_ring->desc)) {
                ret_val = 5;
                goto err_nomem;
        }
@@ -1661,8 +1661,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
                skb_reserve(skb, NET_IP_ALIGN);
                rx_ring->rx_buffer_info[i].skb = skb;
                rx_ring->rx_buffer_info[i].dma =
-                       pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
-                                      PCI_DMA_FROMDEVICE);
+                       dma_map_single(&pdev->dev, skb->data,
+                                      IXGBE_RXBUFFER_2048, DMA_FROM_DEVICE);
                rx_desc->read.pkt_addr =
                                cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
                memset(skb->data, 0x00, skb->len);
@@ -1775,10 +1775,10 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
                        ixgbe_create_lbtest_frame(
                                        tx_ring->tx_buffer_info[k].skb,
                                        1024);
-                       pci_dma_sync_single_for_device(pdev,
+                       dma_sync_single_for_device(&pdev->dev,
                                tx_ring->tx_buffer_info[k].dma,
                                tx_ring->tx_buffer_info[k].length,
-                               PCI_DMA_TODEVICE);
+                               DMA_TO_DEVICE);
                        if (unlikely(++k == tx_ring->count))
                                k = 0;
                }
@@ -1789,10 +1789,10 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
                good_cnt = 0;
                do {
                        /* receive the sent packets */
-                       pci_dma_sync_single_for_cpu(pdev,
+                       dma_sync_single_for_cpu(&pdev->dev,
                                        rx_ring->rx_buffer_info[l].dma,
                                        IXGBE_RXBUFFER_2048,
-                                       PCI_DMA_FROMDEVICE);
+                                       DMA_FROM_DEVICE);
                        ret_val = ixgbe_check_lbtest_frame(
                                        rx_ring->rx_buffer_info[l].skb, 1024);
                        if (!ret_val)
@@ -1971,8 +1971,6 @@ static void ixgbe_get_wol(struct net_device *netdev,
                wol->wolopts |= WAKE_BCAST;
        if (adapter->wol & IXGBE_WUFC_MAG)
                wol->wolopts |= WAKE_MAGIC;
-
-       return;
 }
 
 static int ixgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
@@ -2079,12 +2077,32 @@ static int ixgbe_get_coalesce(struct net_device *netdev,
        return 0;
 }
 
+/*
+ * this function must be called before setting the new value of
+ * rx_itr_setting
+ */
+static bool ixgbe_reenable_rsc(struct ixgbe_adapter *adapter,
+                               struct ethtool_coalesce *ec)
+{
+       /* check the old value and enable RSC if necessary */
+       if ((adapter->rx_itr_setting == 0) &&
+           (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) {
+               adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+               adapter->netdev->features |= NETIF_F_LRO;
+               DPRINTK(PROBE, INFO, "rx-usecs set to %d, re-enabling RSC\n",
+                       ec->rx_coalesce_usecs);
+               return true;
+       }
+       return false;
+}
+
 static int ixgbe_set_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_q_vector *q_vector;
        int i;
+       bool need_reset = false;
 
        /* don't accept tx specific changes if we've got mixed RxTx vectors */
        if (adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count
@@ -2095,11 +2113,20 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                adapter->tx_ring[0]->work_limit = ec->tx_max_coalesced_frames_irq;
 
        if (ec->rx_coalesce_usecs > 1) {
+               u32 max_int;
+               if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
+                       max_int = IXGBE_MAX_RSC_INT_RATE;
+               else
+                       max_int = IXGBE_MAX_INT_RATE;
+
                /* check the limits */
-               if ((1000000/ec->rx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
+               if ((1000000/ec->rx_coalesce_usecs > max_int) ||
                    (1000000/ec->rx_coalesce_usecs < IXGBE_MIN_INT_RATE))
                        return -EINVAL;
 
+               /* check the old value and enable RSC if necessary */
+               need_reset = ixgbe_reenable_rsc(adapter, ec);
+
                /* store the value in ints/second */
                adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs;
 
@@ -2108,6 +2135,9 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                /* clear the lower bit as its used for dynamic state */
                adapter->rx_itr_setting &= ~1;
        } else if (ec->rx_coalesce_usecs == 1) {
+               /* check the old value and enable RSC if necessary */
+               need_reset = ixgbe_reenable_rsc(adapter, ec);
+
                /* 1 means dynamic mode */
                adapter->rx_eitr_param = 20000;
                adapter->rx_itr_setting = 1;
@@ -2116,14 +2146,30 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                 * any other value means disable eitr, which is best
                 * served by setting the interrupt rate very high
                 */
-               if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
-                       adapter->rx_eitr_param = IXGBE_MAX_RSC_INT_RATE;
-               else
-                       adapter->rx_eitr_param = IXGBE_MAX_INT_RATE;
+               adapter->rx_eitr_param = IXGBE_MAX_INT_RATE;
                adapter->rx_itr_setting = 0;
+
+               /*
+                * if hardware RSC is enabled, disable it when
+                * setting low latency mode, to avoid errata, assuming
+                * that when the user set low latency mode they want
+                * it at the cost of anything else
+                */
+               if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
+                       adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
+                       netdev->features &= ~NETIF_F_LRO;
+                       DPRINTK(PROBE, INFO,
+                               "rx-usecs set to 0, disabling RSC\n");
+
+                       need_reset = true;
+               }
        }
 
        if (ec->tx_coalesce_usecs > 1) {
+               /*
+                * don't have to worry about max_int as above because
+                * tx vectors don't do hardware RSC (an rx function)
+                */
                /* check the limits */
                if ((1000000/ec->tx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
                    (1000000/ec->tx_coalesce_usecs < IXGBE_MIN_INT_RATE))
@@ -2167,6 +2213,18 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                ixgbe_write_eitr(q_vector);
        }
 
+       /*
+        * do reset here at the end to make sure EITR==0 case is handled
+        * correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings
+        * also locks in RSC enable/disable which requires reset
+        */
+       if (need_reset) {
+               if (netif_running(netdev))
+                       ixgbe_reinit_locked(adapter);
+               else
+                       ixgbe_reset(adapter);
+       }
+
        return 0;
 }
 
@@ -2178,10 +2236,26 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
        ethtool_op_set_flags(netdev, data);
 
        /* if state changes we need to update adapter->flags and reset */
-       if ((!!(data & ETH_FLAG_LRO)) != 
-           (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
-               adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
-               need_reset = true;
+       if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
+               /*
+                * cast both to bool and verify if they are set the same
+                * but only enable RSC if itr is non-zero, as
+                * itr=0 and RSC are mutually exclusive
+                */
+               if (((!!(data & ETH_FLAG_LRO)) !=
+                    (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) &&
+                   adapter->rx_itr_setting) {
+                       adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
+                       switch (adapter->hw.mac.type) {
+                       case ixgbe_mac_82599EB:
+                               need_reset = true;
+                               break;
+                       default:
+                               break;
+                       }
+               } else if (!adapter->rx_itr_setting) {
+                       netdev->features &= ~ETH_FLAG_LRO;
+               }
        }
 
        /*
index 6493049b663d95e13f73ea5c252bffcd88e0c2cd..45182ab41d6b19d3acc973275edfbb378b7bd64b 100644 (file)
@@ -32,6 +32,7 @@
 #endif /* CONFIG_IXGBE_DCB */
 #include <linux/if_ether.h>
 #include <linux/gfp.h>
+#include <linux/if_vlan.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/fc/fc_fs.h>
@@ -312,10 +313,12 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
        if (fcerr == IXGBE_FCERR_BADCRC)
                skb->ip_summed = CHECKSUM_NONE;
 
-       skb_reset_network_header(skb);
-       skb_set_transport_header(skb, skb_network_offset(skb) +
-                                sizeof(struct fcoe_hdr));
-       fh = (struct fc_frame_header *)skb_transport_header(skb);
+       if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q))
+               fh = (struct fc_frame_header *)(skb->data +
+                       sizeof(struct vlan_hdr) + sizeof(struct fcoe_hdr));
+       else
+               fh = (struct fc_frame_header *)(skb->data +
+                       sizeof(struct fcoe_hdr));
        fctl = ntoh24(fh->fh_f_ctl);
        if (fctl & FC_FC_EX_CTX)
                xid =  be16_to_cpu(fh->fh_ox_id);
@@ -536,12 +539,6 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
                }
                IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA);
                IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0);
-               fcoe_i = f->mask;
-               fcoe_i &= IXGBE_FCRETA_ENTRY_MASK;
-               fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx;
-               IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP),
-                               IXGBE_ETQS_QUEUE_EN |
-                               (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT));
        } else  {
                /* Use single rx queue for FCoE */
                fcoe_i = f->mask;
index 6c00ee493a3bb1c1bae50b59fdb2afb58688c22e..9551cbb7bf01f532e3a5705f9e54e45d0cf8ae6e 100644 (file)
@@ -175,6 +175,345 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
        adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
 }
 
+struct ixgbe_reg_info {
+       u32 ofs;
+       char *name;
+};
+
+static const struct ixgbe_reg_info ixgbe_reg_info_tbl[] = {
+
+       /* General Registers */
+       {IXGBE_CTRL, "CTRL"},
+       {IXGBE_STATUS, "STATUS"},
+       {IXGBE_CTRL_EXT, "CTRL_EXT"},
+
+       /* Interrupt Registers */
+       {IXGBE_EICR, "EICR"},
+
+       /* RX Registers */
+       {IXGBE_SRRCTL(0), "SRRCTL"},
+       {IXGBE_DCA_RXCTRL(0), "DRXCTL"},
+       {IXGBE_RDLEN(0), "RDLEN"},
+       {IXGBE_RDH(0), "RDH"},
+       {IXGBE_RDT(0), "RDT"},
+       {IXGBE_RXDCTL(0), "RXDCTL"},
+       {IXGBE_RDBAL(0), "RDBAL"},
+       {IXGBE_RDBAH(0), "RDBAH"},
+
+       /* TX Registers */
+       {IXGBE_TDBAL(0), "TDBAL"},
+       {IXGBE_TDBAH(0), "TDBAH"},
+       {IXGBE_TDLEN(0), "TDLEN"},
+       {IXGBE_TDH(0), "TDH"},
+       {IXGBE_TDT(0), "TDT"},
+       {IXGBE_TXDCTL(0), "TXDCTL"},
+
+       /* List Terminator */
+       {}
+};
+
+
+/*
+ * ixgbe_regdump - register printout routine
+ */
+static void ixgbe_regdump(struct ixgbe_hw *hw, struct ixgbe_reg_info *reginfo)
+{
+       int i = 0, j = 0;
+       char rname[16];
+       u32 regs[64];
+
+       switch (reginfo->ofs) {
+       case IXGBE_SRRCTL(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
+               break;
+       case IXGBE_DCA_RXCTRL(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
+               break;
+       case IXGBE_RDLEN(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
+               break;
+       case IXGBE_RDH(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
+               break;
+       case IXGBE_RDT(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
+               break;
+       case IXGBE_RXDCTL(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+               break;
+       case IXGBE_RDBAL(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
+               break;
+       case IXGBE_RDBAH(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
+               break;
+       case IXGBE_TDBAL(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
+               break;
+       case IXGBE_TDBAH(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
+               break;
+       case IXGBE_TDLEN(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
+               break;
+       case IXGBE_TDH(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
+               break;
+       case IXGBE_TDT(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
+               break;
+       case IXGBE_TXDCTL(0):
+               for (i = 0; i < 64; i++)
+                       regs[i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+               break;
+       default:
+               printk(KERN_INFO "%-15s %08x\n", reginfo->name,
+                       IXGBE_READ_REG(hw, reginfo->ofs));
+               return;
+       }
+
+       for (i = 0; i < 8; i++) {
+               snprintf(rname, 16, "%s[%d-%d]", reginfo->name, i*8, i*8+7);
+               printk(KERN_ERR "%-15s ", rname);
+               for (j = 0; j < 8; j++)
+                       printk(KERN_CONT "%08x ", regs[i*8+j]);
+               printk(KERN_CONT "\n");
+       }
+
+}
+
+/*
+ * ixgbe_dump - Print registers, tx-rings and rx-rings
+ */
+static void ixgbe_dump(struct ixgbe_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct ixgbe_hw *hw = &adapter->hw;
+       struct ixgbe_reg_info *reginfo;
+       int n = 0;
+       struct ixgbe_ring *tx_ring;
+       struct ixgbe_tx_buffer *tx_buffer_info;
+       union ixgbe_adv_tx_desc *tx_desc;
+       struct my_u0 { u64 a; u64 b; } *u0;
+       struct ixgbe_ring *rx_ring;
+       union ixgbe_adv_rx_desc *rx_desc;
+       struct ixgbe_rx_buffer *rx_buffer_info;
+       u32 staterr;
+       int i = 0;
+
+       if (!netif_msg_hw(adapter))
+               return;
+
+       /* Print netdevice Info */
+       if (netdev) {
+               dev_info(&adapter->pdev->dev, "Net device Info\n");
+               printk(KERN_INFO "Device Name     state            "
+                       "trans_start      last_rx\n");
+               printk(KERN_INFO "%-15s %016lX %016lX %016lX\n",
+               netdev->name,
+               netdev->state,
+               netdev->trans_start,
+               netdev->last_rx);
+       }
+
+       /* Print Registers */
+       dev_info(&adapter->pdev->dev, "Register Dump\n");
+       printk(KERN_INFO " Register Name   Value\n");
+       for (reginfo = (struct ixgbe_reg_info *)ixgbe_reg_info_tbl;
+            reginfo->name; reginfo++) {
+               ixgbe_regdump(hw, reginfo);
+       }
+
+       /* Print TX Ring Summary */
+       if (!netdev || !netif_running(netdev))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC] [bi(ntc)->dma  ] "
+               "leng ntw timestamp\n");
+       for (n = 0; n < adapter->num_tx_queues; n++) {
+               tx_ring = adapter->tx_ring[n];
+               tx_buffer_info =
+                       &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
+               printk(KERN_INFO " %5d %5X %5X %016llX %04X %3X %016llX\n",
+                          n, tx_ring->next_to_use, tx_ring->next_to_clean,
+                          (u64)tx_buffer_info->dma,
+                          tx_buffer_info->length,
+                          tx_buffer_info->next_to_watch,
+                          (u64)tx_buffer_info->time_stamp);
+       }
+
+       /* Print TX Rings */
+       if (!netif_msg_tx_done(adapter))
+               goto rx_ring_summary;
+
+       dev_info(&adapter->pdev->dev, "TX Rings Dump\n");
+
+       /* Transmit Descriptor Formats
+        *
+        * Advanced Transmit Descriptor
+        *   +--------------------------------------------------------------+
+        * 0 |         Buffer Address [63:0]                                |
+        *   +--------------------------------------------------------------+
+        * 8 |  PAYLEN  | PORTS  | IDX | STA | DCMD  |DTYP |  RSV |  DTALEN |
+        *   +--------------------------------------------------------------+
+        *   63       46 45    40 39 36 35 32 31   24 23 20 19              0
+        */
+
+       for (n = 0; n < adapter->num_tx_queues; n++) {
+               tx_ring = adapter->tx_ring[n];
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "TX QUEUE INDEX = %d\n", tx_ring->queue_index);
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "T [desc]     [address 63:0  ] "
+                       "[PlPOIdStDDt Ln] [bi->dma       ] "
+                       "leng  ntw timestamp        bi->skb\n");
+
+               for (i = 0; tx_ring->desc && (i < tx_ring->count); i++) {
+                       tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+                       tx_buffer_info = &tx_ring->tx_buffer_info[i];
+                       u0 = (struct my_u0 *)tx_desc;
+                       printk(KERN_INFO "T [0x%03X]    %016llX %016llX %016llX"
+                               " %04X  %3X %016llX %p", i,
+                               le64_to_cpu(u0->a),
+                               le64_to_cpu(u0->b),
+                               (u64)tx_buffer_info->dma,
+                               tx_buffer_info->length,
+                               tx_buffer_info->next_to_watch,
+                               (u64)tx_buffer_info->time_stamp,
+                               tx_buffer_info->skb);
+                       if (i == tx_ring->next_to_use &&
+                               i == tx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC/U\n");
+                       else if (i == tx_ring->next_to_use)
+                               printk(KERN_CONT " NTU\n");
+                       else if (i == tx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC\n");
+                       else
+                               printk(KERN_CONT "\n");
+
+                       if (netif_msg_pktdata(adapter) &&
+                               tx_buffer_info->dma != 0)
+                               print_hex_dump(KERN_INFO, "",
+                                       DUMP_PREFIX_ADDRESS, 16, 1,
+                                       phys_to_virt(tx_buffer_info->dma),
+                                       tx_buffer_info->length, true);
+               }
+       }
+
+       /* Print RX Rings Summary */
+rx_ring_summary:
+       dev_info(&adapter->pdev->dev, "RX Rings Summary\n");
+       printk(KERN_INFO "Queue [NTU] [NTC]\n");
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               printk(KERN_INFO "%5d %5X %5X\n", n,
+                          rx_ring->next_to_use, rx_ring->next_to_clean);
+       }
+
+       /* Print RX Rings */
+       if (!netif_msg_rx_status(adapter))
+               goto exit;
+
+       dev_info(&adapter->pdev->dev, "RX Rings Dump\n");
+
+       /* Advanced Receive Descriptor (Read) Format
+        *    63                                           1        0
+        *    +-----------------------------------------------------+
+        *  0 |       Packet Buffer Address [63:1]           |A0/NSE|
+        *    +----------------------------------------------+------+
+        *  8 |       Header Buffer Address [63:1]           |  DD  |
+        *    +-----------------------------------------------------+
+        *
+        *
+        * Advanced Receive Descriptor (Write-Back) Format
+        *
+        *   63       48 47    32 31  30      21 20 16 15   4 3     0
+        *   +------------------------------------------------------+
+        * 0 | Packet     IP     |SPH| HDR_LEN   | RSV|Packet|  RSS |
+        *   | Checksum   Ident  |   |           |    | Type | Type |
+        *   +------------------------------------------------------+
+        * 8 | VLAN Tag | Length | Extended Error | Extended Status |
+        *   +------------------------------------------------------+
+        *   63       48 47    32 31            20 19               0
+        */
+       for (n = 0; n < adapter->num_rx_queues; n++) {
+               rx_ring = adapter->rx_ring[n];
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "RX QUEUE INDEX = %d\n", rx_ring->queue_index);
+               printk(KERN_INFO "------------------------------------\n");
+               printk(KERN_INFO "R  [desc]      [ PktBuf     A0] "
+                       "[  HeadBuf   DD] [bi->dma       ] [bi->skb] "
+                       "<-- Adv Rx Read format\n");
+               printk(KERN_INFO "RWB[desc]      [PcsmIpSHl PtRs] "
+                       "[vl er S cks ln] ---------------- [bi->skb] "
+                       "<-- Adv Rx Write-Back format\n");
+
+               for (i = 0; i < rx_ring->count; i++) {
+                       rx_buffer_info = &rx_ring->rx_buffer_info[i];
+                       rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+                       u0 = (struct my_u0 *)rx_desc;
+                       staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+                       if (staterr & IXGBE_RXD_STAT_DD) {
+                               /* Descriptor Done */
+                               printk(KERN_INFO "RWB[0x%03X]     %016llX "
+                                       "%016llX ---------------- %p", i,
+                                       le64_to_cpu(u0->a),
+                                       le64_to_cpu(u0->b),
+                                       rx_buffer_info->skb);
+                       } else {
+                               printk(KERN_INFO "R  [0x%03X]     %016llX "
+                                       "%016llX %016llX %p", i,
+                                       le64_to_cpu(u0->a),
+                                       le64_to_cpu(u0->b),
+                                       (u64)rx_buffer_info->dma,
+                                       rx_buffer_info->skb);
+
+                               if (netif_msg_pktdata(adapter)) {
+                                       print_hex_dump(KERN_INFO, "",
+                                          DUMP_PREFIX_ADDRESS, 16, 1,
+                                          phys_to_virt(rx_buffer_info->dma),
+                                          rx_ring->rx_buf_len, true);
+
+                                       if (rx_ring->rx_buf_len
+                                               < IXGBE_RXBUFFER_2048)
+                                               print_hex_dump(KERN_INFO, "",
+                                                 DUMP_PREFIX_ADDRESS, 16, 1,
+                                                 phys_to_virt(
+                                                   rx_buffer_info->page_dma +
+                                                   rx_buffer_info->page_offset
+                                                 ),
+                                                 PAGE_SIZE/2, true);
+                               }
+                       }
+
+                       if (i == rx_ring->next_to_use)
+                               printk(KERN_CONT " NTU\n");
+                       else if (i == rx_ring->next_to_clean)
+                               printk(KERN_CONT " NTC\n");
+                       else
+                               printk(KERN_CONT "\n");
+
+               }
+       }
+
+exit:
+       return;
+}
+
 static void ixgbe_release_hw_control(struct ixgbe_adapter *adapter)
 {
        u32 ctrl_ext;
@@ -266,15 +605,15 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
 {
        if (tx_buffer_info->dma) {
                if (tx_buffer_info->mapped_as_page)
-                       pci_unmap_page(adapter->pdev,
+                       dma_unmap_page(&adapter->pdev->dev,
                                       tx_buffer_info->dma,
                                       tx_buffer_info->length,
-                                      PCI_DMA_TODEVICE);
+                                      DMA_TO_DEVICE);
                else
-                       pci_unmap_single(adapter->pdev,
+                       dma_unmap_single(&adapter->pdev->dev,
                                         tx_buffer_info->dma,
                                         tx_buffer_info->length,
-                                        PCI_DMA_TODEVICE);
+                                        DMA_TO_DEVICE);
                tx_buffer_info->dma = 0;
        }
        if (tx_buffer_info->skb) {
@@ -286,16 +625,16 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
 }
 
 /**
- * ixgbe_tx_is_paused - check if the tx ring is paused
+ * ixgbe_tx_xon_state - check the tx ring xon state
  * @adapter: the ixgbe adapter
  * @tx_ring: the corresponding tx_ring
  *
  * If not in DCB mode, checks TFCS.TXOFF, otherwise, find out the
  * corresponding TC of this tx_ring when checking TFCS.
  *
- * Returns : true if paused
+ * Returns : true if in xon state (currently not paused)
  */
-static inline bool ixgbe_tx_is_paused(struct ixgbe_adapter *adapter,
+static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
                                       struct ixgbe_ring *tx_ring)
 {
        u32 txoff = IXGBE_TFCS_TXOFF;
@@ -351,7 +690,7 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
        adapter->detect_tx_hung = false;
        if (tx_ring->tx_buffer_info[eop].time_stamp &&
            time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
-           !ixgbe_tx_is_paused(adapter, tx_ring)) {
+           ixgbe_tx_xon_state(adapter, tx_ring)) {
                /* detected Tx unit hang */
                union ixgbe_adv_tx_desc *tx_desc;
                tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
@@ -721,10 +1060,10 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
                                bi->page_offset ^= (PAGE_SIZE / 2);
                        }
 
-                       bi->page_dma = pci_map_page(pdev, bi->page,
+                       bi->page_dma = dma_map_page(&pdev->dev, bi->page,
                                                    bi->page_offset,
                                                    (PAGE_SIZE / 2),
-                                                   PCI_DMA_FROMDEVICE);
+                                                   DMA_FROM_DEVICE);
                }
 
                if (!bi->skb) {
@@ -743,9 +1082,9 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
                                          - skb->data));
 
                        bi->skb = skb;
-                       bi->dma = pci_map_single(pdev, skb->data,
+                       bi->dma = dma_map_single(&pdev->dev, skb->data,
                                                 rx_ring->rx_buf_len,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
                 * each write-back erases this info. */
@@ -821,6 +1160,7 @@ static inline struct sk_buff *ixgbe_transform_rsc_queue(struct sk_buff *skb,
 
 struct ixgbe_rsc_cb {
        dma_addr_t dma;
+       bool delay_unmap;
 };
 
 #define IXGBE_RSC_CB(skb) ((struct ixgbe_rsc_cb *)(skb)->cb)
@@ -861,9 +1201,10 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                        hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc));
                        len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
                               IXGBE_RXDADV_HDRBUFLEN_SHIFT;
-                       if (len > IXGBE_RX_HDR_SIZE)
-                               len = IXGBE_RX_HDR_SIZE;
                        upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+                       if ((len > IXGBE_RX_HDR_SIZE) ||
+                           (upper_len && !(hdr_info & IXGBE_RXDADV_SPH)))
+                               len = IXGBE_RX_HDR_SIZE;
                } else {
                        len = le16_to_cpu(rx_desc->wb.upper.length);
                }
@@ -876,7 +1217,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                if (rx_buffer_info->dma) {
                        if ((adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) &&
                            (!(staterr & IXGBE_RXD_STAT_EOP)) &&
-                                (!(skb->prev)))
+                                (!(skb->prev))) {
                                /*
                                 * When HWRSC is enabled, delay unmapping
                                 * of the first packet. It carries the
@@ -884,18 +1225,21 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                                 * access the header after the writeback.
                                 * Only unmap it when EOP is reached
                                 */
+                               IXGBE_RSC_CB(skb)->delay_unmap = true;
                                IXGBE_RSC_CB(skb)->dma = rx_buffer_info->dma;
-                       else
-                               pci_unmap_single(pdev, rx_buffer_info->dma,
+                       } else {
+                               dma_unmap_single(&pdev->dev,
+                                                rx_buffer_info->dma,
                                                 rx_ring->rx_buf_len,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
+                       }
                        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);
+                       dma_unmap_page(&pdev->dev, rx_buffer_info->page_dma,
+                                      PAGE_SIZE / 2, DMA_FROM_DEVICE);
                        rx_buffer_info->page_dma = 0;
                        skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
                                           rx_buffer_info->page,
@@ -936,11 +1280,13 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
                        if (skb->prev)
                                skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count));
                        if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
-                               if (IXGBE_RSC_CB(skb)->dma) {
-                                       pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma,
+                               if (IXGBE_RSC_CB(skb)->delay_unmap) {
+                                       dma_unmap_single(&pdev->dev,
+                                                        IXGBE_RSC_CB(skb)->dma,
                                                         rx_ring->rx_buf_len,
-                                                        PCI_DMA_FROMDEVICE);
+                                                        DMA_FROM_DEVICE);
                                        IXGBE_RSC_CB(skb)->dma = 0;
+                                       IXGBE_RSC_CB(skb)->delay_unmap = false;
                                }
                                if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED)
                                        rx_ring->rsc_count += skb_shinfo(skb)->nr_frags;
@@ -1189,6 +1535,15 @@ void ixgbe_write_eitr(struct ixgbe_q_vector *q_vector)
                /* must write high and low 16 bits to reset counter */
                itr_reg |= (itr_reg << 16);
        } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               /*
+                * 82599 can support a value of zero, so allow it for
+                * max interrupt rate, but there is an errata where it can
+                * not be zero with RSC
+                */
+               if (itr_reg == 8 &&
+                   !(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))
+                       itr_reg = 0;
+
                /*
                 * set the WDIS bit to not clear the timer bits and cause an
                 * immediate assertion of the interrupt
@@ -1261,8 +1616,6 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
 
                ixgbe_write_eitr(q_vector);
        }
-
-       return;
 }
 
 static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
@@ -1826,8 +2179,6 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
 
                ixgbe_write_eitr(q_vector);
        }
-
-       return;
 }
 
 /**
@@ -2372,7 +2723,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                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);
+               ixgbe_set_vmolr(hw, adapter->num_vfs, true);
        }
 
        /* Program MRQC for the distribution of queues */
@@ -2482,12 +2833,82 @@ static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
        hw->mac.ops.set_vfta(&adapter->hw, vid, pool_ndx, false);
 }
 
+/**
+ * ixgbe_vlan_filter_disable - helper to disable hw vlan filtering
+ * @adapter: driver data
+ */
+static void ixgbe_vlan_filter_disable(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+       int i, j;
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
+               vlnctrl &= ~IXGBE_VLNCTRL_VFE;
+#ifdef CONFIG_IXGBE_DCB
+               if (!(adapter->flags & IXGBE_FLAG_DCB_ENABLED))
+                       vlnctrl &= ~IXGBE_VLNCTRL_VME;
+#endif
+               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+               break;
+       case ixgbe_mac_82599EB:
+               vlnctrl &= ~IXGBE_VLNCTRL_VFE;
+               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+#ifdef CONFIG_IXGBE_DCB
+               if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
+                       break;
+#endif
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+                       j = adapter->rx_ring[i]->reg_idx;
+                       vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
+                       vlnctrl &= ~IXGBE_RXDCTL_VME;
+                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+/**
+ * ixgbe_vlan_filter_enable - helper to enable hw vlan filtering
+ * @adapter: driver data
+ */
+static void ixgbe_vlan_filter_enable(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+       int i, j;
+
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
+               vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+               break;
+       case ixgbe_mac_82599EB:
+               vlnctrl |= IXGBE_VLNCTRL_VFE;
+               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+                       j = adapter->rx_ring[i]->reg_idx;
+                       vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
+                       vlnctrl |= IXGBE_RXDCTL_VME;
+                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
 static void ixgbe_vlan_rx_register(struct net_device *netdev,
                                    struct vlan_group *grp)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       u32 ctrl;
-       int i, j;
 
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                ixgbe_irq_disable(adapter);
@@ -2498,25 +2919,7 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
         * still receive traffic from a DCB-enabled host even if we're
         * not in DCB mode.
         */
-       ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
-
-       /* Disable CFI check */
-       ctrl &= ~IXGBE_VLNCTRL_CFIEN;
-
-       /* enable VLAN tag stripping */
-       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
-               ctrl |= IXGBE_VLNCTRL_VME;
-       } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
-               for (i = 0; i < adapter->num_rx_queues; i++) {
-                       u32 ctrl;
-                       j = adapter->rx_ring[i]->reg_idx;
-                       ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(j));
-                       ctrl |= IXGBE_RXDCTL_VME;
-                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(j), ctrl);
-               }
-       }
-
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+       ixgbe_vlan_filter_enable(adapter);
 
        ixgbe_vlan_rx_add_vid(netdev, 0);
 
@@ -2538,21 +2941,6 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
        }
 }
 
-static u8 *ixgbe_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;
-}
-
 /**
  * ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
  * @netdev: network interface device structure
@@ -2566,42 +2954,36 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 fctrl, vlnctrl;
-       u8 *addr_list = NULL;
-       int addr_count = 0;
+       u32 fctrl;
 
        /* Check for Promiscuous and All Multicast modes */
 
        fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
-       vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
 
        if (netdev->flags & IFF_PROMISC) {
-               hw->addr_ctrl.user_set_promisc = 1;
+               hw->addr_ctrl.user_set_promisc = true;
                fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
-               vlnctrl &= ~IXGBE_VLNCTRL_VFE;
+               /* don't hardware filter vlans in promisc mode */
+               ixgbe_vlan_filter_disable(adapter);
        } else {
                if (netdev->flags & IFF_ALLMULTI) {
                        fctrl |= IXGBE_FCTRL_MPE;
                        fctrl &= ~IXGBE_FCTRL_UPE;
-               } else {
+               } else if (!hw->addr_ctrl.uc_set_promisc) {
                        fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
                }
-               vlnctrl |= IXGBE_VLNCTRL_VFE;
-               hw->addr_ctrl.user_set_promisc = 0;
+               ixgbe_vlan_filter_enable(adapter);
+               hw->addr_ctrl.user_set_promisc = false;
        }
 
        IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
-       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
 
        /* reprogram secondary unicast list */
        hw->mac.ops.update_uc_addr_list(hw, netdev);
 
        /* reprogram multicast list */
-       addr_count = netdev_mc_count(netdev);
-       if (addr_count)
-               addr_list = netdev->mc_list->dmi_addr;
-       hw->mac.ops.update_mc_addr_list(hw, addr_list, addr_count,
-                                       ixgbe_addr_list_itr);
+       hw->mac.ops.update_mc_addr_list(hw, netdev);
+
        if (adapter->num_vfs)
                ixgbe_restore_vf_multicasts(adapter);
 }
@@ -2661,7 +3043,7 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter)
 static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 txdctl, vlnctrl;
+       u32 txdctl;
        int i, j;
 
        ixgbe_dcb_check_config(&adapter->dcb_cfg);
@@ -2679,22 +3061,8 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
        }
        /* Enable VLAN tag insert/strip */
-       vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
-       if (hw->mac.type == ixgbe_mac_82598EB) {
-               vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
-               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
-               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
-       } else if (hw->mac.type == ixgbe_mac_82599EB) {
-               vlnctrl |= IXGBE_VLNCTRL_VFE;
-               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
-               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
-               for (i = 0; i < adapter->num_rx_queues; i++) {
-                       j = adapter->rx_ring[i]->reg_idx;
-                       vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
-                       vlnctrl |= IXGBE_RXDCTL_VME;
-                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
-               }
-       }
+       ixgbe_vlan_filter_enable(adapter);
+
        hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
 }
 
@@ -2750,8 +3118,10 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
        case ixgbe_phy_sfp_ftl:
        case ixgbe_phy_sfp_intel:
        case ixgbe_phy_sfp_unknown:
-       case ixgbe_phy_tw_tyco:
-       case ixgbe_phy_tw_unknown:
+       case ixgbe_phy_sfp_passive_tyco:
+       case ixgbe_phy_sfp_passive_unknown:
+       case ixgbe_phy_sfp_active_unknown:
+       case ixgbe_phy_sfp_ftl_active:
                return true;
        default:
                return false;
@@ -2927,8 +3297,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        for (i = 0; i < adapter->num_tx_queues; i++) {
                j = adapter->tx_ring[i]->reg_idx;
                txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
-               /* enable WTHRESH=8 descriptors, to encourage burst writeback */
-               txdctl |= (8 << 16);
+               if (adapter->rx_itr_setting == 0) {
+                       /* cannot set wthresh when itr==0 */
+                       txdctl &= ~0x007F0000;
+               } else {
+                       /* enable WTHRESH=8 descriptors, to encourage burst writeback */
+                       txdctl |= (8 << 16);
+               }
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
        }
 
@@ -3131,9 +3506,9 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
 
                rx_buffer_info = &rx_ring->rx_buffer_info[i];
                if (rx_buffer_info->dma) {
-                       pci_unmap_single(pdev, rx_buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, rx_buffer_info->dma,
                                         rx_ring->rx_buf_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        rx_buffer_info->dma = 0;
                }
                if (rx_buffer_info->skb) {
@@ -3141,11 +3516,13 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
                        rx_buffer_info->skb = NULL;
                        do {
                                struct sk_buff *this = skb;
-                               if (IXGBE_RSC_CB(this)->dma) {
-                                       pci_unmap_single(pdev, IXGBE_RSC_CB(this)->dma,
+                               if (IXGBE_RSC_CB(this)->delay_unmap) {
+                                       dma_unmap_single(&pdev->dev,
+                                                        IXGBE_RSC_CB(this)->dma,
                                                         rx_ring->rx_buf_len,
-                                                        PCI_DMA_FROMDEVICE);
+                                                        DMA_FROM_DEVICE);
                                        IXGBE_RSC_CB(this)->dma = 0;
+                                       IXGBE_RSC_CB(skb)->delay_unmap = false;
                                }
                                skb = skb->prev;
                                dev_kfree_skb(this);
@@ -3154,8 +3531,8 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
                if (!rx_buffer_info->page)
                        continue;
                if (rx_buffer_info->page_dma) {
-                       pci_unmap_page(pdev, rx_buffer_info->page_dma,
-                                      PAGE_SIZE / 2, PCI_DMA_FROMDEVICE);
+                       dma_unmap_page(&pdev->dev, rx_buffer_info->page_dma,
+                                      PAGE_SIZE / 2, DMA_FROM_DEVICE);
                        rx_buffer_info->page_dma = 0;
                }
                put_page(rx_buffer_info->page);
@@ -3268,22 +3645,23 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
        IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
 
-       netif_tx_disable(netdev);
-
        IXGBE_WRITE_FLUSH(hw);
        msleep(10);
 
        netif_tx_stop_all_queues(netdev);
 
-       ixgbe_irq_disable(adapter);
-
-       ixgbe_napi_disable_all(adapter);
-
        clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
        del_timer_sync(&adapter->sfp_timer);
        del_timer_sync(&adapter->watchdog_timer);
        cancel_work_sync(&adapter->watchdog_task);
 
+       netif_carrier_off(netdev);
+       netif_tx_disable(netdev);
+
+       ixgbe_irq_disable(adapter);
+
+       ixgbe_napi_disable_all(adapter);
+
        if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
            adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
                cancel_work_sync(&adapter->fdir_reinit_task);
@@ -3301,8 +3679,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
                                (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
                                 ~IXGBE_DMATXCTL_TE));
 
-       netif_carrier_off(netdev);
-
        /* clear n-tuple filters that are cached */
        ethtool_ntuple_flush(netdev);
 
@@ -3379,6 +3755,8 @@ static void ixgbe_reset_task(struct work_struct *work)
 
        adapter->tx_timeout_count++;
 
+       ixgbe_dump(adapter);
+       netdev_err(adapter->netdev, "Reset adapter\n");
        ixgbe_reinit_locked(adapter);
 }
 
@@ -3479,12 +3857,12 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
                adapter->num_tx_queues = 1;
 #ifdef CONFIG_IXGBE_DCB
                if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
-                       DPRINTK(PROBE, INFO, "FCoE enabled with DCB \n");
+                       DPRINTK(PROBE, INFO, "FCoE enabled with DCB\n");
                        ixgbe_set_dcb_queues(adapter);
                }
 #endif
                if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
-                       DPRINTK(PROBE, INFO, "FCoE enabled with RSS \n");
+                       DPRINTK(PROBE, INFO, "FCoE enabled with RSS\n");
                        if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
                            (adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
                                ixgbe_set_fdir_queues(adapter);
@@ -4095,7 +4473,6 @@ static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter)
                adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
                pci_disable_msi(adapter->pdev);
        }
-       return;
 }
 
 /**
@@ -4381,8 +4758,8 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
        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);
+       tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+                                          &tx_ring->dma, GFP_KERNEL);
        if (!tx_ring->desc)
                goto err;
 
@@ -4452,7 +4829,8 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
        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);
+       rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+                                          &rx_ring->dma, GFP_KERNEL);
 
        if (!rx_ring->desc) {
                DPRINTK(PROBE, ERR,
@@ -4513,7 +4891,8 @@ void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
        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);
+       dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+                         tx_ring->dma);
 
        tx_ring->desc = NULL;
 }
@@ -4550,7 +4929,8 @@ void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
        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);
+       dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+                         rx_ring->dma);
 
        rx_ring->desc = NULL;
 }
@@ -5100,7 +5480,7 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
                                &(adapter->tx_ring[i]->reinit_state));
        } else {
                DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, "
-                       "ignored adding FDIR ATR filters \n");
+                       "ignored adding FDIR ATR filters\n");
        }
        /* Done FDIR Re-initialization, enable transmits */
        netif_tx_start_all_queues(adapter->netdev);
@@ -5420,10 +5800,10 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
 
                tx_buffer_info->length = size;
                tx_buffer_info->mapped_as_page = false;
-               tx_buffer_info->dma = pci_map_single(pdev,
+               tx_buffer_info->dma = dma_map_single(&pdev->dev,
                                                     skb->data + offset,
-                                                    size, PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+                                                    size, DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
                        goto dma_error;
                tx_buffer_info->time_stamp = jiffies;
                tx_buffer_info->next_to_watch = i;
@@ -5456,12 +5836,12 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
                        size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
 
                        tx_buffer_info->length = size;
-                       tx_buffer_info->dma = pci_map_page(adapter->pdev,
+                       tx_buffer_info->dma = dma_map_page(&adapter->pdev->dev,
                                                           frag->page,
                                                           offset, size,
-                                                          PCI_DMA_TODEVICE);
+                                                          DMA_TO_DEVICE);
                        tx_buffer_info->mapped_as_page = true;
-                       if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+                       if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
                                goto dma_error;
                        tx_buffer_info->time_stamp = jiffies;
                        tx_buffer_info->next_to_watch = i;
@@ -5697,7 +6077,8 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb,
                }
                tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
                tx_flags |= IXGBE_TX_FLAGS_VLAN;
-       } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+       } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED &&
+                  skb->priority != TC_PRIO_CONTROL) {
                tx_flags |= ((skb->queue_mapping & 0x7) << 13);
                tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
                tx_flags |= IXGBE_TX_FLAGS_VLAN;
@@ -5942,6 +6323,10 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_vlan_rx_add_vid    = ixgbe_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = ixgbe_vlan_rx_kill_vid,
        .ndo_do_ioctl           = ixgbe_ioctl,
+       .ndo_set_vf_mac         = ixgbe_ndo_set_vf_mac,
+       .ndo_set_vf_vlan        = ixgbe_ndo_set_vf_vlan,
+       .ndo_set_vf_tx_rate     = ixgbe_ndo_set_vf_bw,
+       .ndo_get_vf_config      = ixgbe_ndo_get_vf_config,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
@@ -6039,13 +6424,14 @@ static int __devinit ixgbe_probe(struct pci_dev *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))) {
+       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
+           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
                pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
                        if (err) {
                                dev_err(&pdev->dev, "No usable DMA "
                                        "configuration, aborting\n");
index 1c1efd3869565162ecc9f11b320a9543a5f67e59..22d21af1478326b7c332f72b7c2759566addb43c 100644 (file)
@@ -475,7 +475,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
                        msleep(edata);
                        break;
                case IXGBE_DATA_NL:
-                       hw_dbg(hw, "DATA:  \n");
+                       hw_dbg(hw, "DATA:\n");
                        data_offset++;
                        hw->eeprom.ops.read(hw, data_offset++,
                                            &phy_offset);
@@ -491,7 +491,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
                        break;
                case IXGBE_CONTROL_NL:
                        data_offset++;
-                       hw_dbg(hw, "CONTROL: \n");
+                       hw_dbg(hw, "CONTROL:\n");
                        if (edata == IXGBE_CONTROL_EOL_NL) {
                                hw_dbg(hw, "EOL\n");
                                end_data = true;
@@ -531,6 +531,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
        u8 comp_codes_10g = 0;
        u8 oui_bytes[3] = {0, 0, 0};
        u8 cable_tech = 0;
+       u8 cable_spec = 0;
        u16 enforce_sfp = 0;
 
        if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) {
@@ -580,14 +581,30 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                        else
                                hw->phy.sfp_type = ixgbe_sfp_type_unknown;
                } else if (hw->mac.type == ixgbe_mac_82599EB) {
-                       if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
+                       if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) {
                                if (hw->bus.lan_id == 0)
                                        hw->phy.sfp_type =
                                                     ixgbe_sfp_type_da_cu_core0;
                                else
                                        hw->phy.sfp_type =
                                                     ixgbe_sfp_type_da_cu_core1;
-                       else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
+                       } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) {
+                               hw->phy.ops.read_i2c_eeprom(
+                                               hw, IXGBE_SFF_CABLE_SPEC_COMP,
+                                               &cable_spec);
+                               if (cable_spec &
+                                   IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) {
+                                       if (hw->bus.lan_id == 0)
+                                               hw->phy.sfp_type =
+                                               ixgbe_sfp_type_da_act_lmt_core0;
+                                       else
+                                               hw->phy.sfp_type =
+                                               ixgbe_sfp_type_da_act_lmt_core1;
+                               } else {
+                                       hw->phy.sfp_type =
+                                               ixgbe_sfp_type_unknown;
+                               }
+                       } else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
                                if (hw->bus.lan_id == 0)
                                        hw->phy.sfp_type =
                                                      ixgbe_sfp_type_srlr_core0;
@@ -637,10 +654,14 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                        switch (vendor_oui) {
                        case IXGBE_SFF_VENDOR_OUI_TYCO:
                                if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
-                                       hw->phy.type = ixgbe_phy_tw_tyco;
+                                       hw->phy.type =
+                                               ixgbe_phy_sfp_passive_tyco;
                                break;
                        case IXGBE_SFF_VENDOR_OUI_FTL:
-                               hw->phy.type = ixgbe_phy_sfp_ftl;
+                               if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
+                                       hw->phy.type = ixgbe_phy_sfp_ftl_active;
+                               else
+                                       hw->phy.type = ixgbe_phy_sfp_ftl;
                                break;
                        case IXGBE_SFF_VENDOR_OUI_AVAGO:
                                hw->phy.type = ixgbe_phy_sfp_avago;
@@ -650,7 +671,11 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                                break;
                        default:
                                if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
-                                       hw->phy.type = ixgbe_phy_tw_unknown;
+                                       hw->phy.type =
+                                               ixgbe_phy_sfp_passive_unknown;
+                               else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE)
+                                       hw->phy.type =
+                                               ixgbe_phy_sfp_active_unknown;
                                else
                                        hw->phy.type = ixgbe_phy_sfp_unknown;
                                break;
@@ -658,7 +683,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                }
 
                /* All passive DA cables are supported */
-               if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) {
+               if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE |
+                   IXGBE_SFF_DA_ACTIVE_CABLE)) {
                        status = 0;
                        goto out;
                }
index 9cf5f3b4cc5dc38227f2ca4733547cab575e1758..c9c545941407fa5f09964c20040f52b5b78bef2f 100644 (file)
 #define IXGBE_SFF_1GBE_COMP_CODES    0x6
 #define IXGBE_SFF_10GBE_COMP_CODES   0x3
 #define IXGBE_SFF_CABLE_TECHNOLOGY   0x8
+#define IXGBE_SFF_CABLE_SPEC_COMP    0x3C
 
 /* Bitmasks */
 #define IXGBE_SFF_DA_PASSIVE_CABLE           0x4
+#define IXGBE_SFF_DA_ACTIVE_CABLE            0x8
+#define IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING    0x4
 #define IXGBE_SFF_1GBASESX_CAPABLE           0x1
 #define IXGBE_SFF_1GBASELX_CAPABLE           0x2
 #define IXGBE_SFF_10GBASESR_CAPABLE          0x10
index d4cd20f301990e576cc12ecf24f71eb1908c5371..f6cee94ec8e8522db891155fb3d131cd8df6dca4 100644 (file)
@@ -48,7 +48,11 @@ int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
                            int entries, u16 *hash_list, u32 vf)
 {
        struct vf_data_storage *vfinfo = &adapter->vfinfo[vf];
+       struct ixgbe_hw *hw = &adapter->hw;
        int i;
+       u32 vector_bit;
+       u32 vector_reg;
+       u32 mta_reg;
 
        /* only so many hash values supported */
        entries = min(entries, IXGBE_MAX_VF_MC_ENTRIES);
@@ -68,8 +72,13 @@ int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
                vfinfo->vf_mc_hashes[i] = hash_list[i];;
        }
 
-       /* Flush and reset the mta with the new values */
-       ixgbe_set_rx_mode(adapter->netdev);
+       for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) {
+               vector_reg = (vfinfo->vf_mc_hashes[i] >> 5) & 0x7F;
+               vector_bit = vfinfo->vf_mc_hashes[i] & 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);
+       }
 
        return 0;
 }
@@ -98,38 +107,51 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
 
 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)
+void ixgbe_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe)
 {
        u32 vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(vf));
-       vmolr |= (IXGBE_VMOLR_AUPE |
-                 IXGBE_VMOLR_ROMPE |
+       vmolr |= (IXGBE_VMOLR_ROMPE |
                  IXGBE_VMOLR_ROPE |
                  IXGBE_VMOLR_BAM);
+       if (aupe)
+               vmolr |= IXGBE_VMOLR_AUPE;
+       else
+               vmolr &= ~IXGBE_VMOLR_AUPE;
        IXGBE_WRITE_REG(hw, IXGBE_VMOLR(vf), vmolr);
 }
 
+static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       if (vid)
+               IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf),
+                               (vid | IXGBE_VMVIR_VLANA_DEFAULT));
+       else
+               IXGBE_WRITE_REG(hw, IXGBE_VMVIR(vf), 0);
+}
+
 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);
-
+       if (adapter->vfinfo[vf].pf_vlan) {
+               ixgbe_set_vf_vlan(adapter, true,
+                                 adapter->vfinfo[vf].pf_vlan, vf);
+               ixgbe_set_vmvir(adapter,
+                               (adapter->vfinfo[vf].pf_vlan |
+                                (adapter->vfinfo[vf].pf_qos <<
+                                 VLAN_PRIO_SHIFT)), vf);
+               ixgbe_set_vmolr(hw, vf, false);
+       } else {
+               ixgbe_set_vmvir(adapter, 0, vf);
+               ixgbe_set_vmolr(hw, vf, true);
+       }
 
        /* reset multicast table array for vf */
        adapter->vfinfo[vf].num_vf_mc_hashes = 0;
@@ -263,10 +285,12 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
        case IXGBE_VF_SET_MAC_ADDR:
                {
                        u8 *new_mac = ((u8 *)(&msgbuf[1]));
-                       if (is_valid_ether_addr(new_mac))
+                       if (is_valid_ether_addr(new_mac) &&
+                           !adapter->vfinfo[vf].pf_set_mac)
                                ixgbe_set_vf_mac(adapter, vf, new_mac);
                        else
-                               retval = -1;
+                               ixgbe_set_vf_mac(adapter,
+                                 vf, adapter->vfinfo[vf].vf_mac_addresses);
                }
                break;
        case IXGBE_VF_SET_MULTICAST:
@@ -360,3 +384,76 @@ void ixgbe_ping_all_vfs(struct ixgbe_adapter *adapter)
        }
 }
 
+int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       if (!is_valid_ether_addr(mac) || (vf >= adapter->num_vfs))
+               return -EINVAL;
+       adapter->vfinfo[vf].pf_set_mac = true;
+       dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf);
+       dev_info(&adapter->pdev->dev, "Reload the VF driver to make this"
+                                     " change effective.");
+       if (test_bit(__IXGBE_DOWN, &adapter->state)) {
+               dev_warn(&adapter->pdev->dev, "The VF MAC address has been set,"
+                        " but the PF device is not up.\n");
+               dev_warn(&adapter->pdev->dev, "Bring the PF device up before"
+                        " attempting to use the VF device.\n");
+       }
+       return ixgbe_set_vf_mac(adapter, vf, mac);
+}
+
+int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
+{
+       int err = 0;
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       if ((vf >= adapter->num_vfs) || (vlan > 4095) || (qos > 7))
+               return -EINVAL;
+       if (vlan || qos) {
+               err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);
+               if (err)
+                       goto out;
+               ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
+               ixgbe_set_vmolr(&adapter->hw, vf, false);
+               adapter->vfinfo[vf].pf_vlan = vlan;
+               adapter->vfinfo[vf].pf_qos = qos;
+               dev_info(&adapter->pdev->dev,
+                        "Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
+               if (test_bit(__IXGBE_DOWN, &adapter->state)) {
+                       dev_warn(&adapter->pdev->dev,
+                                "The VF VLAN has been set,"
+                                " but the PF device is not up.\n");
+                       dev_warn(&adapter->pdev->dev,
+                                "Bring the PF device up before"
+                                " attempting to use the VF device.\n");
+               }
+       } else {
+               err = ixgbe_set_vf_vlan(adapter, false,
+                                       adapter->vfinfo[vf].pf_vlan, vf);
+               ixgbe_set_vmvir(adapter, vlan, vf);
+               ixgbe_set_vmolr(&adapter->hw, vf, true);
+               adapter->vfinfo[vf].pf_vlan = 0;
+               adapter->vfinfo[vf].pf_qos = 0;
+       }
+out:
+       return err;
+}
+
+int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
+{
+       return -EOPNOTSUPP;
+}
+
+int ixgbe_ndo_get_vf_config(struct net_device *netdev,
+                           int vf, struct ifla_vf_info *ivi)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       if (vf >= adapter->num_vfs)
+               return -EINVAL;
+       ivi->vf = vf;
+       memcpy(&ivi->mac, adapter->vfinfo[vf].vf_mac_addresses, ETH_ALEN);
+       ivi->tx_rate = 0;
+       ivi->vlan = adapter->vfinfo[vf].pf_vlan;
+       ivi->qos = adapter->vfinfo[vf].pf_qos;
+       return 0;
+}
index 51d1106c45a1fec2d3074e4098cbb76e2698a6fc..184730ecdfb66c4f668b298b5d411fc4a1a4d47f 100644 (file)
@@ -32,7 +32,7 @@ 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_set_vmolr(struct ixgbe_hw *hw, u32 vf, bool aupe);
 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);
@@ -42,6 +42,12 @@ 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);
+int ixgbe_ndo_set_vf_mac(struct net_device *netdev, int queue, u8 *mac);
+int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int queue, u16 vlan,
+                          u8 qos);
+int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+int ixgbe_ndo_get_vf_config(struct net_device *netdev,
+                           int vf, struct ifla_vf_info *ivi);
 
 #endif /* _IXGBE_SRIOV_H_ */
 
index 534affcc38ca0208a9376e4565a2b65773349b26..39b9be897439b1d745e7c739c5c0089d0b43bf0c 100644 (file)
@@ -73,6 +73,7 @@
 /* NVM Registers */
 #define IXGBE_EEC       0x10010
 #define IXGBE_EERD      0x10014
+#define IXGBE_EEWR      0x10018
 #define IXGBE_FLA       0x1001C
 #define IXGBE_EEMNGCTL  0x10110
 #define IXGBE_EEMNGDATA 0x10114
 #define IXGBE_MTQC      0x08120
 #define IXGBE_VLVF(_i)  (0x0F100 + ((_i) * 4))  /* 64 of these (0-63) */
 #define IXGBE_VLVFB(_i) (0x0F200 + ((_i) * 4))  /* 128 of these (0-127) */
+#define IXGBE_VMVIR(_i) (0x08000 + ((_i) * 4))  /* 64 of these (0-63) */
 #define IXGBE_VT_CTL    0x051B0
 #define IXGBE_VFRE(_i)  (0x051E0 + ((_i) * 4))
 #define IXGBE_VFTE(_i)  (0x08110 + ((_i) * 4))
 #define IXGBE_MREVID    0x11064
 #define IXGBE_DCA_ID    0x11070
 #define IXGBE_DCA_CTRL  0x11074
+#define IXGBE_SWFW_SYNC IXGBE_GSSR
 
 /* PCIe registers 82599-specific */
 #define IXGBE_GCR_EXT           0x11050
 #define IXGBE_VLVF_ENTRIES      64
 #define IXGBE_VLVF_VLANID_MASK  0x00000FFF
 
+/* Per VF Port VLAN insertion rules */
+#define IXGBE_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
+#define IXGBE_VMVIR_VLANA_NEVER   0x80000000 /* Never insert VLAN tag */
+
 #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.1q protocol */
 
 /* STATUS Bit Masks */
 #define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
 #define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
 #define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+#define IXGBE_SWFW_REGSMP 0x80000000 /* Register Semaphore bit 31 */
 
-/* GSSR definitions */
+/* SW_FW_SYNC/GSSR definitions */
 #define IXGBE_GSSR_EEP_SM     0x0001
 #define IXGBE_GSSR_PHY0_SM    0x0002
 #define IXGBE_GSSR_PHY1_SM    0x0004
 #define IXGBE_EEC_GNT       0x00000080 /* EEPROM Access Grant */
 #define IXGBE_EEC_PRES      0x00000100 /* EEPROM Present */
 #define IXGBE_EEC_ARD       0x00000200 /* EEPROM Auto Read Done */
+#define IXGBE_EEC_FLUP      0x00800000 /* Flash update command */
+#define IXGBE_EEC_FLUDONE   0x04000000 /* Flash update done */
 /* EEPROM Addressing bits based on type (0-small, 1-large) */
 #define IXGBE_EEC_ADDR_SIZE 0x00000400
 #define IXGBE_EEC_SIZE      0x00007800 /* EEPROM Size */
 #define IXGBE_EEPROM_ERASE256_OPCODE_SPI  0xDB  /* EEPROM ERASE 256B */
 
 /* EEPROM Read Register */
-#define IXGBE_EEPROM_READ_REG_DATA   16   /* data offset in EEPROM read reg */
-#define IXGBE_EEPROM_READ_REG_DONE   2    /* Offset to READ done bit */
-#define IXGBE_EEPROM_READ_REG_START  1    /* First bit to start operation */
-#define IXGBE_EEPROM_READ_ADDR_SHIFT 2    /* Shift to the address bits */
+#define IXGBE_EEPROM_RW_REG_DATA   16 /* data offset in EEPROM read reg */
+#define IXGBE_EEPROM_RW_REG_DONE   2  /* Offset to READ done bit */
+#define IXGBE_EEPROM_RW_REG_START  1  /* First bit to start operation */
+#define IXGBE_EEPROM_RW_ADDR_SHIFT 2  /* Shift to the address bits */
+#define IXGBE_NVM_POLL_WRITE       1  /* Flag for polling for write complete */
+#define IXGBE_NVM_POLL_READ        0  /* Flag for polling for read complete */
 
 #define IXGBE_ETH_LENGTH_OF_ADDRESS   6
 
 #define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
 #endif
 
-#ifndef IXGBE_EERD_ATTEMPTS
-/* Number of 5 microseconds we wait for EERD read to complete */
-#define IXGBE_EERD_ATTEMPTS 100000
+#ifndef IXGBE_EERD_EEWR_ATTEMPTS
+/* Number of 5 microseconds we wait for EERD read and
+ * EERW write to complete */
+#define IXGBE_EERD_EEWR_ATTEMPTS 100000
+#endif
+
+#ifndef IXGBE_FLUDONE_ATTEMPTS
+/* # attempts we wait for flush update to complete */
+#define IXGBE_FLUDONE_ATTEMPTS 20000
 #endif
 
 #define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET  0x0
@@ -2090,6 +2108,7 @@ typedef u32 ixgbe_physical_layer;
 #define IXGBE_PHYSICAL_LAYER_1000BASE_BX  0x0400
 #define IXGBE_PHYSICAL_LAYER_10GBASE_KR   0x0800
 #define IXGBE_PHYSICAL_LAYER_10GBASE_XAUI 0x1000
+#define IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA 0x2000
 
 /* Software ATR hash keys */
 #define IXGBE_ATR_BUCKET_HASH_KEY    0xE214AD3D
@@ -2159,10 +2178,12 @@ enum ixgbe_phy_type {
        ixgbe_phy_qt,
        ixgbe_phy_xaui,
        ixgbe_phy_nl,
-       ixgbe_phy_tw_tyco,
-       ixgbe_phy_tw_unknown,
+       ixgbe_phy_sfp_passive_tyco,
+       ixgbe_phy_sfp_passive_unknown,
+       ixgbe_phy_sfp_active_unknown,
        ixgbe_phy_sfp_avago,
        ixgbe_phy_sfp_ftl,
+       ixgbe_phy_sfp_ftl_active,
        ixgbe_phy_sfp_unknown,
        ixgbe_phy_sfp_intel,
        ixgbe_phy_sfp_unsupported,
@@ -2190,6 +2211,8 @@ enum ixgbe_sfp_type {
        ixgbe_sfp_type_da_cu_core1 = 4,
        ixgbe_sfp_type_srlr_core0 = 5,
        ixgbe_sfp_type_srlr_core1 = 6,
+       ixgbe_sfp_type_da_act_lmt_core0 = 7,
+       ixgbe_sfp_type_da_act_lmt_core1 = 8,
        ixgbe_sfp_type_not_present = 0xFFFE,
        ixgbe_sfp_type_unknown = 0xFFFF
 };
@@ -2263,6 +2286,7 @@ struct ixgbe_addr_filter_info {
        u32 mc_addr_in_rar_count;
        u32 mta_in_use;
        u32 overflow_promisc;
+       bool uc_set_promisc;
        bool user_set_promisc;
 };
 
@@ -2419,8 +2443,7 @@ struct ixgbe_mac_operations {
        s32 (*clear_vmdq)(struct ixgbe_hw *, u32, u32);
        s32 (*init_rx_addrs)(struct ixgbe_hw *);
        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 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *);
        s32 (*enable_mc)(struct ixgbe_hw *);
        s32 (*disable_mc)(struct ixgbe_hw *);
        s32 (*clear_vfta)(struct ixgbe_hw *);
@@ -2471,6 +2494,7 @@ struct ixgbe_mac_info {
        u32                             mcft_size;
        u32                             vft_size;
        u32                             num_rar_entries;
+       u32                             rar_highwater;
        u32                             max_tx_queues;
        u32                             max_rx_queues;
        u32                             max_msix_vectors;
@@ -2577,8 +2601,10 @@ struct ixgbe_info {
 #define IXGBE_ERR_SFP_NOT_SUPPORTED             -19
 #define IXGBE_ERR_SFP_NOT_PRESENT               -20
 #define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT       -21
+#define IXGBE_ERR_NO_SAN_ADDR_PTR               -22
 #define IXGBE_ERR_FDIR_REINIT_FAILED            -23
 #define IXGBE_ERR_EEPROM_VERSION                -24
+#define IXGBE_ERR_NO_SPACE                      -25
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */
index c44fdb05447adfc274ca5bff611dc61692249f2d..ca2c81f49a0567a133b34bd98ba08afb1495da7f 100644 (file)
@@ -41,11 +41,13 @@ 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
+#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_82599     0x30000000
+#define IXGBE_LINKS_SPEED_10G_82599 0x30000000
+#define IXGBE_LINKS_SPEED_1G_82599  0x20000000
 
 /* Number of Transmit and Receive Descriptors must be a multiple of 8 */
 #define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE  8
index 0cd6202dfaccfc541c0aee86471997e5189f2cf5..a16cff7e54a3ec8daea5f499ca40834c5adb3111 100644 (file)
@@ -139,15 +139,15 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_adapter *adapter,
 {
        if (tx_buffer_info->dma) {
                if (tx_buffer_info->mapped_as_page)
-                       pci_unmap_page(adapter->pdev,
+                       dma_unmap_page(&adapter->pdev->dev,
                                       tx_buffer_info->dma,
                                       tx_buffer_info->length,
-                                      PCI_DMA_TODEVICE);
+                                      DMA_TO_DEVICE);
                else
-                       pci_unmap_single(adapter->pdev,
+                       dma_unmap_single(&adapter->pdev->dev,
                                         tx_buffer_info->dma,
                                         tx_buffer_info->length,
-                                        PCI_DMA_TODEVICE);
+                                        DMA_TO_DEVICE);
                tx_buffer_info->dma = 0;
        }
        if (tx_buffer_info->skb) {
@@ -416,10 +416,10 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,
                                bi->page_offset ^= (PAGE_SIZE / 2);
                        }
 
-                       bi->page_dma = pci_map_page(pdev, bi->page,
+                       bi->page_dma = dma_map_page(&pdev->dev, bi->page,
                                                    bi->page_offset,
                                                    (PAGE_SIZE / 2),
-                                                   PCI_DMA_FROMDEVICE);
+                                                   DMA_FROM_DEVICE);
                }
 
                skb = bi->skb;
@@ -442,9 +442,9 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_adapter *adapter,
                        bi->skb = skb;
                }
                if (!bi->dma) {
-                       bi->dma = pci_map_single(pdev, skb->data,
+                       bi->dma = dma_map_single(&pdev->dev, skb->data,
                                                 rx_ring->rx_buf_len,
-                                                PCI_DMA_FROMDEVICE);
+                                                DMA_FROM_DEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
                 * each write-back erases this info. */
@@ -536,16 +536,16 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
                rx_buffer_info->skb = NULL;
 
                if (rx_buffer_info->dma) {
-                       pci_unmap_single(pdev, rx_buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, rx_buffer_info->dma,
                                         rx_ring->rx_buf_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        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);
+                       dma_unmap_page(&pdev->dev, rx_buffer_info->page_dma,
+                                      PAGE_SIZE / 2, DMA_FROM_DEVICE);
                        rx_buffer_info->page_dma = 0;
                        skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
                                           rx_buffer_info->page,
@@ -604,14 +604,13 @@ static bool ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
                 * packets not getting split correctly
                 */
                if (staterr & IXGBE_RXD_STAT_LB) {
-                       u32 header_fixup_len = skb->len - skb->data_len;
+                       u32 header_fixup_len = skb_headlen(skb);
                        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;
@@ -947,8 +946,6 @@ static void ixgbevf_set_itr_msix(struct ixgbevf_q_vector *q_vector)
                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)
@@ -962,12 +959,28 @@ static irqreturn_t ixgbevf_msix_mbx(int irq, void *data)
        eicr = IXGBE_READ_REG(hw, IXGBE_VTEICS);
        IXGBE_WRITE_REG(hw, IXGBE_VTEICR, eicr);
 
+       if (!hw->mbx.ops.check_for_ack(hw)) {
+               /*
+                * checking for the ack clears the PFACK bit.  Place
+                * it back in the v2p_mailbox cache so that anyone
+                * polling for an ack will not miss it.  Also
+                * avoid the read below because the code to read
+                * the mailbox will also clear the ack bit.  This was
+                * causing lost acks.  Just cache the bit and exit
+                * the IRQ handler.
+                */
+               hw->mbx.v2p_mailbox |= IXGBE_VFMAILBOX_PFACK;
+               goto out;
+       }
+
+       /* Not an ack interrupt, go ahead and read the message */
        hw->mbx.ops.read(hw, &msg, 1);
 
        if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG)
                mod_timer(&adapter->watchdog_timer,
                          round_jiffies(jiffies + 1));
 
+out:
        return IRQ_HANDLED;
 }
 
@@ -1496,22 +1509,6 @@ static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter)
        }
 }
 
-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
@@ -1524,16 +1521,10 @@ 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(netdev);
-       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);
+               hw->mac.ops.update_mc_addr_list(hw, netdev);
 }
 
 static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter)
@@ -1744,9 +1735,9 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter,
 
                rx_buffer_info = &rx_ring->rx_buffer_info[i];
                if (rx_buffer_info->dma) {
-                       pci_unmap_single(pdev, rx_buffer_info->dma,
+                       dma_unmap_single(&pdev->dev, rx_buffer_info->dma,
                                         rx_ring->rx_buf_len,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
                        rx_buffer_info->dma = 0;
                }
                if (rx_buffer_info->skb) {
@@ -1760,8 +1751,8 @@ static void ixgbevf_clean_rx_ring(struct ixgbevf_adapter *adapter,
                }
                if (!rx_buffer_info->page)
                        continue;
-               pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE / 2,
-                              PCI_DMA_FROMDEVICE);
+               dma_unmap_page(&pdev->dev, rx_buffer_info->page_dma,
+                              PAGE_SIZE / 2, DMA_FROM_DEVICE);
                rx_buffer_info->page_dma = 0;
                put_page(rx_buffer_info->page);
                rx_buffer_info->page = NULL;
@@ -2158,8 +2149,6 @@ static void ixgbevf_reset_interrupt_capability(struct ixgbevf_adapter *adapter)
        pci_disable_msix(adapter->pdev);
        kfree(adapter->msix_entries);
        adapter->msix_entries = NULL;
-
-       return;
 }
 
 /**
@@ -2418,9 +2407,9 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
 
        if (link_up) {
                if (!netif_carrier_ok(netdev)) {
-                       hw_dbg(&adapter->hw, "NIC Link is Up %s, ",
-                              ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
-                               "10 Gbps\n" : "1 Gbps\n"));
+                       hw_dbg(&adapter->hw, "NIC Link is Up, %u Gbps\n",
+                              (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+                              10 : 1);
                        netif_carrier_on(netdev);
                        netif_tx_wake_all_queues(netdev);
                } else {
@@ -2468,7 +2457,8 @@ void ixgbevf_free_tx_resources(struct ixgbevf_adapter *adapter,
        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);
+       dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+                         tx_ring->dma);
 
        tx_ring->desc = NULL;
 }
@@ -2513,8 +2503,8 @@ int ixgbevf_setup_tx_resources(struct ixgbevf_adapter *adapter,
        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);
+       tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+                                          &tx_ring->dma, GFP_KERNEL);
        if (!tx_ring->desc)
                goto err;
 
@@ -2584,8 +2574,8 @@ int ixgbevf_setup_rx_resources(struct ixgbevf_adapter *adapter,
        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);
+       rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+                                          &rx_ring->dma, GFP_KERNEL);
 
        if (!rx_ring->desc) {
                hw_dbg(&adapter->hw,
@@ -2646,7 +2636,8 @@ void ixgbevf_free_rx_resources(struct ixgbevf_adapter *adapter,
        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);
+       dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+                         rx_ring->dma);
 
        rx_ring->desc = NULL;
 }
@@ -2958,10 +2949,10 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,
 
                tx_buffer_info->length = size;
                tx_buffer_info->mapped_as_page = false;
-               tx_buffer_info->dma = pci_map_single(adapter->pdev,
+               tx_buffer_info->dma = dma_map_single(&adapter->pdev->dev,
                                                     skb->data + offset,
-                                                    size, PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+                                                    size, DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
                        goto dma_error;
                tx_buffer_info->time_stamp = jiffies;
                tx_buffer_info->next_to_watch = i;
@@ -2987,13 +2978,13 @@ static int ixgbevf_tx_map(struct ixgbevf_adapter *adapter,
                        size = min(len, (unsigned int)IXGBE_MAX_DATA_PER_TXD);
 
                        tx_buffer_info->length = size;
-                       tx_buffer_info->dma = pci_map_page(adapter->pdev,
+                       tx_buffer_info->dma = dma_map_page(&adapter->pdev->dev,
                                                           frag->page,
                                                           offset,
                                                           size,
-                                                          PCI_DMA_TODEVICE);
+                                                          DMA_TO_DEVICE);
                        tx_buffer_info->mapped_as_page = true;
-                       if (pci_dma_mapping_error(pdev, tx_buffer_info->dma))
+                       if (dma_mapping_error(&pdev->dev, tx_buffer_info->dma))
                                goto dma_error;
                        tx_buffer_info->time_stamp = jiffies;
                        tx_buffer_info->next_to_watch = i;
@@ -3189,8 +3180,6 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                         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;
@@ -3334,14 +3323,14 @@ static int __devinit ixgbevf_probe(struct pci_dev *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))) {
+       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
+           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
                pci_using_dac = 1;
        } else {
-               err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = pci_set_consistent_dma_mask(pdev,
-                                                         DMA_BIT_MASK(32));
+                       err = dma_set_coherent_mask(&pdev->dev,
+                                                   DMA_BIT_MASK(32));
                        if (err) {
                                dev_err(&pdev->dev, "No usable DMA "
                                        "configuration, aborting\n");
@@ -3482,7 +3471,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
 
        hw_dbg(hw, "MAC: %d\n", hw->mac.type);
 
-       hw_dbg(hw, "LRO is disabled \n");
+       hw_dbg(hw, "LRO is disabled\n");
 
        hw_dbg(hw, "Intel(R) 82599 Virtual Function\n");
        cards_found++;
index 4b5dec0ec14053c1d7b00c1eb8b13e5b9a776a1c..f6f929958ba0beb3cb3ec60970042976f1062247 100644 (file)
@@ -252,22 +252,18 @@ static s32 ixgbevf_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr,
 /**
  *  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
+ *  @netdev: pointer to net device structure
  *
  *  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)
+static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw,
+                                         struct net_device *netdev)
 {
+       struct netdev_hw_addr *ha;
        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
@@ -278,13 +274,17 @@ static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list,
         * addresses except for in large enterprise network environments.
         */
 
-       cnt = (mc_addr_count > 30) ? 30 : mc_addr_count;
+       cnt = netdev_mc_count(netdev);
+       if (cnt > 30)
+               cnt = 30;
        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;
+       i = 0;
+       netdev_for_each_mc_addr(ha, netdev) {
+               if (i == cnt)
+                       break;
+               vector_list[i++] = ixgbevf_mta_vector(hw, ha->addr);
        }
 
        mbx->ops.write_posted(hw, msgbuf, IXGBE_VFMAILBOX_SIZE);
@@ -359,7 +359,8 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
        else
                *link_up = false;
 
-       if (links_reg & IXGBE_LINKS_SPEED)
+       if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
+           IXGBE_LINKS_SPEED_10G_82599)
                *speed = IXGBE_LINK_SPEED_10GB_FULL;
        else
                *speed = IXGBE_LINK_SPEED_1GB_FULL;
index 1f31b052d4b4b788a7e670199b6c16503cfc5b08..94b750b8874f492d279fac3b68943c58e566be8f 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/if_ether.h>
+#include <linux/netdevice.h>
 
 #include "defines.h"
 #include "regs.h"
@@ -62,8 +63,7 @@ struct ixgbe_mac_operations {
        /* 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 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *);
        s32 (*enable_mc)(struct ixgbe_hw *);
        s32 (*disable_mc)(struct ixgbe_hw *);
        s32 (*clear_vfta)(struct ixgbe_hw *);
index d5932ca3e27db3700c84f19e9518edf447f71250..78ddd8b79e7ea67551d9f683dcf690893d869a5e 100644 (file)
@@ -64,8 +64,6 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
        ixp2000_reg_write(RING_TX_PENDING,
                TX_BUF_DESC_BASE + (entry * sizeof(struct ixpdev_tx_desc)));
 
-       dev->trans_start = jiffies;
-
        local_irq_save(flags);
        ip->tx_queue_entries++;
        if (ip->tx_queue_entries == TX_BUF_COUNT_PER_CHAN)
index b705ad3a53a785a0f64c5f83f831177b192b8c6a..99f24f5cac53f6c6a70e25681253593b3b485a6e 100644 (file)
@@ -103,8 +103,6 @@ jme_mdio_write(struct net_device *netdev,
 
        if (i == 0)
                jeprintk(jme->pdev, "phy(%d) write timeout : %d\n", phy, reg);
-
-       return;
 }
 
 static inline void
@@ -130,8 +128,6 @@ jme_reset_phy_processor(struct jme_adapter *jme)
        jme_mdio_write(jme->dev,
                        jme->mii_if.phy_id,
                        MII_BMCR, val | BMCR_RESET);
-
-       return;
 }
 
 static void
@@ -2010,12 +2006,12 @@ jme_set_multi(struct net_device *netdev)
        } else if (netdev->flags & IFF_ALLMULTI) {
                jme->reg_rxmcs |= RXMCS_ALLMULFRAME;
        } else if (netdev->flags & IFF_MULTICAST) {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                int bit_nr;
 
                jme->reg_rxmcs |= RXMCS_MULFRAME | RXMCS_MULFILTERED;
-               netdev_for_each_mc_addr(mclist, netdev) {
-                       bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3F;
+               netdev_for_each_mc_addr(ha, netdev) {
+                       bit_nr = ether_crc(ETH_ALEN, ha->addr) & 0x3F;
                        mc_hash[bit_nr >> 5] |= 1 << (bit_nr & 0x1F);
                }
 
@@ -2839,7 +2835,7 @@ jme_init_one(struct pci_dev *pdev,
        default:
                jme->reg_txcs = TXCS_DEFAULT | TXCS_DMASIZE_512B;
                break;
-       };
+       }
 
        /*
         * Must check before reset_mac_processor
index 300c2249812d7a89df044d99aa2a6c15f5a874c0..26bf1b76b9977a1510bf3407c34322bed46512ba 100644 (file)
@@ -482,7 +482,7 @@ static void korina_multicast_list(struct net_device *dev)
 {
        struct korina_private *lp = netdev_priv(dev);
        unsigned long flags;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        u32 recognise = ETH_ARC_AB;     /* always accept broadcasts */
        int i;
 
@@ -502,8 +502,8 @@ static void korina_multicast_list(struct net_device *dev)
                for (i = 0; i < 4; i++)
                        hash_table[i] = 0;
 
-               netdev_for_each_mc_addr(dmi, dev) {
-                       char *addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       char *addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
@@ -1135,7 +1135,7 @@ static int korina_probe(struct platform_device *pdev)
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_regs");
        dev->base_addr = r->start;
-       lp->eth_regs = ioremap_nocache(r->start, r->end - r->start);
+       lp->eth_regs = ioremap_nocache(r->start, resource_size(r));
        if (!lp->eth_regs) {
                printk(KERN_ERR DRV_NAME ": cannot remap registers\n");
                rc = -ENXIO;
@@ -1143,7 +1143,7 @@ static int korina_probe(struct platform_device *pdev)
        }
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_rx");
-       lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start);
+       lp->rx_dma_regs = ioremap_nocache(r->start, resource_size(r));
        if (!lp->rx_dma_regs) {
                printk(KERN_ERR DRV_NAME ": cannot remap Rx DMA registers\n");
                rc = -ENXIO;
@@ -1151,7 +1151,7 @@ static int korina_probe(struct platform_device *pdev)
        }
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_tx");
-       lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start);
+       lp->tx_dma_regs = ioremap_nocache(r->start, resource_size(r));
        if (!lp->tx_dma_regs) {
                printk(KERN_ERR DRV_NAME ": cannot remap Tx DMA registers\n");
                rc = -ENXIO;
index 5c45cb58d023827665d22385e044c199a753a96d..f852ab3ae9cf2aaa86ff6ac9718d8b839bea6bdb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ks8842_main.c timberdale KS8842 ethernet driver
+ * ks8842.c timberdale KS8842 ethernet driver
  * Copyright (c) 2009 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * The Micrel KS8842 behind the timberdale FPGA
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/ks8842.h>
 
 #define DRV_NAME "ks8842"
 
@@ -302,6 +305,20 @@ static void ks8842_read_mac_addr(struct ks8842_adapter *adapter, u8 *dest)
        ks8842_write16(adapter, 39, mac, REG_MACAR3);
 }
 
+static void ks8842_write_mac_addr(struct ks8842_adapter *adapter, u8 *mac)
+{
+       unsigned long flags;
+       unsigned i;
+
+       spin_lock_irqsave(&adapter->lock, flags);
+       for (i = 0; i < ETH_ALEN; i++) {
+               ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
+               ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
+                       REG_MACAR1 + i);
+       }
+       spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
 static inline u16 ks8842_tx_fifo_space(struct ks8842_adapter *adapter)
 {
        return ks8842_read16(adapter, 16, REG_TXMIR) & 0x1fff;
@@ -520,13 +537,14 @@ static int ks8842_open(struct net_device *netdev)
        /* reset the HW */
        ks8842_reset_hw(adapter);
 
+       ks8842_write_mac_addr(adapter, netdev->dev_addr);
+
        ks8842_update_link_status(netdev, adapter);
 
        err = request_irq(adapter->irq, ks8842_irq, IRQF_SHARED, DRV_NAME,
                adapter);
        if (err) {
-               printk(KERN_ERR "Failed to request IRQ: %d: %d\n",
-                       adapter->irq, err);
+               pr_err("Failed to request IRQ: %d: %d\n", adapter->irq, err);
                return err;
        }
 
@@ -567,10 +585,8 @@ static netdev_tx_t ks8842_xmit_frame(struct sk_buff *skb,
 static int ks8842_set_mac(struct net_device *netdev, void *p)
 {
        struct ks8842_adapter *adapter = netdev_priv(netdev);
-       unsigned long flags;
        struct sockaddr *addr = p;
        char *mac = (u8 *)addr->sa_data;
-       int i;
 
        dev_dbg(&adapter->pdev->dev, "%s: entry\n", __func__);
 
@@ -579,13 +595,7 @@ static int ks8842_set_mac(struct net_device *netdev, void *p)
 
        memcpy(netdev->dev_addr, mac, netdev->addr_len);
 
-       spin_lock_irqsave(&adapter->lock, flags);
-       for (i = 0; i < ETH_ALEN; i++) {
-               ks8842_write8(adapter, 2, mac[ETH_ALEN - i - 1], REG_MARL + i);
-               ks8842_write8(adapter, 39, mac[ETH_ALEN - i - 1],
-                       REG_MACAR1 + i);
-       }
-       spin_unlock_irqrestore(&adapter->lock, flags);
+       ks8842_write_mac_addr(adapter, mac);
        return 0;
 }
 
@@ -604,6 +614,8 @@ static void ks8842_tx_timeout(struct net_device *netdev)
 
        ks8842_reset_hw(adapter);
 
+       ks8842_write_mac_addr(adapter, netdev->dev_addr);
+
        ks8842_update_link_status(netdev, adapter);
 }
 
@@ -626,7 +638,9 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
        struct resource *iomem;
        struct net_device *netdev;
        struct ks8842_adapter *adapter;
+       struct ks8842_platform_data *pdata = pdev->dev.platform_data;
        u16 id;
+       unsigned i;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!request_mem_region(iomem->start, resource_size(iomem), DRV_NAME))
@@ -657,7 +671,25 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
        netdev->netdev_ops = &ks8842_netdev_ops;
        netdev->ethtool_ops = &ks8842_ethtool_ops;
 
-       ks8842_read_mac_addr(adapter, netdev->dev_addr);
+       /* Check if a mac address was given */
+       i = netdev->addr_len;
+       if (pdata) {
+               for (i = 0; i < netdev->addr_len; i++)
+                       if (pdata->macaddr[i] != 0)
+                               break;
+
+               if (i < netdev->addr_len)
+                       /* an address was passed, use it */
+                       memcpy(netdev->dev_addr, pdata->macaddr,
+                               netdev->addr_len);
+       }
+
+       if (i == netdev->addr_len) {
+               ks8842_read_mac_addr(adapter, netdev->dev_addr);
+
+               if (!is_valid_ether_addr(netdev->dev_addr))
+                       random_ether_addr(netdev->dev_addr);
+       }
 
        id = ks8842_read16(adapter, 32, REG_SW_ID_AND_ENABLE);
 
@@ -668,8 +700,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, netdev);
 
-       printk(KERN_INFO DRV_NAME
-               " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n",
+       pr_info("Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n",
                (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7);
 
        return 0;
index 9e9f9b3497669fbc5c1ce063a28a48e28392c432..b4fb07a6f13ffd489c957816eebb4f831157ccd1 100644 (file)
@@ -9,6 +9,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define DEBUG
 
 #include <linux/module.h>
@@ -76,7 +78,9 @@ union ks8851_tx_hdr {
  * @msg_enable: The message flags controlling driver output (see ethtool).
  * @fid: Incrementing frame id tag.
  * @rc_ier: Cached copy of KS_IER.
+ * @rc_ccr: Cached copy of KS_CCR.
  * @rc_rxqcr: Cached copy of KS_RXQCR.
+ * @eeprom_size: Companion eeprom size in Bytes, 0 if no eeprom
  *
  * The @lock ensures that the chip is protected when certain operations are
  * in progress. When the read or write packet transfer is in progress, most
@@ -107,6 +111,8 @@ struct ks8851_net {
 
        u16                     rc_ier;
        u16                     rc_rxqcr;
+       u16                     rc_ccr;
+       u16                     eeprom_size;
 
        struct mii_if_info      mii;
        struct ks8851_rxctrl    rxctrl;
@@ -125,11 +131,6 @@ struct ks8851_net {
 
 static int msg_enable;
 
-#define ks_info(_ks, _msg...) dev_info(&(_ks)->spidev->dev, _msg)
-#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->spidev->dev, _msg)
-#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->spidev->dev, _msg)
-#define ks_err(_ks, _msg...) dev_err(&(_ks)->spidev->dev, _msg)
-
 /* shift for byte-enable data */
 #define BYTE_EN(_x)    ((_x) << 2)
 
@@ -167,7 +168,7 @@ static void ks8851_wrreg16(struct ks8851_net *ks, unsigned reg, unsigned val)
 
        ret = spi_sync(ks->spidev, msg);
        if (ret < 0)
-               ks_err(ks, "spi_sync() failed\n");
+               netdev_err(ks->netdev, "spi_sync() failed\n");
 }
 
 /**
@@ -197,7 +198,7 @@ static void ks8851_wrreg8(struct ks8851_net *ks, unsigned reg, unsigned val)
 
        ret = spi_sync(ks->spidev, msg);
        if (ret < 0)
-               ks_err(ks, "spi_sync() failed\n");
+               netdev_err(ks->netdev, "spi_sync() failed\n");
 }
 
 /**
@@ -263,7 +264,7 @@ static void ks8851_rdreg(struct ks8851_net *ks, unsigned op,
 
        ret = spi_sync(ks->spidev, msg);
        if (ret < 0)
-               ks_err(ks, "read: spi_sync() failed\n");
+               netdev_err(ks->netdev, "read: spi_sync() failed\n");
        else if (ks8851_rx_1msg(ks))
                memcpy(rxb, trx + 2, rxl);
        else
@@ -417,8 +418,8 @@ static void ks8851_rdfifo(struct ks8851_net *ks, u8 *buff, unsigned len)
        u8 txb[1];
        int ret;
 
-       if (netif_msg_rx_status(ks))
-               ks_dbg(ks, "%s: %d@%p\n", __func__, len, buff);
+       netif_dbg(ks, rx_status, ks->netdev,
+                 "%s: %d@%p\n", __func__, len, buff);
 
        /* set the operation we're issuing */
        txb[0] = KS_SPIOP_RXFIFO;
@@ -434,7 +435,7 @@ static void ks8851_rdfifo(struct ks8851_net *ks, u8 *buff, unsigned len)
 
        ret = spi_sync(ks->spidev, msg);
        if (ret < 0)
-               ks_err(ks, "%s: spi_sync() failed\n", __func__);
+               netdev_err(ks->netdev, "%s: spi_sync() failed\n", __func__);
 }
 
 /**
@@ -446,10 +447,11 @@ static void ks8851_rdfifo(struct ks8851_net *ks, u8 *buff, unsigned len)
 */
 static void ks8851_dbg_dumpkkt(struct ks8851_net *ks, u8 *rxpkt)
 {
-       ks_dbg(ks, "pkt %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
-              rxpkt[4], rxpkt[5], rxpkt[6], rxpkt[7],
-              rxpkt[8], rxpkt[9], rxpkt[10], rxpkt[11],
-              rxpkt[12], rxpkt[13], rxpkt[14], rxpkt[15]);
+       netdev_dbg(ks->netdev,
+                  "pkt %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x\n",
+                  rxpkt[4], rxpkt[5], rxpkt[6], rxpkt[7],
+                  rxpkt[8], rxpkt[9], rxpkt[10], rxpkt[11],
+                  rxpkt[12], rxpkt[13], rxpkt[14], rxpkt[15]);
 }
 
 /**
@@ -471,8 +473,8 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
 
        rxfc = ks8851_rdreg8(ks, KS_RXFC);
 
-       if (netif_msg_rx_status(ks))
-               ks_dbg(ks, "%s: %d packets\n", __func__, rxfc);
+       netif_dbg(ks, rx_status, ks->netdev,
+                 "%s: %d packets\n", __func__, rxfc);
 
        /* Currently we're issuing a read per packet, but we could possibly
         * improve the code by issuing a single read, getting the receive
@@ -489,9 +491,8 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
                rxstat = rxh & 0xffff;
                rxlen = rxh >> 16;
 
-               if (netif_msg_rx_status(ks))
-                       ks_dbg(ks, "rx: stat 0x%04x, len 0x%04x\n",
-                               rxstat, rxlen);
+               netif_dbg(ks, rx_status, ks->netdev,
+                         "rx: stat 0x%04x, len 0x%04x\n", rxstat, rxlen);
 
                /* the length of the packet includes the 32bit CRC */
 
@@ -553,9 +554,8 @@ static void ks8851_irq_work(struct work_struct *work)
 
        status = ks8851_rdreg16(ks, KS_ISR);
 
-       if (netif_msg_intr(ks))
-               dev_dbg(&ks->spidev->dev, "%s: status 0x%04x\n",
-                       __func__, status);
+       netif_dbg(ks, intr, ks->netdev,
+                 "%s: status 0x%04x\n", __func__, status);
 
        if (status & IRQ_LCI) {
                /* should do something about checking link status */
@@ -582,8 +582,8 @@ static void ks8851_irq_work(struct work_struct *work)
                 * system */
                ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
 
-               if (netif_msg_intr(ks))
-                       ks_dbg(ks, "%s: txspace %d\n", __func__, ks->tx_space);
+               netif_dbg(ks, intr, ks->netdev,
+                         "%s: txspace %d\n", __func__, ks->tx_space);
        }
 
        if (status & IRQ_RXI)
@@ -659,9 +659,8 @@ static void ks8851_wrpkt(struct ks8851_net *ks, struct sk_buff *txp, bool irq)
        unsigned fid = 0;
        int ret;
 
-       if (netif_msg_tx_queued(ks))
-               dev_dbg(&ks->spidev->dev, "%s: skb %p, %d@%p, irq %d\n",
-                       __func__, txp, txp->len, txp->data, irq);
+       netif_dbg(ks, tx_queued, ks->netdev, "%s: skb %p, %d@%p, irq %d\n",
+                 __func__, txp, txp->len, txp->data, irq);
 
        fid = ks->fid++;
        fid &= TXFR_TXFID_MASK;
@@ -685,7 +684,7 @@ static void ks8851_wrpkt(struct ks8851_net *ks, struct sk_buff *txp, bool irq)
 
        ret = spi_sync(ks->spidev, msg);
        if (ret < 0)
-               ks_err(ks, "%s: spi_sync() failed\n", __func__);
+               netdev_err(ks->netdev, "%s: spi_sync() failed\n", __func__);
 }
 
 /**
@@ -746,8 +745,7 @@ static void ks8851_set_powermode(struct ks8851_net *ks, unsigned pwrmode)
 {
        unsigned pmecr;
 
-       if (netif_msg_hw(ks))
-               ks_dbg(ks, "setting power mode %d\n", pwrmode);
+       netif_dbg(ks, hw, ks->netdev, "setting power mode %d\n", pwrmode);
 
        pmecr = ks8851_rdreg16(ks, KS_PMECR);
        pmecr &= ~PMECR_PM_MASK;
@@ -771,8 +769,7 @@ static int ks8851_net_open(struct net_device *dev)
         * else at the moment */
        mutex_lock(&ks->lock);
 
-       if (netif_msg_ifup(ks))
-               ks_dbg(ks, "opening %s\n", dev->name);
+       netif_dbg(ks, ifup, ks->netdev, "opening\n");
 
        /* bring chip out of any power saving mode it was in */
        ks8851_set_powermode(ks, PMECR_PM_NORMAL);
@@ -828,8 +825,7 @@ static int ks8851_net_open(struct net_device *dev)
 
        netif_start_queue(ks->netdev);
 
-       if (netif_msg_ifup(ks))
-               ks_dbg(ks, "network device %s up\n", dev->name);
+       netif_dbg(ks, ifup, ks->netdev, "network device up\n");
 
        mutex_unlock(&ks->lock);
        return 0;
@@ -847,8 +843,7 @@ static int ks8851_net_stop(struct net_device *dev)
 {
        struct ks8851_net *ks = netdev_priv(dev);
 
-       if (netif_msg_ifdown(ks))
-               ks_info(ks, "%s: shutting down\n", dev->name);
+       netif_info(ks, ifdown, dev, "shutting down\n");
 
        netif_stop_queue(dev);
 
@@ -876,8 +871,8 @@ static int ks8851_net_stop(struct net_device *dev)
        while (!skb_queue_empty(&ks->txq)) {
                struct sk_buff *txb = skb_dequeue(&ks->txq);
 
-               if (netif_msg_ifdown(ks))
-                       ks_dbg(ks, "%s: freeing txb %p\n", __func__, txb);
+               netif_dbg(ks, ifdown, ks->netdev,
+                         "%s: freeing txb %p\n", __func__, txb);
 
                dev_kfree_skb(txb);
        }
@@ -906,9 +901,8 @@ static netdev_tx_t ks8851_start_xmit(struct sk_buff *skb,
        unsigned needed = calc_txlen(skb->len);
        netdev_tx_t ret = NETDEV_TX_OK;
 
-       if (netif_msg_tx_queued(ks))
-               ks_dbg(ks, "%s: skb %p, %d@%p\n", __func__,
-                      skb, skb->len, skb->data);
+       netif_dbg(ks, tx_queued, ks->netdev,
+                 "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data);
 
        spin_lock(&ks->statelock);
 
@@ -968,13 +962,13 @@ static void ks8851_set_rx_mode(struct net_device *dev)
                rxctrl.rxcr1 = (RXCR1_RXME | RXCR1_RXAE |
                                RXCR1_RXPAFMA | RXCR1_RXMAFMA);
        } else if (dev->flags & IFF_MULTICAST && !netdev_mc_empty(dev)) {
-               struct dev_mc_list *mcptr;
+               struct netdev_hw_addr *ha;
                u32 crc;
 
                /* accept some multicast */
 
-               netdev_for_each_mc_addr(mcptr, dev) {
-                       crc = ether_crc(ETH_ALEN, mcptr->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       crc = ether_crc(ETH_ALEN, ha->addr);
                        crc >>= (32 - 6);  /* get top six bits */
 
                        rxctrl.mchash[crc >> 4] |= (1 << (crc & 0xf));
@@ -1040,6 +1034,234 @@ static const struct net_device_ops ks8851_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
+/* Companion eeprom access */
+
+enum { /* EEPROM programming states */
+       EEPROM_CONTROL,
+       EEPROM_ADDRESS,
+       EEPROM_DATA,
+       EEPROM_COMPLETE
+};
+
+/**
+ * ks8851_eeprom_read - read a 16bits word in ks8851 companion EEPROM
+ * @dev: The network device the PHY is on.
+ * @addr: EEPROM address to read
+ *
+ * eeprom_size: used to define the data coding length. Can be changed
+ * through debug-fs.
+ *
+ * Programs a read on the EEPROM using ks8851 EEPROM SW access feature.
+ * Warning: The READ feature is not supported on ks8851 revision 0.
+ *
+ * Rough programming model:
+ *  - on period start: set clock high and read value on bus
+ *  - on period / 2: set clock low and program value on bus
+ *  - start on period / 2
+ */
+unsigned int ks8851_eeprom_read(struct net_device *dev, unsigned int addr)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       int eepcr;
+       int ctrl = EEPROM_OP_READ;
+       int state = EEPROM_CONTROL;
+       int bit_count = EEPROM_OP_LEN - 1;
+       unsigned int data = 0;
+       int dummy;
+       unsigned int addr_len;
+
+       addr_len = (ks->eeprom_size == 128) ? 6 : 8;
+
+       /* start transaction: chip select high, authorize write */
+       mutex_lock(&ks->lock);
+       eepcr = EEPCR_EESA | EEPCR_EESRWA;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       eepcr |= EEPCR_EECS;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       mutex_unlock(&ks->lock);
+
+       while (state != EEPROM_COMPLETE) {
+               /* falling clock period starts... */
+               /* set EED_IO pin for control and address */
+               eepcr &= ~EEPCR_EEDO;
+               switch (state) {
+               case EEPROM_CONTROL:
+                       eepcr |= ((ctrl >> bit_count) & 1) << 2;
+                       if (bit_count-- <= 0) {
+                               bit_count = addr_len - 1;
+                               state = EEPROM_ADDRESS;
+                       }
+                       break;
+               case EEPROM_ADDRESS:
+                       eepcr |= ((addr >> bit_count) & 1) << 2;
+                       bit_count--;
+                       break;
+               case EEPROM_DATA:
+                       /* Change to receive mode */
+                       eepcr &= ~EEPCR_EESRWA;
+                       break;
+               }
+
+               /* lower clock  */
+               eepcr &= ~EEPCR_EESCK;
+
+               mutex_lock(&ks->lock);
+               ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+               mutex_unlock(&ks->lock);
+
+               /* waitread period / 2 */
+               udelay(EEPROM_SK_PERIOD / 2);
+
+               /* rising clock period starts... */
+
+               /* raise clock */
+               mutex_lock(&ks->lock);
+               eepcr |= EEPCR_EESCK;
+               ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+               mutex_unlock(&ks->lock);
+
+               /* Manage read */
+               switch (state) {
+               case EEPROM_ADDRESS:
+                       if (bit_count < 0) {
+                               bit_count = EEPROM_DATA_LEN - 1;
+                               state = EEPROM_DATA;
+                       }
+                       break;
+               case EEPROM_DATA:
+                       mutex_lock(&ks->lock);
+                       dummy = ks8851_rdreg16(ks, KS_EEPCR);
+                       mutex_unlock(&ks->lock);
+                       data |= ((dummy >> EEPCR_EESB_OFFSET) & 1) << bit_count;
+                       if (bit_count-- <= 0)
+                               state = EEPROM_COMPLETE;
+                       break;
+               }
+
+               /* wait period / 2 */
+               udelay(EEPROM_SK_PERIOD / 2);
+       }
+
+       /* close transaction */
+       mutex_lock(&ks->lock);
+       eepcr &= ~EEPCR_EECS;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       eepcr = 0;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       mutex_unlock(&ks->lock);
+
+       return data;
+}
+
+/**
+ * ks8851_eeprom_write - write a 16bits word in ks8851 companion EEPROM
+ * @dev: The network device the PHY is on.
+ * @op: operand (can be WRITE, EWEN, EWDS)
+ * @addr: EEPROM address to write
+ * @data: data to write
+ *
+ * eeprom_size: used to define the data coding length. Can be changed
+ * through debug-fs.
+ *
+ * Programs a write on the EEPROM using ks8851 EEPROM SW access feature.
+ *
+ * Note that a write enable is required before writing data.
+ *
+ * Rough programming model:
+ *  - on period start: set clock high
+ *  - on period / 2: set clock low and program value on bus
+ *  - start on period / 2
+ */
+void ks8851_eeprom_write(struct net_device *dev, unsigned int op,
+                                       unsigned int addr, unsigned int data)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       int eepcr;
+       int state = EEPROM_CONTROL;
+       int bit_count = EEPROM_OP_LEN - 1;
+       unsigned int addr_len;
+
+       addr_len = (ks->eeprom_size == 128) ? 6 : 8;
+
+       switch (op) {
+       case EEPROM_OP_EWEN:
+               addr = 0x30;
+       break;
+       case EEPROM_OP_EWDS:
+               addr = 0;
+               break;
+       }
+
+       /* start transaction: chip select high, authorize write */
+       mutex_lock(&ks->lock);
+       eepcr = EEPCR_EESA | EEPCR_EESRWA;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       eepcr |= EEPCR_EECS;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       mutex_unlock(&ks->lock);
+
+       while (state != EEPROM_COMPLETE) {
+               /* falling clock period starts... */
+               /* set EED_IO pin for control and address */
+               eepcr &= ~EEPCR_EEDO;
+               switch (state) {
+               case EEPROM_CONTROL:
+                       eepcr |= ((op >> bit_count) & 1) << 2;
+                       if (bit_count-- <= 0) {
+                               bit_count = addr_len - 1;
+                               state = EEPROM_ADDRESS;
+                       }
+                       break;
+               case EEPROM_ADDRESS:
+                       eepcr |= ((addr >> bit_count) & 1) << 2;
+                       if (bit_count-- <= 0) {
+                               if (op == EEPROM_OP_WRITE) {
+                                       bit_count = EEPROM_DATA_LEN - 1;
+                                       state = EEPROM_DATA;
+                               } else {
+                                       state = EEPROM_COMPLETE;
+                               }
+                       }
+                       break;
+               case EEPROM_DATA:
+                       eepcr |= ((data >> bit_count) & 1) << 2;
+                       if (bit_count-- <= 0)
+                               state = EEPROM_COMPLETE;
+                       break;
+               }
+
+               /* lower clock  */
+               eepcr &= ~EEPCR_EESCK;
+
+               mutex_lock(&ks->lock);
+               ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+               mutex_unlock(&ks->lock);
+
+               /* wait period / 2 */
+               udelay(EEPROM_SK_PERIOD / 2);
+
+               /* rising clock period starts... */
+
+               /* raise clock */
+               eepcr |= EEPCR_EESCK;
+               mutex_lock(&ks->lock);
+               ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+               mutex_unlock(&ks->lock);
+
+               /* wait period / 2 */
+               udelay(EEPROM_SK_PERIOD / 2);
+       }
+
+       /* close transaction */
+       mutex_lock(&ks->lock);
+       eepcr &= ~EEPCR_EECS;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       eepcr = 0;
+       ks8851_wrreg16(ks, KS_EEPCR, eepcr);
+       mutex_unlock(&ks->lock);
+
+}
+
 /* ethtool support */
 
 static void ks8851_get_drvinfo(struct net_device *dev,
@@ -1086,6 +1308,117 @@ static int ks8851_nway_reset(struct net_device *dev)
        return mii_nway_restart(&ks->mii);
 }
 
+static int ks8851_get_eeprom_len(struct net_device *dev)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       return ks->eeprom_size;
+}
+
+static int ks8851_get_eeprom(struct net_device *dev,
+                           struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       u16 *eeprom_buff;
+       int first_word;
+       int last_word;
+       int ret_val = 0;
+       u16 i;
+
+       if (eeprom->len == 0)
+               return -EINVAL;
+
+       if (eeprom->len > ks->eeprom_size)
+               return -EINVAL;
+
+       eeprom->magic = ks8851_rdreg16(ks, KS_CIDER);
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+       eeprom_buff = kmalloc(sizeof(u16) *
+                       (last_word - first_word + 1), GFP_KERNEL);
+       if (!eeprom_buff)
+               return -ENOMEM;
+
+       for (i = 0; i < last_word - first_word + 1; i++)
+               eeprom_buff[i] = ks8851_eeprom_read(dev, first_word + 1);
+
+       /* Device's eeprom is little-endian, word addressable */
+       for (i = 0; i < last_word - first_word + 1; i++)
+               le16_to_cpus(&eeprom_buff[i]);
+
+       memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+       kfree(eeprom_buff);
+
+       return ret_val;
+}
+
+static int ks8851_set_eeprom(struct net_device *dev,
+                           struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct ks8851_net *ks = netdev_priv(dev);
+       u16 *eeprom_buff;
+       void *ptr;
+       int max_len;
+       int first_word;
+       int last_word;
+       int ret_val = 0;
+       u16 i;
+
+       if (eeprom->len == 0)
+               return -EOPNOTSUPP;
+
+       if (eeprom->len > ks->eeprom_size)
+               return -EINVAL;
+
+       if (eeprom->magic != ks8851_rdreg16(ks, KS_CIDER))
+               return -EFAULT;
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+       max_len = (last_word - first_word + 1) * 2;
+       eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+       if (!eeprom_buff)
+               return -ENOMEM;
+
+       ptr = (void *)eeprom_buff;
+
+       if (eeprom->offset & 1) {
+               /* need read/modify/write of first changed EEPROM word */
+               /* only the second byte of the word is being modified */
+               eeprom_buff[0] = ks8851_eeprom_read(dev, first_word);
+               ptr++;
+       }
+       if ((eeprom->offset + eeprom->len) & 1)
+               /* need read/modify/write of last changed EEPROM word */
+               /* only the first byte of the word is being modified */
+               eeprom_buff[last_word - first_word] =
+                                       ks8851_eeprom_read(dev, last_word);
+
+
+       /* Device's eeprom is little-endian, word addressable */
+       le16_to_cpus(&eeprom_buff[0]);
+       le16_to_cpus(&eeprom_buff[last_word - first_word]);
+
+       memcpy(ptr, bytes, eeprom->len);
+
+       for (i = 0; i < last_word - first_word + 1; i++)
+               eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
+       ks8851_eeprom_write(dev, EEPROM_OP_EWEN, 0, 0);
+
+       for (i = 0; i < last_word - first_word + 1; i++) {
+               ks8851_eeprom_write(dev, EEPROM_OP_WRITE, first_word + i,
+                                                       eeprom_buff[i]);
+               mdelay(EEPROM_WRITE_TIME);
+       }
+
+       ks8851_eeprom_write(dev, EEPROM_OP_EWDS, 0, 0);
+
+       kfree(eeprom_buff);
+       return ret_val;
+}
+
 static const struct ethtool_ops ks8851_ethtool_ops = {
        .get_drvinfo    = ks8851_get_drvinfo,
        .get_msglevel   = ks8851_get_msglevel,
@@ -1094,6 +1427,9 @@ static const struct ethtool_ops ks8851_ethtool_ops = {
        .set_settings   = ks8851_set_settings,
        .get_link       = ks8851_get_link,
        .nway_reset     = ks8851_nway_reset,
+       .get_eeprom_len = ks8851_get_eeprom_len,
+       .get_eeprom     = ks8851_get_eeprom,
+       .set_eeprom     = ks8851_set_eeprom,
 };
 
 /* MII interface controls */
@@ -1187,17 +1523,17 @@ static int ks8851_read_selftest(struct ks8851_net *ks)
        rd = ks8851_rdreg16(ks, KS_MBIR);
 
        if ((rd & both_done) != both_done) {
-               ks_warn(ks, "Memory selftest not finished\n");
+               netdev_warn(ks->netdev, "Memory selftest not finished\n");
                return 0;
        }
 
        if (rd & MBIR_TXMBFA) {
-               ks_err(ks, "TX memory selftest fail\n");
+               netdev_err(ks->netdev, "TX memory selftest fail\n");
                ret |= 1;
        }
 
        if (rd & MBIR_RXMBFA) {
-               ks_err(ks, "RX memory selftest fail\n");
+               netdev_err(ks->netdev, "RX memory selftest fail\n");
                ret |= 2;
        }
 
@@ -1279,6 +1615,14 @@ static int __devinit ks8851_probe(struct spi_device *spi)
                goto err_id;
        }
 
+       /* cache the contents of the CCR register for EEPROM, etc. */
+       ks->rc_ccr = ks8851_rdreg16(ks, KS_CCR);
+
+       if (ks->rc_ccr & CCR_EEPROM)
+               ks->eeprom_size = 128;
+       else
+               ks->eeprom_size = 0;
+
        ks8851_read_selftest(ks);
        ks8851_init_mac(ks);
 
@@ -1295,9 +1639,9 @@ static int __devinit ks8851_probe(struct spi_device *spi)
                goto err_netdev;
        }
 
-       dev_info(&spi->dev, "revision %d, MAC %pM, IRQ %d\n",
-                CIDER_REV_GET(ks8851_rdreg16(ks, KS_CIDER)),
-                ndev->dev_addr, ndev->irq);
+       netdev_info(ndev, "revision %d, MAC %pM, IRQ %d\n",
+                   CIDER_REV_GET(ks8851_rdreg16(ks, KS_CIDER)),
+                   ndev->dev_addr, ndev->irq);
 
        return 0;
 
@@ -1316,7 +1660,7 @@ static int __devexit ks8851_remove(struct spi_device *spi)
        struct ks8851_net *priv = dev_get_drvdata(&spi->dev);
 
        if (netif_msg_drv(priv))
-               dev_info(&spi->dev, "remove");
+               dev_info(&spi->dev, "remove\n");
 
        unregister_netdev(priv->netdev);
        free_irq(spi->irq, priv);
index f52c312cc356c6deb2af0f2c9934d8a2a46cdd32..537fb06e593200144c8b1d09c1aae732416748e1 100644 (file)
 #define OBCR_ODS_16mA                          (1 << 6)
 
 #define KS_EEPCR                               0x22
+#define EEPCR_EESRWA                           (1 << 5)
 #define EEPCR_EESA                             (1 << 4)
-#define EEPCR_EESB                             (1 << 3)
+#define EEPCR_EESB_OFFSET                      3
+#define EEPCR_EESB                             (1 << EEPCR_EESB_OFFSET)
 #define EEPCR_EEDO                             (1 << 2)
 #define EEPCR_EESCK                            (1 << 1)
 #define EEPCR_EECS                             (1 << 0)
 
+#define EEPROM_OP_LEN                          3       /* bits:*/
+#define EEPROM_OP_READ                         0x06
+#define EEPROM_OP_EWEN                         0x04
+#define EEPROM_OP_WRITE                                0x05
+#define EEPROM_OP_EWDS                         0x14
+
+#define EEPROM_DATA_LEN                                16      /* 16 bits EEPROM */
+#define EEPROM_WRITE_TIME                      4       /* wrt ack time in ms */
+#define EEPROM_SK_PERIOD                       400     /* in us */
+
 #define KS_MBIR                                        0x24
 #define MBIR_TXMBF                             (1 << 12)
 #define MBIR_TXMBFA                            (1 << 11)
index 6354ab3a45a651beb59e5b47d97c7d909357a7a9..2e2c69b24062efb87654684048a1670f486ee741 100644 (file)
@@ -21,6 +21,8 @@
  * KS8851 16bit MLL chip from Micrel Inc.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
@@ -361,7 +363,6 @@ static u8 KS_DEFAULT_MAC_ADDRESS[] = { 0x00, 0x10, 0xA1, 0x86, 0x95, 0x11 };
 
 #define MAX_MCAST_LST                  32
 #define HW_MCAST_SIZE                  8
-#define MAC_ADDR_LEN                   6
 
 /**
  * union ks_tx_hdr - tx header data
@@ -449,7 +450,7 @@ struct ks_net {
        u16                     promiscuous;
        u16                     all_mcast;
        u16                     mcast_lst_size;
-       u8                      mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN];
+       u8                      mcast_lst[MAX_MCAST_LST][ETH_ALEN];
        u8                      mcast_bits[HW_MCAST_SIZE];
        u8                      mac_addr[6];
        u8                      fid;
@@ -459,11 +460,6 @@ struct ks_net {
 
 static int msg_enable;
 
-#define ks_info(_ks, _msg...) dev_info(&(_ks)->pdev->dev, _msg)
-#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->pdev->dev, _msg)
-#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->pdev->dev, _msg)
-#define ks_err(_ks, _msg...) dev_err(&(_ks)->pdev->dev, _msg)
-
 #define BE3             0x8000      /* Byte Enable 3 */
 #define BE2             0x4000      /* Byte Enable 2 */
 #define BE1             0x2000      /* Byte Enable 1 */
@@ -625,8 +621,7 @@ static void ks_set_powermode(struct ks_net *ks, unsigned pwrmode)
 {
        unsigned pmecr;
 
-       if (netif_msg_hw(ks))
-               ks_dbg(ks, "setting power mode %d\n", pwrmode);
+       netif_dbg(ks, hw, ks->netdev, "setting power mode %d\n", pwrmode);
 
        ks_rdreg16(ks, KS_GRR);
        pmecr = ks_rdreg16(ks, KS_PMECR);
@@ -806,11 +801,10 @@ static void ks_rcv(struct ks_net *ks, struct net_device *netdev)
                        /* read data block including CRC 4 bytes */
                        ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len);
                        skb_put(skb, frame_hdr->len);
-                       skb->dev = netdev;
                        skb->protocol = eth_type_trans(skb, netdev);
                        netif_rx(skb);
                } else {
-                       printk(KERN_ERR "%s: err:skb alloc\n", __func__);
+                       pr_err("%s: err:skb alloc\n", __func__);
                        ks_wrreg16(ks, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
                        if (skb)
                                dev_kfree_skb_irq(skb);
@@ -837,9 +831,8 @@ static void ks_update_link_status(struct net_device *netdev, struct ks_net *ks)
                netif_carrier_off(netdev);
                link_up_status = false;
        }
-       if (netif_msg_link(ks))
-               ks_dbg(ks, "%s: %s\n",
-                       __func__, link_up_status ? "UP" : "DOWN");
+       netif_dbg(ks, link, ks->netdev,
+                 "%s: %s\n", __func__, link_up_status ? "UP" : "DOWN");
 }
 
 /**
@@ -909,15 +902,13 @@ static int ks_net_open(struct net_device *netdev)
         * else at the moment.
         */
 
-       if (netif_msg_ifup(ks))
-               ks_dbg(ks, "%s - entry\n", __func__);
+       netif_dbg(ks, ifup, ks->netdev, "%s - entry\n", __func__);
 
        /* reset the HW */
        err = request_irq(ks->irq, ks_irq, KS_INT_FLAGS, DRV_NAME, netdev);
 
        if (err) {
-               printk(KERN_ERR "Failed to request IRQ: %d: %d\n",
-                       ks->irq, err);
+               pr_err("Failed to request IRQ: %d: %d\n", ks->irq, err);
                return err;
        }
 
@@ -930,8 +921,7 @@ static int ks_net_open(struct net_device *netdev)
        ks_enable_qmu(ks);
        netif_start_queue(ks->netdev);
 
-       if (netif_msg_ifup(ks))
-               ks_dbg(ks, "network device %s up\n", netdev->name);
+       netif_dbg(ks, ifup, ks->netdev, "network device up\n");
 
        return 0;
 }
@@ -948,8 +938,7 @@ static int ks_net_stop(struct net_device *netdev)
 {
        struct ks_net *ks = netdev_priv(netdev);
 
-       if (netif_msg_ifdown(ks))
-               ks_info(ks, "%s: shutting down\n", netdev->name);
+       netif_info(ks, ifdown, netdev, "shutting down\n");
 
        netif_stop_queue(netdev);
 
@@ -1181,7 +1170,7 @@ static void ks_set_mcast(struct ks_net *ks, u16 mcast)
 static void ks_set_rx_mode(struct net_device *netdev)
 {
        struct ks_net *ks = netdev_priv(netdev);
-       struct dev_mc_list *ptr;
+       struct netdev_hw_addr *ha;
 
        /* Turn on/off promiscuous mode. */
        if ((netdev->flags & IFF_PROMISC) == IFF_PROMISC)
@@ -1198,13 +1187,12 @@ static void ks_set_rx_mode(struct net_device *netdev)
                if (netdev_mc_count(netdev) <= MAX_MCAST_LST) {
                        int i = 0;
 
-                       netdev_for_each_mc_addr(ptr, netdev) {
-                               if (!(*ptr->dmi_addr & 1))
+                       netdev_for_each_mc_addr(ha, netdev) {
+                               if (!(*ha->addr & 1))
                                        continue;
                                if (i >= MAX_MCAST_LST)
                                        break;
-                               memcpy(ks->mcast_lst[i++], ptr->dmi_addr,
-                               MAC_ADDR_LEN);
+                               memcpy(ks->mcast_lst[i++], ha->addr, ETH_ALEN);
                        }
                        ks->mcast_lst_size = (u8)i;
                        ks_set_grpaddr(ks);
@@ -1430,21 +1418,21 @@ static int ks_read_selftest(struct ks_net *ks)
        rd = ks_rdreg16(ks, KS_MBIR);
 
        if ((rd & both_done) != both_done) {
-               ks_warn(ks, "Memory selftest not finished\n");
+               netdev_warn(ks->netdev, "Memory selftest not finished\n");
                return 0;
        }
 
        if (rd & MBIR_TXMBFA) {
-               ks_err(ks, "TX memory selftest fails\n");
+               netdev_err(ks->netdev, "TX memory selftest fails\n");
                ret |= 1;
        }
 
        if (rd & MBIR_RXMBFA) {
-               ks_err(ks, "RX memory selftest fails\n");
+               netdev_err(ks->netdev, "RX memory selftest fails\n");
                ret |= 2;
        }
 
-       ks_info(ks, "the selftest passes\n");
+       netdev_info(ks->netdev, "the selftest passes\n");
        return ret;
 }
 
@@ -1515,7 +1503,7 @@ static int ks_hw_init(struct ks_net *ks)
        ks->frame_head_info = (struct type_frame_head *) \
                kmalloc(MHEADER_SIZE, GFP_KERNEL);
        if (!ks->frame_head_info) {
-               printk(KERN_ERR "Error: Fail to allocate frame memory\n");
+               pr_err("Error: Fail to allocate frame memory\n");
                return false;
        }
 
@@ -1581,7 +1569,7 @@ static int __devinit ks8851_probe(struct platform_device *pdev)
        ks->mii.mdio_read       = ks_phy_read;
        ks->mii.mdio_write      = ks_phy_write;
 
-       ks_info(ks, "message enable is %d\n", msg_enable);
+       netdev_info(netdev, "message enable is %d\n", msg_enable);
        /* set the default message enable */
        ks->msg_enable = netif_msg_init(msg_enable, (NETIF_MSG_DRV |
                                                     NETIF_MSG_PROBE |
@@ -1590,13 +1578,13 @@ static int __devinit ks8851_probe(struct platform_device *pdev)
 
        /* simple check for a valid chip being connected to the bus */
        if ((ks_rdreg16(ks, KS_CIDER) & ~CIDER_REV_MASK) != CIDER_ID) {
-               ks_err(ks, "failed to read device ID\n");
+               netdev_err(netdev, "failed to read device ID\n");
                err = -ENODEV;
                goto err_register;
        }
 
        if (ks_read_selftest(ks)) {
-               ks_err(ks, "failed to read device ID\n");
+               netdev_err(netdev, "failed to read device ID\n");
                err = -ENODEV;
                goto err_register;
        }
@@ -1627,9 +1615,8 @@ static int __devinit ks8851_probe(struct platform_device *pdev)
 
        id = ks_rdreg16(ks, KS_CIDER);
 
-       printk(KERN_INFO DRV_NAME
-               " Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n",
-               (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7);
+       netdev_info(netdev, "Found chip, family: 0x%x, id: 0x%x, rev: 0x%x\n",
+                   (id >> 8) & 0xff, (id >> 4) & 0xf, (id >> 1) & 0x7);
        return 0;
 
 err_register:
index 0606a1f359fb8a2c2d1ca47fe6907565ce3e489c..c80ca64277b224934bc57e1b541c7cef7193a9ff 100644 (file)
  * GNU General Public License for more details.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
@@ -1484,11 +1485,6 @@ struct dev_priv {
        int promiscuous;
 };
 
-#define ks_info(_ks, _msg...) dev_info(&(_ks)->pdev->dev, _msg)
-#define ks_warn(_ks, _msg...) dev_warn(&(_ks)->pdev->dev, _msg)
-#define ks_dbg(_ks, _msg...) dev_dbg(&(_ks)->pdev->dev, _msg)
-#define ks_err(_ks, _msg...) dev_err(&(_ks)->pdev->dev, _msg)
-
 #define DRV_NAME               "KSZ884X PCI"
 #define DEVICE_NAME            "KSZ884x PCI"
 #define DRV_VERSION            "1.0.0"
@@ -3835,7 +3831,7 @@ static void ksz_check_desc_num(struct ksz_desc_info *info)
                alloc >>= 1;
        }
        if (alloc != 1 || shift < MIN_DESC_SHIFT) {
-               printk(KERN_ALERT "Hardware descriptor numbers not right!\n");
+               pr_alert("Hardware descriptor numbers not right!\n");
                while (alloc) {
                        shift++;
                        alloc >>= 1;
@@ -4546,8 +4542,7 @@ static int ksz_alloc_mem(struct dev_info *adapter)
                (((sizeof(struct ksz_hw_desc) + DESC_ALIGNMENT - 1) /
                DESC_ALIGNMENT) * DESC_ALIGNMENT);
        if (hw->rx_desc_info.size != sizeof(struct ksz_hw_desc))
-               printk(KERN_ALERT
-                       "Hardware descriptor size not right!\n");
+               pr_alert("Hardware descriptor size not right!\n");
        ksz_check_desc_num(&hw->rx_desc_info);
        ksz_check_desc_num(&hw->tx_desc_info);
 
@@ -4689,7 +4684,7 @@ static void send_packet(struct sk_buff *skb, struct net_device *dev)
                int frag;
                skb_frag_t *this_frag;
 
-               dma_buf->len = skb->len - skb->data_len;
+               dma_buf->len = skb_headlen(skb);
 
                dma_buf->dma = pci_map_single(
                        hw_priv->pdev, skb->data, dma_buf->len,
@@ -5049,8 +5044,6 @@ static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw,
                        dma_buf->skb->data, packet_len);
        } while (0);
 
-       skb->dev = dev;
-
        skb->protocol = eth_type_trans(skb, dev);
 
        if (hw->rx_cfg & (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP))
@@ -5061,8 +5054,6 @@ static inline int rx_proc(struct net_device *dev, struct ksz_hw* hw,
        priv->stats.rx_bytes += packet_len;
 
        /* Notify upper layer for received packet. */
-       dev->last_rx = jiffies;
-
        rx_status = netif_rx(skb);
 
        return 0;
@@ -5320,10 +5311,10 @@ static irqreturn_t netdev_intr(int irq, void *dev_id)
                        u32 data;
 
                        hw->intr_mask &= ~KS884X_INT_TX_STOPPED;
-                       printk(KERN_INFO "Tx stopped\n");
+                       pr_info("Tx stopped\n");
                        data = readl(hw->io + KS_DMA_TX_CTRL);
                        if (!(data & DMA_TX_ENABLE))
-                               printk(KERN_INFO "Tx disabled\n");
+                               pr_info("Tx disabled\n");
                        break;
                }
        } while (0);
@@ -5496,6 +5487,18 @@ static int prepare_hardware(struct net_device *dev)
        return 0;
 }
 
+static void set_media_state(struct net_device *dev, int media_state)
+{
+       struct dev_priv *priv = netdev_priv(dev);
+
+       if (media_state == priv->media_state)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
+       netif_info(priv, link, dev, "link %s\n",
+                  media_state == priv->media_state ? "on" : "off");
+}
+
 /**
  * netdev_open - open network device
  * @dev:       Network device.
@@ -5585,15 +5588,7 @@ static int netdev_open(struct net_device *dev)
 
        priv->media_state = port->linked->state;
 
-       if (media_connected == priv->media_state)
-               netif_carrier_on(dev);
-       else
-               netif_carrier_off(dev);
-       if (netif_msg_link(priv))
-               printk(KERN_INFO "%s link %s\n", dev->name,
-                       (media_connected == priv->media_state ?
-                       "on" : "off"));
-
+       set_media_state(dev, media_connected);
        netif_start_queue(dev);
 
        return 0;
@@ -5767,7 +5762,7 @@ static void netdev_set_rx_mode(struct net_device *dev)
        struct dev_priv *priv = netdev_priv(dev);
        struct dev_info *hw_priv = priv->adapter;
        struct ksz_hw *hw = &hw_priv->hw;
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        int multicast = (dev->flags & IFF_ALLMULTI);
 
        dev_set_promiscuous(dev, priv, hw, (dev->flags & IFF_PROMISC));
@@ -5784,7 +5779,7 @@ static void netdev_set_rx_mode(struct net_device *dev)
                int i = 0;
 
                /* List too big to support so turn on all multicast mode. */
-               if (dev->mc_count > MAX_MULTICAST_LIST) {
+               if (netdev_mc_count(dev) > MAX_MULTICAST_LIST) {
                        if (MAX_MULTICAST_LIST != hw->multi_list_size) {
                                hw->multi_list_size = MAX_MULTICAST_LIST;
                                ++hw->all_multi;
@@ -5793,13 +5788,12 @@ static void netdev_set_rx_mode(struct net_device *dev)
                        return;
                }
 
-               netdev_for_each_mc_addr(mc_ptr, dev) {
-                       if (!(*mc_ptr->dmi_addr & 1))
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (!(*ha->addr & 1))
                                continue;
                        if (i >= MAX_MULTICAST_LIST)
                                break;
-                       memcpy(hw->multi_list[i++], mc_ptr->dmi_addr,
-                               MAC_ADDR_LEN);
+                       memcpy(hw->multi_list[i++], ha->addr, MAC_ADDR_LEN);
                }
                hw->multi_list_size = (u8) i;
                hw_set_grp_addr(hw);
@@ -6683,16 +6677,8 @@ static void update_link(struct net_device *dev, struct dev_priv *priv,
 {
        if (priv->media_state != port->linked->state) {
                priv->media_state = port->linked->state;
-               if (netif_running(dev)) {
-                       if (media_connected == priv->media_state)
-                               netif_carrier_on(dev);
-                       else
-                               netif_carrier_off(dev);
-                       if (netif_msg_link(priv))
-                               printk(KERN_INFO "%s link %s\n", dev->name,
-                                       (media_connected == priv->media_state ?
-                                       "on" : "off"));
-               }
+               if (netif_running(dev))
+                       set_media_state(dev, media_connected);
        }
 }
 
@@ -6986,7 +6972,7 @@ static int __init pcidev_init(struct pci_dev *pdev,
        int pi;
        int port_count;
        int result;
-       char banner[80];
+       char banner[sizeof(version)];
        struct ksz_switch *sw = NULL;
 
        result = pci_enable_device(pdev);
@@ -7010,10 +6996,9 @@ static int __init pcidev_init(struct pci_dev *pdev,
 
        result = -ENOMEM;
 
-       info = kmalloc(sizeof(struct platform_info), GFP_KERNEL);
+       info = kzalloc(sizeof(struct platform_info), GFP_KERNEL);
        if (!info)
                goto pcidev_init_dev_err;
-       memset(info, 0, sizeof(struct platform_info));
 
        hw_priv = &info->dev_info;
        hw_priv->pdev = pdev;
@@ -7027,15 +7012,15 @@ static int __init pcidev_init(struct pci_dev *pdev,
        cnt = hw_init(hw);
        if (!cnt) {
                if (msg_enable & NETIF_MSG_PROBE)
-                       printk(KERN_ALERT "chip not detected\n");
+                       pr_alert("chip not detected\n");
                result = -ENODEV;
                goto pcidev_init_alloc_err;
        }
 
-       sprintf(banner, "%s\n", version);
-       banner[13] = cnt + '0';
-       ks_info(hw_priv, "%s", banner);
-       ks_dbg(hw_priv, "Mem = %p; IRQ = %d\n", hw->io, pdev->irq);
+       snprintf(banner, sizeof(banner), "%s", version);
+       banner[13] = cnt + '0';         /* Replace x in "Micrel KSZ884x" */
+       dev_info(&hw_priv->pdev->dev, "%s\n", banner);
+       dev_dbg(&hw_priv->pdev->dev, "Mem = %p; IRQ = %d\n", hw->io, pdev->irq);
 
        /* Assume device is KSZ8841. */
        hw->dev_count = 1;
@@ -7064,10 +7049,9 @@ static int __init pcidev_init(struct pci_dev *pdev,
                        mib_port_count = SWITCH_PORT_NUM;
                }
                hw->mib_port_cnt = TOTAL_PORT_NUM;
-               hw->ksz_switch = kmalloc(sizeof(struct ksz_switch), GFP_KERNEL);
+               hw->ksz_switch = kzalloc(sizeof(struct ksz_switch), GFP_KERNEL);
                if (!hw->ksz_switch)
                        goto pcidev_init_alloc_err;
-               memset(hw->ksz_switch, 0, sizeof(struct ksz_switch));
 
                sw = hw->ksz_switch;
        }
index 7b9447646f8a0c437fba01f007b5f090948c457d..21f8adaa87c164c8b2f604bf75937f5a072fb773 100644 (file)
@@ -945,7 +945,7 @@ static void lance_tx_timeout (struct net_device *dev)
 #endif
        lance_restart (dev, 0x0043, 1);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue (dev);
 }
 
@@ -1011,8 +1011,6 @@ static netdev_tx_t lance_start_xmit(struct sk_buff *skb,
        outw(0x0000, ioaddr+LANCE_ADDR);
        outw(0x0048, ioaddr+LANCE_DATA);
 
-       dev->trans_start = jiffies;
-
        if ((lp->cur_tx - lp->dirty_tx) >= TX_RING_SIZE)
                netif_stop_queue(dev);
 
index 973390b82ec28850cf17f1ab26c18e7538f656a9..ce5d6e9092182a43d2f0660e68667edf44bfae3b 100644 (file)
@@ -963,7 +963,7 @@ static void i596_tx_timeout (struct net_device *dev)
                lp->last_restart = dev->stats.tx_packets;
        }
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue (dev);
 }
 
@@ -974,7 +974,6 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct tx_cmd *tx_cmd;
        struct i596_tbd *tbd;
        short length = skb->len;
-       dev->trans_start = jiffies;
 
        DEB(DEB_STARTTX, printk(KERN_DEBUG
                                "%s: i596_start_xmit(%x,%p) called\n",
@@ -1092,7 +1091,7 @@ static int __devinit i82596_probe(struct net_device *dev)
                DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
                                    (void *)dma, lp->dma_addr);
                return i;
-       };
+       }
 
        DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx, %pM IRQ %d.\n",
                              dev->name, dev->base_addr, dev->dev_addr,
@@ -1388,7 +1387,7 @@ static void set_multicast_list(struct net_device *dev)
        }
 
        if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                unsigned char *cp;
                struct mc_cmd *cmd;
 
@@ -1396,10 +1395,10 @@ static void set_multicast_list(struct net_device *dev)
                cmd->cmd.command = SWAP16(CmdMulticastList);
                cmd->mc_cnt = SWAP16(netdev_mc_count(dev) * 6);
                cp = cmd->mc_addrs;
-               netdev_for_each_mc_addr(dmi, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        if (!cnt--)
                                break;
-                       memcpy(cp, dmi->dmi_addr, 6);
+                       memcpy(cp, ha->addr, 6);
                        if (i596_debug > 1)
                                DEB(DEB_MULTI,
                                    printk(KERN_DEBUG
index 56f66f485400bedc670436d7e1bbe66f09f1a23f..316bb70775b111a11853f783791b265e9a6bc598 100644 (file)
@@ -257,7 +257,7 @@ static void __ei_tx_timeout(struct net_device *dev)
 {
        unsigned long e8390_base = dev->base_addr;
        struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-       int txsr, isr, tickssofar = jiffies - dev->trans_start;
+       int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
        unsigned long flags;
 
        dev->stats.tx_errors++;
@@ -386,7 +386,6 @@ static netdev_tx_t __ei_start_xmit(struct sk_buff *skb,
        {
                ei_local->txing = 1;
                NS8390_trigger_send(dev, send_length, output_page);
-               dev->trans_start = jiffies;
                if (output_page == ei_local->tx_start_page)
                {
                        ei_local->tx1 = -1;
@@ -445,14 +444,14 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id)
 
        if (ei_local->irqlock)
        {
-#if 1 /* This might just be an interrupt for a PCI device sharing this line */
-               /* The "irqlock" check is only for testing. */
-               printk(ei_local->irqlock
-                          ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
-                          : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+               /*
+                * This might just be an interrupt for a PCI device sharing
+                * this line
+                */
+               printk("%s: Interrupted while interrupts are masked!"
+                          " isr=%#2x imr=%#2x.\n",
                           dev->name, ei_inb_p(e8390_base + EN0_ISR),
                           ei_inb_p(e8390_base + EN0_IMR));
-#endif
                spin_unlock(&ei_local->page_lock);
                return IRQ_NONE;
        }
@@ -792,7 +791,6 @@ static void ei_receive(struct net_device *dev)
        /* We used to also ack ENISR_OVER here, but that would sometimes mask
           a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
        ei_outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
-       return;
 }
 
 /**
@@ -905,10 +903,10 @@ static struct net_device_stats *__ei_get_stats(struct net_device *dev)
 
 static inline void make_mc_bits(u8 *bits, struct net_device *dev)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
-       netdev_for_each_mc_addr(dmi, dev) {
-               u32 crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+       netdev_for_each_mc_addr(ha, dev) {
+               u32 crc = ether_crc(ETH_ALEN, ha->addr);
                /*
                 * The 8390 uses the 6 most significant bits of the
                 * CRC to index the multicast table.
index 1af66a1e6911e8c0589c647a210e5425810628a8..c03358434acb8f513464764b1a1ec147add0b681 100644 (file)
@@ -5,8 +5,11 @@
 #include <linux/netdevice.h>
 #include <linux/of.h>
 #include <linux/spinlock.h>
+
+#ifdef CONFIG_PPC_DCR
 #include <asm/dcr.h>
 #include <asm/dcr-regs.h>
+#endif
 
 /* packet size info */
 #define XTE_HDR_SIZE                   14      /* size of Ethernet header */
@@ -290,9 +293,6 @@ This option defaults to enabled (set) */
 
 #define TX_CONTROL_CALC_CSUM_MASK   1
 
-#define XTE_ALIGN       32
-#define BUFFER_ALIGN(adr) ((XTE_ALIGN - ((u32) adr)) % XTE_ALIGN)
-
 #define MULTICAST_CAM_TABLE_NUM 4
 
 /* TX/RX CURDESC_PTR points to first descriptor */
@@ -335,9 +335,15 @@ struct temac_local {
        struct mii_bus *mii_bus;        /* MII bus reference */
        int mdio_irqs[PHY_MAX_ADDR];    /* IRQs table for MDIO bus */
 
-       /* IO registers and IRQs */
+       /* IO registers, dma functions and IRQs */
        void __iomem *regs;
+       void __iomem *sdma_regs;
+#ifdef CONFIG_PPC_DCR
        dcr_host_t sdma_dcrs;
+#endif
+       u32 (*dma_in)(struct temac_local *, int);
+       void (*dma_out)(struct temac_local *, int, u32);
+
        int tx_irq;
        int rx_irq;
        int emac_num;
index ba617e3cf1bbd6c9442419e8fd591bcc582eaab2..b59b24d667f0a0a4d9b3f823961506465a191b44 100644 (file)
@@ -20,9 +20,6 @@
  *   or rx, so this should be okay.
  *
  * TODO:
- * - Fix driver to work on more than just Virtex5.  Right now the driver
- *   assumes that the locallink DMA registers are accessed via DCR
- *   instructions.
  * - Factor out locallink DMA code into separate driver
  * - Fix multicast assignment.
  * - Fix support for hardware checksumming.
@@ -116,16 +113,85 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value)
        temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg);
 }
 
+/**
+ * temac_dma_in32 - Memory mapped DMA read, this function expects a
+ * register input that is based on DCR word addresses which
+ * are then converted to memory mapped byte addresses
+ */
 static u32 temac_dma_in32(struct temac_local *lp, int reg)
 {
-       return dcr_read(lp->sdma_dcrs, reg);
+       return in_be32((u32 *)(lp->sdma_regs + (reg << 2)));
 }
 
+/**
+ * temac_dma_out32 - Memory mapped DMA read, this function expects a
+ * register input that is based on DCR word addresses which
+ * are then converted to memory mapped byte addresses
+ */
 static void temac_dma_out32(struct temac_local *lp, int reg, u32 value)
+{
+       out_be32((u32 *)(lp->sdma_regs + (reg << 2)), value);
+}
+
+/* DMA register access functions can be DCR based or memory mapped.
+ * The PowerPC 440 is DCR based, the PowerPC 405 and MicroBlaze are both
+ * memory mapped.
+ */
+#ifdef CONFIG_PPC_DCR
+
+/**
+ * temac_dma_dcr_in32 - DCR based DMA read
+ */
+static u32 temac_dma_dcr_in(struct temac_local *lp, int reg)
+{
+       return dcr_read(lp->sdma_dcrs, reg);
+}
+
+/**
+ * temac_dma_dcr_out32 - DCR based DMA write
+ */
+static void temac_dma_dcr_out(struct temac_local *lp, int reg, u32 value)
 {
        dcr_write(lp->sdma_dcrs, reg, value);
 }
 
+/**
+ * temac_dcr_setup - If the DMA is DCR based, then setup the address and
+ * I/O  functions
+ */
+static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
+                               struct device_node *np)
+{
+       unsigned int dcrs;
+
+       /* setup the dcr address mapping if it's in the device tree */
+
+       dcrs = dcr_resource_start(np, 0);
+       if (dcrs != 0) {
+               lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
+               lp->dma_in = temac_dma_dcr_in;
+               lp->dma_out = temac_dma_dcr_out;
+               dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
+               return 0;
+       }
+       /* no DCR in the device tree, indicate a failure */
+       return -1;
+}
+
+#else
+
+/*
+ * temac_dcr_setup - This is a stub for when DCR is not supported,
+ * such as with MicroBlaze
+ */
+static int temac_dcr_setup(struct temac_local *lp, struct of_device *op,
+                               struct device_node *np)
+{
+       return -1;
+}
+
+#endif
+
 /**
  * temac_dma_bd_init - Setup buffer descriptor rings
  */
@@ -156,14 +222,14 @@ static int temac_dma_bd_init(struct net_device *ndev)
                lp->rx_bd_v[i].next = lp->rx_bd_p +
                                sizeof(*lp->rx_bd_v) * ((i + 1) % RX_BD_NUM);
 
-               skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE
-                               + XTE_ALIGN, GFP_ATOMIC);
+               skb = netdev_alloc_skb_ip_align(ndev,
+                                               XTE_MAX_JUMBO_FRAME_SIZE);
+
                if (skb == 0) {
                        dev_err(&ndev->dev, "alloc_skb error %d\n", i);
                        return -1;
                }
                lp->rx_skb[i] = skb;
-               skb_reserve(skb,  BUFFER_ALIGN(skb->data));
                /* returns physical address of skb->data */
                lp->rx_bd_v[i].phys = dma_map_single(ndev->dev.parent,
                                                     skb->data,
@@ -173,23 +239,23 @@ static int temac_dma_bd_init(struct net_device *ndev)
                lp->rx_bd_v[i].app0 = STS_CTRL_APP0_IRQONEND;
        }
 
-       temac_dma_out32(lp, TX_CHNL_CTRL, 0x10220400 |
+       lp->dma_out(lp, TX_CHNL_CTRL, 0x10220400 |
                                          CHNL_CTRL_IRQ_EN |
                                          CHNL_CTRL_IRQ_DLY_EN |
                                          CHNL_CTRL_IRQ_COAL_EN);
        /* 0x10220483 */
        /* 0x00100483 */
-       temac_dma_out32(lp, RX_CHNL_CTRL, 0xff010000 |
+       lp->dma_out(lp, RX_CHNL_CTRL, 0xff010000 |
                                          CHNL_CTRL_IRQ_EN |
                                          CHNL_CTRL_IRQ_DLY_EN |
                                          CHNL_CTRL_IRQ_COAL_EN |
                                          CHNL_CTRL_IRQ_IOE);
        /* 0xff010283 */
 
-       temac_dma_out32(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
-       temac_dma_out32(lp, RX_TAILDESC_PTR,
+       lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
+       lp->dma_out(lp, RX_TAILDESC_PTR,
                       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
-       temac_dma_out32(lp, TX_CURDESC_PTR, lp->tx_bd_p);
+       lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
 
        return 0;
 }
@@ -251,20 +317,20 @@ static void temac_set_multicast_list(struct net_device *ndev)
                temac_indirect_out32(lp, XTE_AFM_OFFSET, XTE_AFM_EPPRM_MASK);
                dev_info(&ndev->dev, "Promiscuous mode enabled.\n");
        } else if (!netdev_mc_empty(ndev)) {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                i = 0;
-               netdev_for_each_mc_addr(mclist, ndev) {
+               netdev_for_each_mc_addr(ha, ndev) {
                        if (i >= MULTICAST_CAM_TABLE_NUM)
                                break;
-                       multi_addr_msw = ((mclist->dmi_addr[3] << 24) |
-                                         (mclist->dmi_addr[2] << 16) |
-                                         (mclist->dmi_addr[1] << 8) |
-                                         (mclist->dmi_addr[0]));
+                       multi_addr_msw = ((ha->addr[3] << 24) |
+                                         (ha->addr[2] << 16) |
+                                         (ha->addr[1] << 8) |
+                                         (ha->addr[0]));
                        temac_indirect_out32(lp, XTE_MAW0_OFFSET,
                                             multi_addr_msw);
-                       multi_addr_lsw = ((mclist->dmi_addr[5] << 8) |
-                                         (mclist->dmi_addr[4]) | (i << 16));
+                       multi_addr_lsw = ((ha->addr[5] << 8) |
+                                         (ha->addr[4]) | (i << 16));
                        temac_indirect_out32(lp, XTE_MAW1_OFFSET,
                                             multi_addr_lsw);
                        i++;
@@ -427,9 +493,9 @@ static void temac_device_reset(struct net_device *ndev)
        temac_indirect_out32(lp, XTE_RXC1_OFFSET, val & ~XTE_RXC1_RXEN_MASK);
 
        /* Reset Local Link (DMA) */
-       temac_dma_out32(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
+       lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST);
        timeout = 1000;
-       while (temac_dma_in32(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
+       while (lp->dma_in(lp, DMA_CONTROL_REG) & DMA_CONTROL_RST) {
                udelay(1);
                if (--timeout == 0) {
                        dev_err(&ndev->dev,
@@ -437,7 +503,7 @@ static void temac_device_reset(struct net_device *ndev)
                        break;
                }
        }
-       temac_dma_out32(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
+       lp->dma_out(lp, DMA_CONTROL_REG, DMA_TAIL_ENABLE);
 
        temac_dma_bd_init(ndev);
 
@@ -461,7 +527,7 @@ static void temac_device_reset(struct net_device *ndev)
                dev_err(&ndev->dev, "Error setting TEMAC options\n");
 
        /* Init Driver variable */
-       ndev->trans_start = 0;
+       ndev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 void temac_adjust_link(struct net_device *ndev)
@@ -598,7 +664,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                lp->tx_bd_tail = 0;
 
        /* Kick off the transfer */
-       temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
+       lp->dma_out(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
 
        return NETDEV_TX_OK;
 }
@@ -612,7 +678,6 @@ static void ll_temac_recv(struct net_device *ndev)
        struct cdmac_bd *cur_p;
        dma_addr_t tail_p;
        int length;
-       unsigned long skb_vaddr;
        unsigned long flags;
 
        spin_lock_irqsave(&lp->rx_lock, flags);
@@ -626,8 +691,7 @@ static void ll_temac_recv(struct net_device *ndev)
                skb = lp->rx_skb[lp->rx_bd_ci];
                length = cur_p->app4 & 0x3FFF;
 
-               skb_vaddr = virt_to_bus(skb->data);
-               dma_unmap_single(ndev->dev.parent, skb_vaddr, length,
+               dma_unmap_single(ndev->dev.parent, cur_p->phys, length,
                                 DMA_FROM_DEVICE);
 
                skb_put(skb, length);
@@ -640,16 +704,15 @@ static void ll_temac_recv(struct net_device *ndev)
                ndev->stats.rx_packets++;
                ndev->stats.rx_bytes += length;
 
-               new_skb = alloc_skb(XTE_MAX_JUMBO_FRAME_SIZE + XTE_ALIGN,
-                               GFP_ATOMIC);
+               new_skb = netdev_alloc_skb_ip_align(ndev,
+                                               XTE_MAX_JUMBO_FRAME_SIZE);
+
                if (new_skb == 0) {
                        dev_err(&ndev->dev, "no memory for new sk_buff\n");
                        spin_unlock_irqrestore(&lp->rx_lock, flags);
                        return;
                }
 
-               skb_reserve(new_skb, BUFFER_ALIGN(new_skb->data));
-
                cur_p->app0 = STS_CTRL_APP0_IRQONEND;
                cur_p->phys = dma_map_single(ndev->dev.parent, new_skb->data,
                                             XTE_MAX_JUMBO_FRAME_SIZE,
@@ -664,7 +727,7 @@ static void ll_temac_recv(struct net_device *ndev)
                cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
                bdstat = cur_p->app0;
        }
-       temac_dma_out32(lp, RX_TAILDESC_PTR, tail_p);
+       lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
        spin_unlock_irqrestore(&lp->rx_lock, flags);
 }
@@ -675,8 +738,8 @@ static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
        struct temac_local *lp = netdev_priv(ndev);
        unsigned int status;
 
-       status = temac_dma_in32(lp, TX_IRQ_REG);
-       temac_dma_out32(lp, TX_IRQ_REG, status);
+       status = lp->dma_in(lp, TX_IRQ_REG);
+       lp->dma_out(lp, TX_IRQ_REG, status);
 
        if (status & (IRQ_COAL | IRQ_DLY))
                temac_start_xmit_done(lp->ndev);
@@ -693,8 +756,8 @@ static irqreturn_t ll_temac_rx_irq(int irq, void *_ndev)
        unsigned int status;
 
        /* Read and clear the status registers */
-       status = temac_dma_in32(lp, RX_IRQ_REG);
-       temac_dma_out32(lp, RX_IRQ_REG, status);
+       status = lp->dma_in(lp, RX_IRQ_REG);
+       lp->dma_out(lp, RX_IRQ_REG, status);
 
        if (status & (IRQ_COAL | IRQ_DLY))
                ll_temac_recv(lp->ndev);
@@ -795,7 +858,7 @@ static ssize_t temac_show_llink_regs(struct device *dev,
        int i, len = 0;
 
        for (i = 0; i < 0x11; i++)
-               len += sprintf(buf + len, "%.8x%s", temac_dma_in32(lp, i),
+               len += sprintf(buf + len, "%.8x%s", lp->dma_in(lp, i),
                               (i % 8) == 7 ? "\n" : " ");
        len += sprintf(buf + len, "\n");
 
@@ -821,7 +884,6 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
        struct net_device *ndev;
        const void *addr;
        int size, rc = 0;
-       unsigned int dcrs;
 
        /* Init network device structure */
        ndev = alloc_etherdev(sizeof(*lp));
@@ -871,13 +933,20 @@ temac_of_probe(struct of_device *op, const struct of_device_id *match)
                goto nodev;
        }
 
-       dcrs = dcr_resource_start(np, 0);
-       if (dcrs == 0) {
-               dev_err(&op->dev, "could not get DMA register address\n");
-               goto nodev;
+       /* Setup the DMA register accesses, could be DCR or memory mapped */
+       if (temac_dcr_setup(lp, op, np)) {
+
+               /* no DCR in the device tree, try non-DCR */
+               lp->sdma_regs = of_iomap(np, 0);
+               if (lp->sdma_regs) {
+                       lp->dma_in = temac_dma_in32;
+                       lp->dma_out = temac_dma_out32;
+                       dev_dbg(&op->dev, "MEM base: %p\n", lp->sdma_regs);
+               } else {
+                       dev_err(&op->dev, "unable to map DMA registers\n");
+                       goto nodev;
+               }
        }
-       lp->sdma_dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
-       dev_dbg(&op->dev, "DCR base: %x\n", dcrs);
 
        lp->rx_irq = irq_of_parse_and_map(np, 0);
        lp->tx_irq = irq_of_parse_and_map(np, 1);
index 41cbaaef06548da3f8357afafea280807dfe24f5..8a1097cf8a83b78a3dea7a3b64485ab752cfc946 100644 (file)
@@ -307,8 +307,6 @@ static void lne390_reset_8390(struct net_device *dev)
        ei_status.txing = 0;
        outb(0x01, ioaddr + LNE390_RESET_PORT);
        if (ei_debug > 1) printk("reset done\n");
-
-       return;
 }
 
 /*
index 3e3cc04defd03d37c1bff766e13e25595628b94e..3df046a58b1d484c11625e984b1a8b5b0420c327 100644 (file)
@@ -875,8 +875,6 @@ static netdev_tx_t i596_start_xmit (struct sk_buff *skb, struct net_device *dev)
                length = ETH_ZLEN;
        }
 
-       dev->trans_start = jiffies;
-
        tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
        if (tx_cmd == NULL) {
                printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
@@ -1256,7 +1254,7 @@ static void set_multicast_list(struct net_device *dev) {
                        dev->name, netdev_mc_count(dev));
 
        if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                char *cp;
                cmd = kmalloc(sizeof(struct i596_cmd) + 2 +
                              netdev_mc_count(dev) * 6, GFP_ATOMIC);
@@ -1267,8 +1265,8 @@ static void set_multicast_list(struct net_device *dev) {
                cmd->command = CmdMulticastList;
                *((unsigned short *) (cmd + 1)) = netdev_mc_count(dev) * 6;
                cp = ((char *)(cmd + 1))+2;
-               netdev_for_each_mc_addr(dmi, dev) {
-                       memcpy(cp, dmi->dmi_addr, 6);
+               netdev_for_each_mc_addr(ha, dev) {
+                       memcpy(cp, ha->addr, 6);
                        cp += 6;
                }
                if (i596_debug & LOG_SRCDST)
index c8e68fde0664862dd0af4da936f4f0d1ae87f32e..1136c9a22b6772caa234a576eb5793d3b1e4fd78 100644 (file)
@@ -661,7 +661,6 @@ static void mac8390_no_reset(struct net_device *dev)
        ei_status.txing = 0;
        if (ei_debug > 1)
                pr_info("reset not supported\n");
-       return;
 }
 
 static void interlan_reset(struct net_device *dev)
@@ -673,7 +672,6 @@ static void interlan_reset(struct net_device *dev)
        target[0xC0000] = 0;
        if (ei_debug > 1)
                pr_cont("reset complete\n");
-       return;
 }
 
 /* dayna_memcpy_fromio/dayna_memcpy_toio */
index c0876e915eed7afe6adf84df917bf426a497707b..69fa4ef64dd24d99f6b7981735578d1f7aae65c5 100644 (file)
@@ -408,7 +408,6 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
                                  skb->len+1);
 
        local_irq_restore(flags);
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
 
        return NETDEV_TX_OK;
index c8a18a6203c8638c58963b03de7706b9821b0f74..40797fbdca9f774798668dba14381a96f9b68511 100644 (file)
@@ -666,8 +666,6 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&bp->lock, flags);
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -793,6 +791,7 @@ static void macb_init_hw(struct macb *bp)
        config = macb_readl(bp, NCFGR) & MACB_BF(CLK, -1L);
        config |= MACB_BIT(PAE);                /* PAuse Enable */
        config |= MACB_BIT(DRFCS);              /* Discard Rx FCS */
+       config |= MACB_BIT(BIG);                /* Receive oversized frames */
        if (bp->dev->flags & IFF_PROMISC)
                config |= MACB_BIT(CAF);        /* Copy All Frames */
        if (!(bp->dev->flags & IFF_BROADCAST))
@@ -882,15 +881,15 @@ static int hash_get_index(__u8 *addr)
  */
 static void macb_sethashtable(struct net_device *dev)
 {
-       struct dev_mc_list *curr;
+       struct netdev_hw_addr *ha;
        unsigned long mc_filter[2];
        unsigned int bitnr;
        struct macb *bp = netdev_priv(dev);
 
        mc_filter[0] = mc_filter[1] = 0;
 
-       netdev_for_each_mc_addr(curr, dev) {
-               bitnr = hash_get_index(curr->dmi_addr);
+       netdev_for_each_mc_addr(ha, dev) {
+               bitnr = hash_get_index(ha->addr);
                mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
        }
 
index 962c41d0c8dfb07d7837ee79d3c836fdf2cd90fb..b6855a6476f8eaa3480135d65096c05b870ed101 100644 (file)
@@ -599,7 +599,7 @@ static void mace_set_multicast(struct net_device *dev)
        mp->maccc |= PROM;
     } else {
        unsigned char multicast_filter[8];
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
        if (dev->flags & IFF_ALLMULTI) {
            for (i = 0; i < 8; i++)
@@ -607,8 +607,8 @@ static void mace_set_multicast(struct net_device *dev)
        } else {
            for (i = 0; i < 8; i++)
                multicast_filter[i] = 0;
-           netdev_for_each_mc_addr(dmi, dev) {
-               crc = ether_crc_le(6, dmi->dmi_addr);
+           netdev_for_each_mc_addr(ha, dev) {
+               crc = ether_crc_le(6, ha->addr);
                i = crc >> 26;  /* bit number in multicast_filter */
                multicast_filter[i >> 3] |= 1 << (i & 7);
            }
index 52e9a51c4c4fcf0788d2b33f74f033284779271a..c685a4656878c7793e222e448eab39c75dc93c5f 100644 (file)
@@ -488,7 +488,6 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
@@ -509,7 +508,7 @@ static void mace_set_multicast(struct net_device *dev)
                mb->maccc |= PROM;
        } else {
                unsigned char multicast_filter[8];
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
 
                if (dev->flags & IFF_ALLMULTI) {
                        for (i = 0; i < 8; i++) {
@@ -518,8 +517,8 @@ static void mace_set_multicast(struct net_device *dev)
                } else {
                        for (i = 0; i < 8; i++)
                                multicast_filter[i] = 0;
-                       netdev_for_each_mc_addr(dmi, dev) {
-                               crc = ether_crc_le(6, dmi->dmi_addr);
+                       netdev_for_each_mc_addr(ha, dev) {
+                               crc = ether_crc_le(6, ha->addr);
                                /* bit number in multicast_filter */
                                i = crc >> 26;
                                multicast_filter[i >> 3] |= 1 << (i & 7);
index 40faa368b07a89f175f6e48b0ef750f2d3bf8d57..4e238afab4a3b999d2e4af9ee178b6d593c4a9ed 100644 (file)
@@ -145,19 +145,15 @@ static void macvlan_broadcast(struct sk_buff *skb,
 }
 
 /* called under rcu_read_lock() from netif_receive_skb */
-static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+static struct sk_buff *macvlan_handle_frame(struct macvlan_port *port,
+                                           struct sk_buff *skb)
 {
        const struct ethhdr *eth = eth_hdr(skb);
-       const struct macvlan_port *port;
        const struct macvlan_dev *vlan;
        const struct macvlan_dev *src;
        struct net_device *dev;
        unsigned int len;
 
-       port = rcu_dereference(skb->dev->macvlan_port);
-       if (port == NULL)
-               return skb;
-
        if (is_multicast_ether_addr(eth->h_dest)) {
                src = macvlan_hash_lookup(port, eth->h_source);
                if (!src)
@@ -243,7 +239,7 @@ netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
        int ret;
 
        ret = macvlan_queue_xmit(skb, dev);
-       if (likely(ret == NET_XMIT_SUCCESS)) {
+       if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
                txq->tx_packets++;
                txq->tx_bytes += len;
        } else
@@ -282,7 +278,7 @@ static int macvlan_open(struct net_device *dev)
        if (macvlan_addr_busy(vlan->port, dev->dev_addr))
                goto out;
 
-       err = dev_unicast_add(lowerdev, dev->dev_addr);
+       err = dev_uc_add(lowerdev, dev->dev_addr);
        if (err < 0)
                goto out;
        if (dev->flags & IFF_ALLMULTI) {
@@ -294,7 +290,7 @@ static int macvlan_open(struct net_device *dev)
        return 0;
 
 del_unicast:
-       dev_unicast_delete(lowerdev, dev->dev_addr);
+       dev_uc_del(lowerdev, dev->dev_addr);
 out:
        return err;
 }
@@ -308,7 +304,7 @@ static int macvlan_stop(struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(lowerdev, -1);
 
-       dev_unicast_delete(lowerdev, dev->dev_addr);
+       dev_uc_del(lowerdev, dev->dev_addr);
 
        macvlan_hash_del(vlan);
        return 0;
@@ -332,11 +328,11 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
                if (macvlan_addr_busy(vlan->port, addr->sa_data))
                        return -EBUSY;
 
-               err = dev_unicast_add(lowerdev, addr->sa_data);
+               err = dev_uc_add(lowerdev, addr->sa_data);
                if (err)
                        return err;
 
-               dev_unicast_delete(lowerdev, dev->dev_addr);
+               dev_uc_del(lowerdev, dev->dev_addr);
 
                macvlan_hash_change_addr(vlan, addr->sa_data);
        }
@@ -748,6 +744,9 @@ static int macvlan_device_event(struct notifier_block *unused,
                list_for_each_entry_safe(vlan, next, &port->vlans, list)
                        vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
                break;
+       case NETDEV_PRE_TYPE_CHANGE:
+               /* Forbid underlaying device to change its type. */
+               return NOTIFY_BAD;
        }
        return NOTIFY_DONE;
 }
index abba3cc81f129d99116f6e8dccafa29a0ad5dc75..a8a94e2f6ddcfc04917ab2ec39305ac26e69ecf2 100644 (file)
@@ -37,6 +37,8 @@
 struct macvtap_queue {
        struct sock sk;
        struct socket sock;
+       struct socket_wq wq;
+       int vnet_hdr_sz;
        struct macvlan_dev *vlan;
        struct file *file;
        unsigned int flags;
@@ -181,7 +183,7 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb)
                return -ENOLINK;
 
        skb_queue_tail(&q->sk.sk_receive_queue, skb);
-       wake_up_interruptible_poll(q->sk.sk_sleep, POLLIN | POLLRDNORM | POLLRDBAND);
+       wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND);
        return 0;
 }
 
@@ -242,12 +244,15 @@ static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
 
 static void macvtap_sock_write_space(struct sock *sk)
 {
+       wait_queue_head_t *wqueue;
+
        if (!sock_writeable(sk) ||
            !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
                return;
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_poll(sk->sk_sleep, POLLOUT | POLLWRNORM | POLLWRBAND);
+       wqueue = sk_sleep(sk);
+       if (wqueue && waitqueue_active(wqueue))
+               wake_up_interruptible_poll(wqueue, POLLOUT | POLLWRNORM | POLLWRBAND);
 }
 
 static int macvtap_open(struct inode *inode, struct file *file)
@@ -272,7 +277,8 @@ static int macvtap_open(struct inode *inode, struct file *file)
        if (!q)
                goto out;
 
-       init_waitqueue_head(&q->sock.wait);
+       q->sock.wq = &q->wq;
+       init_waitqueue_head(&q->wq.wait);
        q->sock.type = SOCK_RAW;
        q->sock.state = SS_CONNECTED;
        q->sock.file = file;
@@ -280,6 +286,7 @@ static int macvtap_open(struct inode *inode, struct file *file)
        sock_init_data(&q->sock, &q->sk);
        q->sk.sk_write_space = macvtap_sock_write_space;
        q->flags = IFF_VNET_HDR | IFF_NO_PI | IFF_TAP;
+       q->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
 
        err = macvtap_set_queue(dev, file, q);
        if (err)
@@ -308,7 +315,7 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait)
                goto out;
 
        mask = 0;
-       poll_wait(file, &q->sock.wait, wait);
+       poll_wait(file, &q->wq.wait, wait);
 
        if (!skb_queue_empty(&q->sk.sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
@@ -440,14 +447,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q,
        int vnet_hdr_len = 0;
 
        if (q->flags & IFF_VNET_HDR) {
-               vnet_hdr_len = sizeof(vnet_hdr);
+               vnet_hdr_len = q->vnet_hdr_sz;
 
                err = -EINVAL;
                if ((len -= vnet_hdr_len) < 0)
                        goto err;
 
                err = memcpy_fromiovecend((void *)&vnet_hdr, iv, 0,
-                                          vnet_hdr_len);
+                                          sizeof(vnet_hdr));
                if (err < 0)
                        goto err;
                if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
@@ -529,7 +536,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
 
        if (q->flags & IFF_VNET_HDR) {
                struct virtio_net_hdr vnet_hdr;
-               vnet_hdr_len = sizeof (vnet_hdr);
+               vnet_hdr_len = q->vnet_hdr_sz;
                if ((len -= vnet_hdr_len) < 0)
                        return -EINVAL;
 
@@ -537,7 +544,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
                if (ret)
                        return ret;
 
-               if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, vnet_hdr_len))
+               if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr)))
                        return -EFAULT;
        }
 
@@ -562,7 +569,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
        struct sk_buff *skb;
        ssize_t ret = 0;
 
-       add_wait_queue(q->sk.sk_sleep, &wait);
+       add_wait_queue(sk_sleep(&q->sk), &wait);
        while (len) {
                current->state = TASK_INTERRUPTIBLE;
 
@@ -587,7 +594,7 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
        }
 
        current->state = TASK_RUNNING;
-       remove_wait_queue(q->sk.sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(&q->sk), &wait);
        return ret;
 }
 
@@ -622,6 +629,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
        struct ifreq __user *ifr = argp;
        unsigned int __user *up = argp;
        unsigned int u;
+       int __user *sp = argp;
+       int s;
        int ret;
 
        switch (cmd) {
@@ -667,6 +676,21 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
                q->sk.sk_sndbuf = u;
                return 0;
 
+       case TUNGETVNETHDRSZ:
+               s = q->vnet_hdr_sz;
+               if (put_user(s, sp))
+                       return -EFAULT;
+               return 0;
+
+       case TUNSETVNETHDRSZ:
+               if (get_user(s, sp))
+                       return -EFAULT;
+               if (s < (int)sizeof(struct virtio_net_hdr))
+                       return -EINVAL;
+
+               q->vnet_hdr_sz = s;
+               return 0;
+
        case TUNSETOFFLOAD:
                /* let the user check for future flags */
                if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
index 9f72cb45f4af65933b41b5ec5951032fd5ad6a09..42e3294671d7fc743c910e19ec20dac33cd2b2fb 100644 (file)
@@ -746,10 +746,8 @@ static void meth_tx_timeout(struct net_device *dev)
        /* Enable interrupt */
        spin_unlock_irqrestore(&priv->meth_lock, flags);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
-
-       return;
 }
 
 /*
index 86467b444ac679ab4b4a62e25aaba29c38d12bf2..d5afd037cd7d1ceec5e274318f78195a2eb3a7b3 100644 (file)
@@ -140,8 +140,6 @@ static void mlx4_en_get_wol(struct net_device *netdev,
 {
        wol->supported = 0;
        wol->wolopts = 0;
-
-       return;
 }
 
 static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
index 73c3d20c64534248768d29385b5cb6799b2fc8ba..96180c0ec206ff89b915d83119c101f751c2adef 100644 (file)
@@ -161,39 +161,29 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
 static void mlx4_en_clear_list(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct dev_mc_list *plist = priv->mc_list;
-       struct dev_mc_list *next;
 
-       while (plist) {
-               next = plist->next;
-               kfree(plist);
-               plist = next;
-       }
-       priv->mc_list = NULL;
+       kfree(priv->mc_addrs);
+       priv->mc_addrs_cnt = 0;
 }
 
 static void mlx4_en_cache_mclist(struct net_device *dev)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct dev_mc_list *mclist;
-       struct dev_mc_list *tmp;
-       struct dev_mc_list *plist = NULL;
-
-       for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
-               tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC);
-               if (!tmp) {
-                       en_err(priv, "failed to allocate multicast list\n");
-                       mlx4_en_clear_list(dev);
-                       return;
-               }
-               memcpy(tmp, mclist, sizeof(struct dev_mc_list));
-               tmp->next = NULL;
-               if (plist)
-                       plist->next = tmp;
-               else
-                       priv->mc_list = tmp;
-               plist = tmp;
+       struct netdev_hw_addr *ha;
+       char *mc_addrs;
+       int mc_addrs_cnt = netdev_mc_count(dev);
+       int i;
+
+       mc_addrs = kmalloc(mc_addrs_cnt * ETH_ALEN, GFP_ATOMIC);
+       if (!mc_addrs) {
+               en_err(priv, "failed to allocate multicast list\n");
+               return;
        }
+       i = 0;
+       netdev_for_each_mc_addr(ha, dev)
+               memcpy(mc_addrs + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
+       priv->mc_addrs = mc_addrs;
+       priv->mc_addrs_cnt = mc_addrs_cnt;
 }
 
 
@@ -213,7 +203,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                                                 mcast_task);
        struct mlx4_en_dev *mdev = priv->mdev;
        struct net_device *dev = priv->dev;
-       struct dev_mc_list *mclist;
        u64 mcast_addr = 0;
        int err;
 
@@ -289,6 +278,8 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                if (err)
                        en_err(priv, "Failed disabling multicast filter\n");
        } else {
+               int i;
+
                err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
                                          0, MLX4_MCAST_DISABLE);
                if (err)
@@ -303,8 +294,9 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
                netif_tx_lock_bh(dev);
                mlx4_en_cache_mclist(dev);
                netif_tx_unlock_bh(dev);
-               for (mclist = priv->mc_list; mclist; mclist = mclist->next) {
-                       mcast_addr = mlx4_en_mac_to_u64(mclist->dmi_addr);
+               for (i = 0; i < priv->mc_addrs_cnt; i++) {
+                       mcast_addr =
+                             mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN);
                        mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
                                            mcast_addr, 0, MLX4_MCAST_CONFIG);
                }
@@ -512,7 +504,7 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
 
        err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0);
        if (err)
-               en_dbg(HW, priv, "Could not update stats \n");
+               en_dbg(HW, priv, "Could not update stats\n");
 
        mutex_lock(&mdev->state_lock);
        if (mdev->device_up) {
@@ -985,7 +977,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        priv->flags = prof->flags;
        priv->tx_ring_num = prof->tx_ring_num;
        priv->rx_ring_num = prof->rx_ring_num;
-       priv->mc_list = NULL;
        priv->mac_index = -1;
        priv->msg_enable = MLX4_EN_MSG_LEVEL;
        spin_lock_init(&priv->stats_lock);
index 7365bf488b81a6a1572971da726b7f9662f042e6..423053482ed51c3991495b1dab8771ef45c03231 100644 (file)
@@ -239,7 +239,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                        mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at index %u\n",
                                  eqe->type, eqe->subtype, eq->eqn, eq->cons_index);
                        break;
-               };
+               }
 
                ++eq->cons_index;
                eqes_found = 1;
index 82c3ebc584e33963066385022f76066cff9122aa..b55e46c8b682cefce93fa7179b9964f10c1cf518 100644 (file)
@@ -492,7 +492,8 @@ struct mlx4_en_priv {
        struct mlx4_en_perf_stats pstats;
        struct mlx4_en_pkt_stats pkstats;
        struct mlx4_en_port_stats port_stats;
-       struct dev_mc_list *mc_list;
+       char *mc_addrs;
+       int mc_addrs_cnt;
        struct mlx4_en_stat_out_mbox hw_stats;
 };
 
index 8613a52ddf171b59a78ca652203cef2a8ccb409d..e345ec8cb473cda0d3454d5f2711b08c55fe8bdf 100644 (file)
@@ -882,7 +882,6 @@ static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 
                txq->tx_bytes += skb->len;
                txq->tx_packets++;
-               dev->trans_start = jiffies;
 
                entries_left = txq->tx_ring_size - txq->tx_desc_count;
                if (entries_left < MAX_SKB_FRAGS + 1)
@@ -1770,7 +1769,7 @@ static void mv643xx_eth_program_multicast_filter(struct net_device *dev)
        struct mv643xx_eth_private *mp = netdev_priv(dev);
        u32 *mc_spec;
        u32 *mc_other;
-       struct dev_addr_list *addr;
+       struct netdev_hw_addr *ha;
        int i;
 
        if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
@@ -1795,8 +1794,8 @@ oom:
        memset(mc_spec, 0, 0x100);
        memset(mc_other, 0, 0x100);
 
-       netdev_for_each_mc_addr(addr, dev) {
-               u8 *a = addr->da_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               u8 *a = ha->addr;
                u32 *table;
                int entry;
 
@@ -2609,10 +2608,9 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
                goto out;
 
        ret = -ENOMEM;
-       msp = kmalloc(sizeof(*msp), GFP_KERNEL);
+       msp = kzalloc(sizeof(*msp), GFP_KERNEL);
        if (msp == NULL)
                goto out;
-       memset(msp, 0, sizeof(*msp));
 
        msp->base = ioremap(res->start, res->end - res->start + 1);
        if (msp->base == NULL)
index ecde0876a78583fc8c4e063875be3e4975015d52..e0b47cc8a86e7600da43d0cb4915d7e58feb06b4 100644 (file)
@@ -110,15 +110,15 @@ MODULE_LICENSE("Dual BSD/GPL");
 struct myri10ge_rx_buffer_state {
        struct page *page;
        int page_offset;
-        DECLARE_PCI_UNMAP_ADDR(bus)
-        DECLARE_PCI_UNMAP_LEN(len)
+       DEFINE_DMA_UNMAP_ADDR(bus);
+       DEFINE_DMA_UNMAP_LEN(len);
 };
 
 struct myri10ge_tx_buffer_state {
        struct sk_buff *skb;
        int last;
-        DECLARE_PCI_UNMAP_ADDR(bus)
-        DECLARE_PCI_UNMAP_LEN(len)
+       DEFINE_DMA_UNMAP_ADDR(bus);
+       DEFINE_DMA_UNMAP_LEN(len);
 };
 
 struct myri10ge_cmd {
@@ -1234,7 +1234,7 @@ myri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
                rx->info[idx].page_offset = rx->page_offset;
                /* note that this is the address of the start of the
                 * page */
-               pci_unmap_addr_set(&rx->info[idx], bus, rx->bus);
+               dma_unmap_addr_set(&rx->info[idx], bus, rx->bus);
                rx->shadow[idx].addr_low =
                    htonl(MYRI10GE_LOWPART_TO_U32(rx->bus) + rx->page_offset);
                rx->shadow[idx].addr_high =
@@ -1266,7 +1266,7 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev,
        /* unmap the recvd page if we're the only or last user of it */
        if (bytes >= MYRI10GE_ALLOC_SIZE / 2 ||
            (info->page_offset + 2 * bytes) > MYRI10GE_ALLOC_SIZE) {
-               pci_unmap_page(pdev, (pci_unmap_addr(info, bus)
+               pci_unmap_page(pdev, (dma_unmap_addr(info, bus)
                                      & ~(MYRI10GE_ALLOC_SIZE - 1)),
                               MYRI10GE_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
        }
@@ -1373,21 +1373,21 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index)
                        tx->info[idx].last = 0;
                }
                tx->done++;
-               len = pci_unmap_len(&tx->info[idx], len);
-               pci_unmap_len_set(&tx->info[idx], len, 0);
+               len = dma_unmap_len(&tx->info[idx], len);
+               dma_unmap_len_set(&tx->info[idx], len, 0);
                if (skb) {
                        ss->stats.tx_bytes += skb->len;
                        ss->stats.tx_packets++;
                        dev_kfree_skb_irq(skb);
                        if (len)
                                pci_unmap_single(pdev,
-                                                pci_unmap_addr(&tx->info[idx],
+                                                dma_unmap_addr(&tx->info[idx],
                                                                bus), len,
                                                 PCI_DMA_TODEVICE);
                } else {
                        if (len)
                                pci_unmap_page(pdev,
-                                              pci_unmap_addr(&tx->info[idx],
+                                              dma_unmap_addr(&tx->info[idx],
                                                              bus), len,
                                               PCI_DMA_TODEVICE);
                }
@@ -2094,20 +2094,20 @@ static void myri10ge_free_rings(struct myri10ge_slice_state *ss)
                /* Mark as free */
                tx->info[idx].skb = NULL;
                tx->done++;
-               len = pci_unmap_len(&tx->info[idx], len);
-               pci_unmap_len_set(&tx->info[idx], len, 0);
+               len = dma_unmap_len(&tx->info[idx], len);
+               dma_unmap_len_set(&tx->info[idx], len, 0);
                if (skb) {
                        ss->stats.tx_dropped++;
                        dev_kfree_skb_any(skb);
                        if (len)
                                pci_unmap_single(mgp->pdev,
-                                                pci_unmap_addr(&tx->info[idx],
+                                                dma_unmap_addr(&tx->info[idx],
                                                                bus), len,
                                                 PCI_DMA_TODEVICE);
                } else {
                        if (len)
                                pci_unmap_page(mgp->pdev,
-                                              pci_unmap_addr(&tx->info[idx],
+                                              dma_unmap_addr(&tx->info[idx],
                                                              bus), len,
                                               PCI_DMA_TODEVICE);
                }
@@ -2757,12 +2757,12 @@ again:
        }
 
        /* map the skb for DMA */
-       len = skb->len - skb->data_len;
+       len = skb_headlen(skb);
        idx = tx->req & tx->mask;
        tx->info[idx].skb = skb;
        bus = pci_map_single(mgp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-       pci_unmap_addr_set(&tx->info[idx], bus, bus);
-       pci_unmap_len_set(&tx->info[idx], len, len);
+       dma_unmap_addr_set(&tx->info[idx], bus, bus);
+       dma_unmap_len_set(&tx->info[idx], len, len);
 
        frag_cnt = skb_shinfo(skb)->nr_frags;
        frag_idx = 0;
@@ -2865,8 +2865,8 @@ again:
                len = frag->size;
                bus = pci_map_page(mgp->pdev, frag->page, frag->page_offset,
                                   len, PCI_DMA_TODEVICE);
-               pci_unmap_addr_set(&tx->info[idx], bus, bus);
-               pci_unmap_len_set(&tx->info[idx], len, len);
+               dma_unmap_addr_set(&tx->info[idx], bus, bus);
+               dma_unmap_len_set(&tx->info[idx], len, len);
        }
 
        (req - rdma_count)->rdma_count = rdma_count;
@@ -2903,19 +2903,19 @@ abort_linearize:
        idx = tx->req & tx->mask;
        tx->info[idx].skb = NULL;
        do {
-               len = pci_unmap_len(&tx->info[idx], len);
+               len = dma_unmap_len(&tx->info[idx], len);
                if (len) {
                        if (tx->info[idx].skb != NULL)
                                pci_unmap_single(mgp->pdev,
-                                                pci_unmap_addr(&tx->info[idx],
+                                                dma_unmap_addr(&tx->info[idx],
                                                                bus), len,
                                                 PCI_DMA_TODEVICE);
                        else
                                pci_unmap_page(mgp->pdev,
-                                              pci_unmap_addr(&tx->info[idx],
+                                              dma_unmap_addr(&tx->info[idx],
                                                              bus), len,
                                               PCI_DMA_TODEVICE);
-                       pci_unmap_len_set(&tx->info[idx], len, 0);
+                       dma_unmap_len_set(&tx->info[idx], len, 0);
                        tx->info[idx].skb = NULL;
                }
                idx = (idx + 1) & tx->mask;
@@ -3002,7 +3002,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
 {
        struct myri10ge_priv *mgp = netdev_priv(dev);
        struct myri10ge_cmd cmd;
-       struct dev_mc_list *mc_list;
+       struct netdev_hw_addr *ha;
        __be32 data[2] = { 0, 0 };
        int err;
 
@@ -3039,8 +3039,8 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
        }
 
        /* Walk the multicast list, and add each address */
-       netdev_for_each_mc_addr(mc_list, dev) {
-               memcpy(data, &mc_list->dmi_addr, 6);
+       netdev_for_each_mc_addr(ha, dev) {
+               memcpy(data, &ha->addr, 6);
                cmd.data0 = ntohl(data[0]);
                cmd.data1 = ntohl(data[1]);
                err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP,
@@ -3048,7 +3048,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
 
                if (err != 0) {
                        netdev_err(dev, "Failed MXGEFW_JOIN_MULTICAST_GROUP, error status:%d %pM\n",
-                                  err, mc_list->dmi_addr);
+                                  err, ha->addr);
                        goto abort;
                }
        }
index b72e749afdf102d5bb690be5e29617044a927a75..3898108f98ce6c7d6bd096a868080def27501223 100644 (file)
@@ -865,7 +865,7 @@ static inline void determine_reg_space_size(struct myri_eth *mp)
                printk("myricom: AIEEE weird cpu version %04x assuming pre4.0\n",
                       mp->eeprom.cpuvers);
                mp->reg_size = (3 * 128 * 1024) + 4096;
-       };
+       }
 }
 
 #ifdef DEBUG_DETECT
index e52038783245c86e694807e197eb997f12c74b37..2a17b503feaa9c72975454a983a2e28596667d7d 100644 (file)
@@ -1905,7 +1905,7 @@ static void ns_tx_timeout(struct net_device *dev)
        spin_unlock_irq(&np->lock);
        enable_irq(dev->irq);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        np->stats.tx_errors++;
        netif_wake_queue(dev);
 }
@@ -2119,8 +2119,6 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        }
        spin_unlock_irqrestore(&np->lock, flags);
 
-       dev->trans_start = jiffies;
-
        if (netif_msg_tx_queued(np)) {
                printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
                        dev->name, np->cur_tx, entry);
@@ -2493,12 +2491,12 @@ static void __set_rx_mode(struct net_device *dev)
                rx_mode = RxFilterEnable | AcceptBroadcast
                        | AcceptAllMulticast | AcceptMyPhys;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                int i;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int b = (ether_crc(ETH_ALEN, ha->addr) >> 23) & 0x1ff;
                        mc_filter[b/8] |= (1 << (b & 0x07));
                }
                rx_mode = RxFilterEnable | AcceptBroadcast
index 7bd6662d5b044e2bd59503cd4a80af76a4c92f08..e0b0ef11f11038f64089c164967316affed23a92 100644 (file)
@@ -608,7 +608,6 @@ retry:
 
        outb_p(ENISR_RDC, NE_BASE + EN0_ISR);   /* Ack intr. */
        ei_status.dmaing &= ~0x01;
-       return;
 }
 
 
index f4347f88b6f2c62d73754bbee75adc416ecf8462..b8e2923a1d69e4d50fe7c9e47620c69b42a1005f 100644 (file)
@@ -785,7 +785,6 @@ retry:
 
        outb_p(ENISR_RDC, nic_base + EN0_ISR);  /* Ack intr. */
        ei_status.dmaing &= ~0x01;
-       return;
 }
 
 static int __init ne_drv_probe(struct platform_device *pdev)
index ff3c4c81498847c825869ff009ac8d74ab2243d2..70cdc6996342f9b6f5ab821593da43521ca6eb44 100644 (file)
@@ -730,7 +730,6 @@ retry:
 
        outb_p(ENISR_RDC, nic_base + EN0_ISR);  /* Ack intr. */
        ei_status.dmaing &= ~0x01;
-       return;
 }
 
 
index 85aec4f1013184d47c110c0c22a5c91b2493ec19..3c333cb5d34efd9b28cb78482b483f5499a3506b 100644 (file)
@@ -631,7 +631,6 @@ static void ne2k_pci_block_output(struct net_device *dev, int count,
 
        outb(ENISR_RDC, nic_base + EN0_ISR);    /* Ack intr. */
        ei_status.dmaing &= ~0x01;
-       return;
 }
 
 static void ne2k_pci_get_drvinfo(struct net_device *dev,
index a00bbfb9aed0f5d7f9131082edda777d3d146b2f..243ed2aee88e35e801a2c6582f8a80d4e287ba7b 100644 (file)
@@ -255,8 +255,6 @@ static void ne3210_reset_8390(struct net_device *dev)
        ei_status.txing = 0;
        outb(0x01, ioaddr + NE3210_RESET_PORT);
        if (ei_debug > 1) printk("reset done\n");
-
-       return;
 }
 
 /*
index a361dea35574db454a82d25ddcc9050f057c4a90..ca142c47b2e4c631a90c5b61382c99c49f784dd2 100644 (file)
@@ -665,7 +665,8 @@ static int netconsole_netdev_event(struct notifier_block *this,
        struct netconsole_target *nt;
        struct net_device *dev = ptr;
 
-       if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER))
+       if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
+             event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN))
                goto done;
 
        spin_lock_irqsave(&target_list_lock, flags);
@@ -677,19 +678,21 @@ static int netconsole_netdev_event(struct notifier_block *this,
                                strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
                                break;
                        case NETDEV_UNREGISTER:
-                               if (!nt->enabled)
-                                       break;
                                netpoll_cleanup(&nt->np);
+                               /* Fall through */
+                       case NETDEV_GOING_DOWN:
+                       case NETDEV_BONDING_DESLAVE:
                                nt->enabled = 0;
-                               printk(KERN_INFO "netconsole: network logging stopped"
-                                       ", interface %s unregistered\n",
-                                       dev->name);
                                break;
                        }
                }
                netconsole_target_put(nt);
        }
        spin_unlock_irqrestore(&target_list_lock, flags);
+       if (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE)
+               printk(KERN_INFO "netconsole: network logging stopped, "
+                       "interface %s %s\n",  dev->name,
+                       event == NETDEV_UNREGISTER ? "unregistered" : "released slaves");
 
 done:
        return NOTIFY_DONE;
index 64770298c4f7121a3a49b3752a25a56b5691b509..2e4b42175f3fb3ff6fdae5d0d8b6fceac17af87d 100644 (file)
@@ -126,7 +126,6 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                   FIFO_PTR_FRAMENO(1) |
                   FIFO_PTR_FRAMELEN(len));
 
-       ndev->trans_start = jiffies;
        ndev->stats.tx_packets++;
        ndev->stats.tx_bytes += skb->len;
 
index 0f703838e21ad73b5ad775e35b9984146d60cf5f..ffa1b9ce1cc5a8f4c474136940df4de36d853c55 100644 (file)
@@ -95,6 +95,9 @@
 #define ADDR_IN_WINDOW1(off)   \
        ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
 
+#define ADDR_IN_RANGE(addr, low, high) \
+       (((addr) < (high)) && ((addr) >= (low)))
+
 /*
  * normalize a 64MB crb address to 32MB PCI window
  * To use NETXEN_CRB_NORMALIZE, window _must_ be set to 1
@@ -420,7 +423,6 @@ struct status_desc {
 } __attribute__ ((aligned(16)));
 
 /* UNIFIED ROMIMAGE *************************/
-#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
@@ -1353,6 +1355,8 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable);
 int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
 int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
 void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);
+void netxen_pci_camqm_read_2M(struct netxen_adapter *, u64, u64 *);
+void netxen_pci_camqm_write_2M(struct netxen_adapter *, u64, u64);
 
 int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu);
 int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
index f8499e56cbee4752b37938aa0f0a948663134bec..20f7c58bd0920fefe38d5bc9fb4cc58892d9a526 100644 (file)
@@ -632,6 +632,9 @@ static int netxen_nic_reg_test(struct net_device *dev)
        if ((data_read & 0xffff) != adapter->pdev->vendor)
                return 1;
 
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+               return 0;
+
        data_written = (u32)0xa5a5a5a5;
 
        NXWR32(adapter, CRB_SCRATCHPAD_TEST, data_written);
@@ -703,6 +706,11 @@ netxen_nic_get_ethtool_stats(struct net_device *dev,
        }
 }
 
+static u32 netxen_nic_get_tx_csum(struct net_device *dev)
+{
+       return dev->features & NETIF_F_IP_CSUM;
+}
+
 static u32 netxen_nic_get_rx_csum(struct net_device *dev)
 {
        struct netxen_adapter *adapter = netdev_priv(dev);
@@ -909,6 +917,7 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
        .set_ringparam = netxen_nic_set_ringparam,
        .get_pauseparam = netxen_nic_get_pauseparam,
        .set_pauseparam = netxen_nic_set_pauseparam,
+       .get_tx_csum = netxen_nic_get_tx_csum,
        .set_tx_csum = ethtool_op_set_tx_csum,
        .set_sg = ethtool_op_set_sg,
        .get_tso = netxen_nic_get_tso,
index 622e4c8be937c0c7b3c1c44db335954134235f39..d8bd73d7e29603a59058fde0e635205d8164b535 100644 (file)
@@ -681,14 +681,8 @@ enum {
 #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)
@@ -789,9 +783,7 @@ enum {
  * for backward compability
  */
 #define CRB_NIC_CAPABILITIES_HOST      NETXEN_NIC_REG(0x1a8)
-#define CRB_NIC_CAPABILITIES_FW                NETXEN_NIC_REG(0x1dc)
 #define CRB_NIC_MSI_MODE_HOST          NETXEN_NIC_REG(0x270)
-#define CRB_NIC_MSI_MODE_FW            NETXEN_NIC_REG(0x274)
 
 #define INTR_SCHEME_PERPORT            0x1
 #define MSI_MODE_MULTIFUNC             0x1
index b1cf46a0c48c887c7c0903b2a6343fbcd2ba9135..5c496f8d7c497f16c5a17fe7398794efdca550b3 100644 (file)
@@ -32,7 +32,6 @@
 #define MASK(n) ((1ULL<<(n))-1)
 #define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff))
 #define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff))
-#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
 #define MS_WIN(addr) (addr & 0x0ffc0000)
 
 #define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
@@ -63,9 +62,6 @@ static inline void writeq(u64 val, void __iomem *addr)
 }
 #endif
 
-#define ADDR_IN_RANGE(addr, low, high) \
-       (((addr) < (high)) && ((addr) >= (low)))
-
 #define PCI_OFFSET_FIRST_RANGE(adapter, off)    \
        ((adapter)->ahw.pci_base0 + (off))
 #define PCI_OFFSET_SECOND_RANGE(adapter, off)   \
@@ -538,7 +534,7 @@ netxen_nic_set_mcast_addr(struct netxen_adapter *adapter,
 void netxen_p2_nic_set_multi(struct net_device *netdev)
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u8 null_addr[6];
        int i;
 
@@ -572,8 +568,8 @@ void netxen_p2_nic_set_multi(struct net_device *netdev)
        netxen_nic_enable_mcast_filter(adapter);
 
        i = 0;
-       netdev_for_each_mc_addr(mc_ptr, netdev)
-               netxen_nic_set_mcast_addr(adapter, i++, mc_ptr->dmi_addr);
+       netdev_for_each_mc_addr(ha, netdev)
+               netxen_nic_set_mcast_addr(adapter, i++, ha->addr);
 
        /* Clear out remaining addresses */
        while (i < adapter->max_mc_count)
@@ -681,7 +677,7 @@ static int nx_p3_nic_add_mac(struct netxen_adapter *adapter,
 void netxen_p3_nic_set_multi(struct net_device *netdev)
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        u32 mode = VPORT_MISS_MODE_DROP;
        LIST_HEAD(del_list);
@@ -708,8 +704,8 @@ void netxen_p3_nic_set_multi(struct net_device *netdev)
        }
 
        if (!netdev_mc_empty(netdev)) {
-               netdev_for_each_mc_addr(mc_ptr, netdev)
-                       nx_p3_nic_add_mac(adapter, mc_ptr->dmi_addr, &del_list);
+               netdev_for_each_mc_addr(ha, netdev)
+                       nx_p3_nic_add_mac(adapter, ha->addr, &del_list);
        }
 
 send_fw_cmd:
@@ -1391,18 +1387,8 @@ netxen_nic_pci_set_window_2M(struct netxen_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;
-       }
-
-       if (NX_IS_REVISION_P3P(adapter->ahw.revision_id))
-               window = OCM_WIN_P3P(addr);
-       else
-               window = OCM_WIN(addr);
+       window = OCM_WIN(addr);
 
        writel(window, adapter->ahw.ocm_win_crb);
        /* read back to flush */
@@ -1419,7 +1405,7 @@ netxen_nic_pci_mem_access_direct(struct netxen_adapter *adapter, u64 off,
 {
        void __iomem *addr, *mem_ptr = NULL;
        resource_size_t mem_base;
-       int ret = -EIO;
+       int ret;
        u32 start;
 
        spin_lock(&adapter->ahw.mem_lock);
@@ -1428,20 +1414,23 @@ netxen_nic_pci_mem_access_direct(struct netxen_adapter *adapter, u64 off,
        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);
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+               addr = adapter->ahw.pci_base0 + start;
+       } else {
+               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;
+               }
 
-       mem_ptr = ioremap(mem_base, PAGE_SIZE);
-       if (mem_ptr == NULL) {
-               ret = -EIO;
-               goto unlock;
+               addr = mem_ptr + (start & (PAGE_SIZE-1));
        }
-
-       addr = mem_ptr + (start & (PAGE_SIZE - 1));
-
 noremap:
        if (op == 0)    /* read */
                *data = readq(addr);
@@ -1456,6 +1445,28 @@ unlock:
        return ret;
 }
 
+void
+netxen_pci_camqm_read_2M(struct netxen_adapter *adapter, u64 off, u64 *data)
+{
+       void __iomem *addr = adapter->ahw.pci_base0 +
+               NETXEN_PCI_CAMQM_2M_BASE + (off - NETXEN_PCI_CAMQM);
+
+       spin_lock(&adapter->ahw.mem_lock);
+       *data = readq(addr);
+       spin_unlock(&adapter->ahw.mem_lock);
+}
+
+void
+netxen_pci_camqm_write_2M(struct netxen_adapter *adapter, u64 off, u64 data)
+{
+       void __iomem *addr = adapter->ahw.pci_base0 +
+               NETXEN_PCI_CAMQM_2M_BASE + (off - NETXEN_PCI_CAMQM);
+
+       spin_lock(&adapter->ahw.mem_lock);
+       writeq(data, addr);
+       spin_unlock(&adapter->ahw.mem_lock);
+}
+
 #define MAX_CTL_CHECK   1000
 
 static int
@@ -1621,9 +1632,8 @@ static int
 netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter,
                u64 off, u64 data)
 {
-       int i, j, ret;
+       int j, ret;
        u32 temp, off8;
-       u64 stride;
        void __iomem *mem_crb;
 
        /* Only 64-bit aligned access */
@@ -1650,44 +1660,17 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter,
        return -EIO;
 
 correct:
-       stride = NX_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
-
-       off8 = off & ~(stride-1);
+       off8 = off & 0xfffffff8;
 
        spin_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));
+                       mem_crb + MIU_TEST_AGT_WRDATA_LO);
        writel((data >> 32) & 0xffffffff,
-                       mem_crb + MIU_TEST_AGT_WRDATA(i+1));
+                       mem_crb + MIU_TEST_AGT_WRDATA_HI);
 
        writel((TA_CTL_ENABLE | TA_CTL_WRITE), (mem_crb + TEST_AGT_CTRL));
        writel((TA_CTL_START | TA_CTL_ENABLE | TA_CTL_WRITE),
@@ -1707,7 +1690,6 @@ correct:
        } else
                ret = 0;
 
-done:
        spin_unlock(&adapter->ahw.mem_lock);
 
        return ret;
@@ -1719,7 +1701,7 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter,
 {
        int j, ret;
        u32 temp, off8;
-       u64 val, stride;
+       u64 val;
        void __iomem *mem_crb;
 
        /* Only 64-bit aligned access */
@@ -1748,9 +1730,7 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter,
        return -EIO;
 
 correct:
-       stride = NX_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
-
-       off8 = off & ~(stride-1);
+       off8 = off & 0xfffffff8;
 
        spin_lock(&adapter->ahw.mem_lock);
 
@@ -1771,13 +1751,8 @@ correct:
                                        "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);
+               val = (u64)(readl(mem_crb + MIU_TEST_AGT_RDDATA_HI)) << 32;
+               val |= readl(mem_crb + MIU_TEST_AGT_RDDATA_LO);
                *data = val;
                ret = 0;
        }
index 02876f59cbb21bbcf7f4660868e4f47a8f778f44..045a7c8f5bdf8e08fd4b317a96f0917023f238d3 100644 (file)
@@ -614,22 +614,123 @@ static struct uni_table_desc *nx_get_table_desc(const u8 *unirom, int section)
        return NULL;
 }
 
+#define        QLCNIC_FILEHEADER_SIZE  (14 * 4)
+
 static int
-nx_set_product_offs(struct netxen_adapter *adapter)
-{
-       struct uni_table_desc *ptab_descr;
+netxen_nic_validate_header(struct netxen_adapter *adapter)
+ {
        const u8 *unirom = adapter->fw->data;
-       uint32_t i;
+       struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
+       u32 fw_file_size = adapter->fw->size;
+       u32 tab_size;
        __le32 entries;
+       __le32 entry_size;
+
+       if (fw_file_size < QLCNIC_FILEHEADER_SIZE)
+               return -EINVAL;
+
+       entries = cpu_to_le32(directory->num_entries);
+       entry_size = cpu_to_le32(directory->entry_size);
+       tab_size = cpu_to_le32(directory->findex) + (entries * entry_size);
+
+       if (fw_file_size < tab_size)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int
+netxen_nic_validate_bootld(struct netxen_adapter *adapter)
+{
+       struct uni_table_desc *tab_desc;
+       struct uni_data_desc *descr;
+       const u8 *unirom = adapter->fw->data;
+       __le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
+                               NX_UNI_BOOTLD_IDX_OFF));
+       u32 offs;
+       u32 tab_size;
+       u32 data_size;
+
+       tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_BOOTLD);
+
+       if (!tab_desc)
+               return -EINVAL;
+
+       tab_size = cpu_to_le32(tab_desc->findex) +
+                       (cpu_to_le32(tab_desc->entry_size) * (idx + 1));
+
+       if (adapter->fw->size < tab_size)
+               return -EINVAL;
+
+       offs = cpu_to_le32(tab_desc->findex) +
+               (cpu_to_le32(tab_desc->entry_size) * (idx));
+       descr = (struct uni_data_desc *)&unirom[offs];
+
+       data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
+
+       if (adapter->fw->size < data_size)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int
+netxen_nic_validate_fw(struct netxen_adapter *adapter)
+{
+       struct uni_table_desc *tab_desc;
+       struct uni_data_desc *descr;
+       const u8 *unirom = adapter->fw->data;
+       __le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
+                               NX_UNI_FIRMWARE_IDX_OFF));
+       u32 offs;
+       u32 tab_size;
+       u32 data_size;
+
+       tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_FW);
+
+       if (!tab_desc)
+               return -EINVAL;
+
+       tab_size = cpu_to_le32(tab_desc->findex) +
+                       (cpu_to_le32(tab_desc->entry_size) * (idx + 1));
+
+       if (adapter->fw->size < tab_size)
+               return -EINVAL;
+
+       offs = cpu_to_le32(tab_desc->findex) +
+               (cpu_to_le32(tab_desc->entry_size) * (idx));
+       descr = (struct uni_data_desc *)&unirom[offs];
+       data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
+
+       if (adapter->fw->size < data_size)
+               return -EINVAL;
 
+       return 0;
+}
+
+
+static int
+netxen_nic_validate_product_offs(struct netxen_adapter *adapter)
+{
+       struct uni_table_desc *ptab_descr;
+       const u8 *unirom = adapter->fw->data;
        int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ?
                        1 : netxen_p3_has_mn(adapter);
+       __le32 entries;
+       __le32 entry_size;
+       u32 tab_size;
+       u32 i;
 
        ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL);
        if (ptab_descr == NULL)
-               return -1;
+               return -EINVAL;
 
        entries = cpu_to_le32(ptab_descr->num_entries);
+       entry_size = cpu_to_le32(ptab_descr->entry_size);
+       tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size);
+
+       if (adapter->fw->size < tab_size)
+               return -EINVAL;
 
 nomn:
        for (i = 0; i < entries; i++) {
@@ -658,9 +759,38 @@ nomn:
                goto nomn;
        }
 
-       return -1;
+       return -EINVAL;
 }
 
+static int
+netxen_nic_validate_unified_romimage(struct netxen_adapter *adapter)
+{
+       if (netxen_nic_validate_header(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                               "unified image: header validation failed\n");
+               return -EINVAL;
+       }
+
+       if (netxen_nic_validate_product_offs(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                               "unified image: product validation failed\n");
+               return -EINVAL;
+       }
+
+       if (netxen_nic_validate_bootld(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                               "unified image: bootld validation failed\n");
+               return -EINVAL;
+       }
+
+       if (netxen_nic_validate_fw(adapter)) {
+               dev_err(&adapter->pdev->dev,
+                               "unified image: firmware validation failed\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
 
 static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter,
                        u32 section, u32 idx_offset)
@@ -890,6 +1020,16 @@ netxen_load_firmware(struct netxen_adapter *adapter)
 
                        flashaddr += 8;
                }
+
+               size = (__force u32)nx_get_fw_size(adapter) % 8;
+               if (size) {
+                       data = cpu_to_le64(ptr64[i]);
+
+                       if (adapter->pci_mem_write(adapter,
+                                               flashaddr, data))
+                               return -EIO;
+               }
+
        } else {
                u64 data;
                u32 hi, lo;
@@ -934,27 +1074,23 @@ static int
 netxen_validate_firmware(struct netxen_adapter *adapter)
 {
        __le32 val;
-       u32 ver, min_ver, bios, min_size;
+       u32 ver, min_ver, bios;
        struct pci_dev *pdev = adapter->pdev;
        const struct firmware *fw = adapter->fw;
        u8 fw_type = adapter->fw_type;
 
        if (fw_type == NX_UNIFIED_ROMIMAGE) {
-               if (nx_set_product_offs(adapter))
+               if (netxen_nic_validate_unified_romimage(adapter))
                        return -EINVAL;
-
-               min_size = NX_UNI_FW_MIN_SIZE;
        } else {
                val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);
                if ((__force u32)val != NETXEN_BDINFO_MAGIC)
                        return -EINVAL;
 
-               min_size = NX_FW_MIN_SIZE;
+               if (fw->size < NX_FW_MIN_SIZE)
+                       return -EINVAL;
        }
 
-       if (fw->size < min_size)
-               return -EINVAL;
-
        val = nx_get_fw_version(adapter);
 
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
@@ -1225,10 +1361,12 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
                return err;
 
        NXWR32(adapter, CRB_NIC_CAPABILITIES_HOST, INTR_SCHEME_PERPORT);
-       NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC);
        NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
        NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
 
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+               NXWR32(adapter, CRB_NIC_MSI_MODE_HOST, MSI_MODE_MULTIFUNC);
+
        return err;
 }
 
@@ -1763,6 +1901,5 @@ netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
 void netxen_nic_clear_stats(struct netxen_adapter *adapter)
 {
        memset(&adapter->stats, 0, sizeof(adapter->stats));
-       return;
 }
 
index ce838f7c8b0f3e1cd33702fc72cf5f2a82b6c3ae..c61a61f177b715501a8340e626610438abdb7d4b 100644 (file)
@@ -782,15 +782,22 @@ netxen_check_options(struct netxen_adapter *adapter)
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
                adapter->msix_supported = !!use_msi_x;
                adapter->rss_supported = !!use_msi_x;
-       } else if (adapter->fw_version >= NETXEN_VERSION_CODE(3, 4, 336)) {
-               switch (adapter->ahw.board_type) {
-               case NETXEN_BRDTYPE_P2_SB31_10G:
-               case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
-                       adapter->msix_supported = !!use_msi_x;
-                       adapter->rss_supported = !!use_msi_x;
-                       break;
-               default:
-                       break;
+       } else {
+               u32 flashed_ver = 0;
+               netxen_rom_fast_read(adapter,
+                               NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
+               flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
+
+               if (flashed_ver >= NETXEN_VERSION_CODE(3, 4, 336)) {
+                       switch (adapter->ahw.board_type) {
+                       case NETXEN_BRDTYPE_P2_SB31_10G:
+                       case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
+                               adapter->msix_supported = !!use_msi_x;
+                               adapter->rss_supported = !!use_msi_x;
+                               break;
+                       default:
+                               break;
+                       }
                }
        }
 
@@ -2304,6 +2311,7 @@ netxen_fwinit_work(struct work_struct *work)
                }
                break;
 
+       case NX_DEV_NEED_RESET:
        case NX_DEV_INITALIZING:
                if (++adapter->fw_wait_cnt < FW_POLL_THRESH) {
                        netxen_schedule_work(adapter,
@@ -2347,6 +2355,9 @@ netxen_detach_work(struct work_struct *work)
 
        ref_cnt = nx_decr_dev_ref_cnt(adapter);
 
+       if (ref_cnt == -EIO)
+               goto err_ret;
+
        delay = (ref_cnt == 0) ? 0 : (2 * FW_POLL_DELAY);
 
        adapter->fw_wait_cnt = 0;
@@ -2526,14 +2537,24 @@ static int
 netxen_sysfs_validate_crb(struct netxen_adapter *adapter,
                loff_t offset, size_t size)
 {
+       size_t crb_size = 4;
+
        if (!(adapter->flags & NETXEN_NIC_DIAG_ENABLED))
                return -EIO;
 
-       if ((size != 4) || (offset & 0x3))
-               return  -EINVAL;
+       if (offset < NETXEN_PCI_CRBSPACE) {
+               if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+                       return -EINVAL;
 
-       if (offset < NETXEN_PCI_CRBSPACE)
-               return -EINVAL;
+               if (ADDR_IN_RANGE(offset, NETXEN_PCI_CAMQM,
+                                               NETXEN_PCI_CAMQM_2M_END))
+                       crb_size = 8;
+               else
+                       return -EINVAL;
+       }
+
+       if ((size != crb_size) || (offset & (crb_size-1)))
+               return  -EINVAL;
 
        return 0;
 }
@@ -2545,14 +2566,23 @@ netxen_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = netxen_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       data = NXRD32(adapter, offset);
-       memcpy(buf, &data, size);
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id) &&
+               ADDR_IN_RANGE(offset, NETXEN_PCI_CAMQM,
+                                       NETXEN_PCI_CAMQM_2M_END)) {
+               netxen_pci_camqm_read_2M(adapter, offset, &qmdata);
+               memcpy(buf, &qmdata, size);
+       } else {
+               data = NXRD32(adapter, offset);
+               memcpy(buf, &data, size);
+       }
+
        return size;
 }
 
@@ -2563,14 +2593,23 @@ netxen_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = netxen_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       memcpy(&data, buf, size);
-       NXWR32(adapter, offset, data);
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id) &&
+               ADDR_IN_RANGE(offset, NETXEN_PCI_CAMQM,
+                                       NETXEN_PCI_CAMQM_2M_END)) {
+               memcpy(&qmdata, buf, size);
+               netxen_pci_camqm_write_2M(adapter, offset, qmdata);
+       } else {
+               memcpy(&data, buf, size);
+               NXWR32(adapter, offset, data);
+       }
+
        return size;
 }
 
@@ -2742,7 +2781,6 @@ netxen_config_indev_addr(struct net_device *dev, unsigned long event)
        } endfor_ifa(indev);
 
        in_dev_put(indev);
-       return;
 }
 
 static int netxen_netdev_event(struct notifier_block *this,
index 3892330f244a0e65b6a96bf3be8e2b72236f6e79..4d3f2e2b28bd2f6a6f9f3c1bcba4e7e1467c5d14 100644 (file)
@@ -444,7 +444,7 @@ static void ni5010_timeout(struct net_device *dev)
        /* Try to restart the adaptor. */
        /* FIXME: Give it a real kick here */
        chipset_init(dev, 1);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -460,7 +460,6 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        netif_stop_queue(dev);
        hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
-       dev->trans_start = jiffies;
        dev_kfree_skb (skb);
        return NETDEV_TX_OK;
 }
@@ -515,8 +514,6 @@ static void dump_packet(void *buf, int len)
                if (i % 16 == 15) printk("\n");
        }
        printk("\n");
-
-       return;
 }
 
 /* We have a good packet, get it out of the buffer. */
index f7a8f707361e8bbf60bc9071f40e3bb715a7ee5e..9bddb5fa7a9697d6d4a85ab9ea73960742ed7658 100644 (file)
@@ -595,7 +595,7 @@ static int init586(struct net_device *dev)
        struct iasetup_cmd_struct __iomem *ias_cmd;
        struct tdr_cmd_struct __iomem *tdr_cmd;
        struct mcsetup_cmd_struct __iomem *mc_cmd;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int num_addrs = netdev_mc_count(dev);
 
        ptr = p->scb + 1;
@@ -724,8 +724,8 @@ static int init586(struct net_device *dev)
                writew(num_addrs * 6, &mc_cmd->mc_cnt);
 
                i = 0;
-               netdev_for_each_mc_addr(dmi, dev)
-                       memcpy_toio(mc_cmd->mc_list[i++], dmi->dmi_addr, 6);
+               netdev_for_each_mc_addr(ha, dev)
+                       memcpy_toio(mc_cmd->mc_list[i++], ha->addr, 6);
 
                writew(make16(mc_cmd), &p->scb->cbl_offset);
                writeb(CUC_START, &p->scb->cmd_cuc);
@@ -1147,7 +1147,7 @@ static void ni52_timeout(struct net_device *dev)
                writeb(CUC_START, &p->scb->cmd_cuc);
                ni_attn586();
                wait_for_scb_cmd(dev);
-               dev->trans_start = jiffies;
+               dev->trans_start = jiffies; /* prevent tx timeout */
                return 0;
        }
 #endif
@@ -1165,7 +1165,7 @@ static void ni52_timeout(struct net_device *dev)
                ni52_close(dev);
                ni52_open(dev);
        }
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 /******************************************************
@@ -1218,7 +1218,6 @@ static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
                        writeb(CUC_START, &p->scb->cmd_cuc);
                }
                ni_attn586();
-               dev->trans_start = jiffies;
                if (!i)
                        dev_kfree_skb(skb);
                wait_for_scb_cmd(dev);
@@ -1240,7 +1239,6 @@ static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
        writew(0, &p->nop_cmds[next_nop]->cmd_status);
 
        writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link);
-       dev->trans_start = jiffies;
        p->nop_point = next_nop;
        dev_kfree_skb(skb);
 #      endif
@@ -1256,7 +1254,6 @@ static netdev_tx_t ni52_send_packet(struct sk_buff *skb,
        writew(0, &p->nop_cmds[next_nop]->cmd_status);
        writew(make16(p->xmit_cmds[p->xmit_count]),
                                &p->nop_cmds[p->xmit_count]->cmd_link);
-       dev->trans_start = jiffies;
        p->xmit_count = next_nop;
        {
                unsigned long flags;
index 9225c76cac40fdce9cf83ce5d917fb3439082195..da228a0dd6cd6d810f60d85d1e07e7308e711104 100644 (file)
@@ -784,7 +784,7 @@ static void ni65_stop_start(struct net_device *dev,struct priv *p)
                if(!p->lock)
                        if (p->tmdnum || !p->xmit_queued)
                                netif_wake_queue(dev);
-               dev->trans_start = jiffies;
+               dev->trans_start = jiffies; /* prevent tx timeout */
        }
        else
                writedatareg(CSR0_STRT | csr0);
@@ -1150,7 +1150,7 @@ static void ni65_timeout(struct net_device *dev)
                printk("%02x ",p->tmdhead[i].u.s.status);
        printk("\n");
        ni65_lance_reinit(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -1213,7 +1213,6 @@ static netdev_tx_t ni65_send_packet(struct sk_buff *skb,
                        netif_wake_queue(dev);
 
                p->lock = 0;
-               dev->trans_start = jiffies;
 
                spin_unlock_irqrestore(&p->ring_lock, flags);
        }
index d5cd16bfc907b32a3e287258c9cf41761cd5de1d..30abb4e436f16ed70b3aa85487d59441fad6a313 100644 (file)
@@ -36,8 +36,8 @@
 #include "niu.h"
 
 #define DRV_MODULE_NAME                "niu"
-#define DRV_MODULE_VERSION     "1.0"
-#define DRV_MODULE_RELDATE     "Nov 14, 2008"
+#define DRV_MODULE_VERSION     "1.1"
+#define DRV_MODULE_RELDATE     "Apr 22, 2010"
 
 static char version[] __devinitdata =
        DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -3444,6 +3444,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
                              struct rx_ring_info *rp)
 {
        unsigned int index = rp->rcr_index;
+       struct rx_pkt_hdr1 *rh;
        struct sk_buff *skb;
        int len, num_rcr;
 
@@ -3477,9 +3478,6 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
                if (num_rcr == 1) {
                        int ptype;
 
-                       off += 2;
-                       append_size -= 2;
-
                        ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT);
                        if ((ptype == RCR_PKT_TYPE_TCP ||
                             ptype == RCR_PKT_TYPE_UDP) &&
@@ -3488,8 +3486,7 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
                        else
                                skb->ip_summed = CHECKSUM_NONE;
-               }
-               if (!(val & RCR_ENTRY_MULTI))
+               } else if (!(val & RCR_ENTRY_MULTI))
                        append_size = len - skb->len;
 
                niu_rx_skb_append(skb, page, off, append_size);
@@ -3510,8 +3507,17 @@ static int niu_process_rx_pkt(struct napi_struct *napi, struct niu *np,
        }
        rp->rcr_index = index;
 
-       skb_reserve(skb, NET_IP_ALIGN);
-       __pskb_pull_tail(skb, min(len, VLAN_ETH_HLEN));
+       len += sizeof(*rh);
+       len = min_t(int, len, sizeof(*rh) + VLAN_ETH_HLEN);
+       __pskb_pull_tail(skb, len);
+
+       rh = (struct rx_pkt_hdr1 *) skb->data;
+       if (np->dev->features & NETIF_F_RXHASH)
+               skb->rxhash = ((u32)rh->hashval2_0 << 24 |
+                              (u32)rh->hashval2_1 << 16 |
+                              (u32)rh->hashval1_1 << 8 |
+                              (u32)rh->hashval1_2 << 0);
+       skb_pull(skb, sizeof(*rh));
 
        rp->rx_packets++;
        rp->rx_bytes += skb->len;
@@ -4946,7 +4952,9 @@ static int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
              RX_DMA_CTL_STAT_RCRTO |
              RX_DMA_CTL_STAT_RBR_EMPTY));
        nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32);
-       nw64(RXDMA_CFIG2(channel), (rp->mbox_dma & 0x00000000ffffffc0));
+       nw64(RXDMA_CFIG2(channel),
+            ((rp->mbox_dma & RXDMA_CFIG2_MBADDR_L) |
+             RXDMA_CFIG2_FULL_HDR));
        nw64(RBR_CFIG_A(channel),
             ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) |
             (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR)));
@@ -6314,7 +6322,6 @@ static void niu_set_rx_mode(struct net_device *dev)
 {
        struct niu *np = netdev_priv(dev);
        int i, alt_cnt, err;
-       struct dev_addr_list *addr;
        struct netdev_hw_addr *ha;
        unsigned long flags;
        u16 hash[16] = { 0, };
@@ -6366,8 +6373,8 @@ static void niu_set_rx_mode(struct net_device *dev)
                for (i = 0; i < 16; i++)
                        hash[i] = 0xffff;
        } else if (!netdev_mc_empty(dev)) {
-               netdev_for_each_mc_addr(addr, dev) {
-                       u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       u32 crc = ether_crc_le(ETH_ALEN, ha->addr);
 
                        crc >>= 24;
                        hash[crc >> 4] |= (1 << (15 - (crc & 0xf)));
@@ -7911,6 +7918,18 @@ static int niu_phys_id(struct net_device *dev, u32 data)
        return 0;
 }
 
+static int niu_set_flags(struct net_device *dev, u32 data)
+{
+       if (data & (ETH_FLAG_LRO | ETH_FLAG_NTUPLE))
+               return -EOPNOTSUPP;
+
+       if (data & ETH_FLAG_RXHASH)
+               dev->features |= NETIF_F_RXHASH;
+       else
+               dev->features &= ~NETIF_F_RXHASH;
+       return 0;
+}
+
 static const struct ethtool_ops niu_ethtool_ops = {
        .get_drvinfo            = niu_get_drvinfo,
        .get_link               = ethtool_op_get_link,
@@ -7927,6 +7946,8 @@ static const struct ethtool_ops niu_ethtool_ops = {
        .phys_id                = niu_phys_id,
        .get_rxnfc              = niu_get_nfc,
        .set_rxnfc              = niu_set_nfc,
+       .set_flags              = niu_set_flags,
+       .get_flags              = ethtool_op_get_flags,
 };
 
 static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
@@ -9755,6 +9776,12 @@ static void __devinit niu_device_announce(struct niu *np)
        }
 }
 
+static void __devinit niu_set_basic_features(struct net_device *dev)
+{
+       dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM |
+                         NETIF_F_GRO | NETIF_F_RXHASH);
+}
+
 static int __devinit niu_pci_init_one(struct pci_dev *pdev,
                                      const struct pci_device_id *ent)
 {
@@ -9839,7 +9866,7 @@ static int __devinit niu_pci_init_one(struct pci_dev *pdev,
                }
        }
 
-       dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+       niu_set_basic_features(dev);
 
        np->regs = pci_ioremap_bar(pdev, 0);
        if (!np->regs) {
@@ -10081,7 +10108,7 @@ static int __devinit niu_of_probe(struct of_device *op,
                goto err_out_free_dev;
        }
 
-       dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+       niu_set_basic_features(dev);
 
        np->regs = of_ioremap(&op->resource[1], 0,
                              resource_size(&op->resource[1]),
index 3bd0b5933d590f9312870b979b66025180ccd4a7..d6715465f35d58137e5c78b26e4c3f653b7c6598 100644 (file)
@@ -2706,7 +2706,7 @@ struct rx_pkt_hdr0 {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        u8      inputport:2,
                maccheck:1,
-               class:4;
+               class:5;
        u8      vlan:1,
                llcsnap:1,
                noport:1,
@@ -2715,7 +2715,7 @@ struct rx_pkt_hdr0 {
                tres:2,
                tzfvld:1;
 #elif defined(__BIG_ENDIAN_BITFIELD)
-       u8      class:4,
+       u8      class:5,
                maccheck:1,
                inputport:2;
        u8      tzfvld:1,
@@ -2775,6 +2775,9 @@ struct rx_pkt_hdr1 {
        /* Bits 7:0 of hash value, H1.  */
        u8      hashval1_2;
 
+       u8      hwrsvd5;
+       u8      hwrsvd6;
+
        u8      usrdata_0;      /* Bits 39:32 of user data.  */
        u8      usrdata_1;      /* Bits 31:24 of user data.  */
        u8      usrdata_2;      /* Bits 23:16 of user data.  */
index 8aadc8e2ddd7e062bde2c2a0757019bcfd746ae6..000e792d57c01c42d6129ccca4102f15b2000d05 100644 (file)
@@ -189,12 +189,19 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
 
        mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
        while (mix_orcnt.s.orcnt) {
+               spin_lock_irqsave(&p->tx_list.lock, flags);
+
+               mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+
+               if (mix_orcnt.s.orcnt == 0) {
+                       spin_unlock_irqrestore(&p->tx_list.lock, flags);
+                       break;
+               }
+
                dma_sync_single_for_cpu(p->dev, p->tx_ring_handle,
                                        ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
                                        DMA_BIDIRECTIONAL);
 
-               spin_lock_irqsave(&p->tx_list.lock, flags);
-
                re.d64 = p->tx_ring[p->tx_next_clean];
                p->tx_next_clean =
                        (p->tx_next_clean + 1) % OCTEON_MGMT_TX_RING_SIZE;
@@ -317,7 +324,6 @@ good:
                skb->protocol = eth_type_trans(skb, netdev);
                netdev->stats.rx_packets++;
                netdev->stats.rx_bytes += skb->len;
-               netdev->last_rx = jiffies;
                netif_receive_skb(skb);
                rc = 0;
        } else if (re.s.code == RING_ENTRY_CODE_MORE) {
@@ -374,7 +380,6 @@ done:
        mix_ircnt.s.ircnt = 1;
        cvmx_write_csr(CVMX_MIXX_IRCNT(port), mix_ircnt.u64);
        return rc;
-
 }
 
 static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
@@ -384,7 +389,6 @@ static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
        union cvmx_mixx_ircnt mix_ircnt;
        int rc;
 
-
        mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
        while (work_done < budget && mix_ircnt.s.ircnt) {
 
@@ -475,13 +479,12 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
        unsigned int cam_mode = 1; /* 1 - Accept on CAM match */
        unsigned int multicast_mode = 1; /* 1 - Reject all multicast.  */
        struct octeon_mgmt_cam_state cam_state;
-       struct dev_addr_list *list;
-       struct list_head *pos;
+       struct netdev_hw_addr *ha;
        int available_cam_entries;
 
        memset(&cam_state, 0, sizeof(cam_state));
 
-       if ((netdev->flags & IFF_PROMISC) || netdev->dev_addrs.count > 7) {
+       if ((netdev->flags & IFF_PROMISC) || netdev->uc.count > 7) {
                cam_mode = 0;
                available_cam_entries = 8;
        } else {
@@ -489,13 +492,13 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
                 * One CAM entry for the primary address, leaves seven
                 * for the secondary addresses.
                 */
-               available_cam_entries = 7 - netdev->dev_addrs.count;
+               available_cam_entries = 7 - netdev->uc.count;
        }
 
        if (netdev->flags & IFF_MULTICAST) {
                if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI) ||
                    netdev_mc_count(netdev) > available_cam_entries)
-                       multicast_mode = 2; /* 1 - Accept all multicast.  */
+                       multicast_mode = 2; /* 2 - Accept all multicast.  */
                else
                        multicast_mode = 0; /* 0 - Use CAM.  */
        }
@@ -503,19 +506,14 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
        if (cam_mode == 1) {
                /* Add primary address. */
                octeon_mgmt_cam_state_add(&cam_state, netdev->dev_addr);
-               list_for_each(pos, &netdev->dev_addrs.list) {
-                       struct netdev_hw_addr *hw_addr;
-                       hw_addr = list_entry(pos, struct netdev_hw_addr, list);
-                       octeon_mgmt_cam_state_add(&cam_state, hw_addr->addr);
-                       list = list->next;
-               }
+               netdev_for_each_uc_addr(ha, netdev)
+                       octeon_mgmt_cam_state_add(&cam_state, ha->addr);
        }
        if (multicast_mode == 0) {
-               netdev_for_each_mc_addr(list, netdev)
-                       octeon_mgmt_cam_state_add(&cam_state, list->da_addr);
+               netdev_for_each_mc_addr(ha, netdev)
+                       octeon_mgmt_cam_state_add(&cam_state, ha->addr);
        }
 
-
        spin_lock_irqsave(&p->lock, flags);
 
        /* Disable packet I/O. */
@@ -524,7 +522,6 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
        agl_gmx_prtx.s.en = 0;
        cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
 
-
        adr_ctl.u64 = 0;
        adr_ctl.s.cam_mode = cam_mode;
        adr_ctl.s.mcst = multicast_mode;
@@ -597,8 +594,7 @@ static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id)
        mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(port));
 
        /* Clear any pending interrupts */
-       cvmx_write_csr(CVMX_MIXX_ISR(port),
-                      cvmx_read_csr(CVMX_MIXX_ISR(port)));
+       cvmx_write_csr(CVMX_MIXX_ISR(port), mixx_isr.u64);
        cvmx_read_csr(CVMX_MIXX_ISR(port));
 
        if (mixx_isr.s.irthresh) {
@@ -832,9 +828,9 @@ static int octeon_mgmt_open(struct net_device *netdev)
        mix_irhwm.s.irhwm = 0;
        cvmx_write_csr(CVMX_MIXX_IRHWM(port), mix_irhwm.u64);
 
-       /* Interrupt when we have 5 or more packets to clean.  */
+       /* Interrupt when we have 1 or more packets to clean.  */
        mix_orhwm.u64 = 0;
-       mix_orhwm.s.orhwm = 5;
+       mix_orhwm.s.orhwm = 1;
        cvmx_write_csr(CVMX_MIXX_ORHWM(port), mix_orhwm.u64);
 
        /* Enable receive and transmit interrupts */
@@ -928,7 +924,6 @@ static int octeon_mgmt_stop(struct net_device *netdev)
 
        octeon_mgmt_reset_hw(p);
 
-
        free_irq(p->irq, netdev);
 
        /* dma_unmap is a nop on Octeon, so just free everything.  */
@@ -945,7 +940,6 @@ static int octeon_mgmt_stop(struct net_device *netdev)
                         DMA_BIDIRECTIONAL);
        kfree(p->tx_ring);
 
-
        return 0;
 }
 
@@ -955,6 +949,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
        int port = p->port;
        union mgmt_port_ring_entry re;
        unsigned long flags;
+       int rv = NETDEV_TX_BUSY;
 
        re.d64 = 0;
        re.s.len = skb->len;
@@ -964,15 +959,18 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        spin_lock_irqsave(&p->tx_list.lock, flags);
 
+       if (unlikely(p->tx_current_fill >= ring_max_fill(OCTEON_MGMT_TX_RING_SIZE) - 1)) {
+               spin_unlock_irqrestore(&p->tx_list.lock, flags);
+               netif_stop_queue(netdev);
+               spin_lock_irqsave(&p->tx_list.lock, flags);
+       }
+
        if (unlikely(p->tx_current_fill >=
                     ring_max_fill(OCTEON_MGMT_TX_RING_SIZE))) {
                spin_unlock_irqrestore(&p->tx_list.lock, flags);
-
                dma_unmap_single(p->dev, re.s.addr, re.s.len,
                                 DMA_TO_DEVICE);
-
-               netif_stop_queue(netdev);
-               return NETDEV_TX_BUSY;
+               goto out;
        }
 
        __skb_queue_tail(&p->tx_list, skb);
@@ -994,10 +992,10 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
        /* Ring the bell.  */
        cvmx_write_csr(CVMX_MIXX_ORING2(port), 1);
 
-       netdev->trans_start = jiffies;
-       octeon_mgmt_clean_tx_buffers(p);
+       rv = NETDEV_TX_OK;
+out:
        octeon_mgmt_update_tx_stats(netdev);
-       return NETDEV_TX_OK;
+       return rv;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1007,7 +1005,6 @@ static void octeon_mgmt_poll_controller(struct net_device *netdev)
 
        octeon_mgmt_receive_packets(p, 16);
        octeon_mgmt_update_rx_stats(netdev);
-       return;
 }
 #endif
 
@@ -1107,7 +1104,6 @@ static int __init octeon_mgmt_probe(struct platform_device *pdev)
        netdev->netdev_ops = &octeon_mgmt_ops;
        netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
 
-
        /* The mgmt ports get the first N MACs.  */
        for (i = 0; i < 6; i++)
                netdev->dev_addr[i] = octeon_bootinfo->mac_addr_base[i];
index 370c147d08a3d6d1759a55ad8db01a95ad28e71f..8ab6ae0a61079dd28f606ce3ca4d637dfdf50e52 100644 (file)
@@ -1472,8 +1472,6 @@ static void pasemi_mac_queue_csdesc(const struct sk_buff *skb,
        txring->next_to_fill = fill;
 
        write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), 2);
-
-       return;
 }
 
 static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
index 36785853a149ddb36a7d17ab5966d41a4ee065b6..56f3fc45dbaa84ab9ecbc9f2e8a29902413c6ef6 100644 (file)
@@ -1354,7 +1354,6 @@ static int netdrv_start_xmit(struct sk_buff *skb, struct net_device *dev)
        NETDRV_W32(TxStatus0 + (entry * sizeof(u32)),
                   tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
-       dev->trans_start = jiffies;
        atomic_inc(&tp->cur_tx);
        if ((atomic_read(&tp->cur_tx) - atomic_read(&tp->dirty_tx)) >= NUM_TX_DESC)
                netif_stop_queue(dev);
@@ -1813,12 +1812,12 @@ static void netdrv_set_rx_mode(struct net_device *dev)
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
 
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                }
index 30b7cf70fbe67bf7cae38808ac6f33e50b516453..10ee106a161778d6a510adc9c065123a6784964c 100644 (file)
@@ -613,8 +613,6 @@ static void mdio_write(unsigned int ioaddr, int phy_id, int location, int value)
                outw(MDIO_ENB_IN, mdio_addr);
                outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
        }
-
-       return;
 }
 
 /* Reset and restore all of the 3c574 registers. */
@@ -730,7 +728,7 @@ static void el3_tx_timeout(struct net_device *dev)
        printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
        dump_status(dev);
        dev->stats.tx_errors++;
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        /* Issue TX_RESET and TX_START commands. */
        tc574_wait_for_completion(dev, TxReset);
        outw(TxEnable, ioaddr + EL3_CMD);
@@ -781,8 +779,6 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
        /* ... and the packet rounded to a doubleword. */
        outsl(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
 
-       dev->trans_start = jiffies;
-
        /* TxFree appears only in Window 1, not offset 0x1c. */
        if (inw(ioaddr + TxFree) <= 1536) {
                netif_stop_queue(dev);
index 5ab589d3b38564ece42c36dbf48d1fae7af1beb2..ce63c3773b4c693a78642727fa2223b8c4587b58 100644 (file)
@@ -1,20 +1,20 @@
 /*======================================================================
 
     A PCMCIA ethernet driver for the 3com 3c589 card.
-    
+
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
     3c589_cs.c 1.162 2001/10/13 00:08:50
 
     The network driver code is based on Donald Becker's 3c589 code:
-    
+
     Written 1994 by Donald Becker.
     Copyright 1993 United States Government as represented by the
     Director, National Security Agency.  This software may be used and
     distributed according to the terms of the GNU General Public License,
     incorporated herein by reference.
     Donald Becker may be reached at becker@scyld.com
-    
+
     Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
 
 ======================================================================*/
 /* The top five bits written to EL3_CMD are a command, the lower
    11 bits are the parameter, if applicable. */
 enum c509cmd {
-    TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
-    RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
-    TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
-    FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
-    SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
-    SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
-    StatsDisable = 22<<11, StopCoax = 23<<11,
+       TotalReset      = 0<<11,
+       SelectWindow    = 1<<11,
+       StartCoax       = 2<<11,
+       RxDisable       = 3<<11,
+       RxEnable        = 4<<11,
+       RxReset         = 5<<11,
+       RxDiscard       = 8<<11,
+       TxEnable        = 9<<11,
+       TxDisable       = 10<<11,
+       TxReset         = 11<<11,
+       FakeIntr        = 12<<11,
+       AckIntr         = 13<<11,
+       SetIntrEnb      = 14<<11,
+       SetStatusEnb    = 15<<11,
+       SetRxFilter     = 16<<11,
+       SetRxThreshold  = 17<<11,
+       SetTxThreshold  = 18<<11,
+       SetTxStart      = 19<<11,
+       StatsEnable     = 21<<11,
+       StatsDisable    = 22<<11,
+       StopCoax        = 23<<11
 };
 
 enum c509status {
-    IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
-    TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
-    IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000
+       IntLatch        = 0x0001,
+       AdapterFailure  = 0x0002,
+       TxComplete      = 0x0004,
+       TxAvailable     = 0x0008,
+       RxComplete      = 0x0010,
+       RxEarly         = 0x0020,
+       IntReq          = 0x0040,
+       StatsFull       = 0x0080,
+       CmdBusy         = 0x1000
 };
 
 /* The SetRxFilter command accepts the following classes: */
 enum RxFilter {
-    RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+       RxStation       = 1,
+       RxMulticast     = 2,
+       RxBroadcast     = 4,
+       RxProm          = 8
 };
 
 /* Register window 1 offsets, the window used in normal operation. */
 #define TX_FIFO                0x00
 #define RX_FIFO                0x00
-#define RX_STATUS      0x08
-#define TX_STATUS      0x0B
+#define RX_STATUS      0x08
+#define TX_STATUS      0x0B
 #define TX_FREE                0x0C    /* Remaining free bytes in Tx buffer. */
 
 #define WN0_IRQ                0x08    /* Window 0: Set IRQ line in bits 12-15. */
@@ -106,12 +129,12 @@ enum RxFilter {
 
 struct el3_private {
        struct pcmcia_device    *p_dev;
-    /* For transceiver monitoring */
-    struct timer_list  media;
-    u16                        media_status;
-    u16                        fast_poll;
-    unsigned long      last_irq;
-    spinlock_t         lock;
+       /* For transceiver monitoring */
+       struct timer_list       media;
+       u16                     media_status;
+       u16                     fast_poll;
+       unsigned long           last_irq;
+       spinlock_t              lock;
 };
 
 static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
@@ -163,15 +186,15 @@ static void tc589_detach(struct pcmcia_device *p_dev);
 ======================================================================*/
 
 static const struct net_device_ops el3_netdev_ops = {
-       .ndo_open               = el3_open,
-       .ndo_stop               = el3_close,
+       .ndo_open               = el3_open,
+       .ndo_stop               = el3_close,
        .ndo_start_xmit         = el3_start_xmit,
-       .ndo_tx_timeout         = el3_tx_timeout,
+       .ndo_tx_timeout         = el3_tx_timeout,
        .ndo_set_config         = el3_config,
        .ndo_get_stats          = el3_get_stats,
        .ndo_set_multicast_list = set_multicast_list,
        .ndo_change_mtu         = eth_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
 };
 
@@ -233,7 +256,7 @@ static void tc589_detach(struct pcmcia_device *link)
     tc589_config() is scheduled to run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
-    
+
 ======================================================================*/
 
 static int tc589_config(struct pcmcia_device *link)
@@ -245,7 +268,7 @@ static int tc589_config(struct pcmcia_device *link)
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
     u8 *buf;
     size_t len;
-    
+
     dev_dbg(&link->dev, "3c589_config\n");
 
     phys_addr = (__be16 *)dev->dev_addr;
@@ -274,7 +297,7 @@ static int tc589_config(struct pcmcia_device *link)
     ret = pcmcia_request_configuration(link, &link->conf);
     if (ret)
            goto failed;
-       
+
     dev->irq = link->irq;
     dev->base_addr = link->io.BasePort1;
     ioaddr = dev->base_addr;
@@ -308,7 +331,7 @@ static int tc589_config(struct pcmcia_device *link)
        dev->if_port = if_port;
     else
        printk(KERN_ERR "3c589_cs: invalid if_port requested\n");
-    
+
     SET_NETDEV_DEV(dev, &link->dev);
 
     if (register_netdev(dev) != 0) {
@@ -316,13 +339,12 @@ static int tc589_config(struct pcmcia_device *link)
        goto failed;
     }
 
-    printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, "
-          "hw_addr %pM\n",
-          dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq,
-          dev->dev_addr);
-    printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
-          (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
-          if_names[dev->if_port]);
+    netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
+               (multi ? "562" : "589"), dev->base_addr, dev->irq,
+               dev->dev_addr);
+    netdev_info(dev, "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
+               (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
+               if_names[dev->if_port]);
     return 0;
 
 failed:
@@ -335,7 +357,7 @@ failed:
     After a card is removed, tc589_release() will unregister the net
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
-    
+
 ======================================================================*/
 
 static void tc589_release(struct pcmcia_device *link)
@@ -357,7 +379,7 @@ static int tc589_resume(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
 
-       if (link->open) {
+       if (link->open) {
                tc589_reset(dev);
                netif_device_attach(dev);
        }
@@ -377,8 +399,7 @@ static void tc589_wait_for_completion(struct net_device *dev, int cmd)
     while (--i > 0)
        if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
     if (i == 0)
-       printk(KERN_WARNING "%s: command 0x%04x did not complete!\n",
-              dev->name, cmd);
+       netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
 }
 
 /*
@@ -404,7 +425,7 @@ static void tc589_set_xcvr(struct net_device *dev, int if_port)
 {
     struct el3_private *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
-    
+
     EL3WINDOW(0);
     switch (if_port) {
     case 0: case 1: outw(0, ioaddr + 6); break;
@@ -427,14 +448,13 @@ static void dump_status(struct net_device *dev)
 {
     unsigned int ioaddr = dev->base_addr;
     EL3WINDOW(1);
-    printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
-          "%02x  tx free %04x\n", inw(ioaddr+EL3_STATUS),
-          inw(ioaddr+RX_STATUS), inb(ioaddr+TX_STATUS),
-          inw(ioaddr+TX_FREE));
+    netdev_info(dev, "  irq status %04x, rx status %04x, tx status %02x  tx free %04x\n",
+               inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
+               inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
     EL3WINDOW(4);
-    printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
-          " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
-          inw(ioaddr+0x08), inw(ioaddr+0x0a));
+    netdev_info(dev, "  diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
+               inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
+               inw(ioaddr+0x0a));
     EL3WINDOW(1);
 }
 
@@ -443,18 +463,18 @@ static void tc589_reset(struct net_device *dev)
 {
     unsigned int ioaddr = dev->base_addr;
     int i;
-    
+
     EL3WINDOW(0);
-    outw(0x0001, ioaddr + 4);                  /* Activate board. */ 
+    outw(0x0001, ioaddr + 4);                  /* Activate board. */
     outw(0x3f00, ioaddr + 8);                  /* Set the IRQ line. */
-    
+
     /* Set the station address in window 2. */
     EL3WINDOW(2);
     for (i = 0; i < 6; i++)
        outb(dev->dev_addr[i], ioaddr + i);
 
     tc589_set_xcvr(dev, dev->if_port);
-    
+
     /* Switch to the stats window, and clear all stats by reading. */
     outw(StatsDisable, ioaddr + EL3_CMD);
     EL3WINDOW(6);
@@ -462,7 +482,7 @@ static void tc589_reset(struct net_device *dev)
        inb(ioaddr+i);
     inw(ioaddr + 10);
     inw(ioaddr + 12);
-    
+
     /* Switch to register set 1 for normal use. */
     EL3WINDOW(1);
 
@@ -496,8 +516,7 @@ static int el3_config(struct net_device *dev, struct ifmap *map)
     if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
        if (map->port <= 3) {
            dev->if_port = map->port;
-           printk(KERN_INFO "%s: switched to %s port\n",
-                  dev->name, if_names[dev->if_port]);
+           netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
            tc589_set_xcvr(dev, dev->if_port);
        } else
            return -EINVAL;
@@ -509,13 +528,13 @@ static int el3_open(struct net_device *dev)
 {
     struct el3_private *lp = netdev_priv(dev);
     struct pcmcia_device *link = lp->p_dev;
-    
+
     if (!pcmcia_dev_present(link))
        return -ENODEV;
 
     link->open++;
     netif_start_queue(dev);
-    
+
     tc589_reset(dev);
     init_timer(&lp->media);
     lp->media.function = &media_check;
@@ -525,18 +544,18 @@ static int el3_open(struct net_device *dev)
 
     dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
          dev->name, inw(dev->base_addr + EL3_STATUS));
-    
+
     return 0;
 }
 
 static void el3_tx_timeout(struct net_device *dev)
 {
     unsigned int ioaddr = dev->base_addr;
-    
-    printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name);
+
+    netdev_warn(dev, "Transmit timed out!\n");
     dump_status(dev);
     dev->stats.tx_errors++;
-    dev->trans_start = jiffies;
+    dev->trans_start = jiffies; /* prevent tx timeout */
     /* Issue TX_RESET and TX_START commands. */
     tc589_wait_for_completion(dev, TxReset);
     outw(TxEnable, ioaddr + EL3_CMD);
@@ -547,19 +566,18 @@ static void pop_tx_status(struct net_device *dev)
 {
     unsigned int ioaddr = dev->base_addr;
     int i;
-    
+
     /* Clear the Tx status stack. */
     for (i = 32; i > 0; i--) {
        u_char tx_status = inb(ioaddr + TX_STATUS);
        if (!(tx_status & 0x84)) break;
        /* reset transmitter on jabber error or underrun */
        if (tx_status & 0x30)
-           tc589_wait_for_completion(dev, TxReset);
+               tc589_wait_for_completion(dev, TxReset);
        if (tx_status & 0x38) {
-           pr_debug("%s: transmit error: status 0x%02x\n",
-                 dev->name, tx_status);
-           outw(TxEnable, ioaddr + EL3_CMD);
-           dev->stats.tx_aborted_errors++;
+               netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
+               outw(TxEnable, ioaddr + EL3_CMD);
+               dev->stats.tx_aborted_errors++;
        }
        outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
     }
@@ -572,11 +590,10 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
     struct el3_private *priv = netdev_priv(dev);
     unsigned long flags;
 
-    pr_debug("%s: el3_start_xmit(length = %ld) called, "
-         "status %4.4x.\n", dev->name, (long)skb->len,
-         inw(ioaddr + EL3_STATUS));
+    netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
+              (long)skb->len, inw(ioaddr + EL3_STATUS));
 
-    spin_lock_irqsave(&priv->lock, flags);    
+    spin_lock_irqsave(&priv->lock, flags);
 
     dev->stats.tx_bytes += skb->len;
 
@@ -586,7 +603,6 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
     /* ... and the packet rounded to a doubleword. */
     outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 
-    dev->trans_start = jiffies;
     if (inw(ioaddr + TX_FREE) <= 1536) {
        netif_stop_queue(dev);
        /* Interrupt us when the FIFO has room for max-sized packet. */
@@ -594,9 +610,9 @@ static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
     }
 
     pop_tx_status(dev);
-    spin_unlock_irqrestore(&priv->lock, flags);    
+    spin_unlock_irqrestore(&priv->lock, flags);
     dev_kfree_skb(skb);
-    
+
     return NETDEV_TX_OK;
 }
 
@@ -608,37 +624,32 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
     unsigned int ioaddr;
     __u16 status;
     int i = 0, handled = 1;
-    
+
     if (!netif_device_present(dev))
        return IRQ_NONE;
 
     ioaddr = dev->base_addr;
 
-    pr_debug("%s: interrupt, status %4.4x.\n",
-         dev->name, inw(ioaddr + EL3_STATUS));
+    netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
 
-    spin_lock(&lp->lock);    
+    spin_lock(&lp->lock);
     while ((status = inw(ioaddr + EL3_STATUS)) &
        (IntLatch | RxComplete | StatsFull)) {
        if ((status & 0xe000) != 0x2000) {
-           pr_debug("%s: interrupt from dead card\n", dev->name);
-           handled = 0;
-           break;
+               netdev_dbg(dev, "interrupt from dead card\n");
+               handled = 0;
+               break;
        }
-       
        if (status & RxComplete)
-           el3_rx(dev);
-       
+               el3_rx(dev);
        if (status & TxAvailable) {
-           pr_debug("    TX room bit was handled.\n");
-           /* There's room in the FIFO for a full-sized packet. */
-           outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-           netif_wake_queue(dev);
+               netdev_dbg(dev, "    TX room bit was handled.\n");
+               /* There's room in the FIFO for a full-sized packet. */
+               outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+               netif_wake_queue(dev);
        }
-       
        if (status & TxComplete)
-           pop_tx_status(dev);
-
+               pop_tx_status(dev);
        if (status & (AdapterFailure | RxEarly | StatsFull)) {
            /* Handle all uncommon interrupts. */
            if (status & StatsFull)             /* Empty statistics. */
@@ -652,8 +663,8 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
                EL3WINDOW(4);
                fifo_diag = inw(ioaddr + 4);
                EL3WINDOW(1);
-               printk(KERN_WARNING "%s: adapter failure, FIFO diagnostic"
-                      " register %04x.\n", dev->name, fifo_diag);
+               netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
+                           fifo_diag);
                if (fifo_diag & 0x0400) {
                    /* Tx overrun */
                    tc589_wait_for_completion(dev, TxReset);
@@ -668,22 +679,20 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id)
                outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
            }
        }
-       
        if (++i > 10) {
-           printk(KERN_ERR "%s: infinite loop in interrupt, "
-                  "status %4.4x.\n", dev->name, status);
-           /* Clear all interrupts */
-           outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
-           break;
+               netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
+                          status);
+               /* Clear all interrupts */
+               outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+               break;
        }
        /* Acknowledge the IRQ. */
        outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
     }
-
     lp->last_irq = jiffies;
-    spin_unlock(&lp->lock);    
-    pr_debug("%s: exiting interrupt, status %4.4x.\n",
-         dev->name, inw(ioaddr + EL3_STATUS));
+    spin_unlock(&lp->lock);
+    netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
+              inw(ioaddr + EL3_STATUS));
     return IRQ_RETVAL(handled);
 }
 
@@ -702,7 +711,7 @@ static void media_check(unsigned long arg)
     if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
        (inb(ioaddr + EL3_TIMER) == 0xff)) {
        if (!lp->fast_poll)
-           printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name);
+               netdev_warn(dev, "interrupt(s) dropped!\n");
 
        local_irq_save(flags);
        el3_interrupt(dev->irq, dev);
@@ -719,7 +728,7 @@ static void media_check(unsigned long arg)
 
     /* lp->lock guards the EL3 window. Window should always be 1 except
        when the lock is held */
-    spin_lock_irqsave(&lp->lock, flags);    
+    spin_lock_irqsave(&lp->lock, flags);
     EL3WINDOW(4);
     media = inw(ioaddr+WN4_MEDIA) & 0xc810;
 
@@ -739,32 +748,30 @@ static void media_check(unsigned long arg)
     if (media != lp->media_status) {
        if ((media & lp->media_status & 0x8000) &&
            ((lp->media_status ^ media) & 0x0800))
-           printk(KERN_INFO "%s: %s link beat\n", dev->name,
-                  (lp->media_status & 0x0800 ? "lost" : "found"));
+               netdev_info(dev, "%s link beat\n",
+                           (lp->media_status & 0x0800 ? "lost" : "found"));
        else if ((media & lp->media_status & 0x4000) &&
                 ((lp->media_status ^ media) & 0x0010))
-           printk(KERN_INFO "%s: coax cable %s\n", dev->name,
-                  (lp->media_status & 0x0010 ? "ok" : "problem"));
+               netdev_info(dev, "coax cable %s\n",
+                           (lp->media_status & 0x0010 ? "ok" : "problem"));
        if (dev->if_port == 0) {
            if (media & 0x8000) {
                if (media & 0x0800)
-                   printk(KERN_INFO "%s: flipped to 10baseT\n",
-                          dev->name);
+                       netdev_info(dev, "flipped to 10baseT\n");
                else
-                   tc589_set_xcvr(dev, 2);
+                       tc589_set_xcvr(dev, 2);
            } else if (media & 0x4000) {
                if (media & 0x0010)
                    tc589_set_xcvr(dev, 1);
                else
-                   printk(KERN_INFO "%s: flipped to 10base2\n",
-                          dev->name);
+                   netdev_info(dev, "flipped to 10base2\n");
            }
        }
        lp->media_status = media;
     }
-    
+
     EL3WINDOW(1);
-    spin_unlock_irqrestore(&lp->lock, flags);    
+    spin_unlock_irqrestore(&lp->lock, flags);
 
 reschedule:
     lp->media.expires = jiffies + HZ;
@@ -778,7 +785,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
     struct pcmcia_device *link = lp->p_dev;
 
     if (pcmcia_dev_present(link)) {
-       spin_lock_irqsave(&lp->lock, flags);
+       spin_lock_irqsave(&lp->lock, flags);
        update_stats(dev);
        spin_unlock_irqrestore(&lp->lock, flags);
     }
@@ -790,21 +797,21 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev)
   single-threaded if the device is active. This is expected to be a rare
   operation, and it's simpler for the rest of the driver to assume that
   window 1 is always valid rather than use a special window-state variable.
-  
+
   Caller must hold the lock for this
 */
 static void update_stats(struct net_device *dev)
 {
     unsigned int ioaddr = dev->base_addr;
 
-    pr_debug("%s: updating the statistics.\n", dev->name);
+    netdev_dbg(dev, "updating the statistics.\n");
     /* Turn off statistics updates while reading. */
     outw(StatsDisable, ioaddr + EL3_CMD);
     /* Switch to the stats window, and read everything. */
     EL3WINDOW(6);
-    dev->stats.tx_carrier_errors       += inb(ioaddr + 0);
+    dev->stats.tx_carrier_errors       += inb(ioaddr + 0);
     dev->stats.tx_heartbeat_errors     += inb(ioaddr + 1);
-    /* Multiple collisions. */         inb(ioaddr + 2);
+    /* Multiple collisions. */         inb(ioaddr + 2);
     dev->stats.collisions              += inb(ioaddr + 3);
     dev->stats.tx_window_errors                += inb(ioaddr + 4);
     dev->stats.rx_fifo_errors          += inb(ioaddr + 5);
@@ -813,7 +820,7 @@ static void update_stats(struct net_device *dev)
     /* Tx deferrals */                 inb(ioaddr + 8);
     /* Rx octets */                    inw(ioaddr + 10);
     /* Tx octets */                    inw(ioaddr + 12);
-    
+
     /* Back to window 1, and turn statistics back on. */
     EL3WINDOW(1);
     outw(StatsEnable, ioaddr + EL3_CMD);
@@ -824,9 +831,9 @@ static int el3_rx(struct net_device *dev)
     unsigned int ioaddr = dev->base_addr;
     int worklimit = 32;
     short rx_status;
-    
-    pr_debug("%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
-         dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
+
+    netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+              inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
     while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
                    worklimit > 0) {
        worklimit--;
@@ -844,11 +851,11 @@ static int el3_rx(struct net_device *dev)
        } else {
            short pkt_len = rx_status & 0x7ff;
            struct sk_buff *skb;
-           
+
            skb = dev_alloc_skb(pkt_len+5);
-           
-           pr_debug("    Receiving packet size %d status %4.4x.\n",
-                 pkt_len, rx_status);
+
+           netdev_dbg(dev, "    Receiving packet size %d status %4.4x.\n",
+                      pkt_len, rx_status);
            if (skb != NULL) {
                skb_reserve(skb, 2);
                insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
@@ -858,8 +865,8 @@ static int el3_rx(struct net_device *dev)
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += pkt_len;
            } else {
-               pr_debug("%s: couldn't allocate a sk_buff of"
-                     " size %d.\n", dev->name, pkt_len);
+               netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
+                          pkt_len);
                dev->stats.rx_dropped++;
            }
        }
@@ -867,7 +874,7 @@ static int el3_rx(struct net_device *dev)
        tc589_wait_for_completion(dev, RxDiscard);
     }
     if (worklimit == 0)
-       printk(KERN_WARNING "%s: too much work in el3_rx!\n", dev->name);
+       netdev_warn(dev, "too much work in el3_rx!\n");
     return 0;
 }
 
@@ -898,17 +905,17 @@ static int el3_close(struct net_device *dev)
     struct el3_private *lp = netdev_priv(dev);
     struct pcmcia_device *link = lp->p_dev;
     unsigned int ioaddr = dev->base_addr;
-    
+
     dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
 
     if (pcmcia_dev_present(link)) {
        /* Turn off statistics ASAP.  We update dev->stats below. */
        outw(StatsDisable, ioaddr + EL3_CMD);
-       
+
        /* Disable the receiver and transmitter. */
        outw(RxDisable, ioaddr + EL3_CMD);
        outw(TxDisable, ioaddr + EL3_CMD);
-       
+
        if (dev->if_port == 2)
            /* Turn off thinnet power.  Green! */
            outw(StopCoax, ioaddr + EL3_CMD);
@@ -917,12 +924,12 @@ static int el3_close(struct net_device *dev)
            EL3WINDOW(4);
            outw(0, ioaddr + WN4_MEDIA);
        }
-       
+
        /* Switching back to window 0 disables the IRQ. */
        EL3WINDOW(0);
        /* But we explicitly zero the IRQ line select anyway. */
        outw(0x0f00, ioaddr + WN0_IRQ);
-        
+
        /* Check if the card still exists */
        if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
            update_stats(dev);
@@ -931,7 +938,7 @@ static int el3_close(struct net_device *dev)
     link->open--;
     netif_stop_queue(dev);
     del_timer_sync(&lp->media);
-    
+
     return 0;
 }
 
@@ -953,7 +960,7 @@ static struct pcmcia_driver tc589_driver = {
        },
        .probe          = tc589_probe,
        .remove         = tc589_detach,
-        .id_table       = tc589_ids,
+       .id_table       = tc589_ids,
        .suspend        = tc589_suspend,
        .resume         = tc589_resume,
 };
index 59f6fa3c9ddcc1812e7a085795a7235badda6e89..5b3dfb4ab27985cd8823c08035dd066da36e4d1c 100644 (file)
@@ -994,7 +994,7 @@ static void axnet_tx_timeout(struct net_device *dev)
 {
        long e8390_base = dev->base_addr;
        struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-       int txsr, isr, tickssofar = jiffies - dev->trans_start;
+       int txsr, isr, tickssofar = jiffies - dev_trans_start(dev);
        unsigned long flags;
 
        dev->stats.tx_errors++;
@@ -1499,8 +1499,6 @@ static void ei_receive(struct net_device *dev)
                ei_local->current_page = next_frame;
                outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
        }
-
-       return;
 }
 
 /**
@@ -1611,11 +1609,11 @@ static struct net_device_stats *get_stats(struct net_device *dev)
  
 static inline void make_mc_bits(u8 *bits, struct net_device *dev)
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        u32 crc;
 
-       netdev_for_each_mc_addr(dmi, dev) {
-               crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
+       netdev_for_each_mc_addr(ha, dev) {
+               crc = ether_crc(ETH_ALEN, ha->addr);
                /* 
                 * The 8390 uses the 6 most significant bits of the
                 * CRC to index the multicast table.
index 6580d78397d1cb769299776b095fe0c51a309b80..7c27c50211a55448558f8f674160f20cf6aa1241 100644 (file)
@@ -878,7 +878,6 @@ static netdev_tx_t fjn_start_xmit(struct sk_buff *skb,
            lp->sent = lp->tx_queue ;
            lp->tx_queue = 0;
            lp->tx_queue_len = 0;
-           dev->trans_start = jiffies;
            lp->tx_started = 1;
            netif_start_queue(dev);
        } else {
@@ -1070,8 +1069,6 @@ static void fjn_rx(struct net_device *dev)
                  "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
     }
 */
-
-    return;
 } /* fjn_rx */
 
 /*====================================================================*/
@@ -1184,11 +1181,11 @@ static void set_rx_mode(struct net_device *dev)
        memset(mc_filter, 0x00, sizeof(mc_filter));
        outb(1, ioaddr + RX_MODE);      /* Ignore almost all multicasts. */
     } else {
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
 
        memset(mc_filter, 0, sizeof(mc_filter));
-       netdev_for_each_mc_addr(mclist, dev) {
-           unsigned int bit = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26;
+       netdev_for_each_mc_addr(ha, dev) {
+           unsigned int bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26;
            mc_filter[bit >> 3] |= (1 << (bit & 7));
        }
        outb(2, ioaddr + RX_MODE);      /* Use normal mode. */
index 2e42d80f8cae7b58d4387c18a7d45262ad655efb..67ee9851a8ed5431f140e9c57435fe1574f90421 100644 (file)
@@ -394,8 +394,6 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
 
     /* 0x40 will release the card for use */
     outb(0x40, dev->base_addr);
-
-    return;
 }
 
 static struct pcmcia_device_id ibmtr_ids[] = {
index d8a3b3cf246e484f2a986d35f6cef1736aff5597..9b63dec549cbce4e453f0a996c3d45e7236b3850 100644 (file)
@@ -895,7 +895,7 @@ static void mace_tx_timeout(struct net_device *dev)
 #else /* #if RESET_ON_TIMEOUT */
   printk("NOT resetting card\n");
 #endif /* #if RESET_ON_TIMEOUT */
-  dev->trans_start = jiffies;
+  dev->trans_start = jiffies; /* prevent tx timeout */
   netif_wake_queue(dev);
 }
 
@@ -937,8 +937,6 @@ static netdev_tx_t mace_start_xmit(struct sk_buff *skb,
       outb(skb->data[skb->len-1], ioaddr + AM2150_XMT);
     }
 
-    dev->trans_start = jiffies;
-
 #if MULTI_TX
     if (lp->tx_free_frames > 0)
       netif_start_queue(dev);
@@ -1307,8 +1305,6 @@ static void update_stats(unsigned int ioaddr, struct net_device *dev)
   lp->linux_stats.tx_fifo_errors = lp->mace_stats.uflo;
   lp->linux_stats.tx_heartbeat_errors = lp->mace_stats.cerr;
   /* lp->linux_stats.tx_window_errors; */
-
-  return;
 } /* update_stats */
 
 /* ----------------------------------------------------------------------------
@@ -1467,7 +1463,7 @@ static void set_multicast_list(struct net_device *dev)
 {
   mace_private *lp = netdev_priv(dev);
   int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */
-  struct dev_mc_list *dmi;
+  struct netdev_hw_addr *ha;
 
 #ifdef PCMCIA_DEBUG
   {
@@ -1487,8 +1483,8 @@ static void set_multicast_list(struct net_device *dev)
   if (num_addrs > 0) {
     /* Calculate multicast logical address filter */
     memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
-    netdev_for_each_mc_addr(dmi, dev) {
-      memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN);
+    netdev_for_each_mc_addr(ha, dev) {
+      memcpy(adr, ha->addr, ETHER_ADDR_LEN);
       BuildLAF(lp->multicast_ladrf, adr);
     }
   }
index 59796e7d09c418cc9041286905e65c2226e1462e..7b6fe89f9db0aa4c3f5373a25465efaf8d658ad3 100644 (file)
@@ -1228,7 +1228,6 @@ static void smc_hardware_send_packet(struct net_device * dev)
     dev_kfree_skb_irq(skb);
     dev->trans_start = jiffies;
     netif_start_queue(dev);
-    return;
 }
 
 /*====================================================================*/
@@ -1243,7 +1242,7 @@ static void smc_tx_timeout(struct net_device *dev)
           dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
     dev->stats.tx_errors++;
     smc_reset(dev);
-    dev->trans_start = jiffies;
+    dev->trans_start = jiffies; /* prevent tx timeout */
     smc->saved_skb = NULL;
     netif_wake_queue(dev);
 }
@@ -1358,7 +1357,6 @@ static void smc_tx_err(struct net_device * dev)
     smc->packets_waiting--;
 
     outw(saved_packet, ioaddr + PNR_ARR);
-    return;
 }
 
 /*====================================================================*/
@@ -1578,8 +1576,6 @@ static void smc_rx(struct net_device *dev)
     }
     /* Let the MMU free the memory of this packet. */
     outw(MC_RELEASE, ioaddr + MMU_CMD);
-
-    return;
 }
 
 /*======================================================================
@@ -1610,10 +1606,10 @@ static void set_rx_mode(struct net_device *dev)
        rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
     else {
        if (!netdev_mc_empty(dev)) {
-           struct dev_mc_list *mc_addr;
+           struct netdev_hw_addr *ha;
 
-           netdev_for_each_mc_addr(mc_addr, dev) {
-               u_int position = ether_crc(6, mc_addr->dmi_addr);
+           netdev_for_each_mc_addr(ha, dev) {
+               u_int position = ether_crc(6, ha->addr);
                multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
            }
        }
@@ -1629,8 +1625,6 @@ static void set_rx_mode(struct net_device *dev)
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
     spin_unlock_irqrestore(&smc->lock, flags);
-
-    return;
 }
 
 /*======================================================================
index 5e6b62ba888722786f909a0b3f3ed3cc780f6a66..b6c3644888cd8e09077bb7f4f92872387b49b9ba 100644 (file)
@@ -1265,7 +1265,7 @@ xirc2ps_tx_timeout_task(struct work_struct *work)
        struct net_device *dev = local->dev;
     /* reset the card */
     do_reset(dev,1);
-    dev->trans_start = jiffies;
+    dev->trans_start = jiffies; /* prevent tx timeout */
     netif_wake_queue(dev);
 }
 
@@ -1328,7 +1328,6 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
        PutByte(XIRCREG_CR, TransmitPacket|EnableIntr);
 
     dev_kfree_skb (skb);
-    dev->trans_start = jiffies;
     dev->stats.tx_bytes += pktlen;
     netif_start_queue(dev);
     return NETDEV_TX_OK;
@@ -1368,7 +1367,7 @@ static void set_addresses(struct net_device *dev)
 {
        unsigned int ioaddr = dev->base_addr;
        local_info_t *lp = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        struct set_address_info sa_info;
        int i;
 
@@ -1383,10 +1382,10 @@ static void set_addresses(struct net_device *dev)
 
        set_address(&sa_info, dev->dev_addr);
        i = 0;
-       netdev_for_each_mc_addr(dmi, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                if (i++ == 9)
                        break;
-               set_address(&sa_info, dmi->dmi_addr);
+               set_address(&sa_info, ha->addr);
        }
        while (i++ < 9)
                set_address(&sa_info, dev->dev_addr);
index 084d78dd16376da3932919f883b9656e2dc12882..c200c2821730a0cdd3121f9cf6b6ee023db30f79 100644 (file)
@@ -448,7 +448,7 @@ static void pcnet32_netif_stop(struct net_device *dev)
 {
        struct pcnet32_private *lp = netdev_priv(dev);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        napi_disable(&lp->napi);
        netif_tx_disable(dev);
 }
@@ -647,7 +647,6 @@ free_new_rx_ring:
                            (1 << size),
                            new_rx_ring,
                            new_ring_dma_addr);
-       return;
 }
 
 static void pcnet32_purge_rx_ring(struct net_device *dev)
@@ -1215,7 +1214,6 @@ static void pcnet32_rx_entry(struct net_device *dev,
        skb->protocol = eth_type_trans(skb, dev);
        netif_receive_skb(skb);
        dev->stats.rx_packets++;
-       return;
 }
 
 static int pcnet32_rx(struct net_device *dev, int budget)
@@ -2398,7 +2396,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
        }
        pcnet32_restart(dev, CSR0_NORMAL);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 
        spin_unlock_irqrestore(&lp->lock, flags);
@@ -2449,8 +2447,6 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
        /* Trigger an immediate send poll. */
        lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
 
-       dev->trans_start = jiffies;
-
        if (lp->tx_ring[(entry + 1) & lp->tx_mod_mask].base != 0) {
                lp->tx_full = 1;
                netif_stop_queue(dev);
@@ -2590,7 +2586,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
        struct pcnet32_private *lp = netdev_priv(dev);
        volatile struct pcnet32_init_block *ib = lp->init_block;
        volatile __le16 *mcast_table = (__le16 *)ib->filter;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned long ioaddr = dev->base_addr;
        char *addrs;
        int i;
@@ -2611,8 +2607,8 @@ static void pcnet32_load_multicast(struct net_device *dev)
        ib->filter[1] = 0;
 
        /* Add addresses */
-       netdev_for_each_mc_addr(dmi, dev) {
-               addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrs = ha->addr;
 
                /* multicast address? */
                if (!(*addrs & 1))
@@ -2625,7 +2621,6 @@ static void pcnet32_load_multicast(struct net_device *dev)
        for (i = 0; i < 4; i++)
                lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
                                le16_to_cpu(mcast_table[i]));
-       return;
 }
 
 /*
index 4fed95e8350ef536d9631070a5dd50c98b08e0c2..c1281567983739bdd3a5bbecd0f7c1fbf03e6ba0 100644 (file)
@@ -130,3 +130,11 @@ static void __exit bcm63xx_phy_exit(void)
 
 module_init(bcm63xx_phy_init);
 module_exit(bcm63xx_phy_exit);
+
+static struct mdio_device_id bcm63xx_tbl[] = {
+       { 0x00406000, 0xfffffc00 },
+       { 0x002bdc00, 0xfffffc00 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, bcm63xx_tbl);
index f482fc4f8cf1deb8c1c6415ec6ad88586a220425..cecdbbd549ecd24a5d1be8bf7da8dc19c8768129 100644 (file)
@@ -908,3 +908,19 @@ static void __exit broadcom_exit(void)
 
 module_init(broadcom_init);
 module_exit(broadcom_exit);
+
+static struct mdio_device_id broadcom_tbl[] = {
+       { 0x00206070, 0xfffffff0 },
+       { 0x002060e0, 0xfffffff0 },
+       { 0x002060c0, 0xfffffff0 },
+       { 0x002060b0, 0xfffffff0 },
+       { 0x0143bca0, 0xfffffff0 },
+       { 0x0143bcb0, 0xfffffff0 },
+       { PHY_ID_BCM50610, 0xfffffff0 },
+       { PHY_ID_BCM50610M, 0xfffffff0 },
+       { PHY_ID_BCM57780, 0xfffffff0 },
+       { PHY_ID_BCMAC131, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, broadcom_tbl);
index 92282b31d94bf64d5c53617f385140b305ad14f9..1a325d63756b9cac7230080073fc02a2f38518ec 100644 (file)
@@ -158,3 +158,11 @@ static void __exit cicada_exit(void)
 
 module_init(cicada_init);
 module_exit(cicada_exit);
+
+static struct mdio_device_id cicada_tbl[] = {
+       { 0x000fc410, 0x000ffff0 },
+       { 0x000fc440, 0x000fffc0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, cicada_tbl);
index c722e95853ff5d9d775191504f9d7e918680cc83..29c17617a2ec22ec216ab32129313b491ccf674b 100644 (file)
@@ -218,3 +218,12 @@ static void __exit davicom_exit(void)
 
 module_init(davicom_init);
 module_exit(davicom_exit);
+
+static struct mdio_device_id davicom_tbl[] = {
+       { 0x0181b880, 0x0ffffff0 },
+       { 0x0181b8a0, 0x0ffffff0 },
+       { 0x00181b80, 0x0ffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, davicom_tbl);
index 7712ebeba9bf0a6881f3cb6a03c2124579546046..13995f52d6af1429c556312759ded6f010654be8 100644 (file)
@@ -110,3 +110,10 @@ static void __exit et1011c_exit(void)
 
 module_init(et1011c_init);
 module_exit(et1011c_exit);
+
+static struct mdio_device_id et1011c_tbl[] = {
+       { 0x0282f014, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, et1011c_tbl);
index 904208b95d4b81221fa96271492ee6fd85707cce..439adafeacb1bfed9974e13bc62ff8bb4651d3a7 100644 (file)
@@ -131,3 +131,10 @@ static void __exit ip175c_exit(void)
 
 module_init(ip175c_init);
 module_exit(ip175c_exit);
+
+static struct mdio_device_id icplus_tbl[] = {
+       { 0x02430d80, 0x0ffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, icplus_tbl);
index 057ecaacde6b77fa275b0805aced7259c652724d..8ee929b796d848e5440271f92b103ff32f5c9c8d 100644 (file)
@@ -173,3 +173,11 @@ static void __exit lxt_exit(void)
 
 module_init(lxt_init);
 module_exit(lxt_exit);
+
+static struct mdio_device_id lxt_tbl[] = {
+       { 0x78100000, 0xfffffff0 },
+       { 0x001378e0, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, lxt_tbl);
index 64c7fbe0a8e7e09a451a4c8e000e075e149c4c0d..78b74e83ce5df7f242fe579676f7623c8d84e6f3 100644 (file)
@@ -648,3 +648,16 @@ static void __exit marvell_exit(void)
 
 module_init(marvell_init);
 module_exit(marvell_exit);
+
+static struct mdio_device_id marvell_tbl[] = {
+       { 0x01410c60, 0xfffffff0 },
+       { 0x01410c90, 0xfffffff0 },
+       { 0x01410cc0, 0xfffffff0 },
+       { 0x01410e10, 0xfffffff0 },
+       { 0x01410cb0, 0xfffffff0 },
+       { 0x01410cd0, 0xfffffff0 },
+       { 0x01410e30, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, marvell_tbl);
index 19e70d7e27ab15e68eda7830bcc674015c282c30..65391891d8c41a180592d500825df75f67b44e4c 100644 (file)
 #include <linux/types.h>
 #include <linux/delay.h>
 
-#define MDIO_READ 1
-#define MDIO_WRITE 0
+#define MDIO_READ 2
+#define MDIO_WRITE 1
+
+#define MDIO_C45 (1<<15)
+#define MDIO_C45_ADDR (MDIO_C45 | 0)
+#define MDIO_C45_READ (MDIO_C45 | 3)
+#define MDIO_C45_WRITE (MDIO_C45 | 1)
 
 #define MDIO_SETUP_TIME 10
 #define MDIO_HOLD_TIME 10
@@ -89,7 +94,7 @@ static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
 /* Utility to send the preamble, address, and
  * register (common to read and write).
  */
-static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg)
+static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int op, u8 phy, u8 reg)
 {
        const struct mdiobb_ops *ops = ctrl->ops;
        int i;
@@ -108,23 +113,56 @@ static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg)
        for (i = 0; i < 32; i++)
                mdiobb_send_bit(ctrl, 1);
 
-       /* send the start bit (01) and the read opcode (10) or write (10) */
+       /* send the start bit (01) and the read opcode (10) or write (10).
+          Clause 45 operation uses 00 for the start and 11, 10 for
+          read/write */
        mdiobb_send_bit(ctrl, 0);
-       mdiobb_send_bit(ctrl, 1);
-       mdiobb_send_bit(ctrl, read);
-       mdiobb_send_bit(ctrl, !read);
+       if (op & MDIO_C45)
+               mdiobb_send_bit(ctrl, 0);
+       else
+               mdiobb_send_bit(ctrl, 1);
+       mdiobb_send_bit(ctrl, (op >> 1) & 1);
+       mdiobb_send_bit(ctrl, (op >> 0) & 1);
 
        mdiobb_send_num(ctrl, phy, 5);
        mdiobb_send_num(ctrl, reg, 5);
 }
 
+/* In clause 45 mode all commands are prefixed by MDIO_ADDR to specify the
+   lower 16 bits of the 21 bit address. This transfer is done identically to a
+   MDIO_WRITE except for a different code. To enable clause 45 mode or
+   MII_ADDR_C45 into the address. Theoretically clause 45 and normal devices
+   can exist on the same bus. Normal devices should ignore the MDIO_ADDR
+   phase. */
+static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
+{
+       unsigned int dev_addr = (addr >> 16) & 0x1F;
+       unsigned int reg = addr & 0xFFFF;
+       mdiobb_cmd(ctrl, MDIO_C45_ADDR, phy, dev_addr);
+
+       /* send the turnaround (10) */
+       mdiobb_send_bit(ctrl, 1);
+       mdiobb_send_bit(ctrl, 0);
+
+       mdiobb_send_num(ctrl, reg, 16);
+
+       ctrl->ops->set_mdio_dir(ctrl, 0);
+       mdiobb_get_bit(ctrl);
+
+       return dev_addr;
+}
 
 static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
 {
        struct mdiobb_ctrl *ctrl = bus->priv;
        int ret, i;
 
-       mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+       if (reg & MII_ADDR_C45) {
+               reg = mdiobb_cmd_addr(ctrl, phy, reg);
+               mdiobb_cmd(ctrl, MDIO_C45_READ, phy, reg);
+       } else
+               mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+
        ctrl->ops->set_mdio_dir(ctrl, 0);
 
        /* check the turnaround bit: the PHY should be driving it to zero */
@@ -147,7 +185,11 @@ static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
 {
        struct mdiobb_ctrl *ctrl = bus->priv;
 
-       mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+       if (reg & MII_ADDR_C45) {
+               reg = mdiobb_cmd_addr(ctrl, phy, reg);
+               mdiobb_cmd(ctrl, MDIO_C45_WRITE, phy, reg);
+       } else
+               mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
 
        /* send the turnaround (10) */
        mdiobb_send_bit(ctrl, 1);
index e17b70291bbcfb2c4b98c2e59b7a50166c2be87f..6a6b8199a0d6862467260384e32979584f24d95a 100644 (file)
@@ -208,7 +208,7 @@ EXPORT_SYMBOL(mdiobus_scan);
  * because the bus read/write functions may wait for an interrupt
  * to conclude the operation.
  */
-int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum)
+int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
 {
        int retval;
 
@@ -233,7 +233,7 @@ EXPORT_SYMBOL(mdiobus_read);
  * because the bus read/write functions may wait for an interrupt
  * to conclude the operation.
  */
-int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val)
+int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
 {
        int err;
 
index e67691dca4abae73c501a9d0050a4e1b90903c14..0692f750c404d6e78e101cad5f445f6f19f8d0fe 100644 (file)
@@ -103,3 +103,12 @@ module_exit(ksphy_exit);
 MODULE_DESCRIPTION("Micrel PHY driver");
 MODULE_AUTHOR("David J. Choi");
 MODULE_LICENSE("GPL");
+
+static struct mdio_device_id micrel_tbl[] = {
+       { PHY_ID_KSZ9021, 0x000fff10 },
+       { PHY_ID_VSC8201, 0x00fffff0 },
+       { PHY_ID_KS8001, 0x00fffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, micrel_tbl);
index 6c636eb720896c79b0be943e16c1f2b743c10d46..a73ba0bcc0ce86f632bf8d7e5c5287e9d7e02062 100644 (file)
@@ -97,7 +97,6 @@ static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
        phy_write(phydev, NS_EXP_MEM_DATA, 0x0008);
        phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN));
        phy_write(phydev, LED_CTRL_REG, mode);
-       return;
 }
 
 static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
@@ -110,8 +109,6 @@ static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
 
        printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n",
               (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
-
-       return;
 }
 
 static int ns_config_init(struct phy_device *phydev)
@@ -153,3 +150,10 @@ MODULE_LICENSE("GPL");
 
 module_init(ns_init);
 module_exit(ns_exit);
+
+static struct mdio_device_id ns_tbl[] = {
+       { DP83865_PHY_ID, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, ns_tbl);
index db1794546c5651e827db0941f6f9b659e48e3d50..1a99bb2441064c5dae8014628bd718d033e752e6 100644 (file)
@@ -149,6 +149,7 @@ EXPORT_SYMBOL(phy_scan_fixups);
 struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
 {
        struct phy_device *dev;
+
        /* We allocate the device, and initialize the
         * default values */
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -179,6 +180,17 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
        mutex_init(&dev->lock);
        INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
 
+       /* Request the appropriate module unconditionally; don't
+          bother trying to do so only if it isn't already loaded,
+          because that gets complicated. A hotplug event would have
+          done an unconditional modprobe anyway.
+          We don't do normal hotplug because it won't work for MDIO
+          -- because it relies on the device staying around for long
+          enough for the driver to get loaded. With MDIO, the NIC
+          driver will get bored and give up as soon as it finds that
+          there's no driver _already_ loaded. */
+       request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT, MDIO_ID_ARGS(phy_id));
+
        return dev;
 }
 EXPORT_SYMBOL(phy_device_create);
index f6e190f73c3215c1c0c6c4877a9e7552c06e831e..6736b23f1b28a3828456fbfc80b9b88739050ecb 100644 (file)
@@ -137,3 +137,10 @@ static void __exit qs6612_exit(void)
 
 module_init(qs6612_init);
 module_exit(qs6612_exit);
+
+static struct mdio_device_id qs6612_tbl[] = {
+       { 0x00181440, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, qs6612_tbl);
index a052a6744a51f80b0aee624052d9a9b916453045..f567c0e1aaa1a0d745b8ca1f719b93a8d96c9577 100644 (file)
@@ -78,3 +78,10 @@ static void __exit realtek_exit(void)
 
 module_init(realtek_init);
 module_exit(realtek_exit);
+
+static struct mdio_device_id realtek_tbl[] = {
+       { 0x001cc912, 0x001fffff },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, realtek_tbl);
index ed2644a57500c0673b40709d574e87df06fc8533..78fa988256fce4d2bd691029ca8b4ababba2789a 100644 (file)
@@ -253,3 +253,14 @@ MODULE_LICENSE("GPL");
 
 module_init(smsc_init);
 module_exit(smsc_exit);
+
+static struct mdio_device_id smsc_tbl[] = {
+       { 0x0007c0a0, 0xfffffff0 },
+       { 0x0007c0b0, 0xfffffff0 },
+       { 0x0007c0c0, 0xfffffff0 },
+       { 0x0007c0d0, 0xfffffff0 },
+       { 0x0007c0f0, 0xfffffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, smsc_tbl);
index 6bdb0d53aaf9e6b1434f1ee61ff95e211291f4d2..72290099e5e1f01e2784629ec54e01e9a037926e 100644 (file)
@@ -132,6 +132,14 @@ static void __exit ste10Xp_exit(void)
 module_init(ste10Xp_init);
 module_exit(ste10Xp_exit);
 
+static struct mdio_device_id ste10Xp_tbl[] = {
+       { STE101P_PHY_ID, 0xfffffff0 },
+       { STE100P_PHY_ID, 0xffffffff },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, ste10Xp_tbl);
+
 MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver");
 MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
 MODULE_LICENSE("GPL");
index dd3b2447e85a63936b49e24d2deaffa7e9ac960d..45cce50a279992eee14fd6edf185fabb4fe1e94a 100644 (file)
@@ -191,3 +191,11 @@ static void __exit vsc82xx_exit(void)
 
 module_init(vsc82xx_init);
 module_exit(vsc82xx_exit);
+
+static struct mdio_device_id vitesse_tbl[] = {
+       { PHY_ID_VSC8244, 0x000fffc0 },
+       { PHY_ID_VSC8221, 0x000ffff0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(mdio, vitesse_tbl);
index 9a2103a69e172280e933de679b8cf303ff8ce767..ec0349e84a8a8cd093977a50d3f9aa0879b291e7 100644 (file)
@@ -979,7 +979,6 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
                printk(KERN_DEBUG "%s: send request\n", dev->name);
 
        spin_lock_irq(&nl->lock);
-       dev->trans_start = jiffies;
        snd->skb = skb;
        snd->length.h = skb->len;
        snd->state = PLIP_PK_TRIGGER;
@@ -1192,8 +1191,6 @@ plip_wakeup(void *handle)
                /* Clear the data port. */
                write_data (dev, 0x00);
        }
-
-       return;
 }
 
 static int
@@ -1309,7 +1306,6 @@ err_parport_unregister:
        parport_unregister_device(nl->pardev);
 err_free_dev:
        free_netdev(dev);
-       return;
 }
 
 /* plip_detach() is called (by the parport code) when a port is
index 8518a2e58e5362254221ba11a0ba34146d84f47b..5441688daba70c6ad61f825fd911966041907c29 100644 (file)
@@ -2173,6 +2173,24 @@ int ppp_unit_number(struct ppp_channel *chan)
        return unit;
 }
 
+/*
+ * Return the PPP device interface name of a channel.
+ */
+char *ppp_dev_name(struct ppp_channel *chan)
+{
+       struct channel *pch = chan->ppp;
+       char *name = NULL;
+
+       if (pch) {
+               read_lock_bh(&pch->upl);
+               if (pch->ppp && pch->ppp->dev)
+                       name = pch->ppp->dev->name;
+               read_unlock_bh(&pch->upl);
+       }
+       return name;
+}
+
+
 /*
  * Disconnect a channel from the generic layer.
  * This must be called in process context.
@@ -2901,6 +2919,7 @@ EXPORT_SYMBOL(ppp_register_channel);
 EXPORT_SYMBOL(ppp_unregister_channel);
 EXPORT_SYMBOL(ppp_channel_index);
 EXPORT_SYMBOL(ppp_unit_number);
+EXPORT_SYMBOL(ppp_dev_name);
 EXPORT_SYMBOL(ppp_input);
 EXPORT_SYMBOL(ppp_input_error);
 EXPORT_SYMBOL(ppp_output_wakeup);
index cdd11ba100ea09d28c6871e9d3b6d75accd3a27b..b1b93ff2351f70e7902cf2840885285570799355 100644 (file)
@@ -89,7 +89,6 @@
 #define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS)
 #define PPPOE_HASH_MASK        (PPPOE_HASH_SIZE - 1)
 
-static int pppoe_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
 static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb);
 static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb);
 
@@ -258,7 +257,7 @@ static inline struct pppox_sock *get_item_by_addr(struct net *net,
        dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev);
        if (dev) {
                ifindex = dev->ifindex;
-               pn = net_generic(net, pppoe_net_id);
+               pn = pppoe_pernet(net);
                pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid,
                                sp->sa_addr.pppoe.remote, ifindex);
        }
@@ -290,12 +289,6 @@ static void pppoe_flush_dev(struct net_device *dev)
        struct pppoe_net *pn;
        int i;
 
-       BUG_ON(dev == NULL);
-
-       pn = pppoe_pernet(dev_net(dev));
-       if (!pn) /* already freed */
-               return;
-
        write_lock_bh(&pn->hash_lock);
        for (i = 0; i < PPPOE_HASH_SIZE; i++) {
                struct pppox_sock *po = pn->hash_table[i];
@@ -368,7 +361,7 @@ static int pppoe_device_event(struct notifier_block *this,
 
        default:
                break;
-       };
+       }
 
        return NOTIFY_DONE;
 }
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
deleted file mode 100644 (file)
index 449a982..0000000
+++ /dev/null
@@ -1,2680 +0,0 @@
-/*****************************************************************************
- * Linux PPP over L2TP (PPPoX/PPPoL2TP) Sockets
- *
- * PPPoX    --- Generic PPP encapsulation socket family
- * PPPoL2TP --- PPP over L2TP (RFC 2661)
- *
- * Version:    1.0.0
- *
- * Authors:    Martijn van Oosterhout <kleptog@svana.org>
- *             James Chapman (jchapman@katalix.com)
- * Contributors:
- *             Michal Ostrowski <mostrows@speakeasy.net>
- *             Arnaldo Carvalho de Melo <acme@xconectiva.com.br>
- *             David S. Miller (davem@redhat.com)
- *
- * License:
- *             This program is free software; you can redistribute it and/or
- *             modify it under the terms of the GNU General Public License
- *             as published by the Free Software Foundation; either version
- *             2 of the License, or (at your option) any later version.
- *
- */
-
-/* This driver handles only L2TP data frames; control frames are handled by a
- * userspace application.
- *
- * To send data in an L2TP session, userspace opens a PPPoL2TP socket and
- * attaches it to a bound UDP socket with local tunnel_id / session_id and
- * peer tunnel_id / session_id set. Data can then be sent or received using
- * regular socket sendmsg() / recvmsg() calls. Kernel parameters of the socket
- * can be read or modified using ioctl() or [gs]etsockopt() calls.
- *
- * When a PPPoL2TP socket is connected with local and peer session_id values
- * zero, the socket is treated as a special tunnel management socket.
- *
- * Here's example userspace code to create a socket for sending/receiving data
- * over an L2TP session:-
- *
- *     struct sockaddr_pppol2tp sax;
- *     int fd;
- *     int session_fd;
- *
- *     fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
- *
- *     sax.sa_family = AF_PPPOX;
- *     sax.sa_protocol = PX_PROTO_OL2TP;
- *     sax.pppol2tp.fd = tunnel_fd;    // bound UDP socket
- *     sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr;
- *     sax.pppol2tp.addr.sin_port = addr->sin_port;
- *     sax.pppol2tp.addr.sin_family = AF_INET;
- *     sax.pppol2tp.s_tunnel  = tunnel_id;
- *     sax.pppol2tp.s_session = session_id;
- *     sax.pppol2tp.d_tunnel  = peer_tunnel_id;
- *     sax.pppol2tp.d_session = peer_session_id;
- *
- *     session_fd = connect(fd, (struct sockaddr *)&sax, sizeof(sax));
- *
- * A pppd plugin that allows PPP traffic to be carried over L2TP using
- * this driver is available from the OpenL2TP project at
- * http://openl2tp.sourceforge.net.
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/list.h>
-#include <asm/uaccess.h>
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/kthread.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/jiffies.h>
-
-#include <linux/netdevice.h>
-#include <linux/net.h>
-#include <linux/inetdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/if_pppox.h>
-#include <linux/if_pppol2tp.h>
-#include <net/sock.h>
-#include <linux/ppp_channel.h>
-#include <linux/ppp_defs.h>
-#include <linux/if_ppp.h>
-#include <linux/file.h>
-#include <linux/hash.h>
-#include <linux/sort.h>
-#include <linux/proc_fs.h>
-#include <linux/nsproxy.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
-#include <net/dst.h>
-#include <net/ip.h>
-#include <net/udp.h>
-#include <net/xfrm.h>
-
-#include <asm/byteorder.h>
-#include <asm/atomic.h>
-
-
-#define PPPOL2TP_DRV_VERSION   "V1.0"
-
-/* L2TP header constants */
-#define L2TP_HDRFLAG_T    0x8000
-#define L2TP_HDRFLAG_L    0x4000
-#define L2TP_HDRFLAG_S    0x0800
-#define L2TP_HDRFLAG_O    0x0200
-#define L2TP_HDRFLAG_P    0x0100
-
-#define L2TP_HDR_VER_MASK  0x000F
-#define L2TP_HDR_VER      0x0002
-
-/* Space for UDP, L2TP and PPP headers */
-#define PPPOL2TP_HEADER_OVERHEAD       40
-
-/* Just some random numbers */
-#define L2TP_TUNNEL_MAGIC      0x42114DDA
-#define L2TP_SESSION_MAGIC     0x0C04EB7D
-
-#define PPPOL2TP_HASH_BITS     4
-#define PPPOL2TP_HASH_SIZE     (1 << PPPOL2TP_HASH_BITS)
-
-/* Default trace flags */
-#define PPPOL2TP_DEFAULT_DEBUG_FLAGS   0
-
-#define PRINTK(_mask, _type, _lvl, _fmt, args...)                      \
-       do {                                                            \
-               if ((_mask) & (_type))                                  \
-                       printk(_lvl "PPPOL2TP: " _fmt, ##args);         \
-       } while(0)
-
-/* Number of bytes to build transmit L2TP headers.
- * Unfortunately the size is different depending on whether sequence numbers
- * are enabled.
- */
-#define PPPOL2TP_L2TP_HDR_SIZE_SEQ             10
-#define PPPOL2TP_L2TP_HDR_SIZE_NOSEQ           6
-
-struct pppol2tp_tunnel;
-
-/* Describes a session. It is the sk_user_data field in the PPPoL2TP
- * socket. Contains information to determine incoming packets and transmit
- * outgoing ones.
- */
-struct pppol2tp_session
-{
-       int                     magic;          /* should be
-                                                * L2TP_SESSION_MAGIC */
-       int                     owner;          /* pid that opened the socket */
-
-       struct sock             *sock;          /* Pointer to the session
-                                                * PPPoX socket */
-       struct sock             *tunnel_sock;   /* Pointer to the tunnel UDP
-                                                * socket */
-
-       struct pppol2tp_addr    tunnel_addr;    /* Description of tunnel */
-
-       struct pppol2tp_tunnel  *tunnel;        /* back pointer to tunnel
-                                                * context */
-
-       char                    name[20];       /* "sess xxxxx/yyyyy", where
-                                                * x=tunnel_id, y=session_id */
-       int                     mtu;
-       int                     mru;
-       int                     flags;          /* accessed by PPPIOCGFLAGS.
-                                                * Unused. */
-       unsigned                recv_seq:1;     /* expect receive packets with
-                                                * sequence numbers? */
-       unsigned                send_seq:1;     /* send packets with sequence
-                                                * numbers? */
-       unsigned                lns_mode:1;     /* behave as LNS? LAC enables
-                                                * sequence numbers under
-                                                * control of LNS. */
-       int                     debug;          /* bitmask of debug message
-                                                * categories */
-       int                     reorder_timeout; /* configured reorder timeout
-                                                 * (in jiffies) */
-       u16                     nr;             /* session NR state (receive) */
-       u16                     ns;             /* session NR state (send) */
-       struct sk_buff_head     reorder_q;      /* receive reorder queue */
-       struct pppol2tp_ioc_stats stats;
-       struct hlist_node       hlist;          /* Hash list node */
-};
-
-/* The sk_user_data field of the tunnel's UDP socket. It contains info to track
- * all the associated sessions so incoming packets can be sorted out
- */
-struct pppol2tp_tunnel
-{
-       int                     magic;          /* Should be L2TP_TUNNEL_MAGIC */
-       rwlock_t                hlist_lock;     /* protect session_hlist */
-       struct hlist_head       session_hlist[PPPOL2TP_HASH_SIZE];
-                                               /* hashed list of sessions,
-                                                * hashed by id */
-       int                     debug;          /* bitmask of debug message
-                                                * categories */
-       char                    name[12];       /* "tunl xxxxx" */
-       struct pppol2tp_ioc_stats stats;
-
-       void (*old_sk_destruct)(struct sock *);
-
-       struct sock             *sock;          /* Parent socket */
-       struct list_head        list;           /* Keep a list of all open
-                                                * prepared sockets */
-       struct net              *pppol2tp_net;  /* the net we belong to */
-
-       atomic_t                ref_count;
-};
-
-/* Private data stored for received packets in the skb.
- */
-struct pppol2tp_skb_cb {
-       u16                     ns;
-       u16                     nr;
-       u16                     has_seq;
-       u16                     length;
-       unsigned long           expires;
-};
-
-#define PPPOL2TP_SKB_CB(skb)   ((struct pppol2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)])
-
-static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
-static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel);
-
-static atomic_t pppol2tp_tunnel_count;
-static atomic_t pppol2tp_session_count;
-static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit , NULL };
-static const struct proto_ops pppol2tp_ops;
-
-/* per-net private data for this module */
-static int pppol2tp_net_id __read_mostly;
-struct pppol2tp_net {
-       struct list_head pppol2tp_tunnel_list;
-       rwlock_t pppol2tp_tunnel_list_lock;
-};
-
-static inline struct pppol2tp_net *pppol2tp_pernet(struct net *net)
-{
-       BUG_ON(!net);
-
-       return net_generic(net, pppol2tp_net_id);
-}
-
-/* Helpers to obtain tunnel/session contexts from sockets.
- */
-static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk)
-{
-       struct pppol2tp_session *session;
-
-       if (sk == NULL)
-               return NULL;
-
-       sock_hold(sk);
-       session = (struct pppol2tp_session *)(sk->sk_user_data);
-       if (session == NULL) {
-               sock_put(sk);
-               goto out;
-       }
-
-       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
-out:
-       return session;
-}
-
-static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk)
-{
-       struct pppol2tp_tunnel *tunnel;
-
-       if (sk == NULL)
-               return NULL;
-
-       sock_hold(sk);
-       tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data);
-       if (tunnel == NULL) {
-               sock_put(sk);
-               goto out;
-       }
-
-       BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-out:
-       return tunnel;
-}
-
-/* Tunnel reference counts. Incremented per session that is added to
- * the tunnel.
- */
-static inline void pppol2tp_tunnel_inc_refcount(struct pppol2tp_tunnel *tunnel)
-{
-       atomic_inc(&tunnel->ref_count);
-}
-
-static inline void pppol2tp_tunnel_dec_refcount(struct pppol2tp_tunnel *tunnel)
-{
-       if (atomic_dec_and_test(&tunnel->ref_count))
-               pppol2tp_tunnel_free(tunnel);
-}
-
-/* Session hash list.
- * The session_id SHOULD be random according to RFC2661, but several
- * L2TP implementations (Cisco and Microsoft) use incrementing
- * session_ids.  So we do a real hash on the session_id, rather than a
- * simple bitmask.
- */
-static inline struct hlist_head *
-pppol2tp_session_id_hash(struct pppol2tp_tunnel *tunnel, u16 session_id)
-{
-       unsigned long hash_val = (unsigned long) session_id;
-       return &tunnel->session_hlist[hash_long(hash_val, PPPOL2TP_HASH_BITS)];
-}
-
-/* Lookup a session by id
- */
-static struct pppol2tp_session *
-pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id)
-{
-       struct hlist_head *session_list =
-               pppol2tp_session_id_hash(tunnel, session_id);
-       struct pppol2tp_session *session;
-       struct hlist_node *walk;
-
-       read_lock_bh(&tunnel->hlist_lock);
-       hlist_for_each_entry(session, walk, session_list, hlist) {
-               if (session->tunnel_addr.s_session == session_id) {
-                       read_unlock_bh(&tunnel->hlist_lock);
-                       return session;
-               }
-       }
-       read_unlock_bh(&tunnel->hlist_lock);
-
-       return NULL;
-}
-
-/* Lookup a tunnel by id
- */
-static struct pppol2tp_tunnel *pppol2tp_tunnel_find(struct net *net, u16 tunnel_id)
-{
-       struct pppol2tp_tunnel *tunnel;
-       struct pppol2tp_net *pn = pppol2tp_pernet(net);
-
-       read_lock_bh(&pn->pppol2tp_tunnel_list_lock);
-       list_for_each_entry(tunnel, &pn->pppol2tp_tunnel_list, list) {
-               if (tunnel->stats.tunnel_id == tunnel_id) {
-                       read_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
-                       return tunnel;
-               }
-       }
-       read_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
-
-       return NULL;
-}
-
-/*****************************************************************************
- * Receive data handling
- *****************************************************************************/
-
-/* Queue a skb in order. We come here only if the skb has an L2TP sequence
- * number.
- */
-static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
-{
-       struct sk_buff *skbp;
-       struct sk_buff *tmp;
-       u16 ns = PPPOL2TP_SKB_CB(skb)->ns;
-
-       spin_lock_bh(&session->reorder_q.lock);
-       skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
-               if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
-                       __skb_queue_before(&session->reorder_q, skbp, skb);
-                       PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                              "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
-                              session->name, ns, PPPOL2TP_SKB_CB(skbp)->ns,
-                              skb_queue_len(&session->reorder_q));
-                       session->stats.rx_oos_packets++;
-                       goto out;
-               }
-       }
-
-       __skb_queue_tail(&session->reorder_q, skb);
-
-out:
-       spin_unlock_bh(&session->reorder_q.lock);
-}
-
-/* Dequeue a single skb.
- */
-static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
-{
-       struct pppol2tp_tunnel *tunnel = session->tunnel;
-       int length = PPPOL2TP_SKB_CB(skb)->length;
-       struct sock *session_sock = NULL;
-
-       /* We're about to requeue the skb, so return resources
-        * to its current owner (a socket receive buffer).
-        */
-       skb_orphan(skb);
-
-       tunnel->stats.rx_packets++;
-       tunnel->stats.rx_bytes += length;
-       session->stats.rx_packets++;
-       session->stats.rx_bytes += length;
-
-       if (PPPOL2TP_SKB_CB(skb)->has_seq) {
-               /* Bump our Nr */
-               session->nr++;
-               PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                      "%s: updated nr to %hu\n", session->name, session->nr);
-       }
-
-       /* If the socket is bound, send it in to PPP's input queue. Otherwise
-        * queue it on the session socket.
-        */
-       session_sock = session->sock;
-       if (session_sock->sk_state & PPPOX_BOUND) {
-               struct pppox_sock *po;
-               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-                      "%s: recv %d byte data frame, passing to ppp\n",
-                      session->name, length);
-
-               /* We need to forget all info related to the L2TP packet
-                * gathered in the skb as we are going to reuse the same
-                * skb for the inner packet.
-                * Namely we need to:
-                * - reset xfrm (IPSec) information as it applies to
-                *   the outer L2TP packet and not to the inner one
-                * - release the dst to force a route lookup on the inner
-                *   IP packet since skb->dst currently points to the dst
-                *   of the UDP tunnel
-                * - reset netfilter information as it doesn't apply
-                *   to the inner packet either
-                */
-               secpath_reset(skb);
-               skb_dst_drop(skb);
-               nf_reset(skb);
-
-               po = pppox_sk(session_sock);
-               ppp_input(&po->chan, skb);
-       } else {
-               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
-                      "%s: socket not bound\n", session->name);
-
-               /* Not bound. Nothing we can do, so discard. */
-               session->stats.rx_errors++;
-               kfree_skb(skb);
-       }
-
-       sock_put(session->sock);
-}
-
-/* Dequeue skbs from the session's reorder_q, subject to packet order.
- * Skbs that have been in the queue for too long are simply discarded.
- */
-static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
-{
-       struct sk_buff *skb;
-       struct sk_buff *tmp;
-
-       /* If the pkt at the head of the queue has the nr that we
-        * expect to send up next, dequeue it and any other
-        * in-sequence packets behind it.
-        */
-       spin_lock_bh(&session->reorder_q.lock);
-       skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
-               if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) {
-                       session->stats.rx_seq_discards++;
-                       session->stats.rx_errors++;
-                       PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                              "%s: oos pkt %hu len %d discarded (too old), "
-                              "waiting for %hu, reorder_q_len=%d\n",
-                              session->name, PPPOL2TP_SKB_CB(skb)->ns,
-                              PPPOL2TP_SKB_CB(skb)->length, session->nr,
-                              skb_queue_len(&session->reorder_q));
-                       __skb_unlink(skb, &session->reorder_q);
-                       kfree_skb(skb);
-                       sock_put(session->sock);
-                       continue;
-               }
-
-               if (PPPOL2TP_SKB_CB(skb)->has_seq) {
-                       if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
-                               PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                                      "%s: holding oos pkt %hu len %d, "
-                                      "waiting for %hu, reorder_q_len=%d\n",
-                                      session->name, PPPOL2TP_SKB_CB(skb)->ns,
-                                      PPPOL2TP_SKB_CB(skb)->length, session->nr,
-                                      skb_queue_len(&session->reorder_q));
-                               goto out;
-                       }
-               }
-               __skb_unlink(skb, &session->reorder_q);
-
-               /* Process the skb. We release the queue lock while we
-                * do so to let other contexts process the queue.
-                */
-               spin_unlock_bh(&session->reorder_q.lock);
-               pppol2tp_recv_dequeue_skb(session, skb);
-               spin_lock_bh(&session->reorder_q.lock);
-       }
-
-out:
-       spin_unlock_bh(&session->reorder_q.lock);
-}
-
-static inline int pppol2tp_verify_udp_checksum(struct sock *sk,
-                                              struct sk_buff *skb)
-{
-       struct udphdr *uh = udp_hdr(skb);
-       u16 ulen = ntohs(uh->len);
-       struct inet_sock *inet;
-       __wsum psum;
-
-       if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check)
-               return 0;
-
-       inet = inet_sk(sk);
-       psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen,
-                                 IPPROTO_UDP, 0);
-
-       if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
-           !csum_fold(csum_add(psum, skb->csum)))
-               return 0;
-
-       skb->csum = psum;
-
-       return __skb_checksum_complete(skb);
-}
-
-/* Internal receive frame. Do the real work of receiving an L2TP data frame
- * here. The skb is not on a list when we get here.
- * Returns 0 if the packet was a data packet and was successfully passed on.
- * Returns 1 if the packet was not a good data packet and could not be
- * forwarded.  All such packets are passed up to userspace to deal with.
- */
-static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
-{
-       struct pppol2tp_session *session = NULL;
-       struct pppol2tp_tunnel *tunnel;
-       unsigned char *ptr, *optr;
-       u16 hdrflags;
-       u16 tunnel_id, session_id;
-       int length;
-       int offset;
-
-       tunnel = pppol2tp_sock_to_tunnel(sock);
-       if (tunnel == NULL)
-               goto no_tunnel;
-
-       if (tunnel->sock && pppol2tp_verify_udp_checksum(tunnel->sock, skb))
-               goto discard_bad_csum;
-
-       /* UDP always verifies the packet length. */
-       __skb_pull(skb, sizeof(struct udphdr));
-
-       /* Short packet? */
-       if (!pskb_may_pull(skb, 12)) {
-               PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
-                      "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
-               goto error;
-       }
-
-       /* Point to L2TP header */
-       optr = ptr = skb->data;
-
-       /* Get L2TP header flags */
-       hdrflags = ntohs(*(__be16*)ptr);
-
-       /* Trace packet contents, if enabled */
-       if (tunnel->debug & PPPOL2TP_MSG_DATA) {
-               length = min(16u, skb->len);
-               if (!pskb_may_pull(skb, length))
-                       goto error;
-
-               printk(KERN_DEBUG "%s: recv: ", tunnel->name);
-
-               offset = 0;
-               do {
-                       printk(" %02X", ptr[offset]);
-               } while (++offset < length);
-
-               printk("\n");
-       }
-
-       /* Get length of L2TP packet */
-       length = skb->len;
-
-       /* If type is control packet, it is handled by userspace. */
-       if (hdrflags & L2TP_HDRFLAG_T) {
-               PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-                      "%s: recv control packet, len=%d\n", tunnel->name, length);
-               goto error;
-       }
-
-       /* Skip flags */
-       ptr += 2;
-
-       /* If length is present, skip it */
-       if (hdrflags & L2TP_HDRFLAG_L)
-               ptr += 2;
-
-       /* Extract tunnel and session ID */
-       tunnel_id = ntohs(*(__be16 *) ptr);
-       ptr += 2;
-       session_id = ntohs(*(__be16 *) ptr);
-       ptr += 2;
-
-       /* Find the session context */
-       session = pppol2tp_session_find(tunnel, session_id);
-       if (!session) {
-               /* Not found? Pass to userspace to deal with */
-               PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
-                      "%s: no socket found (%hu/%hu). Passing up.\n",
-                      tunnel->name, tunnel_id, session_id);
-               goto error;
-       }
-       sock_hold(session->sock);
-
-       /* The ref count on the socket was increased by the above call since
-        * we now hold a pointer to the session. Take care to do sock_put()
-        * when exiting this function from now on...
-        */
-
-       /* Handle the optional sequence numbers.  If we are the LAC,
-        * enable/disable sequence numbers under the control of the LNS.  If
-        * no sequence numbers present but we were expecting them, discard
-        * frame.
-        */
-       if (hdrflags & L2TP_HDRFLAG_S) {
-               u16 ns, nr;
-               ns = ntohs(*(__be16 *) ptr);
-               ptr += 2;
-               nr = ntohs(*(__be16 *) ptr);
-               ptr += 2;
-
-               /* Received a packet with sequence numbers. If we're the LNS,
-                * check if we sre sending sequence numbers and if not,
-                * configure it so.
-                */
-               if ((!session->lns_mode) && (!session->send_seq)) {
-                       PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,
-                              "%s: requested to enable seq numbers by LNS\n",
-                              session->name);
-                       session->send_seq = -1;
-               }
-
-               /* Store L2TP info in the skb */
-               PPPOL2TP_SKB_CB(skb)->ns = ns;
-               PPPOL2TP_SKB_CB(skb)->nr = nr;
-               PPPOL2TP_SKB_CB(skb)->has_seq = 1;
-
-               PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                      "%s: recv data ns=%hu, nr=%hu, session nr=%hu\n",
-                      session->name, ns, nr, session->nr);
-       } else {
-               /* No sequence numbers.
-                * If user has configured mandatory sequence numbers, discard.
-                */
-               if (session->recv_seq) {
-                       PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,
-                              "%s: recv data has no seq numbers when required. "
-                              "Discarding\n", session->name);
-                       session->stats.rx_seq_discards++;
-                       goto discard;
-               }
-
-               /* If we're the LAC and we're sending sequence numbers, the
-                * LNS has requested that we no longer send sequence numbers.
-                * If we're the LNS and we're sending sequence numbers, the
-                * LAC is broken. Discard the frame.
-                */
-               if ((!session->lns_mode) && (session->send_seq)) {
-                       PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,
-                              "%s: requested to disable seq numbers by LNS\n",
-                              session->name);
-                       session->send_seq = 0;
-               } else if (session->send_seq) {
-                       PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,
-                              "%s: recv data has no seq numbers when required. "
-                              "Discarding\n", session->name);
-                       session->stats.rx_seq_discards++;
-                       goto discard;
-               }
-
-               /* Store L2TP info in the skb */
-               PPPOL2TP_SKB_CB(skb)->has_seq = 0;
-       }
-
-       /* If offset bit set, skip it. */
-       if (hdrflags & L2TP_HDRFLAG_O) {
-               offset = ntohs(*(__be16 *)ptr);
-               ptr += 2 + offset;
-       }
-
-       offset = ptr - optr;
-       if (!pskb_may_pull(skb, offset))
-               goto discard;
-
-       __skb_pull(skb, offset);
-
-       /* Skip PPP header, if present.  In testing, Microsoft L2TP clients
-        * don't send the PPP header (PPP header compression enabled), but
-        * other clients can include the header. So we cope with both cases
-        * here. The PPP header is always FF03 when using L2TP.
-        *
-        * Note that skb->data[] isn't dereferenced from a u16 ptr here since
-        * the field may be unaligned.
-        */
-       if (!pskb_may_pull(skb, 2))
-               goto discard;
-
-       if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
-               skb_pull(skb, 2);
-
-       /* Prepare skb for adding to the session's reorder_q.  Hold
-        * packets for max reorder_timeout or 1 second if not
-        * reordering.
-        */
-       PPPOL2TP_SKB_CB(skb)->length = length;
-       PPPOL2TP_SKB_CB(skb)->expires = jiffies +
-               (session->reorder_timeout ? session->reorder_timeout : HZ);
-
-       /* Add packet to the session's receive queue. Reordering is done here, if
-        * enabled. Saved L2TP protocol info is stored in skb->sb[].
-        */
-       if (PPPOL2TP_SKB_CB(skb)->has_seq) {
-               if (session->reorder_timeout != 0) {
-                       /* Packet reordering enabled. Add skb to session's
-                        * reorder queue, in order of ns.
-                        */
-                       pppol2tp_recv_queue_skb(session, skb);
-               } else {
-                       /* Packet reordering disabled. Discard out-of-sequence
-                        * packets
-                        */
-                       if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
-                               session->stats.rx_seq_discards++;
-                               PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                                      "%s: oos pkt %hu len %d discarded, "
-                                      "waiting for %hu, reorder_q_len=%d\n",
-                                      session->name, PPPOL2TP_SKB_CB(skb)->ns,
-                                      PPPOL2TP_SKB_CB(skb)->length, session->nr,
-                                      skb_queue_len(&session->reorder_q));
-                               goto discard;
-                       }
-                       skb_queue_tail(&session->reorder_q, skb);
-               }
-       } else {
-               /* No sequence numbers. Add the skb to the tail of the
-                * reorder queue. This ensures that it will be
-                * delivered after all previous sequenced skbs.
-                */
-               skb_queue_tail(&session->reorder_q, skb);
-       }
-
-       /* Try to dequeue as many skbs from reorder_q as we can. */
-       pppol2tp_recv_dequeue(session);
-       sock_put(sock);
-
-       return 0;
-
-discard:
-       session->stats.rx_errors++;
-       kfree_skb(skb);
-       sock_put(session->sock);
-       sock_put(sock);
-
-       return 0;
-
-discard_bad_csum:
-       LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
-       UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0);
-       tunnel->stats.rx_errors++;
-       kfree_skb(skb);
-       sock_put(sock);
-
-       return 0;
-
-error:
-       /* Put UDP header back */
-       __skb_push(skb, sizeof(struct udphdr));
-       sock_put(sock);
-
-no_tunnel:
-       return 1;
-}
-
-/* UDP encapsulation receive handler. See net/ipv4/udp.c.
- * Return codes:
- * 0 : success.
- * <0: error
- * >0: skb should be passed up to userspace as UDP.
- */
-static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
-{
-       struct pppol2tp_tunnel *tunnel;
-
-       tunnel = pppol2tp_sock_to_tunnel(sk);
-       if (tunnel == NULL)
-               goto pass_up;
-
-       PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-              "%s: received %d bytes\n", tunnel->name, skb->len);
-
-       if (pppol2tp_recv_core(sk, skb))
-               goto pass_up_put;
-
-       sock_put(sk);
-       return 0;
-
-pass_up_put:
-       sock_put(sk);
-pass_up:
-       return 1;
-}
-
-/* Receive message. This is the recvmsg for the PPPoL2TP socket.
- */
-static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
-                           struct msghdr *msg, size_t len,
-                           int flags)
-{
-       int err;
-       struct sk_buff *skb;
-       struct sock *sk = sock->sk;
-
-       err = -EIO;
-       if (sk->sk_state & PPPOX_BOUND)
-               goto end;
-
-       msg->msg_namelen = 0;
-
-       err = 0;
-       skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
-                               flags & MSG_DONTWAIT, &err);
-       if (!skb)
-               goto end;
-
-       if (len > skb->len)
-               len = skb->len;
-       else if (len < skb->len)
-               msg->msg_flags |= MSG_TRUNC;
-
-       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
-       if (likely(err == 0))
-               err = len;
-
-       kfree_skb(skb);
-end:
-       return err;
-}
-
-/************************************************************************
- * Transmit handling
- ***********************************************************************/
-
-/* Tell how big L2TP headers are for a particular session. This
- * depends on whether sequence numbers are being used.
- */
-static inline int pppol2tp_l2tp_header_len(struct pppol2tp_session *session)
-{
-       if (session->send_seq)
-               return PPPOL2TP_L2TP_HDR_SIZE_SEQ;
-
-       return PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
-}
-
-/* Build an L2TP header for the session into the buffer provided.
- */
-static void pppol2tp_build_l2tp_header(struct pppol2tp_session *session,
-                                      void *buf)
-{
-       __be16 *bufp = buf;
-       u16 flags = L2TP_HDR_VER;
-
-       if (session->send_seq)
-               flags |= L2TP_HDRFLAG_S;
-
-       /* Setup L2TP header.
-        * FIXME: Can this ever be unaligned? Is direct dereferencing of
-        * 16-bit header fields safe here for all architectures?
-        */
-       *bufp++ = htons(flags);
-       *bufp++ = htons(session->tunnel_addr.d_tunnel);
-       *bufp++ = htons(session->tunnel_addr.d_session);
-       if (session->send_seq) {
-               *bufp++ = htons(session->ns);
-               *bufp++ = 0;
-               session->ns++;
-               PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
-                      "%s: updated ns to %hu\n", session->name, session->ns);
-       }
-}
-
-/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket.  We come here
- * when a user application does a sendmsg() on the session socket. L2TP and
- * PPP headers must be inserted into the user's data.
- */
-static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
-                           size_t total_len)
-{
-       static const unsigned char ppph[2] = { 0xff, 0x03 };
-       struct sock *sk = sock->sk;
-       struct inet_sock *inet;
-       __wsum csum;
-       struct sk_buff *skb;
-       int error;
-       int hdr_len;
-       struct pppol2tp_session *session;
-       struct pppol2tp_tunnel *tunnel;
-       struct udphdr *uh;
-       unsigned int len;
-       struct sock *sk_tun;
-       u16 udp_len;
-
-       error = -ENOTCONN;
-       if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
-               goto error;
-
-       /* Get session and tunnel contexts */
-       error = -EBADF;
-       session = pppol2tp_sock_to_session(sk);
-       if (session == NULL)
-               goto error;
-
-       sk_tun = session->tunnel_sock;
-       tunnel = pppol2tp_sock_to_tunnel(sk_tun);
-       if (tunnel == NULL)
-               goto error_put_sess;
-
-       /* What header length is configured for this session? */
-       hdr_len = pppol2tp_l2tp_header_len(session);
-
-       /* Allocate a socket buffer */
-       error = -ENOMEM;
-       skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
-                          sizeof(struct udphdr) + hdr_len +
-                          sizeof(ppph) + total_len,
-                          0, GFP_KERNEL);
-       if (!skb)
-               goto error_put_sess_tun;
-
-       /* Reserve space for headers. */
-       skb_reserve(skb, NET_SKB_PAD);
-       skb_reset_network_header(skb);
-       skb_reserve(skb, sizeof(struct iphdr));
-       skb_reset_transport_header(skb);
-
-       /* Build UDP header */
-       inet = inet_sk(sk_tun);
-       udp_len = hdr_len + sizeof(ppph) + total_len;
-       uh = (struct udphdr *) skb->data;
-       uh->source = inet->inet_sport;
-       uh->dest = inet->inet_dport;
-       uh->len = htons(udp_len);
-       uh->check = 0;
-       skb_put(skb, sizeof(struct udphdr));
-
-       /* Build L2TP header */
-       pppol2tp_build_l2tp_header(session, skb->data);
-       skb_put(skb, hdr_len);
-
-       /* Add PPP header */
-       skb->data[0] = ppph[0];
-       skb->data[1] = ppph[1];
-       skb_put(skb, 2);
-
-       /* Copy user data into skb */
-       error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);
-       if (error < 0) {
-               kfree_skb(skb);
-               goto error_put_sess_tun;
-       }
-       skb_put(skb, total_len);
-
-       /* Calculate UDP checksum if configured to do so */
-       if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
-               skb->ip_summed = CHECKSUM_NONE;
-       else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) {
-               skb->ip_summed = CHECKSUM_COMPLETE;
-               csum = skb_checksum(skb, 0, udp_len, 0);
-               uh->check = csum_tcpudp_magic(inet->inet_saddr,
-                                             inet->inet_daddr,
-                                             udp_len, IPPROTO_UDP, csum);
-               if (uh->check == 0)
-                       uh->check = CSUM_MANGLED_0;
-       } else {
-               skb->ip_summed = CHECKSUM_PARTIAL;
-               skb->csum_start = skb_transport_header(skb) - skb->head;
-               skb->csum_offset = offsetof(struct udphdr, check);
-               uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
-                                              inet->inet_daddr,
-                                              udp_len, IPPROTO_UDP, 0);
-       }
-
-       /* Debug */
-       if (session->send_seq)
-               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-                      "%s: send %Zd bytes, ns=%hu\n", session->name,
-                      total_len, session->ns - 1);
-       else
-               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-                      "%s: send %Zd bytes\n", session->name, total_len);
-
-       if (session->debug & PPPOL2TP_MSG_DATA) {
-               int i;
-               unsigned char *datap = skb->data;
-
-               printk(KERN_DEBUG "%s: xmit:", session->name);
-               for (i = 0; i < total_len; i++) {
-                       printk(" %02X", *datap++);
-                       if (i == 15) {
-                               printk(" ...");
-                               break;
-                       }
-               }
-               printk("\n");
-       }
-
-       /* Queue the packet to IP for output */
-       len = skb->len;
-       error = ip_queue_xmit(skb, 1);
-
-       /* Update stats */
-       if (error >= 0) {
-               tunnel->stats.tx_packets++;
-               tunnel->stats.tx_bytes += len;
-               session->stats.tx_packets++;
-               session->stats.tx_bytes += len;
-       } else {
-               tunnel->stats.tx_errors++;
-               session->stats.tx_errors++;
-       }
-
-       return error;
-
-error_put_sess_tun:
-       sock_put(session->tunnel_sock);
-error_put_sess:
-       sock_put(sk);
-error:
-       return error;
-}
-
-/* Automatically called when the skb is freed.
- */
-static void pppol2tp_sock_wfree(struct sk_buff *skb)
-{
-       sock_put(skb->sk);
-}
-
-/* For data skbs that we transmit, we associate with the tunnel socket
- * but don't do accounting.
- */
-static inline void pppol2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
-{
-       sock_hold(sk);
-       skb->sk = sk;
-       skb->destructor = pppol2tp_sock_wfree;
-}
-
-/* Transmit function called by generic PPP driver.  Sends PPP frame
- * over PPPoL2TP socket.
- *
- * This is almost the same as pppol2tp_sendmsg(), but rather than
- * being called with a msghdr from userspace, it is called with a skb
- * from the kernel.
- *
- * The supplied skb from ppp doesn't have enough headroom for the
- * insertion of L2TP, UDP and IP headers so we need to allocate more
- * headroom in the skb. This will create a cloned skb. But we must be
- * careful in the error case because the caller will expect to free
- * the skb it supplied, not our cloned skb. So we take care to always
- * leave the original skb unfreed if we return an error.
- */
-static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
-{
-       static const u8 ppph[2] = { 0xff, 0x03 };
-       struct sock *sk = (struct sock *) chan->private;
-       struct sock *sk_tun;
-       int hdr_len;
-       u16 udp_len;
-       struct pppol2tp_session *session;
-       struct pppol2tp_tunnel *tunnel;
-       int rc;
-       int headroom;
-       int data_len = skb->len;
-       struct inet_sock *inet;
-       __wsum csum;
-       struct udphdr *uh;
-       unsigned int len;
-       int old_headroom;
-       int new_headroom;
-
-       if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
-               goto abort;
-
-       /* Get session and tunnel contexts from the socket */
-       session = pppol2tp_sock_to_session(sk);
-       if (session == NULL)
-               goto abort;
-
-       sk_tun = session->tunnel_sock;
-       if (sk_tun == NULL)
-               goto abort_put_sess;
-       tunnel = pppol2tp_sock_to_tunnel(sk_tun);
-       if (tunnel == NULL)
-               goto abort_put_sess;
-
-       /* What header length is configured for this session? */
-       hdr_len = pppol2tp_l2tp_header_len(session);
-
-       /* Check that there's enough headroom in the skb to insert IP,
-        * UDP and L2TP and PPP headers. If not enough, expand it to
-        * make room. Adjust truesize.
-        */
-       headroom = NET_SKB_PAD + sizeof(struct iphdr) +
-               sizeof(struct udphdr) + hdr_len + sizeof(ppph);
-       old_headroom = skb_headroom(skb);
-       if (skb_cow_head(skb, headroom))
-               goto abort_put_sess_tun;
-
-       new_headroom = skb_headroom(skb);
-       skb_orphan(skb);
-       skb->truesize += new_headroom - old_headroom;
-
-       /* Setup PPP header */
-       __skb_push(skb, sizeof(ppph));
-       skb->data[0] = ppph[0];
-       skb->data[1] = ppph[1];
-
-       /* Setup L2TP header */
-       pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
-
-       udp_len = sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len;
-
-       /* Setup UDP header */
-       inet = inet_sk(sk_tun);
-       __skb_push(skb, sizeof(*uh));
-       skb_reset_transport_header(skb);
-       uh = udp_hdr(skb);
-       uh->source = inet->inet_sport;
-       uh->dest = inet->inet_dport;
-       uh->len = htons(udp_len);
-       uh->check = 0;
-
-       /* Debug */
-       if (session->send_seq)
-               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-                      "%s: send %d bytes, ns=%hu\n", session->name,
-                      data_len, session->ns - 1);
-       else
-               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
-                      "%s: send %d bytes\n", session->name, data_len);
-
-       if (session->debug & PPPOL2TP_MSG_DATA) {
-               int i;
-               unsigned char *datap = skb->data;
-
-               printk(KERN_DEBUG "%s: xmit:", session->name);
-               for (i = 0; i < data_len; i++) {
-                       printk(" %02X", *datap++);
-                       if (i == 31) {
-                               printk(" ...");
-                               break;
-                       }
-               }
-               printk("\n");
-       }
-
-       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
-       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
-                             IPSKB_REROUTED);
-       nf_reset(skb);
-
-       /* Get routing info from the tunnel socket */
-       skb_dst_drop(skb);
-       skb_dst_set(skb, dst_clone(__sk_dst_get(sk_tun)));
-       pppol2tp_skb_set_owner_w(skb, sk_tun);
-
-       /* Calculate UDP checksum if configured to do so */
-       if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT)
-               skb->ip_summed = CHECKSUM_NONE;
-       else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
-                (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) {
-               skb->ip_summed = CHECKSUM_COMPLETE;
-               csum = skb_checksum(skb, 0, udp_len, 0);
-               uh->check = csum_tcpudp_magic(inet->inet_saddr,
-                                             inet->inet_daddr,
-                                             udp_len, IPPROTO_UDP, csum);
-               if (uh->check == 0)
-                       uh->check = CSUM_MANGLED_0;
-       } else {
-               skb->ip_summed = CHECKSUM_PARTIAL;
-               skb->csum_start = skb_transport_header(skb) - skb->head;
-               skb->csum_offset = offsetof(struct udphdr, check);
-               uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
-                                              inet->inet_daddr,
-                                              udp_len, IPPROTO_UDP, 0);
-       }
-
-       /* Queue the packet to IP for output */
-       len = skb->len;
-       rc = ip_queue_xmit(skb, 1);
-
-       /* Update stats */
-       if (rc >= 0) {
-               tunnel->stats.tx_packets++;
-               tunnel->stats.tx_bytes += len;
-               session->stats.tx_packets++;
-               session->stats.tx_bytes += len;
-       } else {
-               tunnel->stats.tx_errors++;
-               session->stats.tx_errors++;
-       }
-
-       sock_put(sk_tun);
-       sock_put(sk);
-       return 1;
-
-abort_put_sess_tun:
-       sock_put(sk_tun);
-abort_put_sess:
-       sock_put(sk);
-abort:
-       /* Free the original skb */
-       kfree_skb(skb);
-       return 1;
-}
-
-/*****************************************************************************
- * Session (and tunnel control) socket create/destroy.
- *****************************************************************************/
-
-/* When the tunnel UDP socket is closed, all the attached sockets need to go
- * too.
- */
-static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel)
-{
-       int hash;
-       struct hlist_node *walk;
-       struct hlist_node *tmp;
-       struct pppol2tp_session *session;
-       struct sock *sk;
-
-       BUG_ON(tunnel == NULL);
-
-       PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-              "%s: closing all sessions...\n", tunnel->name);
-
-       write_lock_bh(&tunnel->hlist_lock);
-       for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) {
-again:
-               hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
-                       struct sk_buff *skb;
-
-                       session = hlist_entry(walk, struct pppol2tp_session, hlist);
-
-                       sk = session->sock;
-
-                       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                              "%s: closing session\n", session->name);
-
-                       hlist_del_init(&session->hlist);
-
-                       /* Since we should hold the sock lock while
-                        * doing any unbinding, we need to release the
-                        * lock we're holding before taking that lock.
-                        * Hold a reference to the sock so it doesn't
-                        * disappear as we're jumping between locks.
-                        */
-                       sock_hold(sk);
-                       write_unlock_bh(&tunnel->hlist_lock);
-                       lock_sock(sk);
-
-                       if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
-                               pppox_unbind_sock(sk);
-                               sk->sk_state = PPPOX_DEAD;
-                               sk->sk_state_change(sk);
-                       }
-
-                       /* Purge any queued data */
-                       skb_queue_purge(&sk->sk_receive_queue);
-                       skb_queue_purge(&sk->sk_write_queue);
-                       while ((skb = skb_dequeue(&session->reorder_q))) {
-                               kfree_skb(skb);
-                               sock_put(sk);
-                       }
-
-                       release_sock(sk);
-                       sock_put(sk);
-
-                       /* Now restart from the beginning of this hash
-                        * chain.  We always remove a session from the
-                        * list so we are guaranteed to make forward
-                        * progress.
-                        */
-                       write_lock_bh(&tunnel->hlist_lock);
-                       goto again;
-               }
-       }
-       write_unlock_bh(&tunnel->hlist_lock);
-}
-
-/* Really kill the tunnel.
- * Come here only when all sessions have been cleared from the tunnel.
- */
-static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel)
-{
-       struct pppol2tp_net *pn = pppol2tp_pernet(tunnel->pppol2tp_net);
-
-       /* Remove from socket list */
-       write_lock_bh(&pn->pppol2tp_tunnel_list_lock);
-       list_del_init(&tunnel->list);
-       write_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
-
-       atomic_dec(&pppol2tp_tunnel_count);
-       kfree(tunnel);
-}
-
-/* Tunnel UDP socket destruct hook.
- * The tunnel context is deleted only when all session sockets have been
- * closed.
- */
-static void pppol2tp_tunnel_destruct(struct sock *sk)
-{
-       struct pppol2tp_tunnel *tunnel;
-
-       tunnel = sk->sk_user_data;
-       if (tunnel == NULL)
-               goto end;
-
-       PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-              "%s: closing...\n", tunnel->name);
-
-       /* Close all sessions */
-       pppol2tp_tunnel_closeall(tunnel);
-
-       /* No longer an encapsulation socket. See net/ipv4/udp.c */
-       (udp_sk(sk))->encap_type = 0;
-       (udp_sk(sk))->encap_rcv = NULL;
-
-       /* Remove hooks into tunnel socket */
-       tunnel->sock = NULL;
-       sk->sk_destruct = tunnel->old_sk_destruct;
-       sk->sk_user_data = NULL;
-
-       /* Call original (UDP) socket descructor */
-       if (sk->sk_destruct != NULL)
-               (*sk->sk_destruct)(sk);
-
-       pppol2tp_tunnel_dec_refcount(tunnel);
-
-end:
-       return;
-}
-
-/* Really kill the session socket. (Called from sock_put() if
- * refcnt == 0.)
- */
-static void pppol2tp_session_destruct(struct sock *sk)
-{
-       struct pppol2tp_session *session = NULL;
-
-       if (sk->sk_user_data != NULL) {
-               struct pppol2tp_tunnel *tunnel;
-
-               session = sk->sk_user_data;
-               if (session == NULL)
-                       goto out;
-
-               BUG_ON(session->magic != L2TP_SESSION_MAGIC);
-
-               /* Don't use pppol2tp_sock_to_tunnel() here to
-                * get the tunnel context because the tunnel
-                * socket might have already been closed (its
-                * sk->sk_user_data will be NULL) so use the
-                * session's private tunnel ptr instead.
-                */
-               tunnel = session->tunnel;
-               if (tunnel != NULL) {
-                       BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-
-                       /* If session_id is zero, this is a null
-                        * session context, which was created for a
-                        * socket that is being used only to manage
-                        * tunnels.
-                        */
-                       if (session->tunnel_addr.s_session != 0) {
-                               /* Delete the session socket from the
-                                * hash
-                                */
-                               write_lock_bh(&tunnel->hlist_lock);
-                               hlist_del_init(&session->hlist);
-                               write_unlock_bh(&tunnel->hlist_lock);
-
-                               atomic_dec(&pppol2tp_session_count);
-                       }
-
-                       /* This will delete the tunnel context if this
-                        * is the last session on the tunnel.
-                        */
-                       session->tunnel = NULL;
-                       session->tunnel_sock = NULL;
-                       pppol2tp_tunnel_dec_refcount(tunnel);
-               }
-       }
-
-       kfree(session);
-out:
-       return;
-}
-
-/* Called when the PPPoX socket (session) is closed.
- */
-static int pppol2tp_release(struct socket *sock)
-{
-       struct sock *sk = sock->sk;
-       struct pppol2tp_session *session;
-       int error;
-
-       if (!sk)
-               return 0;
-
-       error = -EBADF;
-       lock_sock(sk);
-       if (sock_flag(sk, SOCK_DEAD) != 0)
-               goto error;
-
-       pppox_unbind_sock(sk);
-
-       /* Signal the death of the socket. */
-       sk->sk_state = PPPOX_DEAD;
-       sock_orphan(sk);
-       sock->sk = NULL;
-
-       session = pppol2tp_sock_to_session(sk);
-
-       /* Purge any queued data */
-       skb_queue_purge(&sk->sk_receive_queue);
-       skb_queue_purge(&sk->sk_write_queue);
-       if (session != NULL) {
-               struct sk_buff *skb;
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
-               sock_put(sk);
-       }
-
-       release_sock(sk);
-
-       /* This will delete the session context via
-        * pppol2tp_session_destruct() if the socket's refcnt drops to
-        * zero.
-        */
-       sock_put(sk);
-
-       return 0;
-
-error:
-       release_sock(sk);
-       return error;
-}
-
-/* Internal function to prepare a tunnel (UDP) socket to have PPPoX
- * sockets attached to it.
- */
-static struct sock *pppol2tp_prepare_tunnel_socket(struct net *net,
-                                       int fd, u16 tunnel_id, int *error)
-{
-       int err;
-       struct socket *sock = NULL;
-       struct sock *sk;
-       struct pppol2tp_tunnel *tunnel;
-       struct pppol2tp_net *pn;
-       struct sock *ret = NULL;
-
-       /* Get the tunnel UDP socket from the fd, which was opened by
-        * the userspace L2TP daemon.
-        */
-       err = -EBADF;
-       sock = sockfd_lookup(fd, &err);
-       if (!sock) {
-               PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
-                      "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
-                      tunnel_id, fd, err);
-               goto err;
-       }
-
-       sk = sock->sk;
-
-       /* Quick sanity checks */
-       err = -EPROTONOSUPPORT;
-       if (sk->sk_protocol != IPPROTO_UDP) {
-               PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
-                      "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
-                      tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
-               goto err;
-       }
-       err = -EAFNOSUPPORT;
-       if (sock->ops->family != AF_INET) {
-               PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
-                      "tunl %hu: fd %d wrong family, got %d, expected %d\n",
-                      tunnel_id, fd, sock->ops->family, AF_INET);
-               goto err;
-       }
-
-       err = -ENOTCONN;
-
-       /* Check if this socket has already been prepped */
-       tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data;
-       if (tunnel != NULL) {
-               /* User-data field already set */
-               err = -EBUSY;
-               BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-
-               /* This socket has already been prepped */
-               ret = tunnel->sock;
-               goto out;
-       }
-
-       /* This socket is available and needs prepping. Create a new tunnel
-        * context and init it.
-        */
-       sk->sk_user_data = tunnel = kzalloc(sizeof(struct pppol2tp_tunnel), GFP_KERNEL);
-       if (sk->sk_user_data == NULL) {
-               err = -ENOMEM;
-               goto err;
-       }
-
-       tunnel->magic = L2TP_TUNNEL_MAGIC;
-       sprintf(&tunnel->name[0], "tunl %hu", tunnel_id);
-
-       tunnel->stats.tunnel_id = tunnel_id;
-       tunnel->debug = PPPOL2TP_DEFAULT_DEBUG_FLAGS;
-
-       /* Hook on the tunnel socket destructor so that we can cleanup
-        * if the tunnel socket goes away.
-        */
-       tunnel->old_sk_destruct = sk->sk_destruct;
-       sk->sk_destruct = pppol2tp_tunnel_destruct;
-
-       tunnel->sock = sk;
-       sk->sk_allocation = GFP_ATOMIC;
-
-       /* Misc init */
-       rwlock_init(&tunnel->hlist_lock);
-
-       /* The net we belong to */
-       tunnel->pppol2tp_net = net;
-       pn = pppol2tp_pernet(net);
-
-       /* Add tunnel to our list */
-       INIT_LIST_HEAD(&tunnel->list);
-       write_lock_bh(&pn->pppol2tp_tunnel_list_lock);
-       list_add(&tunnel->list, &pn->pppol2tp_tunnel_list);
-       write_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
-       atomic_inc(&pppol2tp_tunnel_count);
-
-       /* Bump the reference count. The tunnel context is deleted
-        * only when this drops to zero.
-        */
-       pppol2tp_tunnel_inc_refcount(tunnel);
-
-       /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
-       (udp_sk(sk))->encap_type = UDP_ENCAP_L2TPINUDP;
-       (udp_sk(sk))->encap_rcv = pppol2tp_udp_encap_recv;
-
-       ret = tunnel->sock;
-
-       *error = 0;
-out:
-       if (sock)
-               sockfd_put(sock);
-
-       return ret;
-
-err:
-       *error = err;
-       goto out;
-}
-
-static struct proto pppol2tp_sk_proto = {
-       .name     = "PPPOL2TP",
-       .owner    = THIS_MODULE,
-       .obj_size = sizeof(struct pppox_sock),
-};
-
-/* socket() handler. Initialize a new struct sock.
- */
-static int pppol2tp_create(struct net *net, struct socket *sock)
-{
-       int error = -ENOMEM;
-       struct sock *sk;
-
-       sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto);
-       if (!sk)
-               goto out;
-
-       sock_init_data(sock, sk);
-
-       sock->state  = SS_UNCONNECTED;
-       sock->ops    = &pppol2tp_ops;
-
-       sk->sk_backlog_rcv = pppol2tp_recv_core;
-       sk->sk_protocol    = PX_PROTO_OL2TP;
-       sk->sk_family      = PF_PPPOX;
-       sk->sk_state       = PPPOX_NONE;
-       sk->sk_type        = SOCK_STREAM;
-       sk->sk_destruct    = pppol2tp_session_destruct;
-
-       error = 0;
-
-out:
-       return error;
-}
-
-/* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
- */
-static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
-                           int sockaddr_len, int flags)
-{
-       struct sock *sk = sock->sk;
-       struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr;
-       struct pppox_sock *po = pppox_sk(sk);
-       struct sock *tunnel_sock = NULL;
-       struct pppol2tp_session *session = NULL;
-       struct pppol2tp_tunnel *tunnel;
-       struct dst_entry *dst;
-       int error = 0;
-
-       lock_sock(sk);
-
-       error = -EINVAL;
-       if (sp->sa_protocol != PX_PROTO_OL2TP)
-               goto end;
-
-       /* Check for already bound sockets */
-       error = -EBUSY;
-       if (sk->sk_state & PPPOX_CONNECTED)
-               goto end;
-
-       /* We don't supporting rebinding anyway */
-       error = -EALREADY;
-       if (sk->sk_user_data)
-               goto end; /* socket is already attached */
-
-       /* Don't bind if s_tunnel is 0 */
-       error = -EINVAL;
-       if (sp->pppol2tp.s_tunnel == 0)
-               goto end;
-
-       /* Special case: prepare tunnel socket if s_session and
-        * d_session is 0. Otherwise look up tunnel using supplied
-        * tunnel id.
-        */
-       if ((sp->pppol2tp.s_session == 0) && (sp->pppol2tp.d_session == 0)) {
-               tunnel_sock = pppol2tp_prepare_tunnel_socket(sock_net(sk),
-                                                            sp->pppol2tp.fd,
-                                                            sp->pppol2tp.s_tunnel,
-                                                            &error);
-               if (tunnel_sock == NULL)
-                       goto end;
-
-               sock_hold(tunnel_sock);
-               tunnel = tunnel_sock->sk_user_data;
-       } else {
-               tunnel = pppol2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel);
-
-               /* Error if we can't find the tunnel */
-               error = -ENOENT;
-               if (tunnel == NULL)
-                       goto end;
-
-               tunnel_sock = tunnel->sock;
-       }
-
-       /* Check that this session doesn't already exist */
-       error = -EEXIST;
-       session = pppol2tp_session_find(tunnel, sp->pppol2tp.s_session);
-       if (session != NULL)
-               goto end;
-
-       /* Allocate and initialize a new session context. */
-       session = kzalloc(sizeof(struct pppol2tp_session), GFP_KERNEL);
-       if (session == NULL) {
-               error = -ENOMEM;
-               goto end;
-       }
-
-       skb_queue_head_init(&session->reorder_q);
-
-       session->magic       = L2TP_SESSION_MAGIC;
-       session->owner       = current->pid;
-       session->sock        = sk;
-       session->tunnel      = tunnel;
-       session->tunnel_sock = tunnel_sock;
-       session->tunnel_addr = sp->pppol2tp;
-       sprintf(&session->name[0], "sess %hu/%hu",
-               session->tunnel_addr.s_tunnel,
-               session->tunnel_addr.s_session);
-
-       session->stats.tunnel_id  = session->tunnel_addr.s_tunnel;
-       session->stats.session_id = session->tunnel_addr.s_session;
-
-       INIT_HLIST_NODE(&session->hlist);
-
-       /* Inherit debug options from tunnel */
-       session->debug = tunnel->debug;
-
-       /* Default MTU must allow space for UDP/L2TP/PPP
-        * headers.
-        */
-       session->mtu = session->mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
-
-       /* If PMTU discovery was enabled, use the MTU that was discovered */
-       dst = sk_dst_get(sk);
-       if (dst != NULL) {
-               u32 pmtu = dst_mtu(__sk_dst_get(sk));
-               if (pmtu != 0)
-                       session->mtu = session->mru = pmtu -
-                               PPPOL2TP_HEADER_OVERHEAD;
-               dst_release(dst);
-       }
-
-       /* Special case: if source & dest session_id == 0x0000, this socket is
-        * being created to manage the tunnel. Don't add the session to the
-        * session hash list, just set up the internal context for use by
-        * ioctl() and sockopt() handlers.
-        */
-       if ((session->tunnel_addr.s_session == 0) &&
-           (session->tunnel_addr.d_session == 0)) {
-               error = 0;
-               sk->sk_user_data = session;
-               goto out_no_ppp;
-       }
-
-       /* Get tunnel context from the tunnel socket */
-       tunnel = pppol2tp_sock_to_tunnel(tunnel_sock);
-       if (tunnel == NULL) {
-               error = -EBADF;
-               goto end;
-       }
-
-       /* Right now, because we don't have a way to push the incoming skb's
-        * straight through the UDP layer, the only header we need to worry
-        * about is the L2TP header. This size is different depending on
-        * whether sequence numbers are enabled for the data channel.
-        */
-       po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
-
-       po->chan.private = sk;
-       po->chan.ops     = &pppol2tp_chan_ops;
-       po->chan.mtu     = session->mtu;
-
-       error = ppp_register_net_channel(sock_net(sk), &po->chan);
-       if (error)
-               goto end_put_tun;
-
-       /* This is how we get the session context from the socket. */
-       sk->sk_user_data = session;
-
-       /* Add session to the tunnel's hash list */
-       write_lock_bh(&tunnel->hlist_lock);
-       hlist_add_head(&session->hlist,
-                      pppol2tp_session_id_hash(tunnel,
-                                               session->tunnel_addr.s_session));
-       write_unlock_bh(&tunnel->hlist_lock);
-
-       atomic_inc(&pppol2tp_session_count);
-
-out_no_ppp:
-       pppol2tp_tunnel_inc_refcount(tunnel);
-       sk->sk_state = PPPOX_CONNECTED;
-       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-              "%s: created\n", session->name);
-
-end_put_tun:
-       sock_put(tunnel_sock);
-end:
-       release_sock(sk);
-
-       if (error != 0) {
-               if (session)
-                       PRINTK(session->debug,
-                               PPPOL2TP_MSG_CONTROL, KERN_WARNING,
-                               "%s: connect failed: %d\n",
-                               session->name, error);
-               else
-                       PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
-                               "connect failed: %d\n", error);
-       }
-
-       return error;
-}
-
-/* getname() support.
- */
-static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
-                           int *usockaddr_len, int peer)
-{
-       int len = sizeof(struct sockaddr_pppol2tp);
-       struct sockaddr_pppol2tp sp;
-       int error = 0;
-       struct pppol2tp_session *session;
-
-       error = -ENOTCONN;
-       if (sock->sk->sk_state != PPPOX_CONNECTED)
-               goto end;
-
-       session = pppol2tp_sock_to_session(sock->sk);
-       if (session == NULL) {
-               error = -EBADF;
-               goto end;
-       }
-
-       sp.sa_family    = AF_PPPOX;
-       sp.sa_protocol  = PX_PROTO_OL2TP;
-       memcpy(&sp.pppol2tp, &session->tunnel_addr,
-              sizeof(struct pppol2tp_addr));
-
-       memcpy(uaddr, &sp, len);
-
-       *usockaddr_len = len;
-
-       error = 0;
-       sock_put(sock->sk);
-
-end:
-       return error;
-}
-
-/****************************************************************************
- * ioctl() handlers.
- *
- * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP
- * sockets. However, in order to control kernel tunnel features, we allow
- * userspace to create a special "tunnel" PPPoX socket which is used for
- * control only.  Tunnel PPPoX sockets have session_id == 0 and simply allow
- * the user application to issue L2TP setsockopt(), getsockopt() and ioctl()
- * calls.
- ****************************************************************************/
-
-/* Session ioctl helper.
- */
-static int pppol2tp_session_ioctl(struct pppol2tp_session *session,
-                                 unsigned int cmd, unsigned long arg)
-{
-       struct ifreq ifr;
-       int err = 0;
-       struct sock *sk = session->sock;
-       int val = (int) arg;
-
-       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG,
-              "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
-              session->name, cmd, arg);
-
-       sock_hold(sk);
-
-       switch (cmd) {
-       case SIOCGIFMTU:
-               err = -ENXIO;
-               if (!(sk->sk_state & PPPOX_CONNECTED))
-                       break;
-
-               err = -EFAULT;
-               if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq)))
-                       break;
-               ifr.ifr_mtu = session->mtu;
-               if (copy_to_user((void __user *) arg, &ifr, sizeof(struct ifreq)))
-                       break;
-
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get mtu=%d\n", session->name, session->mtu);
-               err = 0;
-               break;
-
-       case SIOCSIFMTU:
-               err = -ENXIO;
-               if (!(sk->sk_state & PPPOX_CONNECTED))
-                       break;
-
-               err = -EFAULT;
-               if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq)))
-                       break;
-
-               session->mtu = ifr.ifr_mtu;
-
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set mtu=%d\n", session->name, session->mtu);
-               err = 0;
-               break;
-
-       case PPPIOCGMRU:
-               err = -ENXIO;
-               if (!(sk->sk_state & PPPOX_CONNECTED))
-                       break;
-
-               err = -EFAULT;
-               if (put_user(session->mru, (int __user *) arg))
-                       break;
-
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get mru=%d\n", session->name, session->mru);
-               err = 0;
-               break;
-
-       case PPPIOCSMRU:
-               err = -ENXIO;
-               if (!(sk->sk_state & PPPOX_CONNECTED))
-                       break;
-
-               err = -EFAULT;
-               if (get_user(val,(int __user *) arg))
-                       break;
-
-               session->mru = val;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set mru=%d\n", session->name, session->mru);
-               err = 0;
-               break;
-
-       case PPPIOCGFLAGS:
-               err = -EFAULT;
-               if (put_user(session->flags, (int __user *) arg))
-                       break;
-
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get flags=%d\n", session->name, session->flags);
-               err = 0;
-               break;
-
-       case PPPIOCSFLAGS:
-               err = -EFAULT;
-               if (get_user(val, (int __user *) arg))
-                       break;
-               session->flags = val;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set flags=%d\n", session->name, session->flags);
-               err = 0;
-               break;
-
-       case PPPIOCGL2TPSTATS:
-               err = -ENXIO;
-               if (!(sk->sk_state & PPPOX_CONNECTED))
-                       break;
-
-               if (copy_to_user((void __user *) arg, &session->stats,
-                                sizeof(session->stats)))
-                       break;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get L2TP stats\n", session->name);
-               err = 0;
-               break;
-
-       default:
-               err = -ENOSYS;
-               break;
-       }
-
-       sock_put(sk);
-
-       return err;
-}
-
-/* Tunnel ioctl helper.
- *
- * Note the special handling for PPPIOCGL2TPSTATS below. If the ioctl data
- * specifies a session_id, the session ioctl handler is called. This allows an
- * application to retrieve session stats via a tunnel socket.
- */
-static int pppol2tp_tunnel_ioctl(struct pppol2tp_tunnel *tunnel,
-                                unsigned int cmd, unsigned long arg)
-{
-       int err = 0;
-       struct sock *sk = tunnel->sock;
-       struct pppol2tp_ioc_stats stats_req;
-
-       PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG,
-              "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n", tunnel->name,
-              cmd, arg);
-
-       sock_hold(sk);
-
-       switch (cmd) {
-       case PPPIOCGL2TPSTATS:
-               err = -ENXIO;
-               if (!(sk->sk_state & PPPOX_CONNECTED))
-                       break;
-
-               if (copy_from_user(&stats_req, (void __user *) arg,
-                                  sizeof(stats_req))) {
-                       err = -EFAULT;
-                       break;
-               }
-               if (stats_req.session_id != 0) {
-                       /* resend to session ioctl handler */
-                       struct pppol2tp_session *session =
-                               pppol2tp_session_find(tunnel, stats_req.session_id);
-                       if (session != NULL)
-                               err = pppol2tp_session_ioctl(session, cmd, arg);
-                       else
-                               err = -EBADR;
-                       break;
-               }
-#ifdef CONFIG_XFRM
-               tunnel->stats.using_ipsec = (sk->sk_policy[0] || sk->sk_policy[1]) ? 1 : 0;
-#endif
-               if (copy_to_user((void __user *) arg, &tunnel->stats,
-                                sizeof(tunnel->stats))) {
-                       err = -EFAULT;
-                       break;
-               }
-               PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get L2TP stats\n", tunnel->name);
-               err = 0;
-               break;
-
-       default:
-               err = -ENOSYS;
-               break;
-       }
-
-       sock_put(sk);
-
-       return err;
-}
-
-/* Main ioctl() handler.
- * Dispatch to tunnel or session helpers depending on the socket.
- */
-static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
-                         unsigned long arg)
-{
-       struct sock *sk = sock->sk;
-       struct pppol2tp_session *session;
-       struct pppol2tp_tunnel *tunnel;
-       int err;
-
-       if (!sk)
-               return 0;
-
-       err = -EBADF;
-       if (sock_flag(sk, SOCK_DEAD) != 0)
-               goto end;
-
-       err = -ENOTCONN;
-       if ((sk->sk_user_data == NULL) ||
-           (!(sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND))))
-               goto end;
-
-       /* Get session context from the socket */
-       err = -EBADF;
-       session = pppol2tp_sock_to_session(sk);
-       if (session == NULL)
-               goto end;
-
-       /* Special case: if session's session_id is zero, treat ioctl as a
-        * tunnel ioctl
-        */
-       if ((session->tunnel_addr.s_session == 0) &&
-           (session->tunnel_addr.d_session == 0)) {
-               err = -EBADF;
-               tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
-               if (tunnel == NULL)
-                       goto end_put_sess;
-
-               err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
-               sock_put(session->tunnel_sock);
-               goto end_put_sess;
-       }
-
-       err = pppol2tp_session_ioctl(session, cmd, arg);
-
-end_put_sess:
-       sock_put(sk);
-end:
-       return err;
-}
-
-/*****************************************************************************
- * setsockopt() / getsockopt() support.
- *
- * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP
- * sockets. In order to control kernel tunnel features, we allow userspace to
- * create a special "tunnel" PPPoX socket which is used for control only.
- * Tunnel PPPoX sockets have session_id == 0 and simply allow the user
- * application to issue L2TP setsockopt(), getsockopt() and ioctl() calls.
- *****************************************************************************/
-
-/* Tunnel setsockopt() helper.
- */
-static int pppol2tp_tunnel_setsockopt(struct sock *sk,
-                                     struct pppol2tp_tunnel *tunnel,
-                                     int optname, int val)
-{
-       int err = 0;
-
-       switch (optname) {
-       case PPPOL2TP_SO_DEBUG:
-               tunnel->debug = val;
-               PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set debug=%x\n", tunnel->name, tunnel->debug);
-               break;
-
-       default:
-               err = -ENOPROTOOPT;
-               break;
-       }
-
-       return err;
-}
-
-/* Session setsockopt helper.
- */
-static int pppol2tp_session_setsockopt(struct sock *sk,
-                                      struct pppol2tp_session *session,
-                                      int optname, int val)
-{
-       int err = 0;
-
-       switch (optname) {
-       case PPPOL2TP_SO_RECVSEQ:
-               if ((val != 0) && (val != 1)) {
-                       err = -EINVAL;
-                       break;
-               }
-               session->recv_seq = val ? -1 : 0;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set recv_seq=%d\n", session->name,
-                      session->recv_seq);
-               break;
-
-       case PPPOL2TP_SO_SENDSEQ:
-               if ((val != 0) && (val != 1)) {
-                       err = -EINVAL;
-                       break;
-               }
-               session->send_seq = val ? -1 : 0;
-               {
-                       struct sock *ssk      = session->sock;
-                       struct pppox_sock *po = pppox_sk(ssk);
-                       po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
-                               PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
-               }
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set send_seq=%d\n", session->name, session->send_seq);
-               break;
-
-       case PPPOL2TP_SO_LNSMODE:
-               if ((val != 0) && (val != 1)) {
-                       err = -EINVAL;
-                       break;
-               }
-               session->lns_mode = val ? -1 : 0;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set lns_mode=%d\n", session->name,
-                      session->lns_mode);
-               break;
-
-       case PPPOL2TP_SO_DEBUG:
-               session->debug = val;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set debug=%x\n", session->name, session->debug);
-               break;
-
-       case PPPOL2TP_SO_REORDERTO:
-               session->reorder_timeout = msecs_to_jiffies(val);
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: set reorder_timeout=%d\n", session->name,
-                      session->reorder_timeout);
-               break;
-
-       default:
-               err = -ENOPROTOOPT;
-               break;
-       }
-
-       return err;
-}
-
-/* Main setsockopt() entry point.
- * Does API checks, then calls either the tunnel or session setsockopt
- * handler, according to whether the PPPoL2TP socket is a for a regular
- * session or the special tunnel type.
- */
-static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
-                              char __user *optval, unsigned int optlen)
-{
-       struct sock *sk = sock->sk;
-       struct pppol2tp_session *session = sk->sk_user_data;
-       struct pppol2tp_tunnel *tunnel;
-       int val;
-       int err;
-
-       if (level != SOL_PPPOL2TP)
-               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
-
-       if (optlen < sizeof(int))
-               return -EINVAL;
-
-       if (get_user(val, (int __user *)optval))
-               return -EFAULT;
-
-       err = -ENOTCONN;
-       if (sk->sk_user_data == NULL)
-               goto end;
-
-       /* Get session context from the socket */
-       err = -EBADF;
-       session = pppol2tp_sock_to_session(sk);
-       if (session == NULL)
-               goto end;
-
-       /* Special case: if session_id == 0x0000, treat as operation on tunnel
-        */
-       if ((session->tunnel_addr.s_session == 0) &&
-           (session->tunnel_addr.d_session == 0)) {
-               err = -EBADF;
-               tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
-               if (tunnel == NULL)
-                       goto end_put_sess;
-
-               err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val);
-               sock_put(session->tunnel_sock);
-       } else
-               err = pppol2tp_session_setsockopt(sk, session, optname, val);
-
-       err = 0;
-
-end_put_sess:
-       sock_put(sk);
-end:
-       return err;
-}
-
-/* Tunnel getsockopt helper. Called with sock locked.
- */
-static int pppol2tp_tunnel_getsockopt(struct sock *sk,
-                                     struct pppol2tp_tunnel *tunnel,
-                                     int optname, int *val)
-{
-       int err = 0;
-
-       switch (optname) {
-       case PPPOL2TP_SO_DEBUG:
-               *val = tunnel->debug;
-               PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get debug=%x\n", tunnel->name, tunnel->debug);
-               break;
-
-       default:
-               err = -ENOPROTOOPT;
-               break;
-       }
-
-       return err;
-}
-
-/* Session getsockopt helper. Called with sock locked.
- */
-static int pppol2tp_session_getsockopt(struct sock *sk,
-                                      struct pppol2tp_session *session,
-                                      int optname, int *val)
-{
-       int err = 0;
-
-       switch (optname) {
-       case PPPOL2TP_SO_RECVSEQ:
-               *val = session->recv_seq;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get recv_seq=%d\n", session->name, *val);
-               break;
-
-       case PPPOL2TP_SO_SENDSEQ:
-               *val = session->send_seq;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get send_seq=%d\n", session->name, *val);
-               break;
-
-       case PPPOL2TP_SO_LNSMODE:
-               *val = session->lns_mode;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get lns_mode=%d\n", session->name, *val);
-               break;
-
-       case PPPOL2TP_SO_DEBUG:
-               *val = session->debug;
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get debug=%d\n", session->name, *val);
-               break;
-
-       case PPPOL2TP_SO_REORDERTO:
-               *val = (int) jiffies_to_msecs(session->reorder_timeout);
-               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
-                      "%s: get reorder_timeout=%d\n", session->name, *val);
-               break;
-
-       default:
-               err = -ENOPROTOOPT;
-       }
-
-       return err;
-}
-
-/* Main getsockopt() entry point.
- * Does API checks, then calls either the tunnel or session getsockopt
- * handler, according to whether the PPPoX socket is a for a regular session
- * or the special tunnel type.
- */
-static int pppol2tp_getsockopt(struct socket *sock, int level,
-                              int optname, char __user *optval, int __user *optlen)
-{
-       struct sock *sk = sock->sk;
-       struct pppol2tp_session *session = sk->sk_user_data;
-       struct pppol2tp_tunnel *tunnel;
-       int val, len;
-       int err;
-
-       if (level != SOL_PPPOL2TP)
-               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
-
-       if (get_user(len, (int __user *) optlen))
-               return -EFAULT;
-
-       len = min_t(unsigned int, len, sizeof(int));
-
-       if (len < 0)
-               return -EINVAL;
-
-       err = -ENOTCONN;
-       if (sk->sk_user_data == NULL)
-               goto end;
-
-       /* Get the session context */
-       err = -EBADF;
-       session = pppol2tp_sock_to_session(sk);
-       if (session == NULL)
-               goto end;
-
-       /* Special case: if session_id == 0x0000, treat as operation on tunnel */
-       if ((session->tunnel_addr.s_session == 0) &&
-           (session->tunnel_addr.d_session == 0)) {
-               err = -EBADF;
-               tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
-               if (tunnel == NULL)
-                       goto end_put_sess;
-
-               err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val);
-               sock_put(session->tunnel_sock);
-       } else
-               err = pppol2tp_session_getsockopt(sk, session, optname, &val);
-
-       err = -EFAULT;
-       if (put_user(len, (int __user *) optlen))
-               goto end_put_sess;
-
-       if (copy_to_user((void __user *) optval, &val, len))
-               goto end_put_sess;
-
-       err = 0;
-
-end_put_sess:
-       sock_put(sk);
-end:
-       return err;
-}
-
-/*****************************************************************************
- * /proc filesystem for debug
- *****************************************************************************/
-
-#ifdef CONFIG_PROC_FS
-
-#include <linux/seq_file.h>
-
-struct pppol2tp_seq_data {
-       struct seq_net_private p;
-       struct pppol2tp_tunnel *tunnel;         /* current tunnel */
-       struct pppol2tp_session *session;       /* NULL means get first session in tunnel */
-};
-
-static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, struct pppol2tp_session *curr)
-{
-       struct pppol2tp_session *session = NULL;
-       struct hlist_node *walk;
-       int found = 0;
-       int next = 0;
-       int i;
-
-       read_lock_bh(&tunnel->hlist_lock);
-       for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) {
-               hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) {
-                       if (curr == NULL) {
-                               found = 1;
-                               goto out;
-                       }
-                       if (session == curr) {
-                               next = 1;
-                               continue;
-                       }
-                       if (next) {
-                               found = 1;
-                               goto out;
-                       }
-               }
-       }
-out:
-       read_unlock_bh(&tunnel->hlist_lock);
-       if (!found)
-               session = NULL;
-
-       return session;
-}
-
-static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_net *pn,
-                                          struct pppol2tp_tunnel *curr)
-{
-       struct pppol2tp_tunnel *tunnel = NULL;
-
-       read_lock_bh(&pn->pppol2tp_tunnel_list_lock);
-       if (list_is_last(&curr->list, &pn->pppol2tp_tunnel_list)) {
-               goto out;
-       }
-       tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list);
-out:
-       read_unlock_bh(&pn->pppol2tp_tunnel_list_lock);
-
-       return tunnel;
-}
-
-static void *pppol2tp_seq_start(struct seq_file *m, loff_t *offs)
-{
-       struct pppol2tp_seq_data *pd = SEQ_START_TOKEN;
-       struct pppol2tp_net *pn;
-       loff_t pos = *offs;
-
-       if (!pos)
-               goto out;
-
-       BUG_ON(m->private == NULL);
-       pd = m->private;
-       pn = pppol2tp_pernet(seq_file_net(m));
-
-       if (pd->tunnel == NULL) {
-               if (!list_empty(&pn->pppol2tp_tunnel_list))
-                       pd->tunnel = list_entry(pn->pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list);
-       } else {
-               pd->session = next_session(pd->tunnel, pd->session);
-               if (pd->session == NULL) {
-                       pd->tunnel = next_tunnel(pn, pd->tunnel);
-               }
-       }
-
-       /* NULL tunnel and session indicates end of list */
-       if ((pd->tunnel == NULL) && (pd->session == NULL))
-               pd = NULL;
-
-out:
-       return pd;
-}
-
-static void *pppol2tp_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       (*pos)++;
-       return NULL;
-}
-
-static void pppol2tp_seq_stop(struct seq_file *p, void *v)
-{
-       /* nothing to do */
-}
-
-static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
-{
-       struct pppol2tp_tunnel *tunnel = v;
-
-       seq_printf(m, "\nTUNNEL '%s', %c %d\n",
-                  tunnel->name,
-                  (tunnel == tunnel->sock->sk_user_data) ? 'Y':'N',
-                  atomic_read(&tunnel->ref_count) - 1);
-       seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n",
-                  tunnel->debug,
-                  (unsigned long long)tunnel->stats.tx_packets,
-                  (unsigned long long)tunnel->stats.tx_bytes,
-                  (unsigned long long)tunnel->stats.tx_errors,
-                  (unsigned long long)tunnel->stats.rx_packets,
-                  (unsigned long long)tunnel->stats.rx_bytes,
-                  (unsigned long long)tunnel->stats.rx_errors);
-}
-
-static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
-{
-       struct pppol2tp_session *session = v;
-
-       seq_printf(m, "  SESSION '%s' %08X/%d %04X/%04X -> "
-                  "%04X/%04X %d %c\n",
-                  session->name,
-                  ntohl(session->tunnel_addr.addr.sin_addr.s_addr),
-                  ntohs(session->tunnel_addr.addr.sin_port),
-                  session->tunnel_addr.s_tunnel,
-                  session->tunnel_addr.s_session,
-                  session->tunnel_addr.d_tunnel,
-                  session->tunnel_addr.d_session,
-                  session->sock->sk_state,
-                  (session == session->sock->sk_user_data) ?
-                  'Y' : 'N');
-       seq_printf(m, "   %d/%d/%c/%c/%s %08x %u\n",
-                  session->mtu, session->mru,
-                  session->recv_seq ? 'R' : '-',
-                  session->send_seq ? 'S' : '-',
-                  session->lns_mode ? "LNS" : "LAC",
-                  session->debug,
-                  jiffies_to_msecs(session->reorder_timeout));
-       seq_printf(m, "   %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n",
-                  session->nr, session->ns,
-                  (unsigned long long)session->stats.tx_packets,
-                  (unsigned long long)session->stats.tx_bytes,
-                  (unsigned long long)session->stats.tx_errors,
-                  (unsigned long long)session->stats.rx_packets,
-                  (unsigned long long)session->stats.rx_bytes,
-                  (unsigned long long)session->stats.rx_errors);
-}
-
-static int pppol2tp_seq_show(struct seq_file *m, void *v)
-{
-       struct pppol2tp_seq_data *pd = v;
-
-       /* display header on line 1 */
-       if (v == SEQ_START_TOKEN) {
-               seq_puts(m, "PPPoL2TP driver info, " PPPOL2TP_DRV_VERSION "\n");
-               seq_puts(m, "TUNNEL name, user-data-ok session-count\n");
-               seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
-               seq_puts(m, "  SESSION name, addr/port src-tid/sid "
-                        "dest-tid/sid state user-data-ok\n");
-               seq_puts(m, "   mtu/mru/rcvseq/sendseq/lns debug reorderto\n");
-               seq_puts(m, "   nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
-               goto out;
-       }
-
-       /* Show the tunnel or session context.
-        */
-       if (pd->session == NULL)
-               pppol2tp_seq_tunnel_show(m, pd->tunnel);
-       else
-               pppol2tp_seq_session_show(m, pd->session);
-
-out:
-       return 0;
-}
-
-static const struct seq_operations pppol2tp_seq_ops = {
-       .start          = pppol2tp_seq_start,
-       .next           = pppol2tp_seq_next,
-       .stop           = pppol2tp_seq_stop,
-       .show           = pppol2tp_seq_show,
-};
-
-/* Called when our /proc file is opened. We allocate data for use when
- * iterating our tunnel / session contexts and store it in the private
- * data of the seq_file.
- */
-static int pppol2tp_proc_open(struct inode *inode, struct file *file)
-{
-       return seq_open_net(inode, file, &pppol2tp_seq_ops,
-                           sizeof(struct pppol2tp_seq_data));
-}
-
-static const struct file_operations pppol2tp_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = pppol2tp_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release_net,
-};
-
-#endif /* CONFIG_PROC_FS */
-
-/*****************************************************************************
- * Init and cleanup
- *****************************************************************************/
-
-static const struct proto_ops pppol2tp_ops = {
-       .family         = AF_PPPOX,
-       .owner          = THIS_MODULE,
-       .release        = pppol2tp_release,
-       .bind           = sock_no_bind,
-       .connect        = pppol2tp_connect,
-       .socketpair     = sock_no_socketpair,
-       .accept         = sock_no_accept,
-       .getname        = pppol2tp_getname,
-       .poll           = datagram_poll,
-       .listen         = sock_no_listen,
-       .shutdown       = sock_no_shutdown,
-       .setsockopt     = pppol2tp_setsockopt,
-       .getsockopt     = pppol2tp_getsockopt,
-       .sendmsg        = pppol2tp_sendmsg,
-       .recvmsg        = pppol2tp_recvmsg,
-       .mmap           = sock_no_mmap,
-       .ioctl          = pppox_ioctl,
-};
-
-static struct pppox_proto pppol2tp_proto = {
-       .create         = pppol2tp_create,
-       .ioctl          = pppol2tp_ioctl
-};
-
-static __net_init int pppol2tp_init_net(struct net *net)
-{
-       struct pppol2tp_net *pn = pppol2tp_pernet(net);
-       struct proc_dir_entry *pde;
-
-       INIT_LIST_HEAD(&pn->pppol2tp_tunnel_list);
-       rwlock_init(&pn->pppol2tp_tunnel_list_lock);
-
-       pde = proc_net_fops_create(net, "pppol2tp", S_IRUGO, &pppol2tp_proc_fops);
-#ifdef CONFIG_PROC_FS
-       if (!pde)
-               return -ENOMEM;
-#endif
-
-       return 0;
-}
-
-static __net_exit void pppol2tp_exit_net(struct net *net)
-{
-       proc_net_remove(net, "pppol2tp");
-}
-
-static struct pernet_operations pppol2tp_net_ops = {
-       .init = pppol2tp_init_net,
-       .exit = pppol2tp_exit_net,
-       .id   = &pppol2tp_net_id,
-       .size = sizeof(struct pppol2tp_net),
-};
-
-static int __init pppol2tp_init(void)
-{
-       int err;
-
-       err = proto_register(&pppol2tp_sk_proto, 0);
-       if (err)
-               goto out;
-       err = register_pppox_proto(PX_PROTO_OL2TP, &pppol2tp_proto);
-       if (err)
-               goto out_unregister_pppol2tp_proto;
-
-       err = register_pernet_device(&pppol2tp_net_ops);
-       if (err)
-               goto out_unregister_pppox_proto;
-
-       printk(KERN_INFO "PPPoL2TP kernel driver, %s\n",
-              PPPOL2TP_DRV_VERSION);
-
-out:
-       return err;
-out_unregister_pppox_proto:
-       unregister_pppox_proto(PX_PROTO_OL2TP);
-out_unregister_pppol2tp_proto:
-       proto_unregister(&pppol2tp_sk_proto);
-       goto out;
-}
-
-static void __exit pppol2tp_exit(void)
-{
-       unregister_pppox_proto(PX_PROTO_OL2TP);
-       unregister_pernet_device(&pppol2tp_net_ops);
-       proto_unregister(&pppol2tp_sk_proto);
-}
-
-module_init(pppol2tp_init);
-module_exit(pppol2tp_exit);
-
-MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>, "
-             "James Chapman <jchapman@katalix.com>");
-MODULE_DESCRIPTION("PPP over L2TP over UDP");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(PPPOL2TP_DRV_VERSION);
index 5bf229bb34c26e55879ddc62e13be82183e028c7..87d6b8f3630470cce8219a4738352377e9d6cac6 100644 (file)
@@ -327,7 +327,7 @@ static int gelic_descr_prepare_rx(struct gelic_card *card,
        unsigned int bufsize;
 
        if (gelic_descr_get_status(descr) !=  GELIC_DESCR_DMA_NOT_IN_USE)
-               dev_info(ctodev(card), "%s: ERROR status \n", __func__);
+               dev_info(ctodev(card), "%s: ERROR status\n", __func__);
        /* we need to round up the buffer size to a multiple of 128 */
        bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN);
 
@@ -547,7 +547,7 @@ out:
 void gelic_net_set_multi(struct net_device *netdev)
 {
        struct gelic_card *card = netdev_card(netdev);
-       struct dev_mc_list *mc;
+       struct netdev_hw_addr *ha;
        unsigned int i;
        uint8_t *p;
        u64 addr;
@@ -581,9 +581,9 @@ void gelic_net_set_multi(struct net_device *netdev)
        }
 
        /* set multicast addresses */
-       netdev_for_each_mc_addr(mc, netdev) {
+       netdev_for_each_mc_addr(ha, netdev) {
                addr = 0;
-               p = mc->dmi_addr;
+               p = ha->addr;
                for (i = 0; i < ETH_ALEN; i++) {
                        addr <<= 8;
                        addr |= *p++;
@@ -903,9 +903,6 @@ int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
                gelic_descr_release_tx(card, descr->next);
                card->tx_chain.tail = descr->next->next;
                dev_info(ctodev(card), "%s: kick failure\n", __func__);
-       } else {
-               /* OK, DMA started/reserved */
-               netdev->trans_start = jiffies;
        }
 
        spin_unlock_irqrestore(&card->tx_lock, flags);
@@ -1435,7 +1432,7 @@ static void gelic_net_tx_timeout_task(struct work_struct *work)
                container_of(work, struct gelic_card, tx_timeout_task);
        struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET_0];
 
-       dev_info(ctodev(card), "%s:Timed out. Restarting... \n", __func__);
+       dev_info(ctodev(card), "%s:Timed out. Restarting...\n", __func__);
 
        if (!(netdev->flags & IFF_UP))
                goto out;
index 369a8016b1ff3a2f6e17c1f60acb1864da79b83b..43b8d7797f0aa9695a3c78ddc48a68db5a2df770 100644 (file)
@@ -301,7 +301,6 @@ static void gelic_wl_get_ch_info(struct gelic_wl_info *wl)
                        /* 16 bits of MSB has available channels */
                        wl->ch_info = ch_info_raw >> 48;
        }
-       return;
 }
 
 /* SIOGIWRANGE */
@@ -528,7 +527,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len,
        u8 item_len;
        u8 item_id;
 
-       pr_debug("%s: data=%p len=%ld \n", __func__,
+       pr_debug("%s: data=%p len=%ld\n", __func__,
                 data, len);
        memset(ie_info, 0, sizeof(struct ie_info));
 
@@ -897,7 +896,7 @@ static int gelic_wl_set_auth(struct net_device *netdev,
        default:
                ret = -EOPNOTSUPP;
                break;
-       };
+       }
 
        if (!ret)
                set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
@@ -979,7 +978,7 @@ static int gelic_wl_set_essid(struct net_device *netdev,
                pr_debug("%s: essid = '%s'\n", __func__, extra);
                set_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
        } else {
-               pr_debug("%s: ESSID any \n", __func__);
+               pr_debug("%s: ESSID any\n", __func__);
                clear_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat);
        }
        set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
@@ -987,7 +986,7 @@ static int gelic_wl_set_essid(struct net_device *netdev,
 
 
        gelic_wl_try_associate(netdev); /* FIXME */
-       pr_debug("%s: -> \n", __func__);
+       pr_debug("%s: ->\n", __func__);
        return 0;
 }
 
@@ -998,7 +997,7 @@ static int gelic_wl_get_essid(struct net_device *netdev,
        struct gelic_wl_info *wl = port_wl(netdev_priv(netdev));
        unsigned long irqflag;
 
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
        mutex_lock(&wl->assoc_stat_lock);
        spin_lock_irqsave(&wl->lock, irqflag);
        if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) ||
@@ -1011,7 +1010,7 @@ static int gelic_wl_get_essid(struct net_device *netdev,
 
        mutex_unlock(&wl->assoc_stat_lock);
        spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> len=%d \n", __func__, data->essid.length);
+       pr_debug("%s: -> len=%d\n", __func__, data->essid.length);
 
        return 0;
 }
@@ -1028,7 +1027,7 @@ static int gelic_wl_set_encode(struct net_device *netdev,
        int key_index, index_specified;
        int ret = 0;
 
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
        flags = enc->flags & IW_ENCODE_FLAGS;
        key_index = enc->flags & IW_ENCODE_INDEX;
 
@@ -1087,7 +1086,7 @@ static int gelic_wl_set_encode(struct net_device *netdev,
        set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat);
 done:
        spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> \n", __func__);
+       pr_debug("%s: ->\n", __func__);
        return ret;
 }
 
@@ -1101,7 +1100,7 @@ static int gelic_wl_get_encode(struct net_device *netdev,
        unsigned int key_index, index_specified;
        int ret = 0;
 
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
        key_index = enc->flags & IW_ENCODE_INDEX;
        pr_debug("%s: flag=%#x point=%p len=%d extra=%p\n", __func__,
                 enc->flags, enc->pointer, enc->length, extra);
@@ -1215,7 +1214,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
        int key_index;
        int ret = 0;
 
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
        flags = enc->flags & IW_ENCODE_FLAGS;
        alg = ext->alg;
        key_index = enc->flags & IW_ENCODE_INDEX;
@@ -1288,7 +1287,7 @@ static int gelic_wl_set_encodeext(struct net_device *netdev,
        }
 done:
        spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> \n", __func__);
+       pr_debug("%s: ->\n", __func__);
        return ret;
 }
 
@@ -1304,7 +1303,7 @@ static int gelic_wl_get_encodeext(struct net_device *netdev,
        int ret = 0;
        int max_key_len;
 
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
 
        max_key_len = enc->length - sizeof(struct iw_encode_ext);
        if (max_key_len < 0)
@@ -1359,7 +1358,7 @@ static int gelic_wl_get_encodeext(struct net_device *netdev,
        }
 out:
        spin_unlock_irqrestore(&wl->lock, irqflag);
-       pr_debug("%s: -> \n", __func__);
+       pr_debug("%s: ->\n", __func__);
        return ret;
 }
 /* SIOC{S,G}IWMODE */
@@ -1370,7 +1369,7 @@ static int gelic_wl_set_mode(struct net_device *netdev,
        __u32 mode = data->mode;
        int ret;
 
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
        if (mode == IW_MODE_INFRA)
                ret = 0;
        else
@@ -1384,7 +1383,7 @@ static int gelic_wl_get_mode(struct net_device *netdev,
                             union iwreq_data *data, char *extra)
 {
        __u32 *mode = &data->mode;
-       pr_debug("%s: <- \n", __func__);
+       pr_debug("%s: <-\n", __func__);
        *mode = IW_MODE_INFRA;
        pr_debug("%s: ->\n", __func__);
        return 0;
@@ -1992,7 +1991,7 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
        case GELIC_WL_WPA_LEVEL_WPA2:
                ret = gelic_wl_do_wpa_setup(wl);
                break;
-       };
+       }
 
        if (ret) {
                pr_debug("%s: WEP/WPA setup failed %d\n", __func__,
@@ -2022,7 +2021,7 @@ static int gelic_wl_associate_bss(struct gelic_wl_info *wl,
 
        if (!rc) {
                /* timeouted.  Maybe key or cyrpt mode is wrong */
-               pr_info("%s: connect timeout \n", __func__);
+               pr_info("%s: connect timeout\n", __func__);
                cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC,
                                           NULL, 0);
                kfree(cmd);
@@ -2063,7 +2062,7 @@ static void gelic_wl_connected_event(struct gelic_wl_info *wl,
        }
 
        if (desired_event == event) {
-               pr_debug("%s: completed \n", __func__);
+               pr_debug("%s: completed\n", __func__);
                complete(&wl->assoc_done);
                netif_carrier_on(port_to_netdev(wl_port(wl)));
        } else
@@ -2280,26 +2279,25 @@ void gelic_wl_interrupt(struct net_device *netdev, u64 status)
 /*
  * driver helpers
  */
-#define IW_IOCTL(n) [(n) - SIOCSIWCOMMIT]
 static const iw_handler gelic_wl_wext_handler[] =
 {
-       IW_IOCTL(SIOCGIWNAME)           = gelic_wl_get_name,
-       IW_IOCTL(SIOCGIWRANGE)          = gelic_wl_get_range,
-       IW_IOCTL(SIOCSIWSCAN)           = gelic_wl_set_scan,
-       IW_IOCTL(SIOCGIWSCAN)           = gelic_wl_get_scan,
-       IW_IOCTL(SIOCSIWAUTH)           = gelic_wl_set_auth,
-       IW_IOCTL(SIOCGIWAUTH)           = gelic_wl_get_auth,
-       IW_IOCTL(SIOCSIWESSID)          = gelic_wl_set_essid,
-       IW_IOCTL(SIOCGIWESSID)          = gelic_wl_get_essid,
-       IW_IOCTL(SIOCSIWENCODE)         = gelic_wl_set_encode,
-       IW_IOCTL(SIOCGIWENCODE)         = gelic_wl_get_encode,
-       IW_IOCTL(SIOCSIWAP)             = gelic_wl_set_ap,
-       IW_IOCTL(SIOCGIWAP)             = gelic_wl_get_ap,
-       IW_IOCTL(SIOCSIWENCODEEXT)      = gelic_wl_set_encodeext,
-       IW_IOCTL(SIOCGIWENCODEEXT)      = gelic_wl_get_encodeext,
-       IW_IOCTL(SIOCSIWMODE)           = gelic_wl_set_mode,
-       IW_IOCTL(SIOCGIWMODE)           = gelic_wl_get_mode,
-       IW_IOCTL(SIOCGIWNICKN)          = gelic_wl_get_nick,
+       IW_HANDLER(SIOCGIWNAME, gelic_wl_get_name),
+       IW_HANDLER(SIOCGIWRANGE, gelic_wl_get_range),
+       IW_HANDLER(SIOCSIWSCAN, gelic_wl_set_scan),
+       IW_HANDLER(SIOCGIWSCAN, gelic_wl_get_scan),
+       IW_HANDLER(SIOCSIWAUTH, gelic_wl_set_auth),
+       IW_HANDLER(SIOCGIWAUTH, gelic_wl_get_auth),
+       IW_HANDLER(SIOCSIWESSID, gelic_wl_set_essid),
+       IW_HANDLER(SIOCGIWESSID, gelic_wl_get_essid),
+       IW_HANDLER(SIOCSIWENCODE, gelic_wl_set_encode),
+       IW_HANDLER(SIOCGIWENCODE, gelic_wl_get_encode),
+       IW_HANDLER(SIOCSIWAP, gelic_wl_set_ap),
+       IW_HANDLER(SIOCGIWAP, gelic_wl_get_ap),
+       IW_HANDLER(SIOCSIWENCODEEXT, gelic_wl_set_encodeext),
+       IW_HANDLER(SIOCGIWENCODEEXT, gelic_wl_get_encodeext),
+       IW_HANDLER(SIOCSIWMODE, gelic_wl_set_mode),
+       IW_HANDLER(SIOCGIWMODE, gelic_wl_get_mode),
+       IW_HANDLER(SIOCGIWNICKN, gelic_wl_get_nick),
 };
 
 static const struct iw_handler_def gelic_wl_wext_handler_def = {
@@ -2318,7 +2316,7 @@ static struct net_device * __devinit gelic_wl_alloc(struct gelic_card *card)
        pr_debug("%s:start\n", __func__);
        netdev = alloc_etherdev(sizeof(struct gelic_port) +
                                sizeof(struct gelic_wl_info));
-       pr_debug("%s: netdev =%p card=%p \np", __func__, netdev, card);
+       pr_debug("%s: netdev =%p card=%p\n", __func__, netdev, card);
        if (!netdev)
                return NULL;
 
index 4ef0afbcbe1b1980081aa147330b2e0ec4674dad..54ebb65ada1863ecdc7ff97b15587d6516b1e3c7 100644 (file)
@@ -222,7 +222,6 @@ static void ql_write_common_reg_l(struct ql3_adapter *qdev,
        writel(value, reg);
        readl(reg);
        spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
-       return;
 }
 
 static void ql_write_common_reg(struct ql3_adapter *qdev,
@@ -230,7 +229,6 @@ static void ql_write_common_reg(struct ql3_adapter *qdev,
 {
        writel(value, reg);
        readl(reg);
-       return;
 }
 
 static void ql_write_nvram_reg(struct ql3_adapter *qdev,
@@ -239,7 +237,6 @@ static void ql_write_nvram_reg(struct ql3_adapter *qdev,
        writel(value, reg);
        readl(reg);
        udelay(1);
-       return;
 }
 
 static void ql_write_page0_reg(struct ql3_adapter *qdev,
@@ -249,7 +246,6 @@ static void ql_write_page0_reg(struct ql3_adapter *qdev,
                ql_set_register_page(qdev,0);
        writel(value, reg);
        readl(reg);
-       return;
 }
 
 /*
@@ -262,7 +258,6 @@ static void ql_write_page1_reg(struct ql3_adapter *qdev,
                ql_set_register_page(qdev,1);
        writel(value, reg);
        readl(reg);
-       return;
 }
 
 /*
@@ -275,7 +270,6 @@ static void ql_write_page2_reg(struct ql3_adapter *qdev,
                ql_set_register_page(qdev,2);
        writel(value, reg);
        readl(reg);
-       return;
 }
 
 static void ql_disable_interrupts(struct ql3_adapter *qdev)
@@ -343,8 +337,8 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
                            cpu_to_le32(LS_64BITS(map));
                        lrg_buf_cb->buf_phy_addr_high =
                            cpu_to_le32(MS_64BITS(map));
-                       pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
-                       pci_unmap_len_set(lrg_buf_cb, maplen,
+                       dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+                       dma_unmap_len_set(lrg_buf_cb, maplen,
                                          qdev->lrg_buffer_len -
                                          QL_HEADER_SPACE);
                }
@@ -1924,8 +1918,8 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
                                    cpu_to_le32(LS_64BITS(map));
                                lrg_buf_cb->buf_phy_addr_high =
                                    cpu_to_le32(MS_64BITS(map));
-                               pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
-                               pci_unmap_len_set(lrg_buf_cb, maplen,
+                               dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+                               dma_unmap_len_set(lrg_buf_cb, maplen,
                                                  qdev->lrg_buffer_len -
                                                  QL_HEADER_SPACE);
                                --qdev->lrg_buf_skb_check;
@@ -2041,16 +2035,16 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
        }
 
        pci_unmap_single(qdev->pdev,
-                        pci_unmap_addr(&tx_cb->map[0], mapaddr),
-                        pci_unmap_len(&tx_cb->map[0], maplen),
+                        dma_unmap_addr(&tx_cb->map[0], mapaddr),
+                        dma_unmap_len(&tx_cb->map[0], maplen),
                         PCI_DMA_TODEVICE);
        tx_cb->seg_count--;
        if (tx_cb->seg_count) {
                for (i = 1; i < tx_cb->seg_count; i++) {
                        pci_unmap_page(qdev->pdev,
-                                      pci_unmap_addr(&tx_cb->map[i],
+                                      dma_unmap_addr(&tx_cb->map[i],
                                                      mapaddr),
-                                      pci_unmap_len(&tx_cb->map[i], maplen),
+                                      dma_unmap_len(&tx_cb->map[i], maplen),
                                       PCI_DMA_TODEVICE);
                }
        }
@@ -2119,8 +2113,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
 
        skb_put(skb, length);
        pci_unmap_single(qdev->pdev,
-                        pci_unmap_addr(lrg_buf_cb2, mapaddr),
-                        pci_unmap_len(lrg_buf_cb2, maplen),
+                        dma_unmap_addr(lrg_buf_cb2, mapaddr),
+                        dma_unmap_len(lrg_buf_cb2, maplen),
                         PCI_DMA_FROMDEVICE);
        prefetch(skb->data);
        skb->ip_summed = CHECKSUM_NONE;
@@ -2165,8 +2159,8 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
 
        skb_put(skb2, length);  /* Just the second buffer length here. */
        pci_unmap_single(qdev->pdev,
-                        pci_unmap_addr(lrg_buf_cb2, mapaddr),
-                        pci_unmap_len(lrg_buf_cb2, maplen),
+                        dma_unmap_addr(lrg_buf_cb2, mapaddr),
+                        dma_unmap_len(lrg_buf_cb2, maplen),
                         PCI_DMA_FROMDEVICE);
        prefetch(skb2->data);
 
@@ -2258,7 +2252,7 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
                                       "%x.\n",
                                       ndev->name, net_rsp->opcode);
                                printk(KERN_ERR PFX
-                                      "0x%08lx 0x%08lx 0x%08lx 0x%08lx \n",
+                                      "0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
                                       (unsigned long int)tmp[0],
                                       (unsigned long int)tmp[1],
                                       (unsigned long int)tmp[2],
@@ -2454,8 +2448,8 @@ static int ql_send_map(struct ql3_adapter *qdev,
        oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
        oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
        oal_entry->len = cpu_to_le32(len);
-       pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
-       pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
+       dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+       dma_unmap_len_set(&tx_cb->map[seg], maplen, len);
        seg++;
 
        if (seg_cnt == 1) {
@@ -2488,9 +2482,9 @@ static int ql_send_map(struct ql3_adapter *qdev,
                                oal_entry->len =
                                    cpu_to_le32(sizeof(struct oal) |
                                                OAL_CONT_ENTRY);
-                               pci_unmap_addr_set(&tx_cb->map[seg], mapaddr,
+                               dma_unmap_addr_set(&tx_cb->map[seg], mapaddr,
                                                   map);
-                               pci_unmap_len_set(&tx_cb->map[seg], maplen,
+                               dma_unmap_len_set(&tx_cb->map[seg], maplen,
                                                  sizeof(struct oal));
                                oal_entry = (struct oal_entry *)oal;
                                oal++;
@@ -2512,8 +2506,8 @@ static int ql_send_map(struct ql3_adapter *qdev,
                        oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
                        oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
                        oal_entry->len = cpu_to_le32(frag->size);
-                       pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
-                       pci_unmap_len_set(&tx_cb->map[seg], maplen,
+                       dma_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+                       dma_unmap_len_set(&tx_cb->map[seg], maplen,
                                          frag->size);
                }
                /* Terminate the last segment. */
@@ -2539,22 +2533,22 @@ map_error:
                   (seg == 12 && seg_cnt > 13) ||      /* but necessary. */
                   (seg == 17 && seg_cnt > 18)) {
                        pci_unmap_single(qdev->pdev,
-                               pci_unmap_addr(&tx_cb->map[seg], mapaddr),
-                               pci_unmap_len(&tx_cb->map[seg], maplen),
+                               dma_unmap_addr(&tx_cb->map[seg], mapaddr),
+                               dma_unmap_len(&tx_cb->map[seg], maplen),
                                 PCI_DMA_TODEVICE);
                        oal++;
                        seg++;
                }
 
                pci_unmap_page(qdev->pdev,
-                              pci_unmap_addr(&tx_cb->map[seg], mapaddr),
-                              pci_unmap_len(&tx_cb->map[seg], maplen),
+                              dma_unmap_addr(&tx_cb->map[seg], mapaddr),
+                              dma_unmap_len(&tx_cb->map[seg], maplen),
                               PCI_DMA_TODEVICE);
        }
 
        pci_unmap_single(qdev->pdev,
-                        pci_unmap_addr(&tx_cb->map[0], mapaddr),
-                        pci_unmap_addr(&tx_cb->map[0], maplen),
+                        dma_unmap_addr(&tx_cb->map[0], mapaddr),
+                        dma_unmap_addr(&tx_cb->map[0], maplen),
                         PCI_DMA_TODEVICE);
 
        return NETDEV_TX_BUSY;
@@ -2841,8 +2835,8 @@ static void ql_free_large_buffers(struct ql3_adapter *qdev)
                if (lrg_buf_cb->skb) {
                        dev_kfree_skb(lrg_buf_cb->skb);
                        pci_unmap_single(qdev->pdev,
-                                        pci_unmap_addr(lrg_buf_cb, mapaddr),
-                                        pci_unmap_len(lrg_buf_cb, maplen),
+                                        dma_unmap_addr(lrg_buf_cb, mapaddr),
+                                        dma_unmap_len(lrg_buf_cb, maplen),
                                         PCI_DMA_FROMDEVICE);
                        memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
                } else {
@@ -2912,8 +2906,8 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
                                return -ENOMEM;
                        }
 
-                       pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
-                       pci_unmap_len_set(lrg_buf_cb, maplen,
+                       dma_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+                       dma_unmap_len_set(lrg_buf_cb, maplen,
                                          qdev->lrg_buffer_len -
                                          QL_HEADER_SPACE);
                        lrg_buf_cb->buf_phy_addr_low =
@@ -3793,13 +3787,13 @@ static void ql_reset_work(struct work_struct *work)
                                       "%s: Freeing lost SKB.\n",
                                       qdev->ndev->name);
                                pci_unmap_single(qdev->pdev,
-                                        pci_unmap_addr(&tx_cb->map[0], mapaddr),
-                                        pci_unmap_len(&tx_cb->map[0], maplen),
+                                        dma_unmap_addr(&tx_cb->map[0], mapaddr),
+                                        dma_unmap_len(&tx_cb->map[0], maplen),
                                         PCI_DMA_TODEVICE);
                                for(j=1;j<tx_cb->seg_count;j++) {
                                        pci_unmap_page(qdev->pdev,
-                                              pci_unmap_addr(&tx_cb->map[j],mapaddr),
-                                              pci_unmap_len(&tx_cb->map[j],maplen),
+                                              dma_unmap_addr(&tx_cb->map[j],mapaddr),
+                                              dma_unmap_len(&tx_cb->map[j],maplen),
                                               PCI_DMA_TODEVICE);
                                }
                                dev_kfree_skb(tx_cb->skb);
index 7113e71b15a19ecaebfbf98c2e879045ab5d72a3..3362a661248c61065fa50b12fdee49b0d0591dc0 100644 (file)
@@ -998,8 +998,8 @@ enum link_state_t {
 struct ql_rcv_buf_cb {
        struct ql_rcv_buf_cb *next;
        struct sk_buff *skb;
-        DECLARE_PCI_UNMAP_ADDR(mapaddr);
-        DECLARE_PCI_UNMAP_LEN(maplen);
+       DEFINE_DMA_UNMAP_ADDR(mapaddr);
+       DEFINE_DMA_UNMAP_LEN(maplen);
        __le32 buf_phy_addr_low;
        __le32 buf_phy_addr_high;
        int index;
@@ -1029,8 +1029,8 @@ struct oal {
 };
 
 struct map_list {
-        DECLARE_PCI_UNMAP_ADDR(mapaddr);
-        DECLARE_PCI_UNMAP_LEN(maplen);
+       DEFINE_DMA_UNMAP_ADDR(mapaddr);
+       DEFINE_DMA_UNMAP_LEN(maplen);
 };
 
 struct ql_tx_buf_cb {
index 0da94b208db17ca008ccdecd4e80f3c850d1caf9..896d40df9a134dddb3c470373c3c4f01a44e7976 100644 (file)
@@ -51,8 +51,9 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 0
-#define QLCNIC_LINUX_VERSIONID  "5.0.0"
+#define _QLCNIC_LINUX_SUBVERSION 2
+#define QLCNIC_LINUX_VERSIONID  "5.0.2"
+#define QLCNIC_DRV_IDC_VER  0x01
 
 #define QLCNIC_VERSION_CODE(a, b, c)   (((a) << 24) + ((b) << 16) + (c))
 #define _major(v)      (((v) >> 24) & 0xff)
@@ -98,8 +99,6 @@
 #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 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 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
@@ -399,13 +394,9 @@ struct qlcnic_hardware_context {
 
        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;
@@ -428,6 +419,10 @@ struct qlcnic_adapter_stats {
        u64  xmit_on;
        u64  xmit_off;
        u64  skb_alloc_failure;
+       u64  null_skb;
+       u64  null_rxbuf;
+       u64  rx_dma_map_error;
+       u64  tx_dma_map_error;
 };
 
 /*
@@ -916,14 +911,12 @@ struct qlcnic_adapter {
        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;
 
@@ -958,11 +951,15 @@ struct qlcnic_adapter {
        u8 dev_state;
        u8 diag_test;
        u8 diag_cnt;
+       u8 reset_ack_timeo;
+       u8 dev_init_timeo;
        u8 rsrd1;
-       u16 rsrd2;
+       u16 msg_enable;
 
        u8 mac_addr[ETH_ALEN];
 
+       u64 dev_rst_time;
+
        struct qlcnic_adapter_stats stats;
 
        struct qlcnic_recv_context recv_ctx;
@@ -994,6 +991,11 @@ 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);
+void qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *, u64, u64 *);
+void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
+
+#define ADDR_IN_RANGE(addr, low, high) \
+       (((addr) < (high)) && ((addr) >= (low)))
 
 #define QLCRD32(adapter, off) \
        (qlcnic_hw_read_wx_2M(adapter, off))
@@ -1035,6 +1037,7 @@ 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_setup_idc_param(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,
@@ -1128,4 +1131,11 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
 
 extern const struct ethtool_ops qlcnic_ethtool_ops;
 
+#define QLCDB(adapter, lvl, _fmt, _args...) do {       \
+       if (NETIF_MSG_##lvl & adapter->msg_enable)      \
+               printk(KERN_INFO "%s: %s: " _fmt,       \
+                        dev_name(&adapter->pdev->dev), \
+                       __func__, ##_args);             \
+       } while (0)
+
 #endif                         /* __QLCNIC_H_ */
index 0a6a39914aec7e351c581c1bc348495c14cbb464..c2c1f5cc16c6d992d9d00b3a2ab6b84569335874 100644 (file)
@@ -421,7 +421,8 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
 
        if (addr == NULL) {
                dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto err_out_free;
        }
 
        tx_ring->desc_head = (struct cmd_desc_type0 *)addr;
index f83e15fe3e1b41643e94bcf9dfee09f3640aff67..3bd514ec7e8fe07badf0cde0304a77a50edcc0ee 100644 (file)
@@ -69,6 +69,14 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
                QLC_SIZEOF(stats.xmit_off), QLC_OFF(stats.xmit_off)},
        {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
                QLC_OFF(stats.skb_alloc_failure)},
+       {"null skb",
+               QLC_SIZEOF(stats.null_skb), QLC_OFF(stats.null_skb)},
+       {"null rxbuf",
+               QLC_SIZEOF(stats.null_rxbuf), QLC_OFF(stats.null_rxbuf)},
+       {"rx dma map error", QLC_SIZEOF(stats.rx_dma_map_error),
+                                        QLC_OFF(stats.rx_dma_map_error)},
+       {"tx dma map error", QLC_SIZEOF(stats.tx_dma_map_error),
+                                        QLC_OFF(stats.tx_dma_map_error)},
 
 };
 
@@ -404,7 +412,6 @@ qlcnic_get_ringparam(struct net_device *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) {
@@ -598,19 +605,12 @@ qlcnic_set_pauseparam(struct net_device *netdev,
 static int qlcnic_reg_test(struct net_device *dev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
-       u32 data_read, data_written;
+       u32 data_read;
 
        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;
 }
 
@@ -998,6 +998,20 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data)
        return 0;
 }
 
+static u32 qlcnic_get_msglevel(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       return adapter->msg_enable;
+}
+
+static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+       adapter->msg_enable = msglvl;
+}
+
 const struct ethtool_ops qlcnic_ethtool_ops = {
        .get_settings = qlcnic_get_settings,
        .set_settings = qlcnic_set_settings,
@@ -1029,4 +1043,6 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
        .get_flags = ethtool_op_get_flags,
        .set_flags = qlcnic_set_flags,
        .phys_id = qlcnic_blink_led,
+       .set_msglevel = qlcnic_set_msglevel,
+       .get_msglevel = qlcnic_get_msglevel,
 };
index 0469f84360a411a955be25c8f722dbb99648d538..ad9d167723c4480793a98153c0c3e0319c809ccc 100644 (file)
@@ -435,9 +435,10 @@ enum {
 #define QLCNIC_PCI_MS_2M       (0x80000)
 #define QLCNIC_PCI_OCM0_2M     (0x000c0000UL)
 #define QLCNIC_PCI_CRBSPACE    (0x06000000UL)
+#define QLCNIC_PCI_CAMQM       (0x04800000UL)
+#define QLCNIC_PCI_CAMQM_END   (0x04800800UL)
 #define QLCNIC_PCI_2MB_SIZE    (0x00200000UL)
 #define QLCNIC_PCI_CAMQM_2M_BASE       (0x000ff800UL)
-#define QLCNIC_PCI_CAMQM_2M_END        (0x04800800UL)
 
 #define QLCNIC_CRB_CAM QLCNIC_PCI_CRB_WINDOW(QLCNIC_HW_PX_MAP_CRB_CAM)
 
@@ -448,7 +449,7 @@ enum {
 #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)
+#define QLCNIC_ADDR_QDR_NET_MAX (0x0000000307ffffffULL)
 
 /*
  *   Register offsets for MN
@@ -562,38 +563,15 @@ enum {
 #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
@@ -693,15 +671,24 @@ enum {
 #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_CRB_DRV_IDC_VER         (QLCNIC_CAM_RAM(0x174))
+#define QLCNIC_ROM_DEV_INIT_TIMEOUT    (0x3e885c)
+#define QLCNIC_ROM_DRV_RESET_TIMEOUT   (0x3e8860)
+
+/* Device State */
+#define QLCNIC_DEV_COLD                        0x1
+#define QLCNIC_DEV_INITIALIZING                0x2
+#define QLCNIC_DEV_READY               0x3
+#define QLCNIC_DEV_NEED_RESET          0x4
+#define QLCNIC_DEV_NEED_QUISCENT       0x5
+#define QLCNIC_DEV_FAILED              0x6
+#define QLCNIC_DEV_QUISCENT            0x7
+
+#define QLC_DEV_SET_REF_CNT(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
+#define QLC_DEV_CLR_REF_CNT(VAL, FN)           ((VAL) &= ~(1 << (FN * 4)))
+#define QLC_DEV_SET_RST_RDY(VAL, FN)           ((VAL) |= (1 << (FN * 4)))
+#define QLC_DEV_SET_QSCNT_RDY(VAL, FN)         ((VAL) |= (2 << (FN * 4)))
+#define QLC_DEV_CLR_RST_QSCNT(VAL, FN)         ((VAL) &= ~(3 << (FN * 4)))
 
 #define QLCNIC_RCODE_DRIVER_INFO               0x20000000
 #define QLCNIC_RCODE_DRIVER_CAN_RELOAD         0x40000000
@@ -709,9 +696,8 @@ enum {
 #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 FW_POLL_DELAY          (1 * HZ)
+#define FW_FAIL_THRESH         2
 
 #define        ISR_MSI_INT_TRIGGER(FUNC) (QLCNIC_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
 #define ISR_LEGACY_INT_TRIGGERED(VAL)  (((VAL) & 0x300) == 0x200)
index e73ba455aa204c43c1a2d4ec02a1ba1106370247..0c2e1f08f4593af61350bf4bcd4d45452a27f4f4 100644 (file)
@@ -54,21 +54,6 @@ static inline void writeq(u64 val, void __iomem *addr)
 }
 #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 */
@@ -310,8 +295,12 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
                done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
                if (done == 1)
                        break;
-               if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT)
+               if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
+                       dev_err(&adapter->pdev->dev,
+                               "Failed to acquire sem=%d lock;reg_id=%d\n",
+                               sem, id_reg);
                        return -EIO;
+               }
                msleep(1);
        }
 
@@ -427,7 +416,7 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr)
 void qlcnic_set_multi(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        u32 mode = VPORT_MISS_MODE_DROP;
 
@@ -449,8 +438,8 @@ void qlcnic_set_multi(struct net_device *netdev)
        }
 
        if (!netdev_mc_empty(netdev)) {
-               netdev_for_each_mc_addr(mc_ptr, netdev) {
-                       qlcnic_nic_add_mac(adapter, mc_ptr->dmi_addr);
+               netdev_for_each_mc_addr(ha, netdev) {
+                       qlcnic_nic_add_mac(adapter, ha->addr);
                }
        }
 
@@ -787,9 +776,6 @@ qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
 
        window = CRB_HI(off);
 
-       if (adapter->ahw.crb_win == window)
-               return;
-
        writel(window, addr);
        if (readl(addr) != window) {
                if (printk_ratelimit())
@@ -797,7 +783,6 @@ qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
                                "failed to set CRB window to %d off 0x%lx\n",
                                window, off);
        }
-       adapter->ahw.crb_win = window;
 }
 
 int
@@ -878,13 +863,6 @@ 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);
 
@@ -892,7 +870,6 @@ qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter,
        /* 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;
 }
@@ -901,8 +878,7 @@ 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;
+       void __iomem *addr;
        int ret;
        u32 start;
 
@@ -912,21 +888,8 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
        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 = adapter->ahw.pci_base0 + start;
 
-       addr = mem_ptr + (start & (PAGE_SIZE - 1));
-
-noremap:
        if (op == 0)    /* read */
                *data = readq(addr);
        else            /* write */
@@ -935,11 +898,31 @@ noremap:
 unlock:
        mutex_unlock(&adapter->ahw.mem_lock);
 
-       if (mem_ptr)
-               iounmap(mem_ptr);
        return ret;
 }
 
+void
+qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
+{
+       void __iomem *addr = adapter->ahw.pci_base0 +
+               QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
+
+       mutex_lock(&adapter->ahw.mem_lock);
+       *data = readq(addr);
+       mutex_unlock(&adapter->ahw.mem_lock);
+}
+
+void
+qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
+{
+       void __iomem *addr = adapter->ahw.pci_base0 +
+               QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
+
+       mutex_lock(&adapter->ahw.mem_lock);
+       writeq(data, addr);
+       mutex_unlock(&adapter->ahw.mem_lock);
+}
+
 #define MAX_CTL_CHECK   1000
 
 int
@@ -948,7 +931,6 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
 {
        int i, j, ret;
        u32 temp, off8;
-       u64 stride;
        void __iomem *mem_crb;
 
        /* Only 64-bit aligned access */
@@ -957,7 +939,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
 
        /* 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)) {
+                               QLCNIC_ADDR_QDR_NET_MAX)) {
                mem_crb = qlcnic_get_ioaddr(adapter,
                                QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
                goto correct;
@@ -975,9 +957,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
        return -EIO;
 
 correct:
-       stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
-
-       off8 = off & ~(stride-1);
+       off8 = off & ~0xf;
 
        mutex_lock(&adapter->ahw.mem_lock);
 
@@ -985,30 +965,28 @@ correct:
        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;
-               }
+       writel(TA_CTL_ENABLE, (mem_crb + TEST_AGT_CTRL));
+       writel((TA_CTL_START | TA_CTL_ENABLE),
+                       (mem_crb + TEST_AGT_CTRL));
 
-               if (j >= MAX_CTL_CHECK) {
-                       ret = -EIO;
-                       goto done;
-               }
+       for (j = 0; j < MAX_CTL_CHECK; j++) {
+               temp = readl(mem_crb + TEST_AGT_CTRL);
+               if ((temp & TA_CTL_BUSY) == 0)
+                       break;
+       }
 
-               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;
+       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,
@@ -1044,7 +1022,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
 {
        int j, ret;
        u32 temp, off8;
-       u64 val, stride;
+       u64 val;
        void __iomem *mem_crb;
 
        /* Only 64-bit aligned access */
@@ -1053,7 +1031,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
 
        /* 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)) {
+                               QLCNIC_ADDR_QDR_NET_MAX)) {
                mem_crb = qlcnic_get_ioaddr(adapter,
                                QLCNIC_CRB_QDR_NET+MIU_TEST_AGT_BASE);
                goto correct;
@@ -1073,9 +1051,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
        return -EIO;
 
 correct:
-       stride = QLCNIC_IS_REVISION_P3P(adapter->ahw.revision_id) ? 16 : 8;
-
-       off8 = off & ~(stride-1);
+       off8 = off & ~0xf;
 
        mutex_lock(&adapter->ahw.mem_lock);
 
@@ -1097,7 +1073,7 @@ correct:
                ret = -EIO;
        } else {
                off8 = MIU_TEST_AGT_RDDATA_LO;
-               if ((stride == 16) && (off & 0xf))
+               if (off & 0xf)
                        off8 = MIU_TEST_AGT_RDDATA_UPPER_LO;
 
                temp = readl(mem_crb + off8 + 4);
index 9d2c124048fa3934fadf15b68fcf3278e6dc5824..71a4e664ad76970d920c669f3fa8366f92ca62fa 100644 (file)
@@ -210,7 +210,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
        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;
+               goto err_out;
        }
        memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
        tx_ring->cmd_buf_arr = cmd_buf_arr;
@@ -221,7 +221,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
        rds_ring = kzalloc(size, GFP_KERNEL);
        if (rds_ring == NULL) {
                dev_err(&netdev->dev, "failed to allocate rds ring struct\n");
-               return -ENOMEM;
+               goto err_out;
        }
        recv_ctx->rds_rings = rds_ring;
 
@@ -230,17 +230,8 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
                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;
-                       }
+                       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:
@@ -254,13 +245,6 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
                        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));
@@ -530,6 +514,36 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        return 0;
 }
 
+int
+qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
+
+       int timeo;
+       u32 val;
+
+       val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+       val = (val >> (adapter->portnum * 4)) & 0xf;
+
+       if ((val & 0x3) != 1) {
+               dev_err(&adapter->pdev->dev, "Not an Ethernet NIC func=%u\n",
+                                                                       val);
+               return -EIO;
+       }
+
+       adapter->physical_port = (val >> 2);
+
+       if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
+               timeo = 30;
+
+       adapter->dev_init_timeo = timeo;
+
+       if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DRV_RESET_TIMEOUT, &timeo))
+               timeo = 10;
+
+       adapter->reset_ack_timeo = timeo;
+
+       return 0;
+}
+
 static int
 qlcnic_has_mn(struct qlcnic_adapter *adapter)
 {
@@ -540,12 +554,10 @@ qlcnic_has_mn(struct qlcnic_adapter *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;
 
-               capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
-               if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
-                       return 1;
-       }
        return 0;
 }
 
@@ -612,7 +624,7 @@ qlcnic_validate_bootld(struct qlcnic_adapter *adapter)
                return -EINVAL;
 
        tab_size = cpu_to_le32(tab_desc->findex) +
-                       (cpu_to_le32(tab_desc->entry_size * (idx + 1)));
+                       (cpu_to_le32(tab_desc->entry_size) * (idx + 1));
 
        if (adapter->fw->size < tab_size)
                return -EINVAL;
@@ -621,7 +633,7 @@ qlcnic_validate_bootld(struct qlcnic_adapter *adapter)
                (cpu_to_le32(tab_desc->entry_size) * (idx));
        descr = (struct uni_data_desc *)&unirom[offs];
 
-       data_size = descr->findex + cpu_to_le32(descr->size);
+       data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
 
        if (adapter->fw->size < data_size)
                return -EINVAL;
@@ -647,7 +659,7 @@ qlcnic_validate_fw(struct qlcnic_adapter *adapter)
                return -EINVAL;
 
        tab_size = cpu_to_le32(tab_desc->findex) +
-                       (cpu_to_le32(tab_desc->entry_size * (idx + 1)));
+                       (cpu_to_le32(tab_desc->entry_size) * (idx + 1));
 
        if (adapter->fw->size < tab_size)
                return -EINVAL;
@@ -655,7 +667,7 @@ qlcnic_validate_fw(struct qlcnic_adapter *adapter)
        offs = cpu_to_le32(tab_desc->findex) +
                (cpu_to_le32(tab_desc->entry_size) * (idx));
        descr = (struct uni_data_desc *)&unirom[offs];
-       data_size = descr->findex + cpu_to_le32(descr->size);
+       data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
 
        if (adapter->fw->size < data_size)
                return -EINVAL;
@@ -950,6 +962,16 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter)
 
                        flashaddr += 8;
                }
+
+               size = (__force u32)qlcnic_get_fw_size(adapter) % 8;
+               if (size) {
+                       data = cpu_to_le64(ptr64[i]);
+
+                       if (qlcnic_pci_mem_write_2M(adapter,
+                                               flashaddr, data))
+                               return -EIO;
+               }
+
        } else {
                u64 data;
                u32 hi, lo;
@@ -1162,9 +1184,6 @@ int qlcnic_init_firmware(struct qlcnic_adapter *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;
@@ -1254,13 +1273,13 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
 
        skb = buffer->skb;
 
-       if (!adapter->ahw.cut_through)
-               skb_reserve(skb, 2);
+       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)) {
+               adapter->stats.rx_dma_map_error++;
                dev_kfree_skb_any(skb);
                buffer->skb = NULL;
                return -ENOMEM;
@@ -1285,8 +1304,10 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
                        PCI_DMA_FROMDEVICE);
 
        skb = buffer->skb;
-       if (!skb)
+       if (!skb) {
+               adapter->stats.null_skb++;
                goto no_skb;
+       }
 
        if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
                adapter->stats.csummed++;
@@ -1476,6 +1497,8 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
 
                if (rxbuf)
                        list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+               else
+                       adapter->stats.null_rxbuf++;
 
 skip:
                for (; desc_cnt > 0; desc_cnt--) {
@@ -1523,9 +1546,10 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
        int producer, count = 0;
        struct list_head *head;
 
+       spin_lock(&rds_ring->lock);
+
        producer = rds_ring->producer;
 
-       spin_lock(&rds_ring->lock);
        head = &rds_ring->free_list;
        while (!list_empty(head)) {
 
@@ -1547,13 +1571,13 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
 
                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);
        }
+       spin_unlock(&rds_ring->lock);
 }
 
 static void
@@ -1565,10 +1589,11 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
        int producer, count = 0;
        struct list_head *head;
 
-       producer = rds_ring->producer;
        if (!spin_trylock(&rds_ring->lock))
                return;
 
+       producer = rds_ring->producer;
+
        head = &rds_ring->free_list;
        while (!list_empty(head)) {
 
index 234dab1f99823c588e2532ba6ea0a6e35ed6a8e0..1003eb76fda33ed88a3ad53040f2eae6fe15cfcc 100644 (file)
@@ -61,6 +61,10 @@ 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 load_fw_file;
+module_param(load_fw_file, int, 0644);
+MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
+
 static int __devinit qlcnic_probe(struct pci_dev *pdev,
                const struct pci_device_id *ent);
 static void __devexit qlcnic_remove(struct pci_dev *pdev);
@@ -84,6 +88,7 @@ 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_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
 static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter);
 static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
 
@@ -208,6 +213,9 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter)
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
 
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
                napi_enable(&sds_ring->napi);
@@ -222,6 +230,9 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter)
        struct qlcnic_host_sds_ring *sds_ring;
        struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
 
+       if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+               return;
+
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
                qlcnic_disable_int(sds_ring);
@@ -233,67 +244,6 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter)
 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)
@@ -512,13 +462,6 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
        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);
@@ -556,7 +499,9 @@ static void get_brd_name(struct qlcnic_adapter *adapter, char *name)
                        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);
+                               sprintf(name, "%pM: %s" ,
+                                       adapter->mac_addr,
+                                       qlcnic_boards[i].short_name);
                                found = 1;
                                break;
                }
@@ -605,22 +550,10 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                                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");
+       dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
+                       fw_major, fw_minor, fw_build);
 
-       if (adapter->fw_version >= QLCNIC_VERSION_CODE(4, 0, 222))
-               adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+       adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
 
        adapter->flags &= ~QLCNIC_LRO_ENABLED;
 
@@ -637,7 +570,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 
        adapter->num_txd = MAX_CMD_DESCRIPTORS;
 
-       adapter->num_lro_rxd = 0;
        adapter->max_rds_rings = 2;
 }
 
@@ -646,11 +578,10 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
 {
        int val, err, first_boot;
 
-       err = qlcnic_set_dma_mask(adapter);
-       if (err)
+       err = qlcnic_can_start_firmware(adapter);
+       if (err < 0)
                return err;
-
-       if (!qlcnic_can_start_firmware(adapter))
+       else if (!err)
                goto wait_init;
 
        first_boot = QLCRD32(adapter, QLCNIC_CAM_RAM(0x1fc));
@@ -658,7 +589,10 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
                /* This is the first boot after power up */
                QLCWR32(adapter, QLCNIC_CAM_RAM(0x1fc), QLCNIC_BDINFO_MAGIC);
 
-       qlcnic_request_firmware(adapter);
+       if (load_fw_file)
+               qlcnic_request_firmware(adapter);
+       else
+               adapter->fw_type = QLCNIC_FLASH_ROMIMAGE;
 
        err = qlcnic_need_fw_reset(adapter);
        if (err < 0)
@@ -672,7 +606,6 @@ qlcnic_start_firmware(struct qlcnic_adapter *adapter)
                msleep(1);
        }
 
-       QLCWR32(adapter, CRB_DMA_SHIFT, 0x55555555);
        QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS1, 0);
        QLCWR32(adapter, QLCNIC_PEG_HALT_STATUS2, 0);
 
@@ -696,16 +629,18 @@ wait_init:
                goto err_out;
 
        QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
-
-       qlcnic_update_dma_mask(adapter);
+       qlcnic_idc_debug_info(adapter, 1);
 
        qlcnic_check_options(adapter);
 
        adapter->need_fw_reset = 0;
 
-       /* fall through and release firmware */
+       qlcnic_release_firmware(adapter);
+       return 0;
 
 err_out:
+       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_FAILED);
+       dev_err(&adapter->pdev->dev, "Device state set to failed\n");
        qlcnic_release_firmware(adapter);
        return err;
 }
@@ -937,6 +872,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        struct qlcnic_host_sds_ring *sds_ring;
        int ring;
 
+       clear_bit(__QLCNIC_DEV_UP, &adapter->state);
        if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                        sds_ring = &adapter->recv_ctx.sds_rings[ring];
@@ -950,11 +886,11 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
        adapter->max_sds_rings = max_sds_rings;
 
        if (qlcnic_attach(adapter))
-               return;
+               goto out;
 
        if (netif_running(netdev))
                __qlcnic_up(adapter, netdev);
-
+out:
        netif_device_attach(netdev);
 }
 
@@ -976,8 +912,10 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
        adapter->diag_test = test;
 
        ret = qlcnic_attach(adapter);
-       if (ret)
+       if (ret) {
+               netif_device_attach(netdev);
                return ret;
+       }
 
        if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
                for (ring = 0; ring < adapter->max_sds_rings; ring++) {
@@ -985,6 +923,7 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
                        qlcnic_enable_int(sds_ring);
                }
        }
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
 
        return 0;
 }
@@ -1010,23 +949,19 @@ qlcnic_reset_context(struct qlcnic_adapter *adapter)
                if (netif_running(netdev)) {
                        err = qlcnic_attach(adapter);
                        if (!err)
-                               err = __qlcnic_up(adapter, netdev);
-
-                       if (err)
-                               goto done;
+                               __qlcnic_up(adapter, netdev);
                }
 
                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)
+               struct net_device *netdev, u8 pci_using_dac)
 {
        int err;
        struct pci_dev *pdev = adapter->pdev;
@@ -1049,7 +984,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
        netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
 
-       if (adapter->pci_using_dac) {
+       if (pci_using_dac) {
                netdev->features |= NETIF_F_HIGHDMA;
                netdev->vlan_features |= NETIF_F_HIGHDMA;
        }
@@ -1079,6 +1014,22 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        return 0;
 }
 
+static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
+{
+       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 if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) &&
+                       !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+               *pci_using_dac = 0;
+       else {
+               dev_err(&pdev->dev, "Unable to set DMA mask, aborting\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static int __devinit
 qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -1087,6 +1038,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        int err;
        int pci_func_id = PCI_FUNC(pdev->devfn);
        uint8_t revision_id;
+       uint8_t pci_using_dac;
 
        err = pci_enable_device(pdev);
        if (err)
@@ -1097,6 +1049,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_disable_pdev;
        }
 
+       err = qlcnic_set_dma_mask(pdev, &pci_using_dac);
+       if (err)
+               goto err_out_disable_pdev;
+
        err = pci_request_regions(pdev, qlcnic_driver_name);
        if (err)
                goto err_out_disable_pdev;
@@ -1115,6 +1071,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter = netdev_priv(netdev);
        adapter->netdev  = netdev;
        adapter->pdev    = pdev;
+       adapter->dev_rst_time = jiffies;
        adapter->ahw.pci_func  = pci_func_id;
 
        revision_id = pdev->revision;
@@ -1139,21 +1096,23 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_out_iounmap;
        }
 
+       if (qlcnic_read_mac_addr(adapter))
+               dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+       if (qlcnic_setup_idc_param(adapter))
+               goto err_out_iounmap;
 
        err = qlcnic_start_firmware(adapter);
-       if (err)
+       if (err) {
+               dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
                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);
+       err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
        if (err)
                goto err_out_disable_msi;
 
@@ -1304,9 +1263,6 @@ qlcnic_resume(struct pci_dev *pdev)
        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");
@@ -1334,6 +1290,7 @@ err_out_detach:
        qlcnic_detach(adapter);
 err_out:
        qlcnic_clr_all_drv_state(adapter);
+       netif_device_attach(netdev);
        return err;
 }
 #endif
@@ -1570,6 +1527,11 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        int frag_count, no_of_desc;
        u32 num_txd = tx_ring->num_desc;
 
+       if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+               netif_stop_queue(netdev);
+               return NETDEV_TX_BUSY;
+       }
+
        frag_count = skb_shinfo(skb)->nr_frags + 1;
 
        /* 4 fragments per cmd des */
@@ -1586,8 +1548,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        pdev = adapter->pdev;
 
-       if (qlcnic_map_tx_skb(pdev, skb, pbuf))
+       if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
+               adapter->stats.tx_dma_map_error++;
                goto drop_packet;
+       }
 
        pbuf->skb = skb;
        pbuf->frag_count = frag_count;
@@ -1739,6 +1703,7 @@ static void qlcnic_tx_timeout_task(struct work_struct *work)
 request_reset:
        adapter->need_fw_reset = 1;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
+       QLCDB(adapter, DRV, "Resetting adapter\n");
 }
 
 static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
@@ -1750,7 +1715,7 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
 
        stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
        stats->tx_packets = adapter->stats.xmitfinished;
-       stats->rx_bytes = adapter->stats.rxbytes;
+       stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes;
        stats->tx_bytes = adapter->stats.txbytes;
        stats->rx_dropped = adapter->stats.rxdropped;
        stats->tx_dropped = adapter->stats.txdropped;
@@ -1944,7 +1909,20 @@ static void qlcnic_poll_controller(struct net_device *netdev)
 #endif
 
 static void
-qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
+qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding)
+{
+       u32 val;
+
+       val = adapter->portnum & 0xf;
+       val |= encoding << 7;
+       val |= (jiffies - adapter->dev_rst_time) << 8;
+
+       QLCWR32(adapter, QLCNIC_CRB_DRV_SCRATCH, val);
+       adapter->dev_rst_time = jiffies;
+}
+
+static int
+qlcnic_set_drv_state(struct qlcnic_adapter *adapter, u8 state)
 {
        u32  val;
 
@@ -1952,18 +1930,20 @@ qlcnic_set_drv_state(struct qlcnic_adapter *adapter, int state)
                        state != QLCNIC_DEV_NEED_QUISCENT);
 
        if (qlcnic_api_lock(adapter))
-               return ;
+               return -EIO;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
 
        if (state == QLCNIC_DEV_NEED_RESET)
-               val |= ((u32)0x1 << (adapter->portnum * 4));
+               QLC_DEV_SET_RST_RDY(val, adapter->portnum);
        else if (state == QLCNIC_DEV_NEED_QUISCENT)
-               val |= ((u32)0x1 << ((adapter->portnum * 4) + 1));
+               QLC_DEV_SET_QSCNT_RDY(val, adapter->portnum);
 
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
+
+       return 0;
 }
 
 static int
@@ -1975,7 +1955,7 @@ qlcnic_clr_drv_state(struct qlcnic_adapter *adapter)
                return -EBUSY;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       val &= ~((u32)0x3 << (adapter->portnum * 4));
+       QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
@@ -1992,14 +1972,14 @@ qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter)
                goto err;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
-       val &= ~((u32)0x1 << (adapter->portnum * 4));
+       QLC_DEV_CLR_REF_CNT(val, adapter->portnum);
        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));
+       QLC_DEV_CLR_RST_QSCNT(val, adapter->portnum);
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
        qlcnic_api_unlock(adapter);
@@ -2009,6 +1989,7 @@ err:
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 }
 
+/* Grab api lock, before checking state */
 static int
 qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
 {
@@ -2024,73 +2005,103 @@ qlcnic_check_drv_state(struct qlcnic_adapter *adapter)
                return 1;
 }
 
+static int qlcnic_check_idc_ver(struct qlcnic_adapter *adapter)
+{
+       u32 val = QLCRD32(adapter, QLCNIC_CRB_DRV_IDC_VER);
+
+       if (val != QLCNIC_DRV_IDC_VER) {
+               dev_warn(&adapter->pdev->dev, "IDC Version mismatch, driver's"
+                       " idc ver = %x; reqd = %x\n", QLCNIC_DRV_IDC_VER, val);
+       }
+
+       return 0;
+}
+
 static int
 qlcnic_can_start_firmware(struct qlcnic_adapter *adapter)
 {
        u32 val, prev_state;
-       int cnt = 0;
-       int portnum = adapter->portnum;
+       u8 dev_init_timeo = adapter->dev_init_timeo;
+       u8 portnum = adapter->portnum;
+       u8 ret;
+
+       if (test_and_clear_bit(__QLCNIC_START_FW, &adapter->state))
+               return 1;
 
        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));
+       if (!(val & (1 << (portnum * 4)))) {
+               QLC_DEV_SET_REF_CNT(val, portnum);
                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);
+       QLCDB(adapter, HW, "Device state = %u\n", prev_state);
 
        switch (prev_state) {
        case QLCNIC_DEV_COLD:
-start_fw:
-               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITALIZING);
+               QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_INITIALIZING);
+               QLCWR32(adapter, QLCNIC_CRB_DRV_IDC_VER, QLCNIC_DRV_IDC_VER);
+               qlcnic_idc_debug_info(adapter, 0);
                qlcnic_api_unlock(adapter);
                return 1;
 
        case QLCNIC_DEV_READY:
+               ret = qlcnic_check_idc_ver(adapter);
                qlcnic_api_unlock(adapter);
-               return 0;
+               return ret;
 
        case QLCNIC_DEV_NEED_RESET:
                val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-               val |= ((u32)0x1 << (portnum * 4));
+               QLC_DEV_SET_RST_RDY(val, portnum);
                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));
+               QLC_DEV_SET_QSCNT_RDY(val, portnum);
                QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
                break;
 
        case QLCNIC_DEV_FAILED:
+               dev_err(&adapter->pdev->dev, "Device in failed state.\n");
                qlcnic_api_unlock(adapter);
                return -1;
+
+       case QLCNIC_DEV_INITIALIZING:
+       case QLCNIC_DEV_QUISCENT:
+               break;
        }
 
        qlcnic_api_unlock(adapter);
-       msleep(1000);
-       while ((QLCRD32(adapter, QLCNIC_CRB_DEV_STATE) != QLCNIC_DEV_READY) &&
-                       ++cnt < 20)
+
+       do {
                msleep(1000);
+               prev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+               if (prev_state == QLCNIC_DEV_QUISCENT)
+                       continue;
+       } while ((prev_state != QLCNIC_DEV_READY) && --dev_init_timeo);
 
-       if (cnt >= 20)
+       if (!dev_init_timeo) {
+               dev_err(&adapter->pdev->dev,
+                       "Waiting for device to initialize timeout\n");
                return -1;
+       }
 
        if (qlcnic_api_lock(adapter))
                return -1;
 
        val = QLCRD32(adapter, QLCNIC_CRB_DRV_STATE);
-       val &= ~((u32)0x3 << (portnum * 4));
+       QLC_DEV_CLR_RST_QSCNT(val, portnum);
        QLCWR32(adapter, QLCNIC_CRB_DRV_STATE, val);
 
+       ret = qlcnic_check_idc_ver(adapter);
        qlcnic_api_unlock(adapter);
 
-       return 0;
+       return ret;
 }
 
 static void
@@ -2098,44 +2109,84 @@ qlcnic_fwinit_work(struct work_struct *work)
 {
        struct qlcnic_adapter *adapter = container_of(work,
                        struct qlcnic_adapter, fw_work.work);
-       int dev_state;
+       u32 dev_state = 0xf;
 
-       if (++adapter->fw_wait_cnt > FW_POLL_THRESH)
+       if (qlcnic_api_lock(adapter))
                goto err_ret;
 
-       if (test_bit(__QLCNIC_START_FW, &adapter->state)) {
+       dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       if (dev_state ==  QLCNIC_DEV_QUISCENT) {
+               qlcnic_api_unlock(adapter);
+               qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+                                               FW_POLL_DELAY * 2);
+               return;
+       }
+
+       if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
+               dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
+                                       adapter->reset_ack_timeo);
+               goto skip_ack_check;
+       }
+
+       if (!qlcnic_check_drv_state(adapter)) {
+skip_ack_check:
+               dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
-               if (qlcnic_check_drv_state(adapter)) {
-                       qlcnic_schedule_work(adapter,
-                                       qlcnic_fwinit_work, FW_POLL_DELAY);
+               if (dev_state == QLCNIC_DEV_NEED_QUISCENT) {
+                       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                               QLCNIC_DEV_QUISCENT);
+                       qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+                                               FW_POLL_DELAY * 2);
+                       QLCDB(adapter, DRV, "Quiscing the driver\n");
+                       qlcnic_idc_debug_info(adapter, 0);
+
+                       qlcnic_api_unlock(adapter);
                        return;
                }
 
+               if (dev_state == QLCNIC_DEV_NEED_RESET) {
+                       QLCWR32(adapter, QLCNIC_CRB_DEV_STATE,
+                                               QLCNIC_DEV_INITIALIZING);
+                       set_bit(__QLCNIC_START_FW, &adapter->state);
+                       QLCDB(adapter, DRV, "Restarting fw\n");
+                       qlcnic_idc_debug_info(adapter, 0);
+               }
+
+               qlcnic_api_unlock(adapter);
+
                if (!qlcnic_start_firmware(adapter)) {
                        qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
                        return;
                }
-
                goto err_ret;
        }
 
+       qlcnic_api_unlock(adapter);
+
        dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+       QLCDB(adapter, HW, "Func waiting: Device state=%u\n", 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_QUISCENT:
+       case QLCNIC_DEV_NEED_QUISCENT:
+       case QLCNIC_DEV_NEED_RESET:
+               qlcnic_schedule_work(adapter,
+                       qlcnic_fwinit_work, FW_POLL_DELAY);
+               return;
        case QLCNIC_DEV_FAILED:
                break;
 
        default:
-               qlcnic_schedule_work(adapter,
-                       qlcnic_fwinit_work, 2 * FW_POLL_DELAY);
-               return;
+               if (!qlcnic_start_firmware(adapter)) {
+                       qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
+                       return;
+               }
        }
 
 err_ret:
+       dev_err(&adapter->pdev->dev, "Fwinit work failed state=%u "
+               "fw_wait_cnt=%u\n", dev_state, adapter->fw_wait_cnt);
+       netif_device_attach(adapter->netdev);
        qlcnic_clr_all_drv_state(adapter);
 }
 
@@ -2163,7 +2214,8 @@ qlcnic_detach_work(struct work_struct *work)
        if (adapter->temp == QLCNIC_TEMP_PANIC)
                goto err_ret;
 
-       qlcnic_set_drv_state(adapter, adapter->dev_state);
+       if (qlcnic_set_drv_state(adapter, adapter->dev_state))
+               goto err_ret;
 
        adapter->fw_wait_cnt = 0;
 
@@ -2172,10 +2224,14 @@ qlcnic_detach_work(struct work_struct *work)
        return;
 
 err_ret:
+       dev_err(&adapter->pdev->dev, "detach failed; status=%d temp=%d\n",
+                       status, adapter->temp);
+       netif_device_attach(netdev);
        qlcnic_clr_all_drv_state(adapter);
 
 }
 
+/*Transit to RESET state from READY state only */
 static void
 qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 {
@@ -2186,9 +2242,10 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
 
        state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
 
-       if (state != QLCNIC_DEV_INITALIZING && state != QLCNIC_DEV_NEED_RESET) {
+       if (state == QLCNIC_DEV_READY) {
                QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_NEED_RESET);
-               set_bit(__QLCNIC_START_FW, &adapter->state);
+               QLCDB(adapter, DRV, "NEED_RESET state set\n");
+               qlcnic_idc_debug_info(adapter, 0);
        }
 
        qlcnic_api_unlock(adapter);
@@ -2233,9 +2290,8 @@ qlcnic_attach_work(struct work_struct *work)
                qlcnic_config_indev_addr(netdev, NETDEV_UP);
        }
 
-       netif_device_attach(netdev);
-
 done:
+       netif_device_attach(netdev);
        adapter->fw_fail_cnt = 0;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
 
@@ -2253,10 +2309,8 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
        if (qlcnic_check_temp(adapter))
                goto detach;
 
-       if (adapter->need_fw_reset) {
+       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)
@@ -2285,8 +2339,11 @@ detach:
                QLCNIC_DEV_NEED_RESET;
 
        if ((auto_fw_reset == AUTO_FW_RESET_ENABLED) &&
-                       !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+               !test_and_set_bit(__QLCNIC_RESETTING, &adapter->state)) {
+
                qlcnic_schedule_work(adapter, qlcnic_detach_work, 0);
+               QLCDB(adapter, DRV, "fw recovery scheduled.\n");
+       }
 
        return 1;
 }
@@ -2387,14 +2444,21 @@ static int
 qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
                loff_t offset, size_t size)
 {
+       size_t crb_size = 4;
+
        if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
                return -EIO;
 
-       if ((size != 4) || (offset & 0x3))
-               return  -EINVAL;
+       if (offset < QLCNIC_PCI_CRBSPACE) {
+               if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
+                                       QLCNIC_PCI_CAMQM_END))
+                       crb_size = 8;
+               else
+                       return -EINVAL;
+       }
 
-       if (offset < QLCNIC_PCI_CRBSPACE)
-               return -EINVAL;
+       if ((size != crb_size) || (offset & (crb_size-1)))
+               return  -EINVAL;
 
        return 0;
 }
@@ -2406,14 +2470,20 @@ qlcnic_sysfs_read_crb(struct kobject *kobj, struct bin_attribute *attr,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       data = QLCRD32(adapter, offset);
-       memcpy(buf, &data, size);
+       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+               qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
+               memcpy(buf, &qmdata, size);
+       } else {
+               data = QLCRD32(adapter, offset);
+               memcpy(buf, &data, size);
+       }
        return size;
 }
 
@@ -2424,14 +2494,20 @@ qlcnic_sysfs_write_crb(struct kobject *kobj, struct bin_attribute *attr,
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       memcpy(&data, buf, size);
-       QLCWR32(adapter, offset, data);
+       if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+               memcpy(&qmdata, buf, size);
+               qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
+       } else {
+               memcpy(&data, buf, size);
+               QLCWR32(adapter, offset, data);
+       }
        return size;
 }
 
@@ -2553,24 +2629,12 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 
 #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;
@@ -2591,7 +2655,6 @@ qlcnic_config_indev_addr(struct net_device *dev, unsigned long event)
        } endfor_ifa(indev);
 
        in_dev_put(indev);
-       return;
 }
 
 static int qlcnic_netdev_event(struct notifier_block *this,
@@ -2650,7 +2713,7 @@ recheck:
 
        adapter = netdev_priv(dev);
 
-       if (!adapter || !qlcnic_destip_supported(adapter))
+       if (!adapter)
                goto done;
 
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
index 8b742b639ceba5c19d0af01346f82e48fa6c7e8e..20624ba44a37be2bad8f37206588f29b63bd24ce 100644 (file)
@@ -1344,8 +1344,8 @@ struct oal {
 };
 
 struct map_list {
-       DECLARE_PCI_UNMAP_ADDR(mapaddr);
-       DECLARE_PCI_UNMAP_LEN(maplen);
+       DEFINE_DMA_UNMAP_ADDR(mapaddr);
+       DEFINE_DMA_UNMAP_LEN(maplen);
 };
 
 struct tx_ring_desc {
@@ -1373,8 +1373,8 @@ struct bq_desc {
        } p;
        __le64 *addr;
        u32 index;
-        DECLARE_PCI_UNMAP_ADDR(mapaddr);
-        DECLARE_PCI_UNMAP_LEN(maplen);
+       DEFINE_DMA_UNMAP_ADDR(mapaddr);
+       DEFINE_DMA_UNMAP_LEN(maplen);
 };
 
 #define QL_TXQ_IDX(qdev, skb) (smp_processor_id()%(qdev->tx_ring_count))
index 3626646289376c6b5940774ee8868818ad60bc3a..68a1c9b91e74d199fbb6a4cce1a604ef09eea230 100644 (file)
@@ -1340,7 +1340,7 @@ void ql_mpi_core_to_log(struct work_struct *work)
 
        for (i = 0; i < count; i += 8) {
                printk(KERN_ERR "%.08x: %.08x %.08x %.08x %.08x %.08x "
-                       "%.08x %.08x %.08x \n", i,
+                       "%.08x %.08x %.08x\n", i,
                        tmp[i + 0],
                        tmp[i + 1],
                        tmp[i + 2],
@@ -2058,7 +2058,7 @@ void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb)
               ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_LSO ? "LSO" : "",
               ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_UC ? "UC" : "",
               ob_mac_tso_iocb->flags2 & OB_MAC_TSO_IOCB_TC ? "TC" : "");
-       printk(KERN_ERR PFX "flags3          = %s %s %s \n",
+       printk(KERN_ERR PFX "flags3          = %s %s %s\n",
               ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_IC ? "IC" : "",
               ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_DFP ? "DFP" : "",
               ob_mac_tso_iocb->flags3 & OB_MAC_TSO_IOCB_V ? "V" : "");
index 7e09ff4a57554d72bd546356c654db5aa7aaa401..4892d64f4e054b2a630a13f2249f6ca1be7f83cb 100644 (file)
@@ -181,8 +181,6 @@ quit:
        spin_unlock(&qdev->stats_lock);
 
        QL_DUMP_STAT(qdev);
-
-       return;
 }
 
 static char ql_stats_str_arr[][ETH_GSTRING_LEN] = {
index fd34f266c0a80f9cf83daf61d1b50abccdab66cd..fa4b24c49f42875bfad43015a9db6ab089b2add8 100644 (file)
@@ -1057,7 +1057,7 @@ static struct bq_desc *ql_get_curr_lchunk(struct ql_adapter *qdev,
        struct bq_desc *lbq_desc = ql_get_curr_lbuf(rx_ring);
 
        pci_dma_sync_single_for_cpu(qdev->pdev,
-                                       pci_unmap_addr(lbq_desc, mapaddr),
+                                       dma_unmap_addr(lbq_desc, mapaddr),
                                    rx_ring->lbq_buf_size,
                                        PCI_DMA_FROMDEVICE);
 
@@ -1170,8 +1170,8 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 
                        map = lbq_desc->p.pg_chunk.map +
                                lbq_desc->p.pg_chunk.offset;
-                               pci_unmap_addr_set(lbq_desc, mapaddr, map);
-                       pci_unmap_len_set(lbq_desc, maplen,
+                               dma_unmap_addr_set(lbq_desc, mapaddr, map);
+                       dma_unmap_len_set(lbq_desc, maplen,
                                        rx_ring->lbq_buf_size);
                                *lbq_desc->addr = cpu_to_le64(map);
 
@@ -1241,8 +1241,8 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                                        sbq_desc->p.skb = NULL;
                                        return;
                                }
-                               pci_unmap_addr_set(sbq_desc, mapaddr, map);
-                               pci_unmap_len_set(sbq_desc, maplen,
+                               dma_unmap_addr_set(sbq_desc, mapaddr, map);
+                               dma_unmap_len_set(sbq_desc, maplen,
                                                  rx_ring->sbq_buf_size);
                                *sbq_desc->addr = cpu_to_le64(map);
                        }
@@ -1298,18 +1298,18 @@ static void ql_unmap_send(struct ql_adapter *qdev,
                                             "unmapping OAL area.\n");
                        }
                        pci_unmap_single(qdev->pdev,
-                                        pci_unmap_addr(&tx_ring_desc->map[i],
+                                        dma_unmap_addr(&tx_ring_desc->map[i],
                                                        mapaddr),
-                                        pci_unmap_len(&tx_ring_desc->map[i],
+                                        dma_unmap_len(&tx_ring_desc->map[i],
                                                       maplen),
                                         PCI_DMA_TODEVICE);
                } else {
                        netif_printk(qdev, tx_done, KERN_DEBUG, qdev->ndev,
                                     "unmapping frag %d.\n", i);
                        pci_unmap_page(qdev->pdev,
-                                      pci_unmap_addr(&tx_ring_desc->map[i],
+                                      dma_unmap_addr(&tx_ring_desc->map[i],
                                                      mapaddr),
-                                      pci_unmap_len(&tx_ring_desc->map[i],
+                                      dma_unmap_len(&tx_ring_desc->map[i],
                                                     maplen), PCI_DMA_TODEVICE);
                }
        }
@@ -1348,8 +1348,8 @@ static int ql_map_send(struct ql_adapter *qdev,
 
        tbd->len = cpu_to_le32(len);
        tbd->addr = cpu_to_le64(map);
-       pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
-       pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen, len);
+       dma_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
+       dma_unmap_len_set(&tx_ring_desc->map[map_idx], maplen, len);
        map_idx++;
 
        /*
@@ -1402,9 +1402,9 @@ static int ql_map_send(struct ql_adapter *qdev,
                        tbd->len =
                            cpu_to_le32((sizeof(struct tx_buf_desc) *
                                         (frag_cnt - frag_idx)) | TX_DESC_C);
-                       pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr,
+                       dma_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr,
                                           map);
-                       pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
+                       dma_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
                                          sizeof(struct oal));
                        tbd = (struct tx_buf_desc *)&tx_ring_desc->oal;
                        map_idx++;
@@ -1425,8 +1425,8 @@ static int ql_map_send(struct ql_adapter *qdev,
 
                tbd->addr = cpu_to_le64(map);
                tbd->len = cpu_to_le32(frag->size);
-               pci_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
-               pci_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
+               dma_unmap_addr_set(&tx_ring_desc->map[map_idx], mapaddr, map);
+               dma_unmap_len_set(&tx_ring_desc->map[map_idx], maplen,
                                  frag->size);
 
        }
@@ -1742,8 +1742,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                 */
                sbq_desc = ql_get_curr_sbuf(rx_ring);
                pci_unmap_single(qdev->pdev,
-                               pci_unmap_addr(sbq_desc, mapaddr),
-                               pci_unmap_len(sbq_desc, maplen),
+                               dma_unmap_addr(sbq_desc, mapaddr),
+                               dma_unmap_len(sbq_desc, maplen),
                                PCI_DMA_FROMDEVICE);
                skb = sbq_desc->p.skb;
                ql_realign_skb(skb, hdr_len);
@@ -1774,18 +1774,18 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                         */
                        sbq_desc = ql_get_curr_sbuf(rx_ring);
                        pci_dma_sync_single_for_cpu(qdev->pdev,
-                                                   pci_unmap_addr
+                                                   dma_unmap_addr
                                                    (sbq_desc, mapaddr),
-                                                   pci_unmap_len
+                                                   dma_unmap_len
                                                    (sbq_desc, maplen),
                                                    PCI_DMA_FROMDEVICE);
                        memcpy(skb_put(skb, length),
                               sbq_desc->p.skb->data, length);
                        pci_dma_sync_single_for_device(qdev->pdev,
-                                                      pci_unmap_addr
+                                                      dma_unmap_addr
                                                       (sbq_desc,
                                                        mapaddr),
-                                                      pci_unmap_len
+                                                      dma_unmap_len
                                                       (sbq_desc,
                                                        maplen),
                                                       PCI_DMA_FROMDEVICE);
@@ -1798,9 +1798,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                        ql_realign_skb(skb, length);
                        skb_put(skb, length);
                        pci_unmap_single(qdev->pdev,
-                                        pci_unmap_addr(sbq_desc,
+                                        dma_unmap_addr(sbq_desc,
                                                        mapaddr),
-                                        pci_unmap_len(sbq_desc,
+                                        dma_unmap_len(sbq_desc,
                                                       maplen),
                                         PCI_DMA_FROMDEVICE);
                        sbq_desc->p.skb = NULL;
@@ -1839,9 +1839,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                                return NULL;
                        }
                        pci_unmap_page(qdev->pdev,
-                                      pci_unmap_addr(lbq_desc,
+                                      dma_unmap_addr(lbq_desc,
                                                      mapaddr),
-                                      pci_unmap_len(lbq_desc, maplen),
+                                      dma_unmap_len(lbq_desc, maplen),
                                       PCI_DMA_FROMDEVICE);
                        skb_reserve(skb, NET_IP_ALIGN);
                        netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev,
@@ -1874,8 +1874,8 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                int size, i = 0;
                sbq_desc = ql_get_curr_sbuf(rx_ring);
                pci_unmap_single(qdev->pdev,
-                                pci_unmap_addr(sbq_desc, mapaddr),
-                                pci_unmap_len(sbq_desc, maplen),
+                                dma_unmap_addr(sbq_desc, mapaddr),
+                                dma_unmap_len(sbq_desc, maplen),
                                 PCI_DMA_FROMDEVICE);
                if (!(ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS)) {
                        /*
@@ -2737,8 +2737,8 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
                }
                if (sbq_desc->p.skb) {
                        pci_unmap_single(qdev->pdev,
-                                        pci_unmap_addr(sbq_desc, mapaddr),
-                                        pci_unmap_len(sbq_desc, maplen),
+                                        dma_unmap_addr(sbq_desc, mapaddr),
+                                        dma_unmap_len(sbq_desc, maplen),
                                         PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(sbq_desc->p.skb);
                        sbq_desc->p.skb = NULL;
@@ -4207,7 +4207,7 @@ static struct net_device_stats *qlge_get_stats(struct net_device
 static void qlge_set_multicast_list(struct net_device *ndev)
 {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
-       struct dev_mc_list *mc_ptr;
+       struct netdev_hw_addr *ha;
        int i, status;
 
        status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
@@ -4271,8 +4271,8 @@ static void qlge_set_multicast_list(struct net_device *ndev)
                if (status)
                        goto exit;
                i = 0;
-               netdev_for_each_mc_addr(mc_ptr, ndev) {
-                       if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr,
+               netdev_for_each_mc_addr(ha, ndev) {
+                       if (ql_set_mac_addr_reg(qdev, (u8 *) ha->addr,
                                                MAC_ADDR_TYPE_MULTI_MAC, i)) {
                                netif_err(qdev, hw, qdev->ndev,
                                          "Failed to loadmulticast address.\n");
index 0298d8c1dcb6fa002cb2f58bb50a61fd79d748a6..9a251acf5ab8dfb42d9db1ef1f6e3810f71f98e5 100644 (file)
@@ -330,7 +330,7 @@ static int r6040_alloc_rxbufs(struct net_device *dev)
        do {
                skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
                if (!skb) {
-                       printk(KERN_ERR DRV_NAME "%s: failed to alloc skb for rx\n", dev->name);
+                       netdev_err(dev, "failed to alloc skb for rx\n");
                        rc = -ENOMEM;
                        goto err_exit;
                }
@@ -400,9 +400,6 @@ static void r6040_init_mac_regs(struct net_device *dev)
         * we may got called by r6040_tx_timeout which has left
         * some unsent tx buffers */
        iowrite16(0x01, ioaddr + MTPR);
-
-       /* Check media */
-       mii_check_media(&lp->mii_if, 1, 1);
 }
 
 static void r6040_tx_timeout(struct net_device *dev)
@@ -410,9 +407,9 @@ static void r6040_tx_timeout(struct net_device *dev)
        struct r6040_private *priv = netdev_priv(dev);
        void __iomem *ioaddr = priv->base;
 
-       printk(KERN_WARNING "%s: transmit timed out, int enable %4.4x "
+       netdev_warn(dev, "transmit timed out, int enable %4.4x "
                "status %4.4x, PHY status %4.4x\n",
-               dev->name, ioread16(ioaddr + MIER),
+               ioread16(ioaddr + MIER),
                ioread16(ioaddr + MISR),
                r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
 
@@ -530,8 +527,6 @@ static int r6040_phy_mode_chk(struct net_device *dev)
                        phy_dat = 0x0000;
        }
 
-       mii_check_media(&lp->mii_if, 0, 1);
-
        return phy_dat;
 };
 
@@ -813,6 +808,9 @@ static void r6040_timer(unsigned long data)
 
        /* Timer active again */
        mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
+
+       /* Check media */
+       mii_check_media(&lp->mii_if, 1, 1);
 }
 
 /* Read/set MAC address routines */
@@ -897,7 +895,7 @@ static netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
        if (!lp->tx_free_desc) {
                spin_unlock_irqrestore(&lp->lock, flags);
                netif_stop_queue(dev);
-               printk(KERN_ERR DRV_NAME ": no tx descriptor\n");
+               netdev_err(dev, ": no tx descriptor\n");
                return NETDEV_TX_BUSY;
        }
 
@@ -924,7 +922,6 @@ static netdev_tx_t r6040_start_xmit(struct sk_buff *skb,
        if (!lp->tx_free_desc)
                netif_stop_queue(dev);
 
-       dev->trans_start = jiffies;
        spin_unlock_irqrestore(&lp->lock, flags);
 
        return NETDEV_TX_OK;
@@ -937,7 +934,7 @@ static void r6040_multicast_list(struct net_device *dev)
        u16 *adrp;
        u16 reg;
        unsigned long flags;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int i;
 
        /* MAC Address */
@@ -972,8 +969,8 @@ static void r6040_multicast_list(struct net_device *dev)
                for (i = 0; i < 4; i++)
                        hash_table[i] = 0;
 
-               netdev_for_each_mc_addr(dmi, dev) {
-                       char *addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       char *addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
@@ -990,9 +987,9 @@ static void r6040_multicast_list(struct net_device *dev)
        }
        /* Multicast Address 1~4 case */
        i = 0;
-       netdev_for_each_mc_addr(dmi, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                if (i < MCAST_MAX) {
-                       adrp = (u16 *) dmi->dmi_addr;
+                       adrp = (u16 *) ha->addr;
                        iowrite16(adrp[0], ioaddr + MID_1L + 8 * i);
                        iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
                        iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
@@ -1090,20 +1087,20 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        /* this should always be supported */
        err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
        if (err) {
-               printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses"
+               dev_err(&pdev->dev, "32-bit PCI DMA addresses"
                                "not supported by the card\n");
                goto err_out;
        }
        err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
        if (err) {
-               printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses"
+               dev_err(&pdev->dev, "32-bit PCI DMA addresses"
                                "not supported by the card\n");
                goto err_out;
        }
 
        /* IO Size check */
        if (pci_resource_len(pdev, bar) < io_size) {
-               printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n");
+               dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
                err = -EIO;
                goto err_out;
        }
@@ -1112,7 +1109,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
 
        dev = alloc_etherdev(sizeof(struct r6040_private));
        if (!dev) {
-               printk(KERN_ERR DRV_NAME ": Failed to allocate etherdev\n");
+               dev_err(&pdev->dev, "Failed to allocate etherdev\n");
                err = -ENOMEM;
                goto err_out;
        }
@@ -1122,14 +1119,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        err = pci_request_regions(pdev, DRV_NAME);
 
        if (err) {
-               printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+               dev_err(&pdev->dev, "Failed to request PCI regions\n");
                goto err_out_free_dev;
        }
 
        ioaddr = pci_iomap(pdev, bar, io_size);
        if (!ioaddr) {
-               printk(KERN_ERR DRV_NAME ": ioremap failed for device %s\n",
-                       pci_name(pdev));
+               dev_err(&pdev->dev, "ioremap failed for device\n");
                err = -EIO;
                goto err_out_free_res;
        }
@@ -1156,7 +1152,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        /* Some bootloader/BIOSes do not initialize
         * MAC address, warn about that */
        if (!(adrp[0] || adrp[1] || adrp[2])) {
-               printk(KERN_WARNING DRV_NAME ": MAC address not initialized, generating random\n");
+               netdev_warn(dev, "MAC address not initialized, generating random\n");
                random_ether_addr(dev->dev_addr);
        }
 
@@ -1184,7 +1180,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
 
        /* Check the vendor ID on the PHY, if 0xffff assume none attached */
        if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
-               printk(KERN_ERR DRV_NAME ": Failed to detect an attached PHY\n");
+               dev_err(&pdev->dev, "Failed to detect an attached PHY\n");
                err = -ENODEV;
                goto err_out_unmap;
        }
@@ -1192,7 +1188,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
        /* Register net device. After this dev->name assign */
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR DRV_NAME ": Failed to register net device\n");
+               dev_err(&pdev->dev, "Failed to register net device\n");
                goto err_out_unmap;
        }
        return 0;
index dd8106ff35aae6a4035b4cba6a351bd06f0c8d59..217e709bda3ede440478bf2eb73c5646dd96e903 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/tcp.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -509,6 +510,7 @@ struct rtl8169_private {
 
        struct mii_if_info mii;
        struct rtl8169_counters counters;
+       u32 saved_wolopts;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
@@ -748,53 +750,61 @@ static void rtl8169_check_link_status(struct net_device *dev,
 
        spin_lock_irqsave(&tp->lock, flags);
        if (tp->link_ok(ioaddr)) {
+               /* This is to cancel a scheduled suspend if there's one. */
+               pm_request_resume(&tp->pci_dev->dev);
                netif_carrier_on(dev);
                netif_info(tp, ifup, dev, "link up\n");
        } else {
                netif_carrier_off(dev);
                netif_info(tp, ifdown, dev, "link down\n");
+               pm_schedule_suspend(&tp->pci_dev->dev, 100);
        }
        spin_unlock_irqrestore(&tp->lock, flags);
 }
 
-static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+
+static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
 {
-       struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
        u8 options;
-
-       wol->wolopts = 0;
-
-#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
-       wol->supported = WAKE_ANY;
-
-       spin_lock_irq(&tp->lock);
+       u32 wolopts = 0;
 
        options = RTL_R8(Config1);
        if (!(options & PMEnable))
-               goto out_unlock;
+               return 0;
 
        options = RTL_R8(Config3);
        if (options & LinkUp)
-               wol->wolopts |= WAKE_PHY;
+               wolopts |= WAKE_PHY;
        if (options & MagicPacket)
-               wol->wolopts |= WAKE_MAGIC;
+               wolopts |= WAKE_MAGIC;
 
        options = RTL_R8(Config5);
        if (options & UWF)
-               wol->wolopts |= WAKE_UCAST;
+               wolopts |= WAKE_UCAST;
        if (options & BWF)
-               wol->wolopts |= WAKE_BCAST;
+               wolopts |= WAKE_BCAST;
        if (options & MWF)
-               wol->wolopts |= WAKE_MCAST;
+               wolopts |= WAKE_MCAST;
 
-out_unlock:
-       spin_unlock_irq(&tp->lock);
+       return wolopts;
 }
 
-static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
+
+       spin_lock_irq(&tp->lock);
+
+       wol->supported = WAKE_ANY;
+       wol->wolopts = __rtl8169_get_wol(tp);
+
+       spin_unlock_irq(&tp->lock);
+}
+
+static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
+{
        void __iomem *ioaddr = tp->mmio_addr;
        unsigned int i;
        static const struct {
@@ -811,23 +821,29 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
                { WAKE_ANY,   Config5, LanWake }
        };
 
-       spin_lock_irq(&tp->lock);
-
        RTL_W8(Cfg9346, Cfg9346_Unlock);
 
        for (i = 0; i < ARRAY_SIZE(cfg); i++) {
                u8 options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
-               if (wol->wolopts & cfg[i].opt)
+               if (wolopts & cfg[i].opt)
                        options |= cfg[i].mask;
                RTL_W8(cfg[i].reg, options);
        }
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
+}
+
+static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       spin_lock_irq(&tp->lock);
 
        if (wol->wolopts)
                tp->features |= RTL_FEATURE_WOL;
        else
                tp->features &= ~RTL_FEATURE_WOL;
+       __rtl8169_set_wol(tp, wol->wolopts);
        device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
 
        spin_unlock_irq(&tp->lock);
@@ -3192,6 +3208,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
 
+       if (pci_dev_run_wake(pdev)) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_enable(&pdev->dev);
+       }
+       pm_runtime_idle(&pdev->dev);
+
 out:
        return rc;
 
@@ -3213,10 +3235,18 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rtl8169_private *tp = netdev_priv(dev);
 
+       pm_runtime_get_sync(&pdev->dev);
+
        flush_scheduled_work();
 
        unregister_netdev(dev);
 
+       if (pci_dev_run_wake(pdev)) {
+               pm_runtime_disable(&pdev->dev);
+               pm_runtime_set_suspended(&pdev->dev);
+       }
+       pm_runtime_put_noidle(&pdev->dev);
+
        /* restore original MAC address */
        rtl_rar_set(tp, dev->perm_addr);
 
@@ -3243,6 +3273,7 @@ static int rtl8169_open(struct net_device *dev)
        struct pci_dev *pdev = tp->pci_dev;
        int retval = -ENOMEM;
 
+       pm_runtime_get_sync(&pdev->dev);
 
        /*
         * Note that we use a magic value here, its wierd I know
@@ -3263,7 +3294,7 @@ static int rtl8169_open(struct net_device *dev)
        tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
                                               &tp->TxPhyAddr);
        if (!tp->TxDescArray)
-               goto out;
+               goto err_pm_runtime_put;
 
        tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
                                               &tp->RxPhyAddr);
@@ -3290,6 +3321,9 @@ static int rtl8169_open(struct net_device *dev)
 
        rtl8169_request_timer(dev);
 
+       tp->saved_wolopts = 0;
+       pm_runtime_put_noidle(&pdev->dev);
+
        rtl8169_check_link_status(dev, tp, tp->mmio_addr);
 out:
        return retval;
@@ -3299,9 +3333,13 @@ err_release_ring_2:
 err_free_rx_1:
        pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
                            tp->RxPhyAddr);
+       tp->RxDescArray = NULL;
 err_free_tx_0:
        pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
                            tp->TxPhyAddr);
+       tp->TxDescArray = NULL;
+err_pm_runtime_put:
+       pm_runtime_put_noidle(&pdev->dev);
        goto out;
 }
 
@@ -4720,6 +4758,8 @@ static int rtl8169_close(struct net_device *dev)
        struct rtl8169_private *tp = netdev_priv(dev);
        struct pci_dev *pdev = tp->pci_dev;
 
+       pm_runtime_get_sync(&pdev->dev);
+
        /* update counters before going down */
        rtl8169_update_counters(dev);
 
@@ -4734,6 +4774,8 @@ static int rtl8169_close(struct net_device *dev)
        tp->TxDescArray = NULL;
        tp->RxDescArray = NULL;
 
+       pm_runtime_put_sync(&pdev->dev);
+
        return 0;
 }
 
@@ -4759,12 +4801,12 @@ static void rtl_set_rx_mode(struct net_device *dev)
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                rx_mode = AcceptBroadcast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                        rx_mode |= AcceptMulticast;
                }
@@ -4832,21 +4874,74 @@ static int rtl8169_suspend(struct device *device)
        return 0;
 }
 
+static void __rtl8169_resume(struct net_device *dev)
+{
+       netif_device_attach(dev);
+       rtl8169_schedule_work(dev, rtl8169_reset_task);
+}
+
 static int rtl8169_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct net_device *dev = pci_get_drvdata(pdev);
 
-       if (!netif_running(dev))
-               goto out;
+       if (netif_running(dev))
+               __rtl8169_resume(dev);
 
-       netif_device_attach(dev);
+       return 0;
+}
+
+static int rtl8169_runtime_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       if (!tp->TxDescArray)
+               return 0;
+
+       spin_lock_irq(&tp->lock);
+       tp->saved_wolopts = __rtl8169_get_wol(tp);
+       __rtl8169_set_wol(tp, WAKE_ANY);
+       spin_unlock_irq(&tp->lock);
+
+       rtl8169_net_suspend(dev);
+
+       return 0;
+}
+
+static int rtl8169_runtime_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       if (!tp->TxDescArray)
+               return 0;
+
+       spin_lock_irq(&tp->lock);
+       __rtl8169_set_wol(tp, tp->saved_wolopts);
+       tp->saved_wolopts = 0;
+       spin_unlock_irq(&tp->lock);
+
+       __rtl8169_resume(dev);
 
-       rtl8169_schedule_work(dev, rtl8169_reset_task);
-out:
        return 0;
 }
 
+static int rtl8169_runtime_idle(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       if (!tp->TxDescArray)
+               return 0;
+
+       rtl8169_check_link_status(dev, tp, tp->mmio_addr);
+       return -EBUSY;
+}
+
 static const struct dev_pm_ops rtl8169_pm_ops = {
        .suspend = rtl8169_suspend,
        .resume = rtl8169_resume,
@@ -4854,6 +4949,9 @@ static const struct dev_pm_ops rtl8169_pm_ops = {
        .thaw = rtl8169_resume,
        .poweroff = rtl8169_suspend,
        .restore = rtl8169_resume,
+       .runtime_suspend = rtl8169_runtime_suspend,
+       .runtime_resume = rtl8169_runtime_resume,
+       .runtime_idle = rtl8169_runtime_idle,
 };
 
 #define RTL8169_PM_OPS (&rtl8169_pm_ops)
index f2e335f0d1b760d7e8c0d23ae9cb5999d24f013c..e26e107f93e0c4ee18156a3c188bdc673c7c3691 100644 (file)
@@ -1467,7 +1467,6 @@ static netdev_tx_t rr_start_xmit(struct sk_buff *skb,
 
        spin_unlock_irqrestore(&rrpriv->lock, flags);
 
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
index 92ae8d3de39be642cccc50321696895bac745f1c..668327ccd8d0f8c29f60b974234efaa6a51e5859 100644 (file)
@@ -2400,7 +2400,7 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data,
                return NULL;
        }
        pci_unmap_single(nic->pdev, (dma_addr_t)txds->Buffer_Pointer,
-                        skb->len - skb->data_len, PCI_DMA_TODEVICE);
+                        skb_headlen(skb), PCI_DMA_TODEVICE);
        frg_cnt = skb_shinfo(skb)->nr_frags;
        if (frg_cnt) {
                txds++;
@@ -2943,7 +2943,6 @@ static void s2io_netpoll(struct net_device *dev)
                }
        }
        enable_irq(dev->irq);
-       return;
 }
 #endif
 
@@ -4202,7 +4201,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
                txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag);
        }
 
-       frg_len = skb->len - skb->data_len;
+       frg_len = skb_headlen(skb);
        if (offload_type == SKB_GSO_UDP) {
                int ufo_size;
 
@@ -4756,7 +4755,6 @@ reset:
        s2io_stop_all_tx_queue(sp);
        schedule_work(&sp->rst_timer_task);
        sw_stat->soft_reset_cnt++;
-       return;
 }
 
 /**
@@ -4965,7 +4963,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
 static void s2io_set_multicast(struct net_device *dev)
 {
        int i, j, prev_cnt;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        struct s2io_nic *sp = netdev_priv(dev);
        struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
@@ -5094,12 +5092,12 @@ static void s2io_set_multicast(struct net_device *dev)
 
                /* Create the new Rx filter list and update the same in H/W. */
                i = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       memcpy(sp->usr_addrs[i].addr, mclist->dmi_addr,
+               netdev_for_each_mc_addr(ha, dev) {
+                       memcpy(sp->usr_addrs[i].addr, ha->addr,
                               ETH_ALEN);
                        mac_addr = 0;
                        for (j = 0; j < ETH_ALEN; j++) {
-                               mac_addr |= mclist->dmi_addr[j];
+                               mac_addr |= ha->addr[j];
                                mac_addr <<= 8;
                        }
                        mac_addr >>= 8;
@@ -8645,7 +8643,6 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
        first->truesize += skb->truesize;
        lro->last_frag = skb;
        swstats->clubbed_frms_cnt++;
-       return;
 }
 
 /**
index 45f26344b36821ebe619cd30e2b753bce2944f96..a7ff8ea342b4329baae598c4f1b08a704e016356 100644 (file)
@@ -396,7 +396,6 @@ static void s6gmac_rx_interrupt(struct net_device *dev)
                } else {
                        skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN)
                                & S6_GMAC_BURST_POSTRD_LEN_MASK);
-                       skb->dev = dev;
                        skb->protocol = eth_type_trans(skb, dev);
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                        netif_rx(skb);
@@ -853,8 +852,8 @@ static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct s6gmac *pd = netdev_priv(dev);
        unsigned long flags;
+
        spin_lock_irqsave(&pd->lock, flags);
-       dev->trans_start = jiffies;
        writel(skb->len << S6_GMAC_BURST_PREWR_LEN |
                0 << S6_GMAC_BURST_PREWR_CFE |
                1 << S6_GMAC_BURST_PREWR_PPE |
index abc8eefdd4b6bcd7c7b075d2cccfd7c70e9b92d3..a9ae505e1baf1e0fb35e32c940a5c63d17e8d7ff 100644 (file)
@@ -426,7 +426,6 @@ sb1000_send_command(const int ioaddr[], const char* name,
        if (sb1000_debug > 3)
                printk(KERN_DEBUG "%s: sb1000_send_command out: %02x%02x%02x%02x"
                        "%02x%02x\n", name, out[0], out[1], out[2], out[3], out[4], out[5]);
-       return;
 }
 
 /* Card Read Status (to be used during frame rx) */
@@ -438,7 +437,6 @@ sb1000_read_status(const int ioaddr[], unsigned char in[])
        in[3] = inb(ioaddr[0] + 3);
        in[4] = inb(ioaddr[0] + 4);
        in[0] = inb(ioaddr[0] + 5);
-       return;
 }
 
 /* Issue Read Command (to be used during frame rx) */
@@ -450,7 +448,6 @@ sb1000_issue_read_command(const int ioaddr[], const char* name)
        sb1000_wait_for_ready_clear(ioaddr, name);
        outb(0xa0, ioaddr[0] + 6);
        sb1000_send_command(ioaddr, name, Command0);
-       return;
 }
 
 
@@ -733,7 +730,6 @@ sb1000_print_status_buffer(const char* name, unsigned char st[],
                        printk("\n");
                }
        }
-       return;
 }
 
 /*
@@ -926,7 +922,6 @@ sb1000_error_dpc(struct net_device *dev)
        sb1000_read_status(ioaddr, st);
        if (st[1] & 0x10)
                lp->rx_error_dpc_count = ErrorDpcCounterInitialize;
-       return;
 }
 
 
index 04efc0c1bda93b95bfbd840c7778d8a57ac2c5ad..1f3acc3a5dfd0510d487334ac31b2a266eac13db 100644 (file)
 #include <asm/io.h>
 #include <asm/processor.h>     /* Processor type for cache alignment. */
 
-/* This is only here until the firmware is ready.  In that case,
-   the firmware leaves the ethernet address in the register for us. */
-#ifdef CONFIG_SIBYTE_STANDALONE
-#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
-#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
-#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
-#define SBMAC_ETH3_HWADDR "40:00:00:00:01:03"
-#endif
-
-
-/* These identify the driver base version and may not be removed. */
-#if 0
-static char version1[] __initdata =
-"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
-#endif
-
-
 /* Operational parameters that usually are not changed. */
 
 #define CONFIG_SBMAC_COALESCE
@@ -349,7 +332,6 @@ static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
  ********************************************************************* */
 
 static char sbmac_string[] = "sb1250-mac";
-static char sbmac_pretty[] = "SB1250 MAC";
 
 static char sbmac_mdio_string[] = "sb1250-mac-mdio";
 
@@ -2086,8 +2068,6 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_BUSY;
        }
 
-       dev->trans_start = jiffies;
-
        spin_unlock_irqrestore(&sc->sbm_lock, flags);
 
        return NETDEV_TX_OK;
@@ -2112,7 +2092,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
        uint64_t reg;
        void __iomem *port;
        int idx;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        struct net_device *dev = sc->sbm_dev;
 
        /*
@@ -2161,10 +2141,10 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
         * XXX if the table overflows */
 
        idx = 1;                /* skip station address */
-       netdev_for_each_mc_addr(mclist, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                if (idx == MAC_ADDR_COUNT)
                        break;
-               reg = sbmac_addr2reg(mclist->dmi_addr);
+               reg = sbmac_addr2reg(ha->addr);
                port = sc->sbm_base + R_MAC_ADDR_BASE+(idx * sizeof(uint64_t));
                __raw_writeq(reg, port);
                idx++;
@@ -2182,85 +2162,6 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
        }
 }
 
-#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
-/**********************************************************************
- *  SBMAC_PARSE_XDIGIT(str)
- *
- *  Parse a hex digit, returning its value
- *
- *  Input parameters:
- *        str - character
- *
- *  Return value:
- *        hex value, or -1 if invalid
- ********************************************************************* */
-
-static int sbmac_parse_xdigit(char str)
-{
-       int digit;
-
-       if ((str >= '0') && (str <= '9'))
-               digit = str - '0';
-       else if ((str >= 'a') && (str <= 'f'))
-               digit = str - 'a' + 10;
-       else if ((str >= 'A') && (str <= 'F'))
-               digit = str - 'A' + 10;
-       else
-               return -1;
-
-       return digit;
-}
-
-/**********************************************************************
- *  SBMAC_PARSE_HWADDR(str,hwaddr)
- *
- *  Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
- *  Ethernet address.
- *
- *  Input parameters:
- *        str - string
- *        hwaddr - pointer to hardware address
- *
- *  Return value:
- *        0 if ok, else -1
- ********************************************************************* */
-
-static int sbmac_parse_hwaddr(char *str, unsigned char *hwaddr)
-{
-       int digit1,digit2;
-       int idx = 6;
-
-       while (*str && (idx > 0)) {
-               digit1 = sbmac_parse_xdigit(*str);
-               if (digit1 < 0)
-                       return -1;
-               str++;
-               if (!*str)
-                       return -1;
-
-               if ((*str == ':') || (*str == '-')) {
-                       digit2 = digit1;
-                       digit1 = 0;
-               }
-               else {
-                       digit2 = sbmac_parse_xdigit(*str);
-                       if (digit2 < 0)
-                               return -1;
-                       str++;
-               }
-
-               *hwaddr++ = (digit1 << 4) | digit2;
-               idx--;
-
-               if (*str == '-')
-                       str++;
-               if (*str == ':')
-                       str++;
-       }
-       return 0;
-}
-#endif
-
 static int sb1250_change_mtu(struct net_device *_dev, int new_mtu)
 {
        if (new_mtu >  ENET_PACKET_SIZE)
@@ -2585,7 +2486,7 @@ static void sbmac_tx_timeout (struct net_device *dev)
        spin_lock_irqsave(&sc->sbm_lock, flags);
 
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
 
        spin_unlock_irqrestore(&sc->sbm_lock, flags);
@@ -2662,7 +2563,6 @@ static int sbmac_close(struct net_device *dev)
 static int sbmac_poll(struct napi_struct *napi, int budget)
 {
        struct sbmac_softc *sc = container_of(napi, struct sbmac_softc, napi);
-       struct net_device *dev = sc->sbm_dev;
        int work_done;
 
        work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), budget, 1);
@@ -2766,162 +2666,6 @@ static int __exit sbmac_remove(struct platform_device *pldev)
        return 0;
 }
 
-
-static struct platform_device **sbmac_pldev;
-static int sbmac_max_units;
-
-#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
-static void __init sbmac_setup_hwaddr(int idx, char *addr)
-{
-       void __iomem *sbm_base;
-       unsigned long start, end;
-       uint8_t eaddr[6];
-       uint64_t val;
-
-       if (idx >= sbmac_max_units)
-               return;
-
-       start = A_MAC_CHANNEL_BASE(idx);
-       end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
-
-       sbm_base = ioremap_nocache(start, end - start + 1);
-       if (!sbm_base) {
-               printk(KERN_ERR "%s: unable to map device registers\n",
-                      sbmac_string);
-               return;
-       }
-
-       sbmac_parse_hwaddr(addr, eaddr);
-       val = sbmac_addr2reg(eaddr);
-       __raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR);
-       val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
-
-       iounmap(sbm_base);
-}
-#endif
-
-static int __init sbmac_platform_probe_one(int idx)
-{
-       struct platform_device *pldev;
-       struct {
-               struct resource r;
-               char name[strlen(sbmac_pretty) + 4];
-       } *res;
-       int err;
-
-       res = kzalloc(sizeof(*res), GFP_KERNEL);
-       if (!res) {
-               printk(KERN_ERR "%s.%d: unable to allocate memory\n",
-                      sbmac_string, idx);
-               err = -ENOMEM;
-               goto out_err;
-       }
-
-       /*
-        * This is the base address of the MAC.
-        */
-       snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx);
-       res->r.name = res->name;
-       res->r.flags = IORESOURCE_MEM;
-       res->r.start = A_MAC_CHANNEL_BASE(idx);
-       res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
-
-       pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1);
-       if (IS_ERR(pldev)) {
-               printk(KERN_ERR "%s.%d: unable to register platform device\n",
-                      sbmac_string, idx);
-               err = PTR_ERR(pldev);
-               goto out_kfree;
-       }
-
-       if (!pldev->dev.driver) {
-               err = 0;                /* No hardware at this address. */
-               goto out_unregister;
-       }
-
-       sbmac_pldev[idx] = pldev;
-       return 0;
-
-out_unregister:
-       platform_device_unregister(pldev);
-
-out_kfree:
-       kfree(res);
-
-out_err:
-       return err;
-}
-
-static void __init sbmac_platform_probe(void)
-{
-       int i;
-
-       /* Set the number of available units based on the SOC type.  */
-       switch (soc_type) {
-       case K_SYS_SOC_TYPE_BCM1250:
-       case K_SYS_SOC_TYPE_BCM1250_ALT:
-               sbmac_max_units = 3;
-               break;
-       case K_SYS_SOC_TYPE_BCM1120:
-       case K_SYS_SOC_TYPE_BCM1125:
-       case K_SYS_SOC_TYPE_BCM1125H:
-       case K_SYS_SOC_TYPE_BCM1250_ALT2:       /* Hybrid */
-               sbmac_max_units = 2;
-               break;
-       case K_SYS_SOC_TYPE_BCM1x55:
-       case K_SYS_SOC_TYPE_BCM1x80:
-               sbmac_max_units = 4;
-               break;
-       default:
-               return;                         /* none */
-       }
-
-       /*
-        * For bringup when not using the firmware, we can pre-fill
-        * the MAC addresses using the environment variables
-        * specified in this file (or maybe from the config file?)
-        */
-#ifdef SBMAC_ETH0_HWADDR
-       sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR);
-#endif
-#ifdef SBMAC_ETH1_HWADDR
-       sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR);
-#endif
-#ifdef SBMAC_ETH2_HWADDR
-       sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR);
-#endif
-#ifdef SBMAC_ETH3_HWADDR
-       sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR);
-#endif
-
-       sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev),
-                             GFP_KERNEL);
-       if (!sbmac_pldev) {
-               printk(KERN_ERR "%s: unable to allocate memory\n",
-                      sbmac_string);
-               return;
-       }
-
-       /*
-        * Walk through the Ethernet controllers and find
-        * those who have their MAC addresses set.
-        */
-       for (i = 0; i < sbmac_max_units; i++)
-               if (sbmac_platform_probe_one(i))
-                       break;
-}
-
-
-static void __exit sbmac_platform_cleanup(void)
-{
-       int i;
-
-       for (i = 0; i < sbmac_max_units; i++)
-               platform_device_unregister(sbmac_pldev[i]);
-       kfree(sbmac_pldev);
-}
-
-
 static struct platform_driver sbmac_driver = {
        .probe = sbmac_probe,
        .remove = __exit_p(sbmac_remove),
@@ -2932,20 +2676,11 @@ static struct platform_driver sbmac_driver = {
 
 static int __init sbmac_init_module(void)
 {
-       int err;
-
-       err = platform_driver_register(&sbmac_driver);
-       if (err)
-               return err;
-
-       sbmac_platform_probe();
-
-       return err;
+       return platform_driver_register(&sbmac_driver);
 }
 
 static void __exit sbmac_cleanup_module(void)
 {
-       sbmac_platform_cleanup();
        platform_driver_unregister(&sbmac_driver);
 }
 
index d87c4787fffaccd37693ca4fae2ebd09609e2640..8c4067af32b0fbc671d2d38652a09e0594268611 100644 (file)
@@ -433,13 +433,13 @@ static void _sc92031_set_mar(struct net_device *dev)
            (dev->flags & IFF_ALLMULTI))
                mar0 = mar1 = 0xffffffff;
        else if (dev->flags & IFF_MULTICAST) {
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
 
-               netdev_for_each_mc_addr(mc_list, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        u32 crc;
                        unsigned bit = 0;
 
-                       crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr);
+                       crc = ~ether_crc(ETH_ALEN, ha->addr);
                        crc >>= 24;
 
                        if (crc & 0x01) bit |= 0x02;
@@ -987,8 +987,6 @@ static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb,
        iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
        mmiowb();
 
-       dev->trans_start = jiffies;
-
        if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
                netif_stop_queue(dev);
 
index 374832cca11fd092a42ee15719a8421f106e4f24..d2fce98f557fbf2195c704e1d7b56a1339c916aa 100644 (file)
@@ -390,7 +390,7 @@ static void seeq8005_timeout(struct net_device *dev)
                   tx_done(dev) ? "IRQ conflict" : "network cable problem");
        /* Try to restart the adaptor. */
        seeq8005_init(dev, 1);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -411,7 +411,6 @@ static netdev_tx_t seeq8005_send_packet(struct sk_buff *skb,
        netif_stop_queue(dev);
 
        hardware_send_packet(dev, buf, length);
-       dev->trans_start = jiffies;
        dev->stats.tx_bytes += length;
        dev_kfree_skb (skb);
        /* You might need to clean up and record Tx statistics here. */
@@ -579,7 +578,6 @@ static void seeq8005_rx(struct net_device *dev)
        /* If any worth-while packets have been received, netif_rx()
           has done a mark_bh(NET_BH) for us and will work on them
           when we get to the bottom-half routine. */
-       return;
 }
 
 /* The inverse routine to net_open(). */
index 649a264d6a81b80ee35f54850fce49a4545565c1..156460527231b4899044b714f489cb9bc357cb56 100644 (file)
@@ -225,17 +225,17 @@ static void efx_fini_channels(struct efx_nic *efx);
  * never be concurrently called more than once on the same channel,
  * though different channels may be being processed concurrently.
  */
-static int efx_process_channel(struct efx_channel *channel, int rx_quota)
+static int efx_process_channel(struct efx_channel *channel, int budget)
 {
        struct efx_nic *efx = channel->efx;
-       int rx_packets;
+       int spent;
 
        if (unlikely(efx->reset_pending != RESET_TYPE_NONE ||
                     !channel->enabled))
                return 0;
 
-       rx_packets = efx_nic_process_eventq(channel, rx_quota);
-       if (rx_packets == 0)
+       spent = efx_nic_process_eventq(channel, budget);
+       if (spent == 0)
                return 0;
 
        /* Deliver last RX packet. */
@@ -249,7 +249,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota)
 
        efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
 
-       return rx_packets;
+       return spent;
 }
 
 /* Mark channel as finished processing
@@ -278,17 +278,17 @@ static int efx_poll(struct napi_struct *napi, int budget)
 {
        struct efx_channel *channel =
                container_of(napi, struct efx_channel, napi_str);
-       int rx_packets;
+       int spent;
 
        EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
                  channel->channel, raw_smp_processor_id());
 
-       rx_packets = efx_process_channel(channel, budget);
+       spent = efx_process_channel(channel, budget);
 
-       if (rx_packets < budget) {
+       if (spent < budget) {
                struct efx_nic *efx = channel->efx;
 
-               if (channel->used_flags & EFX_USED_BY_RX &&
+               if (channel->channel < efx->n_rx_channels &&
                    efx->irq_rx_adaptive &&
                    unlikely(++channel->irq_count == 1000)) {
                        if (unlikely(channel->irq_mod_score <
@@ -318,7 +318,7 @@ static int efx_poll(struct napi_struct *napi, int budget)
                efx_channel_processed(channel);
        }
 
-       return rx_packets;
+       return spent;
 }
 
 /* Process the eventq of the specified channel immediately on this CPU
@@ -333,7 +333,6 @@ void efx_process_channel_now(struct efx_channel *channel)
 {
        struct efx_nic *efx = channel->efx;
 
-       BUG_ON(!channel->used_flags);
        BUG_ON(!channel->enabled);
 
        /* Disable interrupts and wait for ISRs to complete */
@@ -446,12 +445,12 @@ static void efx_set_channel_names(struct efx_nic *efx)
 
        efx_for_each_channel(channel, efx) {
                number = channel->channel;
-               if (efx->n_channels > efx->n_rx_queues) {
-                       if (channel->channel < efx->n_rx_queues) {
+               if (efx->n_channels > efx->n_rx_channels) {
+                       if (channel->channel < efx->n_rx_channels) {
                                type = "-rx";
                        } else {
                                type = "-tx";
-                               number -= efx->n_rx_queues;
+                               number -= efx->n_rx_channels;
                        }
                }
                snprintf(channel->name, sizeof(channel->name),
@@ -585,8 +584,6 @@ static void efx_remove_channel(struct efx_channel *channel)
        efx_for_each_channel_tx_queue(tx_queue, channel)
                efx_remove_tx_queue(tx_queue);
        efx_remove_eventq(channel);
-
-       channel->used_flags = 0;
 }
 
 void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
@@ -956,10 +953,9 @@ static void efx_fini_io(struct efx_nic *efx)
        pci_disable_device(efx->pci_dev);
 }
 
-/* Get number of RX queues wanted.  Return number of online CPU
- * packages in the expectation that an IRQ balancer will spread
- * interrupts across them. */
-static int efx_wanted_rx_queues(void)
+/* Get number of channels wanted.  Each channel will have its own IRQ,
+ * 1 RX queue and/or 2 TX queues. */
+static int efx_wanted_channels(void)
 {
        cpumask_var_t core_mask;
        int count;
@@ -995,34 +991,39 @@ static void efx_probe_interrupts(struct efx_nic *efx)
 
        if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
                struct msix_entry xentries[EFX_MAX_CHANNELS];
-               int wanted_ints;
-               int rx_queues;
+               int n_channels;
 
-               /* We want one RX queue and interrupt per CPU package
-                * (or as specified by the rss_cpus module parameter).
-                * We will need one channel per interrupt.
-                */
-               rx_queues = rss_cpus ? rss_cpus : efx_wanted_rx_queues();
-               wanted_ints = rx_queues + (separate_tx_channels ? 1 : 0);
-               wanted_ints = min(wanted_ints, max_channels);
+               n_channels = efx_wanted_channels();
+               if (separate_tx_channels)
+                       n_channels *= 2;
+               n_channels = min(n_channels, max_channels);
 
-               for (i = 0; i < wanted_ints; i++)
+               for (i = 0; i < n_channels; i++)
                        xentries[i].entry = i;
-               rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints);
+               rc = pci_enable_msix(efx->pci_dev, xentries, n_channels);
                if (rc > 0) {
                        EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors"
-                               " available (%d < %d).\n", rc, wanted_ints);
+                               " available (%d < %d).\n", rc, n_channels);
                        EFX_ERR(efx, "WARNING: Performance may be reduced.\n");
-                       EFX_BUG_ON_PARANOID(rc >= wanted_ints);
-                       wanted_ints = rc;
+                       EFX_BUG_ON_PARANOID(rc >= n_channels);
+                       n_channels = rc;
                        rc = pci_enable_msix(efx->pci_dev, xentries,
-                                            wanted_ints);
+                                            n_channels);
                }
 
                if (rc == 0) {
-                       efx->n_rx_queues = min(rx_queues, wanted_ints);
-                       efx->n_channels = wanted_ints;
-                       for (i = 0; i < wanted_ints; i++)
+                       efx->n_channels = n_channels;
+                       if (separate_tx_channels) {
+                               efx->n_tx_channels =
+                                       max(efx->n_channels / 2, 1U);
+                               efx->n_rx_channels =
+                                       max(efx->n_channels -
+                                           efx->n_tx_channels, 1U);
+                       } else {
+                               efx->n_tx_channels = efx->n_channels;
+                               efx->n_rx_channels = efx->n_channels;
+                       }
+                       for (i = 0; i < n_channels; i++)
                                efx->channel[i].irq = xentries[i].vector;
                } else {
                        /* Fall back to single channel MSI */
@@ -1033,8 +1034,9 @@ static void efx_probe_interrupts(struct efx_nic *efx)
 
        /* Try single interrupt MSI */
        if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
-               efx->n_rx_queues = 1;
                efx->n_channels = 1;
+               efx->n_rx_channels = 1;
+               efx->n_tx_channels = 1;
                rc = pci_enable_msi(efx->pci_dev);
                if (rc == 0) {
                        efx->channel[0].irq = efx->pci_dev->irq;
@@ -1046,8 +1048,9 @@ static void efx_probe_interrupts(struct efx_nic *efx)
 
        /* Assume legacy interrupts */
        if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
-               efx->n_rx_queues = 1;
                efx->n_channels = 1 + (separate_tx_channels ? 1 : 0);
+               efx->n_rx_channels = 1;
+               efx->n_tx_channels = 1;
                efx->legacy_irq = efx->pci_dev->irq;
        }
 }
@@ -1068,21 +1071,24 @@ static void efx_remove_interrupts(struct efx_nic *efx)
 
 static void efx_set_channels(struct efx_nic *efx)
 {
+       struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
+       unsigned tx_channel_offset =
+               separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
 
-       efx_for_each_tx_queue(tx_queue, efx) {
-               if (separate_tx_channels)
-                       tx_queue->channel = &efx->channel[efx->n_channels-1];
-               else
-                       tx_queue->channel = &efx->channel[0];
-               tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+       efx_for_each_channel(channel, efx) {
+               if (channel->channel - tx_channel_offset < efx->n_tx_channels) {
+                       channel->tx_queue = &efx->tx_queue[
+                               (channel->channel - tx_channel_offset) *
+                               EFX_TXQ_TYPES];
+                       efx_for_each_channel_tx_queue(tx_queue, channel)
+                               tx_queue->channel = channel;
+               }
        }
 
-       efx_for_each_rx_queue(rx_queue, efx) {
+       efx_for_each_rx_queue(rx_queue, efx)
                rx_queue->channel = &efx->channel[rx_queue->queue];
-               rx_queue->channel->used_flags |= EFX_USED_BY_RX;
-       }
 }
 
 static int efx_probe_nic(struct efx_nic *efx)
@@ -1096,11 +1102,12 @@ static int efx_probe_nic(struct efx_nic *efx)
        if (rc)
                return rc;
 
-       /* Determine the number of channels and RX queues by trying to hook
+       /* Determine the number of channels and queues by trying to hook
         * in MSI-X interrupts. */
        efx_probe_interrupts(efx);
 
        efx_set_channels(efx);
+       efx->net_dev->real_num_tx_queues = efx->n_tx_channels;
 
        /* Initialise the interrupt moderation settings */
        efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true);
@@ -1187,11 +1194,12 @@ static void efx_start_all(struct efx_nic *efx)
        /* Mark the port as enabled so port reconfigurations can start, then
         * restart the transmit interface early so the watchdog timer stops */
        efx_start_port(efx);
-       if (efx_dev_registered(efx))
-               efx_wake_queue(efx);
 
-       efx_for_each_channel(channel, efx)
+       efx_for_each_channel(channel, efx) {
+               if (efx_dev_registered(efx))
+                       efx_wake_queue(channel);
                efx_start_channel(channel);
+       }
 
        efx_nic_enable_interrupts(efx);
 
@@ -1282,7 +1290,9 @@ static void efx_stop_all(struct efx_nic *efx)
        /* Stop the kernel transmit interface late, so the watchdog
         * timer isn't ticking over the flush */
        if (efx_dev_registered(efx)) {
-               efx_stop_queue(efx);
+               struct efx_channel *channel;
+               efx_for_each_channel(channel, efx)
+                       efx_stop_queue(channel);
                netif_tx_lock_bh(efx->net_dev);
                netif_tx_unlock_bh(efx->net_dev);
        }
@@ -1537,9 +1547,8 @@ static void efx_watchdog(struct net_device *net_dev)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
 
-       EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:"
-               " resetting channels\n",
-               atomic_read(&efx->netif_stop_count), efx->port_enabled);
+       EFX_ERR(efx, "TX stuck with port_enabled=%d: resetting channels\n",
+               efx->port_enabled);
 
        efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG);
 }
@@ -1603,7 +1612,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
 static void efx_set_multicast_list(struct net_device *net_dev)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
-       struct dev_mc_list *mc_list;
+       struct netdev_hw_addr *ha;
        union efx_multicast_hash *mc_hash = &efx->multicast_hash;
        u32 crc;
        int bit;
@@ -1615,8 +1624,8 @@ static void efx_set_multicast_list(struct net_device *net_dev)
                memset(mc_hash, 0xff, sizeof(*mc_hash));
        } else {
                memset(mc_hash, 0x00, sizeof(*mc_hash));
-               netdev_for_each_mc_addr(mc_list, net_dev) {
-                       crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr);
+               netdev_for_each_mc_addr(ha, net_dev) {
+                       crc = ether_crc_le(ETH_ALEN, ha->addr);
                        bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
                        set_bit_le(bit, mc_hash->byte);
                }
@@ -2014,22 +2023,22 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
 
        efx->net_dev = net_dev;
        efx->rx_checksum_enabled = true;
-       spin_lock_init(&efx->netif_stop_lock);
        spin_lock_init(&efx->stats_lock);
        mutex_init(&efx->mac_lock);
        efx->mac_op = type->default_mac_ops;
        efx->phy_op = &efx_dummy_phy_operations;
        efx->mdio.dev = net_dev;
        INIT_WORK(&efx->mac_work, efx_mac_work);
-       atomic_set(&efx->netif_stop_count, 1);
 
        for (i = 0; i < EFX_MAX_CHANNELS; i++) {
                channel = &efx->channel[i];
                channel->efx = efx;
                channel->channel = i;
                channel->work_pending = false;
+               spin_lock_init(&channel->tx_stop_lock);
+               atomic_set(&channel->tx_stop_count, 1);
        }
-       for (i = 0; i < EFX_TX_QUEUE_COUNT; i++) {
+       for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
                tx_queue = &efx->tx_queue[i];
                tx_queue->efx = efx;
                tx_queue->queue = i;
@@ -2201,7 +2210,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
        int i, rc;
 
        /* Allocate and initialise a struct net_device and struct efx_nic */
-       net_dev = alloc_etherdev(sizeof(*efx));
+       net_dev = alloc_etherdev_mq(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES);
        if (!net_dev)
                return -ENOMEM;
        net_dev->features |= (type->offload_features | NETIF_F_SG |
index 7eff0a615cb39d07b394490c0d473dd3f10810e6..ffd708c5304af0dd7d584c50b733babb1f6b36ad 100644 (file)
@@ -35,8 +35,8 @@ efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
 extern netdev_tx_t
 efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
 extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
-extern void efx_stop_queue(struct efx_nic *efx);
-extern void efx_wake_queue(struct efx_nic *efx);
+extern void efx_stop_queue(struct efx_channel *channel);
+extern void efx_wake_queue(struct efx_channel *channel);
 #define EFX_TXQ_SIZE 1024
 #define EFX_TXQ_MASK (EFX_TXQ_SIZE - 1)
 
index d9f9c02a928ecdb8cb44537bcfccce51116bc708..22026bfbc4c1e8adbef1bacf30079edb0bf2f1c3 100644 (file)
@@ -304,7 +304,7 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
 {
        struct efx_tx_queue *tx_queue;
 
-       efx_for_each_tx_queue(tx_queue, efx) {
+       efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) {
                efx_fill_test(test_index++, strings, data,
                              &lb_tests->tx_sent[tx_queue->queue],
                              EFX_TX_QUEUE_NAME(tx_queue),
@@ -647,7 +647,7 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
        efx_for_each_tx_queue(tx_queue, efx) {
                channel = tx_queue->channel;
                if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
-                       if (channel->used_flags != EFX_USED_BY_RX_TX)
+                       if (channel->channel < efx->n_rx_channels)
                                coalesce->tx_coalesce_usecs_irq =
                                        channel->irq_moderation;
                        else
@@ -690,7 +690,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
 
        /* If the channel is shared only allow RX parameters to be set */
        efx_for_each_tx_queue(tx_queue, efx) {
-               if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
+               if ((tx_queue->channel->channel < efx->n_rx_channels) &&
                    tx_usecs) {
                        EFX_ERR(efx, "Channel is shared. "
                                "Only RX coalescing may be set\n");
index 08278e7302b386145f75c408c1c3eef193981978..655b697b45b2db80a147722a0d1c91bedb093672 100644 (file)
@@ -175,16 +175,19 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
        EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
                  irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
-       /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
-       if (unlikely(syserr))
-               return efx_nic_fatal_interrupt(efx);
-
        /* Determine interrupting queues, clear interrupt status
         * register and acknowledge the device interrupt.
         */
        BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS);
        queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q);
+
+       /* Check to see if we have a serious error condition */
+       if (queues & (1U << efx->fatal_irq_level)) {
+               syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
+               if (unlikely(syserr))
+                       return efx_nic_fatal_interrupt(efx);
+       }
+
        EFX_ZERO_OWORD(*int_ker);
        wmb(); /* Ensure the vector is cleared before interrupt ack */
        falcon_irq_ack_a1(efx);
@@ -504,6 +507,9 @@ static void falcon_reset_macs(struct efx_nic *efx)
        /* Ensure the correct MAC is selected before statistics
         * are re-enabled by the caller */
        efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
+
+       /* This can run even when the GMAC is selected */
+       falcon_setup_xaui(efx);
 }
 
 void falcon_drain_tx_fifo(struct efx_nic *efx)
index 8ccab2c67a2094680ef743df277cd7e20a8d16c2..c84a2ce2ccbbb905458d110172f2d272f00edf2a 100644 (file)
@@ -26,7 +26,7 @@
  *************************************************************************/
 
 /* Configure the XAUI driver that is an output from Falcon */
-static void falcon_setup_xaui(struct efx_nic *efx)
+void falcon_setup_xaui(struct efx_nic *efx)
 {
        efx_oword_t sdctl, txdrv;
 
@@ -85,14 +85,14 @@ int falcon_reset_xaui(struct efx_nic *efx)
        return -ETIMEDOUT;
 }
 
-static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
+static void falcon_ack_status_intr(struct efx_nic *efx)
 {
        efx_oword_t reg;
 
        if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
                return;
 
-       /* We expect xgmii faults if the wireside link is up */
+       /* We expect xgmii faults if the wireside link is down */
        if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up)
                return;
 
@@ -101,14 +101,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
        if (efx->xmac_poll_required)
                return;
 
-       /* Flush the ISR */
-       if (enable)
-               efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
-
-       EFX_POPULATE_OWORD_2(reg,
-                            FRF_AB_XM_MSK_RMTFLT, !enable,
-                            FRF_AB_XM_MSK_LCLFLT, !enable);
-       efx_writeo(efx, &reg, FR_AB_XM_MGT_INT_MASK);
+       efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
 }
 
 static bool falcon_xgxs_link_ok(struct efx_nic *efx)
@@ -283,15 +276,13 @@ static bool falcon_xmac_check_fault(struct efx_nic *efx)
 
 static int falcon_reconfigure_xmac(struct efx_nic *efx)
 {
-       falcon_mask_status_intr(efx, false);
-
        falcon_reconfigure_xgxs_core(efx);
        falcon_reconfigure_xmac_core(efx);
 
        falcon_reconfigure_mac_wrapper(efx);
 
        efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 5);
-       falcon_mask_status_intr(efx, true);
+       falcon_ack_status_intr(efx);
 
        return 0;
 }
@@ -362,9 +353,8 @@ void falcon_poll_xmac(struct efx_nic *efx)
            !efx->xmac_poll_required)
                return;
 
-       falcon_mask_status_intr(efx, false);
        efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1);
-       falcon_mask_status_intr(efx, true);
+       falcon_ack_status_intr(efx);
 }
 
 struct efx_mac_operations falcon_xmac_operations = {
index c48669c774141965c2f12cbe2f1d9749e5642ea9..93cc3c1b9450b28cb0587617855818af8de580e5 100644 (file)
@@ -613,7 +613,7 @@ int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build)
        }
 
        if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) {
-               rc = -EMSGSIZE;
+               rc = -EIO;
                goto fail;
        }
 
@@ -647,8 +647,10 @@ int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
                          outbuf, sizeof(outbuf), &outlen);
        if (rc)
                goto fail;
-       if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN)
+       if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) {
+               rc = -EIO;
                goto fail;
+       }
 
        if (was_attached != NULL)
                *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE);
@@ -676,7 +678,7 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
                goto fail;
 
        if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LEN) {
-               rc = -EMSGSIZE;
+               rc = -EIO;
                goto fail;
        }
 
@@ -738,8 +740,10 @@ int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out)
                          outbuf, sizeof(outbuf), &outlen);
        if (rc)
                goto fail;
-       if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN)
+       if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) {
+               rc = -EIO;
                goto fail;
+       }
 
        *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES);
        return 0;
@@ -765,8 +769,10 @@ int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type,
                          outbuf, sizeof(outbuf), &outlen);
        if (rc)
                goto fail;
-       if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN)
+       if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) {
+               rc = -EIO;
                goto fail;
+       }
 
        *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE);
        *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE);
@@ -926,20 +932,26 @@ int efx_mcdi_nvram_test_all(struct efx_nic *efx)
 
        rc = efx_mcdi_nvram_types(efx, &nvram_types);
        if (rc)
-               return rc;
+               goto fail1;
 
        type = 0;
        while (nvram_types != 0) {
                if (nvram_types & 1) {
                        rc = efx_mcdi_nvram_test(efx, type);
                        if (rc)
-                               return rc;
+                               goto fail2;
                }
                type++;
                nvram_types >>= 1;
        }
 
        return 0;
+
+fail2:
+       EFX_ERR(efx, "%s: failed type=%u\n", __func__, type);
+fail1:
+       EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc);
+       return rc;
 }
 
 static int efx_mcdi_read_assertion(struct efx_nic *efx)
@@ -968,7 +980,7 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
        if (rc)
                return rc;
        if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
-               return -EINVAL;
+               return -EIO;
 
        /* Print out any recorded assertion state */
        flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS);
@@ -1086,7 +1098,7 @@ int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
                goto fail;
 
        if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) {
-               rc = -EMSGSIZE;
+               rc = -EIO;
                goto fail;
        }
 
@@ -1121,7 +1133,7 @@ int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out)
                goto fail;
 
        if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) {
-               rc = -EMSGSIZE;
+               rc = -EIO;
                goto fail;
        }
 
index 06d24a1e412aa74dffde75421687b45bd57cb494..39182631ac924a3938e3cbb39e1d28073c5cca55 100644 (file)
@@ -80,7 +80,7 @@ int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
        u8 inbuf[MC_CMD_MAC_STATS_IN_LEN];
        int rc;
        efx_dword_t *cmd_ptr;
-       int period = 1000;
+       int period = enable ? 1000 : 0;
        u32 addr_hi;
        u32 addr_lo;
 
@@ -92,21 +92,14 @@ int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
        MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo);
        MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi);
        cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD);
-       if (enable)
-               EFX_POPULATE_DWORD_6(*cmd_ptr,
-                                    MC_CMD_MAC_STATS_CMD_DMA, 1,
-                                    MC_CMD_MAC_STATS_CMD_CLEAR, clear,
-                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1,
-                                    MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 1,
-                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0,
-                                    MC_CMD_MAC_STATS_CMD_PERIOD_MS, period);
-       else
-               EFX_POPULATE_DWORD_5(*cmd_ptr,
-                                    MC_CMD_MAC_STATS_CMD_DMA, 0,
-                                    MC_CMD_MAC_STATS_CMD_CLEAR, clear,
-                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1,
-                                    MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 0,
-                                    MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0);
+       EFX_POPULATE_DWORD_7(*cmd_ptr,
+                            MC_CMD_MAC_STATS_CMD_DMA, !!enable,
+                            MC_CMD_MAC_STATS_CMD_CLEAR, clear,
+                            MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1,
+                            MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, !!enable,
+                            MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0,
+                            MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT, 1,
+                            MC_CMD_MAC_STATS_CMD_PERIOD_MS, period);
        MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len);
 
        rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
index bd59302695b3af4d7d07c4c0983dcff488496e8f..90359e6440063bc232a4fd2a6b40143b0eb77347 100644 (file)
  * bist output. The driver should only consume the BIST output
  * after validating OUTLEN and PHY_CFG.PHY_TYPE.
  *
- * If a driver can't succesfully parse the BIST output, it should
+ * If a driver can't successfully parse the BIST output, it should
  * still respect the pass/Fail in OUT.RESULT
  *
  * Locks required: PHY_LOCK if doing a  PHY BIST
 #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_SFT9001_LEN 36
 #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
 /* 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_OUT_SFT9001_CABLE_LENGTH_A_OFST 4
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B_OFST 8
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C_OFST 12
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D_OFST 16
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_A_OFST 20
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_B_OFST 24
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_C_OFST 28
+#define MC_CMD_POLL_BIST_OUT_SFT9001_CABLE_STATUS_D_OFST 32
 #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
 /* MC_CMD_PHY_STATS:
  * Get generic PHY statistics
  *
- * This call returns the statistics for a generic PHY, by direct DMA
- * into host memory, in a sparse array (indexed by the enumerate).
- * Each value is represented by a 32bit number.
+ * This call returns the statistics for a generic PHY in a sparse
+ * array (indexed by the enumerate). Each value is represented by
+ * a 32bit number.
+ *
+ * If the DMA_ADDR is 0, then no DMA is performed, and the statistics
+ * may be read directly out of shared memory. If DMA_ADDR != 0, then
+ * the statistics are dmad to that (page-aligned location)
  *
  * Locks required: None
  * Returns: 0, ETIME
 #define MC_CMD_PHY_STATS_IN_LEN 8
 #define MC_CMD_PHY_STATS_IN_DMA_ADDR_LO_OFST 0
 #define MC_CMD_PHY_STATS_IN_DMA_ADDR_HI_OFST 4
-#define MC_CMD_PHY_STATS_OUT_LEN 0
+#define MC_CMD_PHY_STATS_OUT_DMA_LEN 0
+#define MC_CMD_PHY_STATS_OUT_NO_DMA_LEN (MC_CMD_PHY_NSTATS * 4)
 
 /* Unified MAC statistics enumeration */
 #define MC_CMD_MAC_GENERATION_START 0
 #define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1
 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2
 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1
-/* Fields only relevent when PERIODIC_CHANGE is set */
+/* Remaining PERIOD* fields only relevent when PERIODIC_CHANGE is set */
 #define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3
 #define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1
 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4
 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_WIDTH 1
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT_LBN 5
+#define MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT_WIDTH 1
 #define MC_CMD_MAC_STATS_CMD_PERIOD_MS_LBN 16
 #define MC_CMD_MAC_STATS_CMD_PERIOD_MS_WIDTH 16
 #define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12
 #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 */
 
+/* MC_CMD_TEST_HACK: (debug (unsurprisingly))
+  * Change bits of network port state for test purposes in ways that would never be
+  * useful in normal operation and so need a special command to change. */
+#define MC_CMD_TEST_HACK 0x2f
+#define MC_CMD_TEST_HACK_IN_LEN 8
+#define MC_CMD_TEST_HACK_IN_TXPAD_OFST 0
+#define   MC_CMD_TEST_HACK_IN_TXPAD_AUTO  0 /* Let the MC manage things */
+#define   MC_CMD_TEST_HACK_IN_TXPAD_ON    1 /* Force on */
+#define   MC_CMD_TEST_HACK_IN_TXPAD_OFF   2 /* Force on */
+#define MC_CMD_TEST_HACK_IN_IPG_OFST   4 /* Takes a value in bits */
+#define   MC_CMD_TEST_HACK_IN_IPG_AUTO    0 /* The MC picks the value */
+#define MC_CMD_TEST_HACK_OUT_LEN 0
+
+/* MC_CMD_SENSOR_SET_LIMS: (debug) (mostly) adjust the sensor limits. This
+ * is a warranty-voiding operation.
+  *
+ * IN: sensor identifier (one of the enumeration starting with MC_CMD_SENSOR_CONTROLLER_TEMP
+ * followed by 4 32-bit values: min(warning) max(warning), min(fatal), max(fatal). Which
+ * of these limits are meaningful and what their interpretation is is sensor-specific.
+ *
+ * OUT: nothing
+ *
+ * Returns: ENOENT if the sensor specified does not exist, EINVAL if the limits are
+  * out of range.
+ */
+#define MC_CMD_SENSOR_SET_LIMS 0x4e
+#define MC_CMD_SENSOR_SET_LIMS_IN_LEN 20
+#define MC_CMD_SENSOR_SET_LIMS_IN_SENSOR_OFST 0
+#define MC_CMD_SENSOR_SET_LIMS_IN_LOW0_OFST 4
+#define MC_CMD_SENSOR_SET_LIMS_IN_HI0_OFST  8
+#define MC_CMD_SENSOR_SET_LIMS_IN_LOW1_OFST 12
+#define MC_CMD_SENSOR_SET_LIMS_IN_HI1_OFST  16
+
 /* 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. */
index 2f2354696663cc8f207af5bc8449b8f7d3d31e2a..6032c0e1f1f8bcd261d37fb89b69885e48635cea 100644 (file)
@@ -17,6 +17,8 @@
 #include "mcdi.h"
 #include "mcdi_pcol.h"
 #include "mdio_10g.h"
+#include "nic.h"
+#include "selftest.h"
 
 struct efx_mcdi_phy_cfg {
        u32 flags;
@@ -48,7 +50,7 @@ efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
                goto fail;
 
        if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) {
-               rc = -EMSGSIZE;
+               rc = -EIO;
                goto fail;
        }
 
@@ -111,7 +113,7 @@ static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes)
                goto fail;
 
        if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) {
-               rc = -EMSGSIZE;
+               rc = -EIO;
                goto fail;
        }
 
@@ -587,13 +589,153 @@ static int efx_mcdi_phy_test_alive(struct efx_nic *efx)
                return rc;
 
        if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN)
-               return -EMSGSIZE;
+               return -EIO;
        if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK)
                return -EINVAL;
 
        return 0;
 }
 
+static const char *const mcdi_sft9001_cable_diag_names[] = {
+       "cable.pairA.length",
+       "cable.pairB.length",
+       "cable.pairC.length",
+       "cable.pairD.length",
+       "cable.pairA.status",
+       "cable.pairB.status",
+       "cable.pairC.status",
+       "cable.pairD.status",
+};
+
+static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode,
+                        int *results)
+{
+       unsigned int retry, i, count = 0;
+       size_t outlen;
+       u32 status;
+       u8 *buf, *ptr;
+       int rc;
+
+       buf = kzalloc(0x100, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0);
+       MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode);
+       rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN,
+                         NULL, 0, NULL);
+       if (rc)
+               goto out;
+
+       /* Wait up to 10s for BIST to finish */
+       for (retry = 0; retry < 100; ++retry) {
+               BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0);
+               rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
+                                 buf, 0x100, &outlen);
+               if (rc)
+                       goto out;
+
+               status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT);
+               if (status != MC_CMD_POLL_BIST_RUNNING)
+                       goto finished;
+
+               msleep(100);
+       }
+
+       rc = -ETIMEDOUT;
+       goto out;
+
+finished:
+       results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1;
+
+       /* SFT9001 specific cable diagnostics output */
+       if (efx->phy_type == PHY_TYPE_SFT9001B &&
+           (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT ||
+            bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) {
+               ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
+               if (status == MC_CMD_POLL_BIST_PASSED &&
+                   outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) {
+                       for (i = 0; i < 8; i++) {
+                               results[count + i] =
+                                       EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i],
+                                                       EFX_DWORD_0);
+                       }
+               }
+               count += 8;
+       }
+       rc = count;
+
+out:
+       kfree(buf);
+
+       return rc;
+}
+
+static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
+                                 unsigned flags)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+       u32 mode;
+       int rc;
+
+       if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
+               rc = efx_mcdi_bist(efx, MC_CMD_PHY_BIST, results);
+               if (rc < 0)
+                       return rc;
+
+               results += rc;
+       }
+
+       /* If we support both LONG and SHORT, then run each in response to
+        * break or not. Otherwise, run the one we support */
+       mode = 0;
+       if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN)) {
+               if ((flags & ETH_TEST_FL_OFFLINE) &&
+                   (phy_cfg->flags &
+                    (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN)))
+                       mode = MC_CMD_PHY_BIST_CABLE_LONG;
+               else
+                       mode = MC_CMD_PHY_BIST_CABLE_SHORT;
+       } else if (phy_cfg->flags &
+                  (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))
+               mode = MC_CMD_PHY_BIST_CABLE_LONG;
+
+       if (mode != 0) {
+               rc = efx_mcdi_bist(efx, mode, results);
+               if (rc < 0)
+                       return rc;
+               results += rc;
+       }
+
+       return 0;
+}
+
+const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
+{
+       struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+
+       if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
+               if (index == 0)
+                       return "bist";
+               --index;
+       }
+
+       if (phy_cfg->flags & ((1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_SHORT_LBN) |
+                             (1 << MC_CMD_GET_PHY_CFG_BIST_CABLE_LONG_LBN))) {
+               if (index == 0)
+                       return "cable";
+               --index;
+
+               if (efx->phy_type == PHY_TYPE_SFT9001B) {
+                       if (index < ARRAY_SIZE(mcdi_sft9001_cable_diag_names))
+                               return mcdi_sft9001_cable_diag_names[index];
+                       index -= ARRAY_SIZE(mcdi_sft9001_cable_diag_names);
+               }
+       }
+
+       return NULL;
+}
+
 struct efx_phy_operations efx_mcdi_phy_ops = {
        .probe          = efx_mcdi_phy_probe,
        .init           = efx_port_dummy_op_int,
@@ -604,6 +746,6 @@ struct efx_phy_operations efx_mcdi_phy_ops = {
        .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,
+       .run_tests      = efx_mcdi_phy_run_tests,
+       .test_name      = efx_mcdi_phy_test_name,
 };
index cb018e272097e56caee175c0cad55f72d353be8b..2e6fd89f2a72d722555357bf46595754f6426e38 100644 (file)
@@ -85,9 +85,13 @@ do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
 #define EFX_MAX_CHANNELS 32
 #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
 
-#define EFX_TX_QUEUE_OFFLOAD_CSUM      0
-#define EFX_TX_QUEUE_NO_CSUM           1
-#define EFX_TX_QUEUE_COUNT             2
+/* Checksum generation is a per-queue option in hardware, so each
+ * queue visible to the networking core is backed by two hardware TX
+ * queues. */
+#define EFX_MAX_CORE_TX_QUEUES EFX_MAX_CHANNELS
+#define EFX_TXQ_TYPE_OFFLOAD   1
+#define EFX_TXQ_TYPES          2
+#define EFX_MAX_TX_QUEUES      (EFX_TXQ_TYPES * EFX_MAX_CORE_TX_QUEUES)
 
 /**
  * struct efx_special_buffer - An Efx special buffer
@@ -187,7 +191,7 @@ struct efx_tx_buffer {
 struct efx_tx_queue {
        /* Members which don't change on the fast path */
        struct efx_nic *efx ____cacheline_aligned_in_smp;
-       int queue;
+       unsigned queue;
        struct efx_channel *channel;
        struct efx_nic *nic;
        struct efx_tx_buffer *buffer;
@@ -306,11 +310,6 @@ struct efx_buffer {
 };
 
 
-/* Flags for channel->used_flags */
-#define EFX_USED_BY_RX 1
-#define EFX_USED_BY_TX 2
-#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX)
-
 enum efx_rx_alloc_method {
        RX_ALLOC_METHOD_AUTO = 0,
        RX_ALLOC_METHOD_SKB = 1,
@@ -327,7 +326,6 @@ enum efx_rx_alloc_method {
  * @efx: Associated Efx NIC
  * @channel: Channel instance number
  * @name: Name for channel and IRQ
- * @used_flags: Channel is used by net driver
  * @enabled: Channel enabled indicator
  * @irq: IRQ number (MSI and MSI-X only)
  * @irq_moderation: IRQ moderation value (in hardware ticks)
@@ -352,12 +350,14 @@ enum efx_rx_alloc_method {
  * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
  * @n_rx_overlength: Count of RX_OVERLENGTH errors
  * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
+ * @tx_queue: Pointer to first TX queue, or %NULL if not used for TX
+ * @tx_stop_count: Core TX queue stop count
+ * @tx_stop_lock: Core TX queue stop lock
  */
 struct efx_channel {
        struct efx_nic *efx;
        int channel;
        char name[IFNAMSIZ + 6];
-       int used_flags;
        bool enabled;
        int irq;
        unsigned int irq_moderation;
@@ -389,6 +389,9 @@ struct efx_channel {
        struct efx_rx_buffer *rx_pkt;
        bool rx_pkt_csummed;
 
+       struct efx_tx_queue *tx_queue;
+       atomic_t tx_stop_count;
+       spinlock_t tx_stop_lock;
 };
 
 enum efx_led_mode {
@@ -661,8 +664,9 @@ union efx_multicast_hash {
  * @rx_queue: RX DMA queues
  * @channel: Channels
  * @next_buffer_table: First available buffer table id
- * @n_rx_queues: Number of RX queues
  * @n_channels: Number of channels in use
+ * @n_rx_channels: Number of channels used for RX (= number of RX queues)
+ * @n_tx_channels: Number of channels used for TX
  * @rx_buffer_len: RX buffer length
  * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
  * @int_error_count: Number of internal errors seen recently
@@ -672,6 +676,8 @@ union efx_multicast_hash {
  *     This register is written with the SMP processor ID whenever an
  *     interrupt is handled.  It is used by efx_nic_test_interrupt()
  *     to verify that an interrupt has occurred.
+ * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0
+ * @fatal_irq_level: IRQ level (bit number) used for serious errors
  * @spi_flash: SPI flash device
  *     This field will be %NULL if no flash device is present (or for Siena).
  * @spi_eeprom: SPI EEPROM device
@@ -691,8 +697,6 @@ union efx_multicast_hash {
  * @port_initialized: Port initialized?
  * @net_dev: Operating system network device. Consider holding the rtnl lock
  * @rx_checksum_enabled: RX checksumming enabled
- * @netif_stop_count: Port stop count
- * @netif_stop_lock: Port stop lock
  * @mac_stats: MAC statistics. These include all statistics the MACs
  *     can provide.  Generic code converts these into a standard
  *     &struct net_device_stats.
@@ -740,13 +744,14 @@ struct efx_nic {
        enum nic_state state;
        enum reset_type reset_pending;
 
-       struct efx_tx_queue tx_queue[EFX_TX_QUEUE_COUNT];
+       struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
        struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
        struct efx_channel channel[EFX_MAX_CHANNELS];
 
        unsigned next_buffer_table;
-       int n_rx_queues;
-       int n_channels;
+       unsigned n_channels;
+       unsigned n_rx_channels;
+       unsigned n_tx_channels;
        unsigned int rx_buffer_len;
        unsigned int rx_buffer_order;
 
@@ -755,7 +760,8 @@ struct efx_nic {
 
        struct efx_buffer irq_status;
        volatile signed int last_irq_cpu;
-       unsigned long irq_zero_count;
+       unsigned irq_zero_count;
+       unsigned fatal_irq_level;
 
        struct efx_spi_device *spi_flash;
        struct efx_spi_device *spi_eeprom;
@@ -777,9 +783,6 @@ struct efx_nic {
        struct net_device *net_dev;
        bool rx_checksum_enabled;
 
-       atomic_t netif_stop_count;
-       spinlock_t netif_stop_lock;
-
        struct efx_mac_stats mac_stats;
        struct efx_buffer stats_buffer;
        spinlock_t stats_lock;
@@ -924,40 +927,35 @@ struct efx_nic_type {
 
 /* Iterate over all used channels */
 #define efx_for_each_channel(_channel, _efx)                           \
-       for (_channel = &_efx->channel[0];                              \
-            _channel < &_efx->channel[EFX_MAX_CHANNELS];               \
-            _channel++)                                                \
-               if (!_channel->used_flags)                              \
-                       continue;                                       \
-               else
+       for (_channel = &((_efx)->channel[0]);                          \
+            _channel < &((_efx)->channel[(efx)->n_channels]);          \
+            _channel++)
 
 /* Iterate over all used TX queues */
 #define efx_for_each_tx_queue(_tx_queue, _efx)                         \
-       for (_tx_queue = &_efx->tx_queue[0];                            \
-            _tx_queue < &_efx->tx_queue[EFX_TX_QUEUE_COUNT];           \
+       for (_tx_queue = &((_efx)->tx_queue[0]);                        \
+            _tx_queue < &((_efx)->tx_queue[EFX_TXQ_TYPES *             \
+                                           (_efx)->n_tx_channels]);    \
             _tx_queue++)
 
 /* Iterate over all TX queues belonging to a channel */
 #define efx_for_each_channel_tx_queue(_tx_queue, _channel)             \
-       for (_tx_queue = &_channel->efx->tx_queue[0];                   \
-            _tx_queue < &_channel->efx->tx_queue[EFX_TX_QUEUE_COUNT];  \
-            _tx_queue++)                                               \
-               if (_tx_queue->channel != _channel)                     \
-                       continue;                                       \
-               else
+       for (_tx_queue = (_channel)->tx_queue;                          \
+            _tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
+            _tx_queue++)
 
 /* Iterate over all used RX queues */
 #define efx_for_each_rx_queue(_rx_queue, _efx)                         \
-       for (_rx_queue = &_efx->rx_queue[0];                            \
-            _rx_queue < &_efx->rx_queue[_efx->n_rx_queues];            \
+       for (_rx_queue = &((_efx)->rx_queue[0]);                        \
+            _rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_channels]);    \
             _rx_queue++)
 
 /* Iterate over all RX queues belonging to a channel */
 #define efx_for_each_channel_rx_queue(_rx_queue, _channel)             \
-       for (_rx_queue = &_channel->efx->rx_queue[_channel->channel];   \
+       for (_rx_queue = &((_channel)->efx->rx_queue[(_channel)->channel]); \
             _rx_queue;                                                 \
             _rx_queue = NULL)                                          \
-               if (_rx_queue->channel != _channel)                     \
+               if (_rx_queue->channel != (_channel))                   \
                        continue;                                       \
                else
 
index b06f8e348307d3896f4f10e0e9f0cb3c4b7807e0..5d3aaec58556b5ba8a47f66dad535899149afdda 100644 (file)
@@ -418,7 +418,7 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
                              FRF_BZ_TX_NON_IP_DROP_DIS, 1);
 
        if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
-               int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
+               int csum = tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD;
                EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum);
                EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS,
                                    !csum);
@@ -431,10 +431,10 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
                efx_oword_t reg;
 
                /* Only 128 bits in this register */
-               BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128);
+               BUILD_BUG_ON(EFX_MAX_TX_QUEUES > 128);
 
                efx_reado(efx, &reg, FR_AA_TX_CHKSM_CFG);
-               if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM)
+               if (tx_queue->queue & EFX_TXQ_TYPE_OFFLOAD)
                        clear_bit_le(tx_queue->queue, (void *)&reg);
                else
                        set_bit_le(tx_queue->queue, (void *)&reg);
@@ -654,22 +654,23 @@ void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
  * The NIC batches TX completion events; the message we receive is of
  * the form "complete all TX events up to this index".
  */
-static void
+static int
 efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
 {
        unsigned int tx_ev_desc_ptr;
        unsigned int tx_ev_q_label;
        struct efx_tx_queue *tx_queue;
        struct efx_nic *efx = channel->efx;
+       int tx_packets = 0;
 
        if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
                /* Transmit completion */
                tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR);
                tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL);
                tx_queue = &efx->tx_queue[tx_ev_q_label];
-               channel->irq_mod_score +=
-                       (tx_ev_desc_ptr - tx_queue->read_count) &
-                       EFX_TXQ_MASK;
+               tx_packets = ((tx_ev_desc_ptr - tx_queue->read_count) &
+                             EFX_TXQ_MASK);
+               channel->irq_mod_score += tx_packets;
                efx_xmit_done(tx_queue, tx_ev_desc_ptr);
        } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) {
                /* Rewrite the FIFO write pointer */
@@ -689,6 +690,8 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
                        EFX_QWORD_FMT"\n", channel->channel,
                        EFX_QWORD_VAL(*event));
        }
+
+       return tx_packets;
 }
 
 /* Detect errors included in the rx_evt_pkt_ok bit. */
@@ -947,16 +950,17 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
        }
 }
 
-int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
+int efx_nic_process_eventq(struct efx_channel *channel, int budget)
 {
        unsigned int read_ptr;
        efx_qword_t event, *p_event;
        int ev_code;
-       int rx_packets = 0;
+       int tx_packets = 0;
+       int spent = 0;
 
        read_ptr = channel->eventq_read_ptr;
 
-       do {
+       for (;;) {
                p_event = efx_event(channel, read_ptr);
                event = *p_event;
 
@@ -970,15 +974,23 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
                /* Clear this event by marking it all ones */
                EFX_SET_QWORD(*p_event);
 
+               /* Increment read pointer */
+               read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
+
                ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE);
 
                switch (ev_code) {
                case FSE_AZ_EV_CODE_RX_EV:
                        efx_handle_rx_event(channel, &event);
-                       ++rx_packets;
+                       if (++spent == budget)
+                               goto out;
                        break;
                case FSE_AZ_EV_CODE_TX_EV:
-                       efx_handle_tx_event(channel, &event);
+                       tx_packets += efx_handle_tx_event(channel, &event);
+                       if (tx_packets >= EFX_TXQ_SIZE) {
+                               spent = budget;
+                               goto out;
+                       }
                        break;
                case FSE_AZ_EV_CODE_DRV_GEN_EV:
                        channel->eventq_magic = EFX_QWORD_FIELD(
@@ -1001,14 +1013,11 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota)
                                " (data " EFX_QWORD_FMT ")\n", channel->channel,
                                ev_code, EFX_QWORD_VAL(event));
                }
+       }
 
-               /* Increment read pointer */
-               read_ptr = (read_ptr + 1) & EFX_EVQ_MASK;
-
-       } while (rx_packets < rx_quota);
-
+out:
        channel->eventq_read_ptr = read_ptr;
-       return rx_packets;
+       return spent;
 }
 
 
@@ -1123,7 +1132,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
                    ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) {
                        ev_queue = EFX_QWORD_FIELD(*event,
                                                   FSF_AZ_DRIVER_EV_SUBDATA);
-                       if (ev_queue < EFX_TX_QUEUE_COUNT) {
+                       if (ev_queue < EFX_TXQ_TYPES * efx->n_tx_channels) {
                                tx_queue = efx->tx_queue + ev_queue;
                                tx_queue->flushed = FLUSH_DONE;
                        }
@@ -1133,7 +1142,7 @@ static void efx_poll_flush_events(struct efx_nic *efx)
                                *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
                        ev_failed = EFX_QWORD_FIELD(
                                *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
-                       if (ev_queue < efx->n_rx_queues) {
+                       if (ev_queue < efx->n_rx_channels) {
                                rx_queue = efx->rx_queue + ev_queue;
                                rx_queue->flushed =
                                        ev_failed ? FLUSH_FAILED : FLUSH_DONE;
@@ -1229,15 +1238,9 @@ static inline void efx_nic_interrupts(struct efx_nic *efx,
                                      bool enabled, bool force)
 {
        efx_oword_t int_en_reg_ker;
-       unsigned int level = 0;
-
-       if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx))
-               /* Set the level always even if we're generating a test
-                * interrupt, because our legacy interrupt handler is safe */
-               level = 0x1f;
 
        EFX_POPULATE_OWORD_3(int_en_reg_ker,
-                            FRF_AZ_KER_INT_LEVE_SEL, level,
+                            FRF_AZ_KER_INT_LEVE_SEL, efx->fatal_irq_level,
                             FRF_AZ_KER_INT_KER, force,
                             FRF_AZ_DRV_INT_EN_KER, enabled);
        efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER);
@@ -1291,11 +1294,10 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
                EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
                EFX_OWORD_VAL(fatal_intr),
                error ? "disabling bus mastering" : "no recognised error");
-       if (error == 0)
-               goto out;
 
        /* If this is a memory parity error dump which blocks are offending */
-       mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER);
+       mem_perr = (EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER) ||
+                   EFX_OWORD_FIELD(fatal_intr, FRF_AZ_SRM_PERR_INT_KER));
        if (mem_perr) {
                efx_oword_t reg;
                efx_reado(efx, &reg, FR_AZ_MEM_STAT);
@@ -1324,7 +1326,7 @@ irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx)
                        "NIC will be disabled\n");
                efx_schedule_reset(efx, RESET_TYPE_DISABLE);
        }
-out:
+
        return IRQ_HANDLED;
 }
 
@@ -1346,9 +1348,11 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
        queues = EFX_EXTRACT_DWORD(reg, 0, 31);
 
        /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
-       if (unlikely(syserr))
-               return efx_nic_fatal_interrupt(efx);
+       if (queues & (1U << efx->fatal_irq_level)) {
+               syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
+               if (unlikely(syserr))
+                       return efx_nic_fatal_interrupt(efx);
+       }
 
        if (queues != 0) {
                if (EFX_WORKAROUND_15783(efx))
@@ -1362,33 +1366,28 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
                }
                result = IRQ_HANDLED;
 
-       } else if (EFX_WORKAROUND_15783(efx) &&
-                  efx->irq_zero_count++ == 0) {
+       } else if (EFX_WORKAROUND_15783(efx)) {
                efx_qword_t *event;
 
-               /* Ensure we rearm all event queues */
+               /* We can't return IRQ_HANDLED more than once on seeing ISR=0
+                * because this might be a shared interrupt. */
+               if (efx->irq_zero_count++ == 0)
+                       result = IRQ_HANDLED;
+
+               /* Ensure we schedule or rearm all event queues */
                efx_for_each_channel(channel, efx) {
                        event = efx_event(channel, channel->eventq_read_ptr);
                        if (efx_event_present(event))
                                efx_schedule_channel(channel);
+                       else
+                               efx_nic_eventq_read_ack(channel);
                }
-
-               result = IRQ_HANDLED;
        }
 
        if (result == IRQ_HANDLED) {
                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;
@@ -1413,9 +1412,11 @@ static irqreturn_t efx_msi_interrupt(int irq, void *dev_id)
                  irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
        /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
-       if (unlikely(syserr))
-               return efx_nic_fatal_interrupt(efx);
+       if (channel->channel == efx->fatal_irq_level) {
+               syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
+               if (unlikely(syserr))
+                       return efx_nic_fatal_interrupt(efx);
+       }
 
        /* Schedule processing of the channel */
        efx_schedule_channel(channel);
@@ -1440,7 +1441,7 @@ static void efx_setup_rss_indir_table(struct efx_nic *efx)
             offset < FR_BZ_RX_INDIRECTION_TBL + 0x800;
             offset += 0x10) {
                EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
-                                    i % efx->n_rx_queues);
+                                    i % efx->n_rx_channels);
                efx_writed(efx, &dword, offset);
                i++;
        }
@@ -1553,6 +1554,13 @@ void efx_nic_init_common(struct efx_nic *efx)
                             FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
        efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER);
 
+       if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx))
+               /* Use an interrupt level unused by event queues */
+               efx->fatal_irq_level = 0x1f;
+       else
+               /* Use a valid MSI-X vector */
+               efx->fatal_irq_level = 0;
+
        /* Enable all the genuinely fatal interrupts.  (They are still
         * masked by the overall interrupt mask, controlled by
         * falcon_interrupts()).
@@ -1563,6 +1571,8 @@ void efx_nic_init_common(struct efx_nic *efx)
                             FRF_AZ_ILL_ADR_INT_KER_EN, 1,
                             FRF_AZ_RBUF_OWN_INT_KER_EN, 1,
                             FRF_AZ_TBUF_OWN_INT_KER_EN, 1);
+       if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
+               EFX_SET_OWORD_FIELD(temp, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 1);
        EFX_INVERT_OWORD(temp);
        efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER);
 
index 3166bafdfbefc617d6df6fe1cf1589008c66b19f..bbc2c0c2f8430d15f386fc93807bc8b86c33f245 100644 (file)
@@ -135,12 +135,14 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx)
  * @fw_build: Firmware build number
  * @mcdi: Management-Controller-to-Driver Interface
  * @wol_filter_id: Wake-on-LAN packet filter id
+ * @ipv6_rss_key: Toeplitz hash key for IPv6 RSS
  */
 struct siena_nic_data {
        u64 fw_version;
        u32 fw_build;
        struct efx_mcdi_iface mcdi;
        int wol_filter_id;
+       u8 ipv6_rss_key[40];
 };
 
 extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len);
@@ -203,6 +205,7 @@ extern void falcon_irq_ack_a1(struct efx_nic *efx);
 extern int efx_nic_flush_queues(struct efx_nic *efx);
 extern void falcon_start_nic_stats(struct efx_nic *efx);
 extern void falcon_stop_nic_stats(struct efx_nic *efx);
+extern void falcon_setup_xaui(struct efx_nic *efx);
 extern int falcon_reset_xaui(struct efx_nic *efx);
 extern void efx_nic_init_common(struct efx_nic *efx);
 
index 0106b1d9aae216312f344d6d25e5899c4ae4c2e6..371e86cc090f3c93eb1fad2775012af54ef0547f 100644 (file)
@@ -616,10 +616,10 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests,
                        goto out;
                }
 
-               /* Test every TX queue */
-               efx_for_each_tx_queue(tx_queue, efx) {
-                       state->offload_csum = (tx_queue->queue ==
-                                              EFX_TX_QUEUE_OFFLOAD_CSUM);
+               /* Test both types of TX queue */
+               efx_for_each_channel_tx_queue(tx_queue, &efx->channel[0]) {
+                       state->offload_csum = (tx_queue->queue &
+                                              EFX_TXQ_TYPE_OFFLOAD);
                        rc = efx_test_loopback(tx_queue,
                                               &tests->loopback[mode]);
                        if (rc)
index 643bef72b99d0515647d7a783d056dfb79e88a03..aed495a4dad7c7756a7dd6e67a0ba4d5156aad1e 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 struct efx_loopback_self_tests {
-       int tx_sent[EFX_TX_QUEUE_COUNT];
-       int tx_done[EFX_TX_QUEUE_COUNT];
+       int tx_sent[EFX_TXQ_TYPES];
+       int tx_done[EFX_TXQ_TYPES];
        int rx_good;
        int rx_bad;
 };
index e0c46f59d1f8793d365710d1e80d6c51ae469b9d..727b4228e0819bfe336e38ed6504bd8c2d852edc 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/random.h>
 #include "net_driver.h"
 #include "bitfield.h"
 #include "efx.h"
@@ -274,6 +275,9 @@ static int siena_probe_nic(struct efx_nic *efx)
                goto fail5;
        }
 
+       get_random_bytes(&nic_data->ipv6_rss_key,
+                        sizeof(nic_data->ipv6_rss_key));
+
        return 0;
 
 fail5:
@@ -293,6 +297,7 @@ fail1:
  */
 static int siena_init_nic(struct efx_nic *efx)
 {
+       struct siena_nic_data *nic_data = efx->nic_data;
        efx_oword_t temp;
        int rc;
 
@@ -319,6 +324,20 @@ static int siena_init_nic(struct efx_nic *efx)
        EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1);
        efx_writeo(efx, &temp, FR_AZ_RX_CFG);
 
+       /* Enable IPv6 RSS */
+       BUILD_BUG_ON(sizeof(nic_data->ipv6_rss_key) !=
+                    2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 ||
+                    FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0);
+       memcpy(&temp, nic_data->ipv6_rss_key, sizeof(temp));
+       efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1);
+       memcpy(&temp, nic_data->ipv6_rss_key + sizeof(temp), sizeof(temp));
+       efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2);
+       EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1,
+                            FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1);
+       memcpy(&temp, nic_data->ipv6_rss_key + 2 * sizeof(temp),
+              FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
+       efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
+
        if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0)
                /* No MCDI operation has been defined to set thresholds */
                EFX_ERR(efx, "ignoring RX flow control thresholds\n");
index be0e110a1f73b4584582868e475cf3492cead862..6bb12a87ef2d5f4292f4343f41e6ed010fd5f14f 100644 (file)
  */
 #define EFX_TXQ_THRESHOLD (EFX_TXQ_MASK / 2u)
 
-/* We want to be able to nest calls to netif_stop_queue(), since each
- * channel can have an individual stop on the queue.
- */
-void efx_stop_queue(struct efx_nic *efx)
+/* We need to be able to nest calls to netif_tx_stop_queue(), partly
+ * because of the 2 hardware queues associated with each core queue,
+ * but also so that we can inhibit TX for reasons other than a full
+ * hardware queue. */
+void efx_stop_queue(struct efx_channel *channel)
 {
-       spin_lock_bh(&efx->netif_stop_lock);
+       struct efx_nic *efx = channel->efx;
+
+       if (!channel->tx_queue)
+               return;
+
+       spin_lock_bh(&channel->tx_stop_lock);
        EFX_TRACE(efx, "stop TX queue\n");
 
-       atomic_inc(&efx->netif_stop_count);
-       netif_stop_queue(efx->net_dev);
+       atomic_inc(&channel->tx_stop_count);
+       netif_tx_stop_queue(
+               netdev_get_tx_queue(
+                       efx->net_dev,
+                       channel->tx_queue->queue / EFX_TXQ_TYPES));
 
-       spin_unlock_bh(&efx->netif_stop_lock);
+       spin_unlock_bh(&channel->tx_stop_lock);
 }
 
-/* Wake netif's TX queue
- * We want to be able to nest calls to netif_stop_queue(), since each
- * channel can have an individual stop on the queue.
- */
-void efx_wake_queue(struct efx_nic *efx)
+/* Decrement core TX queue stop count and wake it if the count is 0 */
+void efx_wake_queue(struct efx_channel *channel)
 {
+       struct efx_nic *efx = channel->efx;
+
+       if (!channel->tx_queue)
+               return;
+
        local_bh_disable();
-       if (atomic_dec_and_lock(&efx->netif_stop_count,
-                               &efx->netif_stop_lock)) {
+       if (atomic_dec_and_lock(&channel->tx_stop_count,
+                               &channel->tx_stop_lock)) {
                EFX_TRACE(efx, "waking TX queue\n");
-               netif_wake_queue(efx->net_dev);
-               spin_unlock(&efx->netif_stop_lock);
+               netif_tx_wake_queue(
+                       netdev_get_tx_queue(
+                               efx->net_dev,
+                               channel->tx_queue->queue / EFX_TXQ_TYPES));
+               spin_unlock(&channel->tx_stop_lock);
        }
        local_bh_enable();
 }
@@ -298,7 +312,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
        rc = NETDEV_TX_BUSY;
 
        if (tx_queue->stopped == 1)
-               efx_stop_queue(efx);
+               efx_stop_queue(tx_queue->channel);
 
  unwind:
        /* Work backwards until we hit the original insert pointer value */
@@ -374,10 +388,9 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
        if (unlikely(efx->port_inhibited))
                return NETDEV_TX_BUSY;
 
+       tx_queue = &efx->tx_queue[EFX_TXQ_TYPES * skb_get_queue_mapping(skb)];
        if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
-               tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM];
-       else
-               tx_queue = &efx->tx_queue[EFX_TX_QUEUE_NO_CSUM];
+               tx_queue += EFX_TXQ_TYPE_OFFLOAD;
 
        return efx_enqueue_skb(tx_queue, skb);
 }
@@ -405,7 +418,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
                        netif_tx_lock(efx->net_dev);
                        if (tx_queue->stopped) {
                                tx_queue->stopped = 0;
-                               efx_wake_queue(efx);
+                               efx_wake_queue(tx_queue->channel);
                        }
                        netif_tx_unlock(efx->net_dev);
                }
@@ -488,7 +501,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
        /* Release queue's stop on port, if any */
        if (tx_queue->stopped) {
                tx_queue->stopped = 0;
-               efx_wake_queue(tx_queue->efx);
+               efx_wake_queue(tx_queue->channel);
        }
 }
 
@@ -1120,7 +1133,7 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue,
 
        /* Stop the queue if it wasn't stopped before. */
        if (tx_queue->stopped == 1)
-               efx_stop_queue(efx);
+               efx_stop_queue(tx_queue->channel);
 
  unwind:
        /* Free the DMA mapping we were in the process of writing out */
index acd9c734e4830e5305156b5de5e618de29be7685..518f7fc914732c12248bb5d3417e79fc7d3e74ce 100644 (file)
@@ -37,7 +37,7 @@
 /* Truncated IPv4 packets can confuse the TX packet parser */
 #define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB
 /* Legacy ISR read can return zero once */
-#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA
+#define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS
 /* Legacy interrupt storm when interrupt fifo fills */
 #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA
 
index c8fc896fc4600dfc348d0229f0cf91b8755be037..cc4bd8c65f8b6a58846065430f8b89c1be6a4bc3 100644 (file)
@@ -574,7 +574,7 @@ static inline int sgiseeq_reset(struct net_device *dev)
        if (err)
                return err;
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 
        return 0;
@@ -638,8 +638,6 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE))
                kick_tx(dev, sp, hregs);
 
-       dev->trans_start = jiffies;
-
        if (!TX_BUFFS_AVAIL(sp))
                netif_stop_queue(dev);
        spin_unlock_irqrestore(&sp->tx_lock, flags);
@@ -652,7 +650,7 @@ static void timeout(struct net_device *dev)
        printk(KERN_NOTICE "%s: transmit timed out, resetting\n", dev->name);
        sgiseeq_reset(dev);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
index 6242b85d5d1589bfeb8728308ad4e5a93b7bf4d3..586ed0915a293f25d6dd5d6cd1fee28e6ece283e 100644 (file)
@@ -1148,8 +1148,6 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        if (!(ctrl_inl(ndev->base_addr + EDTRR) & EDTRR_TRNS))
                ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR);
 
-       ndev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
index b30ce752bbf3986987061a9b7323c4b59892ea98..a5d6a6bd0c1adfae58469ab7f08fe56e14e17d9f 100644 (file)
@@ -849,13 +849,13 @@ static void sis190_set_rx_mode(struct net_device *dev)
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                rx_mode = AcceptBroadcast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        int bit_nr =
-                               ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
+                               ether_crc(ETH_ALEN, ha->addr) & 0x3f;
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                        rx_mode |= AcceptMulticast;
                }
index cc0c731c4f09588bc924c87dc007e5a41084b2a1..bbbded76ff14d28e561edeed2bfcfa6b91db7187 100644 (file)
@@ -858,7 +858,6 @@ static void mdio_reset(long mdio_addr)
                outl(MDDIR | MDIO | MDC, mdio_addr);
                mdio_delay();
        }
-       return;
 }
 
 /**
@@ -953,8 +952,6 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location,
                mdio_delay();
        }
        outl(0x00, mdio_addr);
-
-       return;
 }
 
 
@@ -1264,7 +1261,6 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision)
                        mdio_write(net_dev, sis_priv->cur_phy, MII_RESV,
                                                (reg14h | 0x2000) & 0xBFFF);
        }
-       return;
 }
 
 /**
@@ -1499,7 +1495,7 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex
        }
 
        if(netif_msg_link(sis_priv))
-               printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
+               printk(KERN_INFO "%s: Media Link On %s %s-duplex\n",
                                        net_dev->name,
                                        *speed == HW_SPEED_100_MBPS ?
                                                "100mbps" : "10mbps",
@@ -1523,7 +1519,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
        int i;
 
        if(netif_msg_tx_err(sis_priv))
-               printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x \n",
+               printk(KERN_INFO "%s: Transmit timeout, status %8.8x %8.8x\n",
                        net_dev->name, inl(ioaddr + cr), inl(ioaddr + isr));
 
        /* Disable interrupts by clearing the interrupt mask. */
@@ -1553,14 +1549,13 @@ static void sis900_tx_timeout(struct net_device *net_dev)
 
        spin_unlock_irqrestore(&sis_priv->lock, flags);
 
-       net_dev->trans_start = jiffies;
+       net_dev->trans_start = jiffies; /* prevent tx timeout */
 
        /* load Transmit Descriptor Register */
        outl(sis_priv->tx_ring_dma, ioaddr + txdp);
 
        /* Enable all known interrupts by setting the interrupt mask. */
        outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
-       return;
 }
 
 /**
@@ -1623,8 +1618,6 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
 
        spin_unlock_irqrestore(&sis_priv->lock, flags);
 
-       net_dev->trans_start = jiffies;
-
        if (netif_msg_tx_queued(sis_priv))
                printk(KERN_DEBUG "%s: Queued Tx packet at %p size %d "
                       "to slot %d.\n",
@@ -2298,12 +2291,14 @@ static void set_rx_mode(struct net_device *net_dev)
                /* Accept Broadcast packet, destination address matchs our
                 * MAC address, use Receive Filter to reject unwanted MCAST
                 * packets */
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                rx_mode = RFAAB;
 
-               netdev_for_each_mc_addr(mclist, net_dev) {
-                       unsigned int bit_nr =
-                               sis900_mcast_bitnr(mclist->dmi_addr, sis_priv->chipset_rev);
+               netdev_for_each_mc_addr(ha, net_dev) {
+                       unsigned int bit_nr;
+
+                       bit_nr = sis900_mcast_bitnr(ha->addr,
+                                                   sis_priv->chipset_rev);
                        mc_filter[bit_nr >> 4] |= (1 << (bit_nr & 0xf));
                }
        }
@@ -2330,8 +2325,6 @@ static void set_rx_mode(struct net_device *net_dev)
                /* restore cr */
                outl(cr_saved, ioaddr + cr);
        }
-
-       return;
 }
 
 /**
index 6028bbb3b28a5f9c1e1ff36de421bb0066e62e18..9d8d1ac48176dfc1558de9f944cb6bf6cadee26a 100644 (file)
@@ -1352,7 +1352,7 @@ void rtm_set_timer(struct s_smc *smc)
        /*
         * MIB timer and hardware timer have the same resolution of 80nS
         */
-       DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns \n",
+       DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns\n",
                (int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ;
        outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ;
 }
index e6b33ee05ede1473ba91c8b4e8d9124a9122f793..ba45bc794d774d76c6c110572137ee81958062d8 100644 (file)
@@ -1277,7 +1277,7 @@ static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy)
 
        mib = phy->mib ;
 
-       DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ;
+       DB_PCMN(1,"SIG rec %x %x:\n", bit,phy->r_val[bit] ) ;
        bit++ ;
 
        switch(bit) {
@@ -1580,7 +1580,7 @@ static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy
                mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ;
                break ;
        }
-       DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ;
+       DB_PCMN(1,"SIG snd %x %x:\n", bit,phy->t_val[bit] ) ;
 }
 
 /*
index d9016b75abc2d023e64da67db02acf172a4598dc..31b2dabf094cdbce1a9ace31b1657d28e5a459ac 100644 (file)
@@ -844,7 +844,6 @@ static void skfp_ctl_set_multicast_list(struct net_device *dev)
        spin_lock_irqsave(&bp->DriverLock, Flags);
        skfp_ctl_set_multicast_list_wo_lock(dev);
        spin_unlock_irqrestore(&bp->DriverLock, Flags);
-       return;
 }                              // skfp_ctl_set_multicast_list
 
 
@@ -852,7 +851,7 @@ static void skfp_ctl_set_multicast_list(struct net_device *dev)
 static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
 {
        struct s_smc *smc = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
        /* Enable promiscuous mode, if necessary */
        if (dev->flags & IFF_PROMISC) {
@@ -876,13 +875,13 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
                                /* use exact filtering */
 
                                // point to first multicast addr
-                               netdev_for_each_mc_addr(dmi, dev) {
-                                       mac_add_multicast(smc, 
-                                                         (struct fddi_addr *)dmi->dmi_addr, 
-                                                         1);
+                               netdev_for_each_mc_addr(ha, dev) {
+                                       mac_add_multicast(smc,
+                                               (struct fddi_addr *)ha->addr,
+                                               1);
 
                                        pr_debug(KERN_INFO "ENABLE MC ADDRESS: %pMF\n",
-                                               dmi->dmi_addr);
+                                               ha->addr);
                                }
 
                        } else {        // more MC addresses than HW supports
@@ -898,7 +897,6 @@ static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
                /* Update adapter filters */
                mac_update_multicast(smc);
        }
-       return;
 }                              // skfp_ctl_set_multicast_list_wo_lock
 
 
@@ -1076,7 +1074,6 @@ static netdev_tx_t skfp_send_pkt(struct sk_buff *skb,
        if (bp->QueueSkb == 0) {
                netif_stop_queue(dev);
        }
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 
 }                              // skfp_send_pkt
index 83d16fecfac4280608099dbb3747707f76000d54..6f35bb77595f2ffab9cdb939f75a95efb8d0a27b 100644 (file)
@@ -574,7 +574,7 @@ void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs)
                if (smt_check_para(smc,sm,plist_nif)) {
                        DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ;
                        break ;
-               } ;
+               }
                switch (sm->smt_type) {
                case SMT_ANNOUNCE :
                case SMT_REQUEST :
index 6caf713b744c59aab2c81d724f99ca0e8096178e..40882b3faba6c3238d9edd75502c17b9abb72e8e 100644 (file)
@@ -414,7 +414,7 @@ static void smt_send_srf(struct s_smc *smc)
        smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ;
        mb->sm_len = smt->smt_len + sizeof(struct smt_header) ;
 
-       DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ;
+       DB_SMT("SRF: sending SRF at %x, len %d\n",smt,mb->sm_len) ;
        DB_SMT("SRF: state SR%d Threshold %d\n",
                smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ;
 #ifdef DEBUG
index 50eb70609f2039622feb551c981cbdc848c2e45e..40e5c46e7571ad46f1c7abf655d0235f89762bfd 100644 (file)
@@ -984,8 +984,8 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
        wmb();
 
        rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
-       pci_unmap_addr_set(e, mapaddr, map);
-       pci_unmap_len_set(e, maplen, bufsize);
+       dma_unmap_addr_set(e, mapaddr, map);
+       dma_unmap_len_set(e, maplen, bufsize);
 }
 
 /* Resume receiving using existing skb,
@@ -1018,8 +1018,8 @@ static void skge_rx_clean(struct skge_port *skge)
                rd->control = 0;
                if (e->skb) {
                        pci_unmap_single(hw->pdev,
-                                        pci_unmap_addr(e, mapaddr),
-                                        pci_unmap_len(e, maplen),
+                                        dma_unmap_addr(e, mapaddr),
+                                        dma_unmap_len(e, maplen),
                                         PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(e->skb);
                        e->skb = NULL;
@@ -2756,8 +2756,8 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
        e->skb = skb;
        len = skb_headlen(skb);
        map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
-       pci_unmap_addr_set(e, mapaddr, map);
-       pci_unmap_len_set(e, maplen, len);
+       dma_unmap_addr_set(e, mapaddr, map);
+       dma_unmap_len_set(e, maplen, len);
 
        td->dma_lo = map;
        td->dma_hi = map >> 32;
@@ -2799,8 +2799,8 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
 
                        tf->dma_lo = map;
                        tf->dma_hi = (u64) map >> 32;
-                       pci_unmap_addr_set(e, mapaddr, map);
-                       pci_unmap_len_set(e, maplen, frag->size);
+                       dma_unmap_addr_set(e, mapaddr, map);
+                       dma_unmap_len_set(e, maplen, frag->size);
 
                        tf->control = BMU_OWN | BMU_SW | control | frag->size;
                }
@@ -2837,12 +2837,12 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
 
        /* skb header vs. fragment */
        if (control & BMU_STF)
-               pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr),
-                                pci_unmap_len(e, maplen),
+               pci_unmap_single(pdev, dma_unmap_addr(e, mapaddr),
+                                dma_unmap_len(e, maplen),
                                 PCI_DMA_TODEVICE);
        else
-               pci_unmap_page(pdev, pci_unmap_addr(e, mapaddr),
-                              pci_unmap_len(e, maplen),
+               pci_unmap_page(pdev, dma_unmap_addr(e, mapaddr),
+                              dma_unmap_len(e, maplen),
                               PCI_DMA_TODEVICE);
 
        if (control & BMU_EOF) {
@@ -2918,7 +2918,7 @@ static void genesis_set_multicast(struct net_device *dev)
        struct skge_port *skge = netdev_priv(dev);
        struct skge_hw *hw = skge->hw;
        int port = skge->port;
-       struct dev_mc_list *list;
+       struct netdev_hw_addr *ha;
        u32 mode;
        u8 filter[8];
 
@@ -2938,8 +2938,8 @@ static void genesis_set_multicast(struct net_device *dev)
                    skge->flow_status == FLOW_STAT_SYMMETRIC)
                        genesis_add_filter(filter, pause_mc_addr);
 
-               netdev_for_each_mc_addr(list, dev)
-                       genesis_add_filter(filter, list->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       genesis_add_filter(filter, ha->addr);
        }
 
        xm_write32(hw, port, XM_MODE, mode);
@@ -2957,7 +2957,7 @@ static void yukon_set_multicast(struct net_device *dev)
        struct skge_port *skge = netdev_priv(dev);
        struct skge_hw *hw = skge->hw;
        int port = skge->port;
-       struct dev_mc_list *list;
+       struct netdev_hw_addr *ha;
        int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND ||
                        skge->flow_status == FLOW_STAT_SYMMETRIC);
        u16 reg;
@@ -2980,8 +2980,8 @@ static void yukon_set_multicast(struct net_device *dev)
                if (rx_pause)
                        yukon_add_filter(filter, pause_mc_addr);
 
-               netdev_for_each_mc_addr(list, dev)
-                       yukon_add_filter(filter, list->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       yukon_add_filter(filter, ha->addr);
        }
 
 
@@ -3060,11 +3060,11 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                        goto resubmit;
 
                pci_dma_sync_single_for_cpu(skge->hw->pdev,
-                                           pci_unmap_addr(e, mapaddr),
+                                           dma_unmap_addr(e, mapaddr),
                                            len, PCI_DMA_FROMDEVICE);
                skb_copy_from_linear_data(e->skb, skb->data, len);
                pci_dma_sync_single_for_device(skge->hw->pdev,
-                                              pci_unmap_addr(e, mapaddr),
+                                              dma_unmap_addr(e, mapaddr),
                                               len, PCI_DMA_FROMDEVICE);
                skge_rx_reuse(e, skge->rx_buf_size);
        } else {
@@ -3075,8 +3075,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                        goto resubmit;
 
                pci_unmap_single(skge->hw->pdev,
-                                pci_unmap_addr(e, mapaddr),
-                                pci_unmap_len(e, maplen),
+                                dma_unmap_addr(e, mapaddr),
+                                dma_unmap_len(e, maplen),
                                 PCI_DMA_FROMDEVICE);
                skb = e->skb;
                prefetch(skb->data);
@@ -3667,7 +3667,7 @@ static int skge_debug_show(struct seq_file *seq, void *v)
                           t->csum_offs, t->csum_write, t->csum_start);
        }
 
-       seq_printf(seq, "\nRx Ring: \n");
+       seq_printf(seq, "\nRx Ring:\n");
        for (e = skge->rx_ring.to_clean; ; e = e->next) {
                const struct skge_rx_desc *r = e->desc;
 
index 831de1b6e96e49284973b2eb013ef490f3e0eb3c..507addcaffa3aa844368b4b7dd61b5285156089c 100644 (file)
@@ -2393,8 +2393,8 @@ struct skge_element {
        struct skge_element     *next;
        void                    *desc;
        struct sk_buff          *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapaddr);
-       DECLARE_PCI_UNMAP_LEN(maplen);
+       DEFINE_DMA_UNMAP_ADDR(mapaddr);
+       DEFINE_DMA_UNMAP_LEN(maplen);
 };
 
 struct skge_ring {
index 088c797eb73b8a215e36fa09ef6f8e96ffa42b79..2111c7bbf57831209b689871ceea4cb48a82de87 100644 (file)
@@ -53,7 +53,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.27"
+#define DRV_VERSION            "1.28"
 
 /*
  * The Yukon II chipset takes 64 bit command blocks (called list elements)
    VLAN:GSO + CKSUM + Data + skb_frags * DMA */
 #define MAX_SKB_TX_LE  (2 + (sizeof(dma_addr_t)/sizeof(u32))*(MAX_SKB_FRAGS+1))
 #define TX_MIN_PENDING         (MAX_SKB_TX_LE+1)
-#define TX_MAX_PENDING         4096
+#define TX_MAX_PENDING         1024
 #define TX_DEF_PENDING         127
 
-#define STATUS_RING_SIZE       2048    /* 2 ports * (TX + 2*RX) */
-#define STATUS_LE_BYTES                (STATUS_RING_SIZE*sizeof(struct sky2_status_le))
 #define TX_WATCHDOG            (5 * HZ)
 #define NAPI_WEIGHT            64
 #define PHY_RETRIES            1000
 
 #define SKY2_EEPROM_MAGIC      0x9955aabb
 
-
 #define RING_NEXT(x,s) (((x)+1) & ((s)-1))
 
 static const u32 default_msg =
@@ -227,7 +224,7 @@ static void sky2_power_on(struct sky2_hw *hw)
        /* disable Core Clock Division, */
        sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > CHIP_REV_YU_XL_A1)
                /* enable bits are inverted */
                sky2_write8(hw, B2_Y2_CLK_GATE,
                            Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
@@ -269,7 +266,7 @@ static void sky2_power_on(struct sky2_hw *hw)
 
 static void sky2_power_aux(struct sky2_hw *hw)
 {
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > CHIP_REV_YU_XL_A1)
                sky2_write8(hw, B2_Y2_CLK_GATE, 0);
        else
                /* enable bits are inverted */
@@ -652,7 +649,7 @@ static void sky2_phy_power_up(struct sky2_hw *hw, unsigned port)
        reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
        reg1 &= ~phy_power[port];
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > CHIP_REV_YU_XL_A1)
                reg1 |= coma_mode[port];
 
        sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
@@ -824,7 +821,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 
        sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 && port == 1) {
+       if (hw->chip_id == CHIP_ID_YUKON_XL &&
+           hw->chip_rev == CHIP_REV_YU_XL_A0 &&
+           port == 1) {
                /* WA DEV_472 -- looks like crossed wires on port 2 */
                /* clear GMAC 1 Control reset */
                sky2_write8(hw, SK_REG(0, GMAC_CTRL), GMC_RST_CLR);
@@ -878,6 +877,10 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        if (hw->dev[port]->mtu > ETH_DATA_LEN)
                reg |= GM_SMOD_JUMBO_ENA;
 
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
+           hw->chip_rev == CHIP_REV_YU_EC_U_B1)
+               reg |= GM_NEW_FLOW_CTRL;
+
        gma_write16(hw, port, GM_SERIAL_MODE, reg);
 
        /* virtual address for data */
@@ -1126,7 +1129,7 @@ static int sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
        if (pci_dma_mapping_error(pdev, re->data_addr))
                goto mapping_error;
 
-       pci_unmap_len_set(re, data_size, size);
+       dma_unmap_len_set(re, data_size, size);
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -1148,7 +1151,7 @@ map_page_error:
                               PCI_DMA_FROMDEVICE);
        }
 
-       pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size),
+       pci_unmap_single(pdev, re->data_addr, dma_unmap_len(re, data_size),
                         PCI_DMA_FROMDEVICE);
 
 mapping_error:
@@ -1163,7 +1166,7 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
        struct sk_buff *skb = re->skb;
        int i;
 
-       pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size),
+       pci_unmap_single(pdev, re->data_addr, dma_unmap_len(re, data_size),
                         PCI_DMA_FROMDEVICE);
 
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
@@ -1190,6 +1193,39 @@ static void rx_set_checksum(struct sky2_port *sky2)
                     ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
 }
 
+/* Enable/disable receive hash calculation (RSS) */
+static void rx_set_rss(struct net_device *dev)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+       int i, nkeys = 4;
+
+       /* Supports IPv6 and other modes */
+       if (hw->flags & SKY2_HW_NEW_LE) {
+               nkeys = 10;
+               sky2_write32(hw, SK_REG(sky2->port, RSS_CFG), HASH_ALL);
+       }
+
+       /* Program RSS initial values */
+       if (dev->features & NETIF_F_RXHASH) {
+               u32 key[nkeys];
+
+               get_random_bytes(key, nkeys * sizeof(u32));
+               for (i = 0; i < nkeys; i++)
+                       sky2_write32(hw, SK_REG(sky2->port, RSS_KEY + i * 4),
+                                    key[i]);
+
+               /* Need to turn on (undocumented) flag to make hashing work  */
+               sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T),
+                            RX_STFW_ENA);
+
+               sky2_write32(hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            BMU_ENA_RX_RSS_HASH);
+       } else
+               sky2_write32(hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+                            BMU_DIS_RX_RSS_HASH);
+}
+
 /*
  * The RX Stop command will not work for Yukon-2 if the BMU does not
  * reach the end of packet and since we can't make sure that we have
@@ -1414,8 +1450,7 @@ static void sky2_rx_start(struct sky2_port *sky2)
        /* These chips have no ram buffer?
         * MAC Rx RAM Read is controlled by hardware */
        if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
-           (hw->chip_rev == CHIP_REV_YU_EC_U_A1 ||
-            hw->chip_rev == CHIP_REV_YU_EC_U_B0))
+           hw->chip_rev > CHIP_REV_YU_EC_U_A0)
                sky2_write32(hw, Q_ADDR(rxq, Q_TEST), F_M_RX_RAM_DIS);
 
        sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
@@ -1423,6 +1458,9 @@ static void sky2_rx_start(struct sky2_port *sky2)
        if (!(hw->flags & SKY2_HW_NEW_LE))
                rx_set_checksum(sky2);
 
+       if (!(hw->flags & SKY2_HW_RSS_BROKEN))
+               rx_set_rss(sky2->netdev);
+
        /* submit Rx ring */
        for (i = 0; i < sky2->rx_pending; i++) {
                re = sky2->rx_ring + i;
@@ -1657,12 +1695,12 @@ static unsigned tx_le_req(const struct sk_buff *skb)
 static void sky2_tx_unmap(struct pci_dev *pdev, struct tx_ring_info *re)
 {
        if (re->flags & TX_MAP_SINGLE)
-               pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
-                                pci_unmap_len(re, maplen),
+               pci_unmap_single(pdev, dma_unmap_addr(re, mapaddr),
+                                dma_unmap_len(re, maplen),
                                 PCI_DMA_TODEVICE);
        else if (re->flags & TX_MAP_PAGE)
-               pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
-                              pci_unmap_len(re, maplen),
+               pci_unmap_page(pdev, dma_unmap_addr(re, mapaddr),
+                              dma_unmap_len(re, maplen),
                               PCI_DMA_TODEVICE);
        re->flags = 0;
 }
@@ -1773,8 +1811,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
 
        re = sky2->tx_ring + slot;
        re->flags = TX_MAP_SINGLE;
-       pci_unmap_addr_set(re, mapaddr, mapping);
-       pci_unmap_len_set(re, maplen, len);
+       dma_unmap_addr_set(re, mapaddr, mapping);
+       dma_unmap_len_set(re, maplen, len);
 
        le = get_tx_le(sky2, &slot);
        le->addr = cpu_to_le32(lower_32_bits(mapping));
@@ -1802,8 +1840,8 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
 
                re = sky2->tx_ring + slot;
                re->flags = TX_MAP_PAGE;
-               pci_unmap_addr_set(re, mapaddr, mapping);
-               pci_unmap_len_set(re, maplen, frag->size);
+               dma_unmap_addr_set(re, mapaddr, mapping);
+               dma_unmap_len_set(re, maplen, frag->size);
 
                le = get_tx_le(sky2, &slot);
                le->addr = cpu_to_le32(lower_32_bits(mapping));
@@ -2142,7 +2180,8 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
                   istatus, phystat);
 
        if (istatus & PHY_M_IS_AN_COMPL) {
-               if (sky2_autoneg_done(sky2, phystat) == 0)
+               if (sky2_autoneg_done(sky2, phystat) == 0 &&
+                   !netif_carrier_ok(dev))
                        sky2_link_up(sky2);
                goto out;
        }
@@ -2236,8 +2275,8 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        sky2_write32(hw, B0_IMSK, 0);
 
        dev->trans_start = jiffies;     /* prevent tx timeout */
-       netif_stop_queue(dev);
        napi_disable(&hw->napi);
+       netif_tx_disable(dev);
 
        synchronize_irq(hw->pdev->irq);
 
@@ -2531,6 +2570,14 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
        }
 }
 
+static void sky2_rx_hash(struct sky2_port *sky2, u32 status)
+{
+       struct sk_buff *skb;
+
+       skb = sky2->rx_ring[sky2->rx_next].skb;
+       skb->rxhash = le32_to_cpu(status);
+}
+
 /* Process status response ring */
 static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 {
@@ -2552,7 +2599,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                if (!(opcode & HW_OWNER))
                        break;
 
-               hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
+               hw->st_idx = RING_NEXT(hw->st_idx, hw->st_size);
 
                port = le->css & CSS_LINK_BIT;
                dev = hw->dev[port];
@@ -2603,6 +2650,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
                                sky2_rx_checksum(sky2, status);
                        break;
 
+               case OP_RSS_HASH:
+                       sky2_rx_hash(sky2, status);
+                       break;
+
                case OP_TXINDEXLE:
                        /* TX index reports status for both ports */
                        sky2_tx_done(hw->dev[0], status & 0xfff);
@@ -2957,6 +3008,8 @@ static int __devinit sky2_init(struct sky2_hw *hw)
        switch(hw->chip_id) {
        case CHIP_ID_YUKON_XL:
                hw->flags = SKY2_HW_GIGABIT | SKY2_HW_NEWER_PHY;
+               if (hw->chip_rev < CHIP_REV_YU_XL_A2)
+                       hw->flags |= SKY2_HW_RSS_BROKEN;
                break;
 
        case CHIP_ID_YUKON_EC_U:
@@ -2982,10 +3035,11 @@ static int __devinit sky2_init(struct sky2_hw *hw)
                        dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
                        return -EOPNOTSUPP;
                }
-               hw->flags = SKY2_HW_GIGABIT;
+               hw->flags = SKY2_HW_GIGABIT | SKY2_HW_RSS_BROKEN;
                break;
 
        case CHIP_ID_YUKON_FE:
+               hw->flags = SKY2_HW_RSS_BROKEN;
                break;
 
        case CHIP_ID_YUKON_FE_P:
@@ -3192,7 +3246,7 @@ static void sky2_reset(struct sky2_hw *hw)
        for (i = 0; i < hw->ports; i++)
                sky2_gmac_reset(hw, i);
 
-       memset(hw->st_le, 0, STATUS_LE_BYTES);
+       memset(hw->st_le, 0, hw->st_size * sizeof(struct sky2_status_le));
        hw->st_idx = 0;
 
        sky2_write32(hw, STAT_CTRL, SC_STAT_RST_SET);
@@ -3202,7 +3256,7 @@ static void sky2_reset(struct sky2_hw *hw)
        sky2_write32(hw, STAT_LIST_ADDR_HI, (u64) hw->st_dma >> 32);
 
        /* Set the list last index */
-       sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1);
+       sky2_write16(hw, STAT_LAST_IDX, hw->st_size - 1);
 
        sky2_write16(hw, STAT_TX_IDX_TH, 10);
        sky2_write8(hw, STAT_FIFO_WM, 16);
@@ -3258,18 +3312,14 @@ static int sky2_reattach(struct net_device *dev)
        return err;
 }
 
-static void sky2_restart(struct work_struct *work)
+static void sky2_all_down(struct sky2_hw *hw)
 {
-       struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work);
-       u32 imask;
        int i;
 
-       rtnl_lock();
-
-       napi_disable(&hw->napi);
-       synchronize_irq(hw->pdev->irq);
-       imask = sky2_read32(hw, B0_IMSK);
+       sky2_read32(hw, B0_IMSK);
        sky2_write32(hw, B0_IMSK, 0);
+       synchronize_irq(hw->pdev->irq);
+       napi_disable(&hw->napi);
 
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
@@ -3282,8 +3332,12 @@ static void sky2_restart(struct work_struct *work)
                netif_tx_disable(dev);
                sky2_hw_down(sky2);
        }
+}
 
-       sky2_reset(hw);
+static void sky2_all_up(struct sky2_hw *hw)
+{
+       u32 imask = Y2_IS_BASE;
+       int i;
 
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
@@ -3293,6 +3347,8 @@ static void sky2_restart(struct work_struct *work)
                        continue;
 
                sky2_hw_up(sky2);
+               sky2_set_multicast(dev);
+               imask |= portirq_msk[i];
                netif_wake_queue(dev);
        }
 
@@ -3301,6 +3357,17 @@ static void sky2_restart(struct work_struct *work)
 
        sky2_read32(hw, B0_Y2_SP_LISR);
        napi_enable(&hw->napi);
+}
+
+static void sky2_restart(struct work_struct *work)
+{
+       struct sky2_hw *hw = container_of(work, struct sky2_hw, restart_work);
+
+       rtnl_lock();
+
+       sky2_all_down(hw);
+       sky2_reset(hw);
+       sky2_all_up(hw);
 
        rtnl_unlock();
 }
@@ -3622,7 +3689,7 @@ static void sky2_set_multicast(struct net_device *dev)
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
-       struct dev_mc_list *list;
+       struct netdev_hw_addr *ha;
        u16 reg;
        u8 filter[8];
        int rx_pause;
@@ -3646,8 +3713,8 @@ static void sky2_set_multicast(struct net_device *dev)
                if (rx_pause)
                        sky2_add_filter(filter, pause_mc_addr);
 
-               netdev_for_each_mc_addr(list, dev)
-                       sky2_add_filter(filter, list->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       sky2_add_filter(filter, ha->addr);
        }
 
        gma_write16(hw, port, GM_MC_ADDR_H1,
@@ -4109,6 +4176,25 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
        return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
 }
 
+static int sky2_set_flags(struct net_device *dev, u32 data)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+
+       if (data & ~ETH_FLAG_RXHASH)
+               return -EOPNOTSUPP;
+
+       if (data & ETH_FLAG_RXHASH) {
+               if (sky2->hw->flags & SKY2_HW_RSS_BROKEN)
+                       return -EINVAL;
+
+               dev->features |= NETIF_F_RXHASH;
+       } else
+               dev->features &= ~NETIF_F_RXHASH;
+
+       rx_set_rss(dev);
+
+       return 0;
+}
 
 static const struct ethtool_ops sky2_ethtool_ops = {
        .get_settings   = sky2_get_settings,
@@ -4140,6 +4226,7 @@ static const struct ethtool_ops sky2_ethtool_ops = {
        .phys_id        = sky2_phys_id,
        .get_sset_count = sky2_get_sset_count,
        .get_ethtool_stats = sky2_get_ethtool_stats,
+       .set_flags      = sky2_set_flags,
 };
 
 #ifdef CONFIG_SKY2_DEBUG
@@ -4250,12 +4337,13 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
        napi_disable(&hw->napi);
        last = sky2_read16(hw, STAT_PUT_IDX);
 
+       seq_printf(seq, "Status ring %u\n", hw->st_size);
        if (hw->st_idx == last)
                seq_puts(seq, "Status ring (empty)\n");
        else {
                seq_puts(seq, "Status ring\n");
-               for (idx = hw->st_idx; idx != last && idx < STATUS_RING_SIZE;
-                    idx = RING_NEXT(idx, STATUS_RING_SIZE)) {
+               for (idx = hw->st_idx; idx != last && idx < hw->st_size;
+                    idx = RING_NEXT(idx, hw->st_size)) {
                        const struct sky2_status_le *le = hw->st_le + idx;
                        seq_printf(seq, "[%d] %#x %d %#x\n",
                                   idx, le->opcode, le->length, le->status);
@@ -4492,6 +4580,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
        if (highmem)
                dev->features |= NETIF_F_HIGHDMA;
 
+       /* Enable receive hashing unless hardware is known broken */
+       if (!(hw->flags & SKY2_HW_RSS_BROKEN))
+               dev->features |= NETIF_F_RXHASH;
+
 #ifdef SKY2_VLAN_TAG_USED
        /* The workaround for FE+ status conflicts with VLAN tag detection. */
        if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
@@ -4683,15 +4775,17 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
                goto err_out_free_hw;
        }
 
-       /* ring for status responses */
-       hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma);
-       if (!hw->st_le)
-               goto err_out_iounmap;
-
        err = sky2_init(hw);
        if (err)
                goto err_out_iounmap;
 
+       /* ring for status responses */
+       hw->st_size = hw->ports * roundup_pow_of_two(3*RX_MAX_PENDING + TX_MAX_PENDING);
+       hw->st_le = pci_alloc_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
+                                        &hw->st_dma);
+       if (!hw->st_le)
+               goto err_out_reset;
+
        dev_info(&pdev->dev, "Yukon-2 %s chip revision %d\n",
                 sky2_name(hw->chip_id, buf1, sizeof(buf1)), hw->chip_rev);
 
@@ -4765,8 +4859,10 @@ err_out_unregister:
 err_out_free_netdev:
        free_netdev(dev);
 err_out_free_pci:
+       pci_free_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
+                           hw->st_le, hw->st_dma);
+err_out_reset:
        sky2_write8(hw, B0_CTST, CS_RST_SET);
-       pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
 err_out_iounmap:
        iounmap(hw->regs);
 err_out_free_hw:
@@ -4804,7 +4900,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
        free_irq(pdev->irq, hw);
        if (hw->flags & SKY2_HW_USE_MSI)
                pci_disable_msi(pdev);
-       pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
+       pci_free_consistent(pdev, hw->st_size * sizeof(struct sky2_status_le),
+                           hw->st_le, hw->st_dma);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
 
@@ -4829,12 +4926,12 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
        cancel_work_sync(&hw->restart_work);
 
        rtnl_lock();
+
+       sky2_all_down(hw);
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
                struct sky2_port *sky2 = netdev_priv(dev);
 
-               sky2_detach(dev);
-
                if (sky2->wol)
                        sky2_wol_init(sky2);
 
@@ -4843,8 +4940,6 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 
        device_set_wakeup_enable(&pdev->dev, wol != 0);
 
-       sky2_write32(hw, B0_IMSK, 0);
-       napi_disable(&hw->napi);
        sky2_power_aux(hw);
        rtnl_unlock();
 
@@ -4859,12 +4954,11 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 static int sky2_resume(struct pci_dev *pdev)
 {
        struct sky2_hw *hw = pci_get_drvdata(pdev);
-       int i, err;
+       int err;
 
        if (!hw)
                return 0;
 
-       rtnl_lock();
        err = pci_set_power_state(pdev, PCI_D0);
        if (err)
                goto out;
@@ -4882,20 +4976,13 @@ static int sky2_resume(struct pci_dev *pdev)
                goto out;
        }
 
+       rtnl_lock();
        sky2_reset(hw);
-       sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
-       napi_enable(&hw->napi);
-
-       for (i = 0; i < hw->ports; i++) {
-               err = sky2_reattach(hw->dev[i]);
-               if (err)
-                       goto out;
-       }
+       sky2_all_up(hw);
        rtnl_unlock();
 
        return 0;
 out:
-       rtnl_unlock();
 
        dev_err(&pdev->dev, "resume failed (%d)\n", err);
        pci_disable_device(pdev);
index a5e182dd981980f3798f2702f87a7a6e5a0f61af..084eff21b67a87b5300c733eb298c45dbfee1bdd 100644 (file)
@@ -548,6 +548,14 @@ enum {
        CHIP_ID_YUKON_UL_2 = 0xba, /* YUKON-2 Ultra 2 */
        CHIP_ID_YUKON_OPT  = 0xbc, /* YUKON-2 Optima */
 };
+
+enum yukon_xl_rev {
+       CHIP_REV_YU_XL_A0  = 0,
+       CHIP_REV_YU_XL_A1  = 1,
+       CHIP_REV_YU_XL_A2  = 2,
+       CHIP_REV_YU_XL_A3  = 3,
+};
+
 enum yukon_ec_rev {
        CHIP_REV_YU_EC_A1    = 0,  /* Chip Rev. for Yukon-EC A1/A0 */
        CHIP_REV_YU_EC_A2    = 1,  /* Chip Rev. for Yukon-EC A2 */
@@ -557,6 +565,7 @@ enum yukon_ec_u_rev {
        CHIP_REV_YU_EC_U_A0  = 1,
        CHIP_REV_YU_EC_U_A1  = 2,
        CHIP_REV_YU_EC_U_B0  = 3,
+       CHIP_REV_YU_EC_U_B1  = 5,
 };
 enum yukon_fe_rev {
        CHIP_REV_YU_FE_A1    = 1,
@@ -685,8 +694,21 @@ enum {
        TXA_CTRL        = 0x0210,/*  8 bit      Tx Arbiter Control Register */
        TXA_TEST        = 0x0211,/*  8 bit      Tx Arbiter Test Register */
        TXA_STAT        = 0x0212,/*  8 bit      Tx Arbiter Status Register */
+
+       RSS_KEY         = 0x0220, /* RSS Key setup */
+       RSS_CFG         = 0x0248, /* RSS Configuration */
 };
 
+enum {
+       HASH_TCP_IPV6_EX_CTRL   = 1<<5,
+       HASH_IPV6_EX_CTRL       = 1<<4,
+       HASH_TCP_IPV6_CTRL      = 1<<3,
+       HASH_IPV6_CTRL          = 1<<2,
+       HASH_TCP_IPV4_CTRL      = 1<<1,
+       HASH_IPV4_CTRL          = 1<<0,
+
+       HASH_ALL                = 0x3f,
+};
 
 enum {
        B6_EXT_REG      = 0x0300,/* External registers (GENESIS only) */
@@ -1775,10 +1797,13 @@ enum {
 /*     GM_SERIAL_MODE                  16 bit r/w      Serial Mode Register */
 enum {
        GM_SMOD_DATABL_MSK      = 0x1f<<11, /* Bit 15..11:      Data Blinder (r/o) */
-       GM_SMOD_LIMIT_4         = 1<<10, /* Bit 10:     4 consecutive Tx trials */
-       GM_SMOD_VLAN_ENA        = 1<<9, /* Bit  9:      Enable VLAN  (Max. Frame Len) */
-       GM_SMOD_JUMBO_ENA       = 1<<8, /* Bit  8:      Enable Jumbo (Max. Frame Len) */
-        GM_SMOD_IPG_MSK        = 0x1f  /* Bit 4..0:    Inter-Packet Gap (IPG) */
+       GM_SMOD_LIMIT_4         = 1<<10, /* 4 consecutive Tx trials */
+       GM_SMOD_VLAN_ENA        = 1<<9,  /* Enable VLAN  (Max. Frame Len) */
+       GM_SMOD_JUMBO_ENA       = 1<<8,  /* Enable Jumbo (Max. Frame Len) */
+
+       GM_NEW_FLOW_CTRL        = 1<<6,  /* Enable New Flow-Control */
+
+       GM_SMOD_IPG_MSK         = 0x1f   /* Bit 4..0:   Inter-Packet Gap (IPG) */
 };
 
 #define DATA_BLIND_VAL(x)      (((x)<<11) & GM_SMOD_DATABL_MSK)
@@ -2157,14 +2182,14 @@ struct tx_ring_info {
        unsigned long flags;
 #define TX_MAP_SINGLE   0x0001
 #define TX_MAP_PAGE     0x0002
-       DECLARE_PCI_UNMAP_ADDR(mapaddr);
-       DECLARE_PCI_UNMAP_LEN(maplen);
+       DEFINE_DMA_UNMAP_ADDR(mapaddr);
+       DEFINE_DMA_UNMAP_LEN(maplen);
 };
 
 struct rx_ring_info {
        struct sk_buff  *skb;
        dma_addr_t      data_addr;
-       DECLARE_PCI_UNMAP_LEN(data_size);
+       DEFINE_DMA_UNMAP_LEN(data_size);
        dma_addr_t      frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
 };
 
@@ -2249,6 +2274,7 @@ struct sky2_hw {
 #define SKY2_HW_NEW_LE         0x00000020      /* new LSOv2 format */
 #define SKY2_HW_AUTO_TX_SUM    0x00000040      /* new IP decode for Tx */
 #define SKY2_HW_ADV_POWER_CTL  0x00000080      /* additional PHY power regs */
+#define SKY2_HW_RSS_BROKEN     0x00000100
 
        u8                   chip_id;
        u8                   chip_rev;
@@ -2256,6 +2282,7 @@ struct sky2_hw {
        u8                   ports;
 
        struct sky2_status_le *st_le;
+       u32                  st_size;
        u32                  st_idx;
        dma_addr_t           st_dma;
 
index 140d63f3cafa8ff2b976e3d26fd5ef488c9cb4d7..ac279fad9d450d28489a908a39884678676c3f73 100644 (file)
@@ -731,7 +731,6 @@ void
 slhc_free(struct slcompress *comp)
 {
   printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
-  return;
 }
 struct slcompress *
 slhc_init(int rslots, int tslots)
index 89696156c059a826231dd8c6bb8c2ae14ca6645e..fa434fb8fb7c087df16bacaf9108dfa3646e35db 100644 (file)
@@ -458,7 +458,7 @@ static void sl_tx_timeout(struct net_device *dev)
                 *      14 Oct 1994 Dmitry Gorodchanin.
                 */
 #ifdef SL_CHECK_TRANSMIT
-               if (time_before(jiffies, dev->trans_start + 20 * HZ))  {
+               if (time_before(jiffies, dev_trans_start(dev) + 20 * HZ))  {
                        /* 20 sec timeout not reached */
                        goto out;
                }
@@ -1269,7 +1269,7 @@ static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
        case SIOCGLEASE:
                *p = sl->leased;
-       };
+       }
        spin_unlock_bh(&sl->lock);
        return 0;
 }
index a93f122e9a966b20e2380eddb74837ec93a07ac4..d07c39cb4daf59ae1e765b927d5156e816b80a9b 100644 (file)
@@ -460,7 +460,6 @@ static void ultramca_reset_8390(struct net_device *dev)
 
        if (ei_debug > 1)
                printk("reset done\n");
-       return;
 }
 
 /* Grab the 8390 specific header. Similar to the block_input routine, but
index 0291ea098a06ca2fe365cb90ed347f1a7ae7ebfb..d2dd8e6113ab9be23121d7a4f061acfcd305e420 100644 (file)
@@ -421,7 +421,6 @@ ultra_reset_8390(struct net_device *dev)
                outb(0x01, cmd_port + 6);               /* Enable interrupts and memory. */
 
        if (ei_debug > 1) printk("reset done\n");
-       return;
 }
 
 /* Grab the 8390 specific header. Similar to the block_input routine, but
index 7a554adc70fbde2710cb51944d7acfd357ad7da0..e459c3b2510a57257efe95143cf633e2d4db883d 100644 (file)
@@ -352,7 +352,6 @@ static void ultra32_reset_8390(struct net_device *dev)
        outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */
        outb(0x01, ioaddr + 6); /* Enable Interrupts. */
        if (ei_debug > 1) printk("reset done\n");
-       return;
 }
 
 /* Grab the 8390 specific header. Similar to the block_input routine, but
index 635820d42b194252004bda1426d6c0d796c345f1..66831f378396b1e910e79b74a0340499c7d3c5b5 100644 (file)
@@ -382,7 +382,7 @@ static inline void   smc911x_rcv(struct net_device *dev)
        DBG(SMC_DEBUG_FUNC | SMC_DEBUG_RX, "%s: --> %s\n",
                dev->name, __func__);
        status = SMC_GET_RX_STS_FIFO(lp);
-       DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x \n",
+       DBG(SMC_DEBUG_RX, "%s: Rx pkt len %d status 0x%08x\n",
                dev->name, (status & 0x3fff0000) >> 16, status & 0xc000ffff);
        pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
        if (status & RX_STS_ES_) {
@@ -1135,7 +1135,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
                }
 #else
                if (status & INT_STS_TSFL_) {
-                       DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq \n", dev->name, );
+                       DBG(SMC_DEBUG_TX, "%s: TX status FIFO limit (%d) irq\n", dev->name, );
                        smc911x_tx(dev);
                        SMC_ACK_INT(lp, INT_STS_TSFL_);
                }
@@ -1274,7 +1274,7 @@ static void smc911x_timeout(struct net_device *dev)
        status = SMC_GET_INT(lp);
        mask = SMC_GET_INT_EN(lp);
        spin_unlock_irqrestore(&lp->lock, flags);
-       DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x \n",
+       DBG(SMC_DEBUG_MISC, "%s: INT 0x%02x MASK 0x%02x\n",
                dev->name, status, mask);
 
        /* Dump the current TX FIFO contents and restart */
@@ -1289,7 +1289,7 @@ static void smc911x_timeout(struct net_device *dev)
                schedule_work(&lp->phy_configure);
 
        /* We can accept TX packets again */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -1340,7 +1340,7 @@ static void smc911x_set_multicast_list(struct net_device *dev)
         * within that register.
         */
        else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *cur_addr;
+               struct netdev_hw_addr *ha;
 
                /* Set the Hash perfec mode */
                mcr |= MAC_CR_HPFILT_;
@@ -1348,19 +1348,16 @@ static void smc911x_set_multicast_list(struct net_device *dev)
                /* start with a table of all zeros: reject all */
                memset(multicast_table, 0, sizeof(multicast_table));
 
-               netdev_for_each_mc_addr(cur_addr, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        u32 position;
 
-                       /* do we have a pointer here? */
-                       if (!cur_addr)
-                               break;
                        /* make sure this is a multicast address -
                                shouldn't this be a given if we have it here ? */
-                       if (!(*cur_addr->dmi_addr & 1))
-                                continue;
+                       if (!(*ha->addr & 1))
+                               continue;
 
                        /* upper 6 bits are used as hash index */
-                       position = ether_crc(ETH_ALEN, cur_addr->dmi_addr)>>26;
+                       position = ether_crc(ETH_ALEN, ha->addr)>>26;
 
                        multicast_table[position>>5] |= 1 << (position&0x1f);
                }
index 3f2f7843aa4eacb86fc2923dec080695fd67647c..7486d0908064c598a0de1252d4ecfd85aba12789 100644 (file)
@@ -416,7 +416,7 @@ static void smc_shutdown( int ioaddr )
 
 
 /*
- . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
+ . Function: smc_setmulticast( int ioaddr, struct net_device *dev )
  . Purpose:
  .    This sets the internal hardware table to filter out unwanted multicast
  .    packets before they take up memory.
@@ -437,26 +437,23 @@ static void smc_setmulticast(int ioaddr, struct net_device *dev)
 {
        int                     i;
        unsigned char           multicast_table[ 8 ];
-       struct dev_mc_list *cur_addr;
+       struct netdev_hw_addr *ha;
        /* table for flipping the order of 3 bits */
        unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
 
        /* start with a table of all zeros: reject all */
        memset( multicast_table, 0, sizeof( multicast_table ) );
 
-       netdev_for_each_mc_addr(cur_addr, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                int position;
 
-               /* do we have a pointer here? */
-               if ( !cur_addr )
-                       break;
                /* make sure this is a multicast address - shouldn't this
                   be a given if we have it here ? */
-               if ( !( *cur_addr->dmi_addr & 1 ) )
+               if (!(*ha->addr & 1))
                        continue;
 
                /* only use the low order bits */
-               position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f;
+               position = ether_crc_le(6, ha->addr) & 0x3f;
 
                /* do some messy swapping to put the bit in the right spot */
                multicast_table[invert3[position&7]] |=
@@ -528,7 +525,7 @@ static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
        numPages =  ((length & 0xfffe) + 6) / 256;
 
        if (numPages > 7 ) {
-               printk(CARDNAME": Far too big packet error. \n");
+               printk(CARDNAME": Far too big packet error.\n");
                /* freeing the packet is a good thing here... but should
                 . any packets of this size get down here?   */
                dev_kfree_skb (skb);
@@ -570,9 +567,9 @@ static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
        if ( !time_out ) {
                /* oh well, wait until the chip finds memory later */
                SMC_ENABLE_INT( IM_ALLOC_INT );
-               PRINTK2((CARDNAME": memory allocation deferred. \n"));
+               PRINTK2((CARDNAME": memory allocation deferred.\n"));
                /* it's deferred, but I'll handle it later */
-               return NETDEV_TX_OK;
+               return NETDEV_TX_OK;
        }
        /* or YES! I can send the packet now.. */
        smc_hardware_send_packet(dev);
@@ -610,7 +607,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
        ioaddr = dev->base_addr;
 
        if ( !skb ) {
-               PRINTK((CARDNAME": In XMIT with no packet to send \n"));
+               PRINTK((CARDNAME": In XMIT with no packet to send\n"));
                return;
        }
        length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
@@ -620,7 +617,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
        packet_no = inb( ioaddr + PNR_ARR + 1 );
        if ( packet_no & 0x80 ) {
                /* or isn't there?  BAD CHIP! */
-               printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
+               printk(KERN_DEBUG CARDNAME": Memory allocation failed.\n");
                dev_kfree_skb_any(skb);
                lp->saved_skb = NULL;
                netif_wake_queue(dev);
@@ -685,7 +682,7 @@ static void smc_hardware_send_packet( struct net_device * dev )
        /* and let the chipset deal with it */
        outw( MC_ENQUEUE , ioaddr + MMU_CMD );
 
-       PRINTK2((CARDNAME": Sent packet of length %d \n",length));
+       PRINTK2((CARDNAME": Sent packet of length %d\n", length));
 
        lp->saved_skb = NULL;
        dev_kfree_skb_any (skb);
@@ -694,8 +691,6 @@ static void smc_hardware_send_packet( struct net_device * dev )
 
        /* we can send another packet */
        netif_wake_queue(dev);
-
-       return;
 }
 
 /*-------------------------------------------------------------------------
@@ -937,7 +932,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
        if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] ) {
                /* I don't recognize this chip, so... */
                printk(CARDNAME ": IO %x: Unrecognized revision register:"
-                       " %x, Contact author. \n", ioaddr, revision_register );
+                       " %x, Contact author.\n", ioaddr, revision_register);
 
                retval = -ENODEV;
                goto err_out;
@@ -1045,9 +1040,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr)
        */
        printk("ADDR: %pM\n", dev->dev_addr);
 
-       /* set the private data to zero by default */
-       memset(netdev_priv(dev), 0, sizeof(struct smc_local));
-
        /* Grab the IRQ */
        retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev);
        if (retval) {
@@ -1074,7 +1066,7 @@ static void print_packet( byte * buf, int length )
        int remainder;
        int lines;
 
-       printk("Packet of length %d \n", length );
+       printk("Packet of length %d\n", length);
        lines = length / 16;
        remainder = length % 16;
 
@@ -1170,7 +1162,7 @@ static void smc_timeout(struct net_device *dev)
        /* "kick" the adaptor */
        smc_reset( dev->base_addr );
        smc_enable( dev->base_addr );
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        /* clear anything saved */
        ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL;
        netif_wake_queue(dev);
@@ -1201,7 +1193,7 @@ static void smc_rcv(struct net_device *dev)
 
        if ( packet_number & FP_RXEMPTY ) {
                /* we got called , but nothing was on the FIFO */
-               PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO. \n"));
+               PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n"));
                /* don't need to restore anything */
                return;
        }
@@ -1257,14 +1249,14 @@ static void smc_rcv(struct net_device *dev)
                   to send the DWORDs or the bytes first, or some
                   mixture.  A mixture might improve already slow PIO
                   performance  */
-               PRINTK3((" Reading %d dwords (and %d bytes) \n",
+               PRINTK3((" Reading %d dwords (and %d bytes)\n",
                        packet_length >> 2, packet_length & 3 ));
                insl(ioaddr + DATA_1 , data, packet_length >> 2 );
                /* read the left over bytes */
                insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC),
                        packet_length & 0x3  );
 #else
-               PRINTK3((" Reading %d words and %d byte(s) \n",
+               PRINTK3((" Reading %d words and %d byte(s)\n",
                        (packet_length >> 1 ), packet_length & 1 ));
                insw(ioaddr + DATA_1 , data, packet_length >> 1);
                if ( packet_length & 1 ) {
@@ -1333,7 +1325,7 @@ static void smc_tx( struct net_device * dev )
        outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER );
 
        tx_status = inw( ioaddr + DATA_1 );
-       PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));
+       PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status));
 
        dev->stats.tx_errors++;
        if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
@@ -1347,7 +1339,7 @@ static void smc_tx( struct net_device * dev )
 #endif
 
        if ( tx_status & TS_SUCCESS ) {
-               printk(CARDNAME": Successful packet caused interrupt \n");
+               printk(CARDNAME": Successful packet caused interrupt\n");
        }
        /* re-enable transmit */
        SMC_SELECT_BANK( 0 );
@@ -1361,7 +1353,6 @@ static void smc_tx( struct net_device * dev )
        lp->packets_waiting--;
 
        outb( saved_packet, ioaddr + PNR_ARR );
-       return;
 }
 
 /*--------------------------------------------------------------------
@@ -1393,7 +1384,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
        int handled = 0;
 
 
-       PRINTK3((CARDNAME": SMC interrupt started \n"));
+       PRINTK3((CARDNAME": SMC interrupt started\n"));
 
        saved_bank = inw( ioaddr + BANK_SELECT );
 
@@ -1408,7 +1399,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
        /* set a timeout value, so I don't stay here forever */
        timeout = 4;
 
-       PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));
+       PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask));
        do {
                /* read the status flag, and mask it */
                status = inb( ioaddr + INTERRUPT ) & mask;
@@ -1418,7 +1409,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
                handled = 1;
 
                PRINTK3((KERN_WARNING CARDNAME
-                       ": Handling interrupt status %x \n", status ));
+                       ": Handling interrupt status %x\n", status));
 
                if (status & IM_RCV_INT) {
                        /* Got a packet(s). */
@@ -1452,7 +1443,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
 
                } else if (status & IM_ALLOC_INT ) {
                        PRINTK2((KERN_DEBUG CARDNAME
-                               ": Allocation interrupt \n"));
+                               ": Allocation interrupt\n"));
                        /* clear this interrupt so it doesn't happen again */
                        mask &= ~IM_ALLOC_INT;
 
@@ -1470,9 +1461,9 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
                        dev->stats.rx_fifo_errors++;
                        outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
                } else if (status & IM_EPH_INT ) {
-                       PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
+                       PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n"));
                } else if (status & IM_ERCV_INT ) {
-                       PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n"));
+                       PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n"));
                        outb( IM_ERCV_INT, ioaddr + INTERRUPT );
                }
        } while ( timeout -- );
@@ -1482,7 +1473,7 @@ static irqreturn_t smc_interrupt(int irq, void * dev_id)
        SMC_SELECT_BANK( 2 );
        outb( mask, ioaddr + INT_MASK );
 
-       PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask ));
+       PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask));
        outw( saved_pointer, ioaddr + POINTER );
 
        SMC_SELECT_BANK( saved_bank );
index 860339d51d586c14915596807b31dfa322ccc921..10cf0cbc218507111b26959f119645672fcd5666 100644 (file)
@@ -1285,7 +1285,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
                        smc_phy_interrupt(dev);
                } else if (status & IM_ERCV_INT) {
                        SMC_ACK_INT(lp, IM_ERCV_INT);
-                       PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);
+                       PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT\n", dev->name);
                }
        } while (--timeout);
 
@@ -1360,7 +1360,7 @@ static void smc_timeout(struct net_device *dev)
                schedule_work(&lp->phy_configure);
 
        /* We can accept TX packets again */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -1412,7 +1412,7 @@ static void smc_set_multicast_list(struct net_device *dev)
         * within that register.
         */
        else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *cur_addr;
+               struct netdev_hw_addr *ha;
 
                /* table for flipping the order of 3 bits */
                static const unsigned char invert3[] = {0, 4, 2, 6, 1, 5, 3, 7};
@@ -1420,16 +1420,16 @@ static void smc_set_multicast_list(struct net_device *dev)
                /* start with a table of all zeros: reject all */
                memset(multicast_table, 0, sizeof(multicast_table));
 
-               netdev_for_each_mc_addr(cur_addr, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        int position;
 
                        /* make sure this is a multicast address -
                           shouldn't this be a given if we have it here ? */
-                       if (!(*cur_addr->dmi_addr & 1))
+                       if (!(*ha->addr & 1))
                                continue;
 
                        /* only use the low order bits */
-                       position = crc32_le(~0, cur_addr->dmi_addr, 6) & 0x3f;
+                       position = crc32_le(~0, ha->addr, 6) & 0x3f;
 
                        /* do some messy swapping to put the bit in the right spot */
                        multicast_table[invert3[position&7]] |=
index ffbaa608e002eb87bab2cea144ac5f86dd55f25e..cc559741b0facf24b076e8b96eabe1c90ad78170 100644 (file)
@@ -1335,7 +1335,6 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
        freespace -= (skb->len + 32);
        dev_kfree_skb(skb);
-       dev->trans_start = jiffies;
 
        if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
                smsc911x_tx_update_txcounters(dev);
@@ -1382,13 +1381,13 @@ static void smsc911x_set_multicast_list(struct net_device *dev)
                /* Enabling specific multicast addresses */
                unsigned int hash_high = 0;
                unsigned int hash_low = 0;
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
 
                pdata->set_bits_mask = MAC_CR_HPFILT_;
                pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_);
 
-               netdev_for_each_mc_addr(mc_list, dev) {
-                       unsigned int bitnum = smsc911x_hash(mc_list->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       unsigned int bitnum = smsc911x_hash(ha->addr);
                        unsigned int mask = 0x01 << (bitnum & 0x1F);
 
                        if (bitnum & 0x20)
index aafaebf4574895689ea2aa15da6e7a34f2cb44cd..6cdee6a15f9f2897fa06baa40ad5c34c90c2e27d 100644 (file)
@@ -1034,8 +1034,6 @@ static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb,
        smsc9420_reg_write(pd, TX_POLL_DEMAND, 1);
        smsc9420_pci_flush_write(pd);
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -1064,12 +1062,12 @@ static void smsc9420_set_multicast_list(struct net_device *dev)
                mac_cr |= MAC_CR_MCPAS_;
                mac_cr &= (~MAC_CR_HPFILT_);
        } else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
                u32 hash_lo = 0, hash_hi = 0;
 
                smsc_dbg(HW, "Multicast filter enabled");
-               netdev_for_each_mc_addr(mc_list, dev) {
-                       u32 bit_num = smsc9420_hash(mc_list->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       u32 bit_num = smsc9420_hash(ha->addr);
                        u32 mask = 1 << (bit_num & 0x1F);
 
                        if (bit_num & 0x20)
index 287c251075e5ddec1eb48de335bdc7086815efb4..26e25d7f58298c16cd0d48df2b58d368f56cfafa 100644 (file)
@@ -174,7 +174,7 @@ static void sonic_tx_timeout(struct net_device *dev)
        /* Try to restart the adaptor. */
        sonic_init(dev);
        lp->stats.tx_errors++;
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -263,8 +263,6 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 
        SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -531,7 +529,7 @@ static void sonic_multicast_list(struct net_device *dev)
 {
        struct sonic_local *lp = netdev_priv(dev);
        unsigned int rcr;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned char *addr;
        int i;
 
@@ -550,8 +548,8 @@ static void sonic_multicast_list(struct net_device *dev)
                                       netdev_mc_count(dev));
                        sonic_set_cam_enable(dev, 1);  /* always enable our own address */
                        i = 1;
-                       netdev_for_each_mc_addr(dmi, dev) {
-                               addr = dmi->dmi_addr;
+                       netdev_for_each_mc_addr(ha, dev) {
+                               addr = ha->addr;
                                sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]);
                                sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]);
                                sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]);
index dd3cb0f2d21fe5b2af2643b25d1b2076595024f9..1636a34d95dd60ca6e8c4c6e0ea4871366ad220b 100644 (file)
@@ -625,7 +625,7 @@ spider_net_get_multicast_hash(struct net_device *netdev, __u8 *addr)
 static void
 spider_net_set_multi(struct net_device *netdev)
 {
-       struct dev_mc_list *mc;
+       struct netdev_hw_addr *ha;
        u8 hash;
        int i;
        u32 reg;
@@ -646,8 +646,8 @@ spider_net_set_multi(struct net_device *netdev)
        hash = spider_net_get_multicast_hash(netdev, netdev->broadcast); */
        set_bit(0xfd, bitmask);
 
-       netdev_for_each_mc_addr(mc, netdev) {
-               hash = spider_net_get_multicast_hash(netdev, mc->dmi_addr);
+       netdev_for_each_mc_addr(ha, netdev) {
+               hash = spider_net_get_multicast_hash(netdev, ha->addr);
                set_bit(hash, bitmask);
        }
 
@@ -2095,8 +2095,6 @@ static void spider_net_link_phy(unsigned long data)
                card->netdev->name, phy->speed,
                phy->duplex == 1 ? "Full" : "Half",
                phy->autoneg == 1 ? "" : "no ");
-
-       return;
 }
 
 /**
index 6dfa698990198f12f55ee312e7ae701f8bd0e40e..74b7ae76906e3b482d0c4ad7a47f5c4893adeb7e 100644 (file)
@@ -1173,7 +1173,7 @@ static void tx_timeout(struct net_device *dev)
 
        /* Trigger an immediate transmit demand. */
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        np->stats.tx_errors++;
        netif_wake_queue(dev);
 }
@@ -1221,8 +1221,6 @@ static void init_ring(struct net_device *dev)
 
        for (i = 0; i < TX_RING_SIZE; i++)
                memset(&np->tx_info[i], 0, sizeof(np->tx_info[i]));
-
-       return;
 }
 
 
@@ -1312,8 +1310,6 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        if ((np->cur_tx - np->dirty_tx) + 4 > TX_RING_SIZE)
                netif_stop_queue(dev);
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -1766,7 +1762,7 @@ static void set_rx_mode(struct net_device *dev)
        struct netdev_private *np = netdev_priv(dev);
        void __iomem *ioaddr = np->base;
        u32 rx_mode = MinVLANPrio;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        int i;
 #ifdef VLAN_SUPPORT
 
@@ -1804,8 +1800,8 @@ static void set_rx_mode(struct net_device *dev)
                /* Use the 16 element perfect filter, skip first two entries. */
                void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
                __be16 *eaddrs;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       eaddrs = (__be16 *)mclist->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       eaddrs = (__be16 *) ha->addr;
                        writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4;
                        writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
                        writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8;
@@ -1825,10 +1821,10 @@ static void set_rx_mode(struct net_device *dev)
                __le16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));   /* Multicast hash filter */
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        /* The chip uses the upper 9 CRC bits
                           as index into the hash table */
-                       int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
+                       int bit_nr = ether_crc_le(ETH_ALEN, ha->addr) >> 23;
                        __le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1];
 
                        *fptr |= cpu_to_le32(1 << (bit_nr & 31));
index c776af15fe1a690ba65a49e15fd92db895dadc94..9691733ddb8e7cea628ae6091897f66a458d2759 100644 (file)
@@ -2,4 +2,4 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o
 stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
 stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o     \
              dwmac_lib.o dwmac1000_core.o  dwmac1000_dma.o     \
-             dwmac100.o $(stmmac-y)
+             dwmac100_core.o dwmac100_dma.o enh_desc.o  norm_desc.o $(stmmac-y)
index 2a58172e986ab1bee855df66c573b943bba6485d..144f76fd3e39c71cd7870acb01a5db211f99a860 100644 (file)
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#include "descs.h"
 #include <linux/netdevice.h>
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define STMMAC_VLAN_TAG_USED
+#include <linux/if_vlan.h>
+#endif
+
+#include "descs.h"
+
+#undef CHIP_DEBUG_PRINT
+/* Turn-on extra printk debug for MAC core, dma and descriptors */
+/* #define CHIP_DEBUG_PRINT */
+
+#ifdef CHIP_DEBUG_PRINT
+#define CHIP_DBG(fmt, args...)  printk(fmt, ## args)
+#else
+#define CHIP_DBG(fmt, args...)  do { } while (0)
+#endif
+
+#undef FRAME_FILTER_DEBUG
+/* #define FRAME_FILTER_DEBUG */
 
 struct stmmac_extra_stats {
        /* Transmit errors */
@@ -231,3 +249,4 @@ 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);
+extern void dwmac_dma_flush_tx_fifo(unsigned long ioaddr);
diff --git a/drivers/net/stmmac/dwmac100.c b/drivers/net/stmmac/dwmac100.c
deleted file mode 100644 (file)
index 4cacca6..0000000
+++ /dev/null
@@ -1,538 +0,0 @@
-/*******************************************************************************
-  This is the driver for the MAC 10/100 on-chip Ethernet controller
-  currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
-
-  DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
-  this code.
-
-  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 <linux/mii.h>
-#include <linux/phy.h>
-#include <linux/slab.h>
-
-#include "common.h"
-#include "dwmac100.h"
-#include "dwmac_dma.h"
-
-#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 dwmac100_core_init(unsigned long ioaddr)
-{
-       u32 value = readl(ioaddr + MAC_CONTROL);
-
-       writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
-
-#ifdef STMMAC_VLAN_TAG_USED
-       writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
-#endif
-       return;
-}
-
-static void dwmac100_dump_mac_regs(unsigned long ioaddr)
-{
-       pr_info("\t----------------------------------------------\n"
-               "\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));
-       pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", 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));
-       pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
-               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));
-       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));
-       pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", 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));
-       pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
-               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));
-       pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
-               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));
-       return;
-}
-
-static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
-                          u32 dma_rx)
-{
-       u32 value = readl(ioaddr + DMA_BUS_MODE);
-       /* DMA SW reset */
-       value |= DMA_BUS_MODE_SFT_RESET;
-       writel(value, ioaddr + DMA_BUS_MODE);
-       do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
-
-       /* Enable Application Access by writing to DMA CSR0 */
-       writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
-              ioaddr + DMA_BUS_MODE);
-
-       /* Mask interrupts by writing to CSR7 */
-       writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
-
-       /* The base address of the RX/TX descriptor lists must be written into
-        * DMA CSR3 and CSR4, respectively. */
-       writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
-       writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
-
-       return 0;
-}
-
-/* Store and Forward capability is not used at all..
- * The transmit threshold can be programmed by
- * setting the TTC bits in the DMA control register.*/
-static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
-                                     int rxmode)
-{
-       u32 csr6 = readl(ioaddr + DMA_CONTROL);
-
-       if (txmode <= 32)
-               csr6 |= DMA_CONTROL_TTC_32;
-       else if (txmode <= 64)
-               csr6 |= DMA_CONTROL_TTC_64;
-       else
-               csr6 |= DMA_CONTROL_TTC_128;
-
-       writel(csr6, ioaddr + DMA_CONTROL);
-
-       return;
-}
-
-static void dwmac100_dump_dma_regs(unsigned long ioaddr)
-{
-       int i;
-
-       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),
-                      readl(ioaddr + DMA_BUS_MODE + i * 4));
-       DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
-           DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
-       DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
-           DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
-       return;
-}
-
-/* DMA controller has two counters to track the number of
- * the receive missed frames. */
-static void dwmac100_dma_diagnostic_fr(void *data,
-                                    struct stmmac_extra_stats *x,
-                                    unsigned long ioaddr)
-{
-       struct net_device_stats *stats = (struct net_device_stats *)data;
-       u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
-
-       if (unlikely(csr8)) {
-               if (csr8 & DMA_MISSED_FRAME_OVE) {
-                       stats->rx_over_errors += 0x800;
-                       x->rx_overflow_cntr += 0x800;
-               } else {
-                       unsigned int ove_cntr;
-                       ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
-                       stats->rx_over_errors += ove_cntr;
-                       x->rx_overflow_cntr += ove_cntr;
-               }
-
-               if (csr8 & DMA_MISSED_FRAME_OVE_M) {
-                       stats->rx_missed_errors += 0xffff;
-                       x->rx_missed_cntr += 0xffff;
-               } else {
-                       unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
-                       stats->rx_missed_errors += miss_f;
-                       x->rx_missed_cntr += miss_f;
-               }
-       }
-       return;
-}
-
-static int dwmac100_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;
-
-       if (unlikely(p->des01.tx.error_summary)) {
-               if (unlikely(p->des01.tx.underflow_error)) {
-                       x->tx_underflow++;
-                       stats->tx_fifo_errors++;
-               }
-               if (unlikely(p->des01.tx.no_carrier)) {
-                       x->tx_carrier++;
-                       stats->tx_carrier_errors++;
-               }
-               if (unlikely(p->des01.tx.loss_carrier)) {
-                       x->tx_losscarrier++;
-                       stats->tx_carrier_errors++;
-               }
-               if (unlikely((p->des01.tx.excessive_deferral) ||
-                            (p->des01.tx.excessive_collisions) ||
-                            (p->des01.tx.late_collision)))
-                       stats->collisions += p->des01.tx.collision_count;
-               ret = -1;
-       }
-       if (unlikely(p->des01.tx.heartbeat_fail)) {
-               x->tx_heartbeat++;
-               stats->tx_heartbeat_errors++;
-               ret = -1;
-       }
-       if (unlikely(p->des01.tx.deferred))
-               x->tx_deferred++;
-
-       return ret;
-}
-
-static int dwmac100_get_tx_len(struct dma_desc *p)
-{
-       return p->des01.tx.buffer1_size;
-}
-
-/* This function verifies if each incoming frame has some errors
- * 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 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("dwmac100 Error: Oversized Ethernet "
-                          "frame spanned multiple buffers\n");
-               stats->rx_length_errors++;
-               return discard_frame;
-       }
-
-       if (unlikely(p->des01.rx.error_summary)) {
-               if (unlikely(p->des01.rx.descriptor_error))
-                       x->rx_desc++;
-               if (unlikely(p->des01.rx.partial_frame_error))
-                       x->rx_partial++;
-               if (unlikely(p->des01.rx.run_frame))
-                       x->rx_runt++;
-               if (unlikely(p->des01.rx.frame_too_long))
-                       x->rx_toolong++;
-               if (unlikely(p->des01.rx.collision)) {
-                       x->rx_collision++;
-                       stats->collisions++;
-               }
-               if (unlikely(p->des01.rx.crc_error)) {
-                       x->rx_crc++;
-                       stats->rx_crc_errors++;
-               }
-               ret = discard_frame;
-       }
-       if (unlikely(p->des01.rx.dribbling))
-               ret = discard_frame;
-
-       if (unlikely(p->des01.rx.length_error)) {
-               x->rx_length++;
-               ret = discard_frame;
-       }
-       if (unlikely(p->des01.rx.mii_error)) {
-               x->rx_mii++;
-               ret = discard_frame;
-       }
-       if (p->des01.rx.multicast_frame) {
-               x->rx_multicast++;
-               stats->multicast++;
-       }
-       return ret;
-}
-
-static void dwmac100_irq_status(unsigned long ioaddr)
-{
-       return;
-}
-
-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 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 dwmac100_set_filter(struct net_device *dev)
-{
-       unsigned long ioaddr = dev->base_addr;
-       u32 value = readl(ioaddr + MAC_CONTROL);
-
-       if (dev->flags & IFF_PROMISC) {
-               value |= MAC_CONTROL_PR;
-               value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
-                          MAC_CONTROL_HP);
-       } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
-                  || (dev->flags & IFF_ALLMULTI)) {
-               value |= MAC_CONTROL_PM;
-               value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
-               writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
-               writel(0xffffffff, ioaddr + MAC_HASH_LOW);
-       } else if (netdev_mc_empty(dev)) {      /* no multicast */
-               value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
-                          MAC_CONTROL_HO | MAC_CONTROL_HP);
-       } else {
-               u32 mc_filter[2];
-               struct dev_mc_list *mclist;
-
-               /* 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);
-
-               memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       /* The upper 6 bits of the calculated CRC are used to
-                        * index the contens of the hash table */
-                       int bit_nr =
-                           ether_crc(ETH_ALEN, mclist->dmi_addr) >> 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 + MAC_HASH_LOW);
-               writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
-       }
-
-       writel(value, ioaddr + MAC_CONTROL);
-
-       DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
-           "HI 0x%08x, LO 0x%08x\n",
-           __func__, readl(ioaddr + MAC_CONTROL),
-           readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
-       return;
-}
-
-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;
-
-       if (duplex)
-               flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
-       writel(flow, ioaddr + MAC_FLOW_CTRL);
-
-       return;
-}
-
-/* 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 dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
-                               int disable_rx_ic)
-{
-       int i;
-       for (i = 0; i < ring_size; i++) {
-               p->des01.rx.own = 1;
-               p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
-               if (i == ring_size - 1)
-                       p->des01.rx.end_ring = 1;
-               if (disable_rx_ic)
-                       p->des01.rx.disable_ic = 1;
-               p++;
-       }
-       return;
-}
-
-static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
-{
-       int i;
-       for (i = 0; i < ring_size; i++) {
-               p->des01.tx.own = 0;
-               if (i == ring_size - 1)
-                       p->des01.tx.end_ring = 1;
-               p++;
-       }
-       return;
-}
-
-static int dwmac100_get_tx_owner(struct dma_desc *p)
-{
-       return p->des01.tx.own;
-}
-
-static int dwmac100_get_rx_owner(struct dma_desc *p)
-{
-       return p->des01.rx.own;
-}
-
-static void dwmac100_set_tx_owner(struct dma_desc *p)
-{
-       p->des01.tx.own = 1;
-}
-
-static void dwmac100_set_rx_owner(struct dma_desc *p)
-{
-       p->des01.rx.own = 1;
-}
-
-static int dwmac100_get_tx_ls(struct dma_desc *p)
-{
-       return p->des01.tx.last_segment;
-}
-
-static void dwmac100_release_tx_desc(struct dma_desc *p)
-{
-       int ter = p->des01.tx.end_ring;
-
-       /* clean field used within the xmit */
-       p->des01.tx.first_segment = 0;
-       p->des01.tx.last_segment = 0;
-       p->des01.tx.buffer1_size = 0;
-
-       /* clean status reported */
-       p->des01.tx.error_summary = 0;
-       p->des01.tx.underflow_error = 0;
-       p->des01.tx.no_carrier = 0;
-       p->des01.tx.loss_carrier = 0;
-       p->des01.tx.excessive_deferral = 0;
-       p->des01.tx.excessive_collisions = 0;
-       p->des01.tx.late_collision = 0;
-       p->des01.tx.heartbeat_fail = 0;
-       p->des01.tx.deferred = 0;
-
-       /* set termination field */
-       p->des01.tx.end_ring = ter;
-
-       return;
-}
-
-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 dwmac100_clear_tx_ic(struct dma_desc *p)
-{
-       p->des01.tx.interrupt = 0;
-}
-
-static void dwmac100_close_tx_desc(struct dma_desc *p)
-{
-       p->des01.tx.last_segment = 1;
-       p->des01.tx.interrupt = 1;
-}
-
-static int dwmac100_get_rx_frame_len(struct dma_desc *p)
-{
-       return p->des01.rx.frame_length;
-}
-
-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 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("\tDWMAC100\n");
-
-       mac->mac = &dwmac100_ops;
-       mac->desc = &dwmac100_desc_ops;
-       mac->dma = &dwmac100_dma_ops;
-
-       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;
-}
index 0f8f110d004a3f33747cf198431a29c10f8c2d20..97956cbf1cb4de2a374e0626f20df4977e680fd1 100644 (file)
@@ -22,6 +22,9 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
+#include <linux/phy.h>
+#include "common.h"
+
 /*----------------------------------------------------------------------------
  *                             MAC BLOCK defines
  *---------------------------------------------------------------------------*/
@@ -114,3 +117,5 @@ enum ttc_control {
 #define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000   /* Overflow Frame Counter */
 #define DMA_MISSED_FRAME_OVE_M 0x00010000      /* Missed Frame Overflow */
 #define DMA_MISSED_FRAME_M_CNTR        0x0000ffff      /* Missed Frame Couinter */
+
+extern struct stmmac_dma_ops dwmac100_dma_ops;
index 62dca0e384e726a01f01fd70744d4c8729f74027..d8d0f3553770333145ca016a0277cc8b526f99fa 100644 (file)
@@ -172,7 +172,6 @@ enum rfd {
        deac_full_minus_4 = 0x00401800,
 };
 #define DMA_CONTROL_TSF                0x00200000 /* Transmit  Store and Forward */
-#define DMA_CONTROL_FTF                0x00100000 /* Flush transmit FIFO */
 
 enum ttc_control {
        DMA_CONTROL_TTC_64 = 0x00000000,
@@ -206,15 +205,4 @@ enum rtc_control {
 #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;
index 5bd95ebfe498837ec0313ac49b7df51e42a41636..917b4e16923b800b550fee4502fae7239d67657b 100644 (file)
@@ -48,7 +48,6 @@ static void dwmac1000_core_init(unsigned long ioaddr)
        /* Tag detection without filtering */
        writel(0x0, ioaddr + GMAC_VLAN_TAG);
 #endif
-       return;
 }
 
 static void dwmac1000_dump_regs(unsigned long ioaddr)
@@ -61,7 +60,6 @@ static void dwmac1000_dump_regs(unsigned long ioaddr)
                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,
@@ -83,8 +81,8 @@ 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__, netdev_mc_count(dev), netdev_uc_count(dev));
+       CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
+                __func__, netdev_mc_count(dev), netdev_uc_count(dev));
 
        if (dev->flags & IFF_PROMISC)
                value = GMAC_FRAME_FILTER_PR;
@@ -95,17 +93,17 @@ static void dwmac1000_set_filter(struct net_device *dev)
                writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
        } else if (!netdev_mc_empty(dev)) {
                u32 mc_filter[2];
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                /* Hash filter for multicast */
                value = GMAC_FRAME_FILTER_HMC;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        /* 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;
+                           bitrev32(~crc32_le(~0, ha->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. */
@@ -136,11 +134,9 @@ static void dwmac1000_set_filter(struct net_device *dev)
 #endif
        writel(value, ioaddr + GMAC_FRAME_FILTER);
 
-       DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
+       CHIP_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,
@@ -148,23 +144,22 @@ static void dwmac1000_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
 {
        unsigned int flow = 0;
 
-       DBG(KERN_DEBUG "GMAC Flow-Control:\n");
+       CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n");
        if (fc & FLOW_RX) {
-               DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
+               CHIP_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");
+               CHIP_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);
+               CHIP_DBG(KERN_DEBUG "\tduplex mode: PAUSE %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)
@@ -172,15 +167,14 @@ 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");
+               CHIP_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");
+               CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
                pmt |= global_unicast;
        }
 
        writel(pmt, ioaddr + GMAC_PMT);
-       return;
 }
 
 
@@ -190,22 +184,20 @@ static void dwmac1000_irq_status(unsigned long ioaddr)
 
        /* 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",
+               CHIP_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",
+               CHIP_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",
+               CHIP_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");
+               CHIP_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 = {
@@ -230,7 +222,6 @@ struct mac_device_info *dwmac1000_setup(unsigned long ioaddr)
        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;
index 39d436a2da6866a21a3182aa11cee9aae127588c..415805057cb0ff12e116bd7621fa2246831efeca 100644 (file)
@@ -3,7 +3,7 @@
   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.
+  This contains the functions to handle the dma.
 
   Copyright (C) 2007-2009  STMicroelectronics Ltd
 
@@ -58,29 +58,20 @@ static int dwmac1000_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
        return 0;
 }
 
-/* Transmit FIFO flush operation */
-static void dwmac1000_flush_tx_fifo(unsigned long ioaddr)
-{
-       u32 csr6 = readl(ioaddr + DMA_CONTROL);
-       writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
-
-       do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
-}
-
 static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
                                    int rxmode)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
 
        if (txmode == SF_DMA_MODE) {
-               DBG(KERN_DEBUG "GMAC: enabling TX store and forward mode\n");
+               CHIP_DBG(KERN_DEBUG "GMAC: enable TX store and forward mode\n");
                /* Transmit COE type 2 cannot be done in cut-through mode. */
                csr6 |= DMA_CONTROL_TSF;
                /* Operating on second frame increase the performance
                 * especially when transmit store-and-forward is used.*/
                csr6 |= DMA_CONTROL_OSF;
        } else {
-               DBG(KERN_DEBUG "GMAC: disabling TX store and forward mode"
+               CHIP_DBG(KERN_DEBUG "GMAC: disabling TX store and forward mode"
                              " (threshold = %d)\n", txmode);
                csr6 &= ~DMA_CONTROL_TSF;
                csr6 &= DMA_CONTROL_TC_TX_MASK;
@@ -98,10 +89,10 @@ static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
        }
 
        if (rxmode == SF_DMA_MODE) {
-               DBG(KERN_DEBUG "GMAC: enabling RX store and forward mode\n");
+               CHIP_DBG(KERN_DEBUG "GMAC: enable RX store and forward mode\n");
                csr6 |= DMA_CONTROL_RSF;
        } else {
-               DBG(KERN_DEBUG "GMAC: disabling RX store and forward mode"
+               CHIP_DBG(KERN_DEBUG "GMAC: disabling RX store and forward mode"
                              " (threshold = %d)\n", rxmode);
                csr6 &= ~DMA_CONTROL_RSF;
                csr6 &= DMA_CONTROL_TC_RX_MASK;
@@ -116,7 +107,6 @@ static void dwmac1000_dma_operation_mode(unsigned long ioaddr, int txmode,
        }
 
        writel(csr6, ioaddr + DMA_CONTROL);
-       return;
 }
 
 /* Not yet implemented --- no RMON module */
@@ -138,306 +128,6 @@ static void dwmac1000_dump_dma_regs(unsigned long ioaddr)
                               readl(ioaddr + DMA_BUS_MODE + offset));
                }
        }
-       return;
-}
-
-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;
-
-       if (unlikely(p->des01.etx.error_summary)) {
-               DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
-               if (unlikely(p->des01.etx.jabber_timeout)) {
-                       DBG(KERN_ERR "\tjabber_timeout error\n");
-                       x->tx_jabber++;
-               }
-
-               if (unlikely(p->des01.etx.frame_flushed)) {
-                       DBG(KERN_ERR "\tframe_flushed error\n");
-                       x->tx_frame_flushed++;
-                       dwmac1000_flush_tx_fifo(ioaddr);
-               }
-
-               if (unlikely(p->des01.etx.loss_carrier)) {
-                       DBG(KERN_ERR "\tloss_carrier error\n");
-                       x->tx_losscarrier++;
-                       stats->tx_carrier_errors++;
-               }
-               if (unlikely(p->des01.etx.no_carrier)) {
-                       DBG(KERN_ERR "\tno_carrier error\n");
-                       x->tx_carrier++;
-                       stats->tx_carrier_errors++;
-               }
-               if (unlikely(p->des01.etx.late_collision)) {
-                       DBG(KERN_ERR "\tlate_collision error\n");
-                       stats->collisions += p->des01.etx.collision_count;
-               }
-               if (unlikely(p->des01.etx.excessive_collisions)) {
-                       DBG(KERN_ERR "\texcessive_collisions\n");
-                       stats->collisions += p->des01.etx.collision_count;
-               }
-               if (unlikely(p->des01.etx.excessive_deferral)) {
-                       DBG(KERN_INFO "\texcessive tx_deferral\n");
-                       x->tx_deferred++;
-               }
-
-               if (unlikely(p->des01.etx.underflow_error)) {
-                       DBG(KERN_ERR "\tunderflow error\n");
-                       dwmac1000_flush_tx_fifo(ioaddr);
-                       x->tx_underflow++;
-               }
-
-               if (unlikely(p->des01.etx.ip_header_error)) {
-                       DBG(KERN_ERR "\tTX IP header csum error\n");
-                       x->tx_ip_header_error++;
-               }
-
-               if (unlikely(p->des01.etx.payload_error)) {
-                       DBG(KERN_ERR "\tAddr/Payload csum error\n");
-                       x->tx_payload_error++;
-                       dwmac1000_flush_tx_fifo(ioaddr);
-               }
-
-               ret = -1;
-       }
-
-       if (unlikely(p->des01.etx.deferred)) {
-               DBG(KERN_INFO "GMAC TX status: tx deferred\n");
-               x->tx_deferred++;
-       }
-#ifdef STMMAC_VLAN_TAG_USED
-       if (p->des01.etx.vlan_frame) {
-               DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
-               x->tx_vlan++;
-       }
-#endif
-
-       return ret;
-}
-
-static int dwmac1000_get_tx_len(struct dma_desc *p)
-{
-       return p->des01.etx.buffer1_size;
-}
-
-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;
-
-       /* bits 5 7 0 | Frame status
-        * ----------------------------------------------------------
-        *      0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
-        *      1 0 0 | IPv4/6 No CSUM errorS.
-        *      1 0 1 | IPv4/6 CSUM PAYLOAD error
-        *      1 1 0 | IPv4/6 CSUM IP HR error
-        *      1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
-        *      0 0 1 | IPv4/6 unsupported IP PAYLOAD
-        *      0 1 1 | COE bypassed.. no IPv4/6 frame
-        *      0 1 0 | Reserved.
-        */
-       if (status == 0x0) {
-               DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
-               ret = good_frame;
-       } else if (status == 0x4) {
-               DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
-               ret = good_frame;
-       } else if (status == 0x5) {
-               DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
-               ret = csum_none;
-       } else if (status == 0x6) {
-               DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
-               ret = csum_none;
-       } else if (status == 0x7) {
-               DBG(KERN_ERR
-                   "RX Des0 status: IPv4/6 Header and Payload Error.\n");
-               ret = csum_none;
-       } else if (status == 0x1) {
-               DBG(KERN_ERR
-                   "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
-               ret = discard_frame;
-       } else if (status == 0x3) {
-               DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
-               ret = discard_frame;
-       }
-       return ret;
-}
-
-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;
-
-       if (unlikely(p->des01.erx.error_summary)) {
-               DBG(KERN_ERR "GMAC RX Error Summary... 0x%08x\n", p->des01.erx);
-               if (unlikely(p->des01.erx.descriptor_error)) {
-                       DBG(KERN_ERR "\tdescriptor error\n");
-                       x->rx_desc++;
-                       stats->rx_length_errors++;
-               }
-               if (unlikely(p->des01.erx.overflow_error)) {
-                       DBG(KERN_ERR "\toverflow error\n");
-                       x->rx_gmac_overflow++;
-               }
-
-               if (unlikely(p->des01.erx.ipc_csum_error))
-                       DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
-
-               if (unlikely(p->des01.erx.late_collision)) {
-                       DBG(KERN_ERR "\tlate_collision error\n");
-                       stats->collisions++;
-                       stats->collisions++;
-               }
-               if (unlikely(p->des01.erx.receive_watchdog)) {
-                       DBG(KERN_ERR "\treceive_watchdog error\n");
-                       x->rx_watchdog++;
-               }
-               if (unlikely(p->des01.erx.error_gmii)) {
-                       DBG(KERN_ERR "\tReceive Error\n");
-                       x->rx_mii++;
-               }
-               if (unlikely(p->des01.erx.crc_error)) {
-                       DBG(KERN_ERR "\tCRC error\n");
-                       x->rx_crc++;
-                       stats->rx_crc_errors++;
-               }
-               ret = discard_frame;
-       }
-
-       /* After a payload csum error, the ES bit is set.
-        * 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 = 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)) {
-               DBG(KERN_ERR "GMAC RX: dribbling error\n");
-               ret = discard_frame;
-       }
-       if (unlikely(p->des01.erx.sa_filter_fail)) {
-               DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
-               x->sa_rx_filter_fail++;
-               ret = discard_frame;
-       }
-       if (unlikely(p->des01.erx.da_filter_fail)) {
-               DBG(KERN_ERR "GMAC RX : Destination Address filter fail\n");
-               x->da_rx_filter_fail++;
-               ret = discard_frame;
-       }
-       if (unlikely(p->des01.erx.length_error)) {
-               DBG(KERN_ERR "GMAC RX: length_error error\n");
-               x->rx_length++;
-               ret = discard_frame;
-       }
-#ifdef STMMAC_VLAN_TAG_USED
-       if (p->des01.erx.vlan_tag) {
-               DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
-               x->rx_vlan++;
-       }
-#endif
-       return ret;
-}
-
-static void dwmac1000_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
-                               int disable_rx_ic)
-{
-       int i;
-       for (i = 0; i < ring_size; i++) {
-               p->des01.erx.own = 1;
-               p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
-               /* To support jumbo frames */
-               p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
-               if (i == ring_size - 1)
-                       p->des01.erx.end_ring = 1;
-               if (disable_rx_ic)
-                       p->des01.erx.disable_ic = 1;
-               p++;
-       }
-       return;
-}
-
-static void dwmac1000_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
-{
-       int i;
-
-       for (i = 0; i < ring_size; i++) {
-               p->des01.etx.own = 0;
-               if (i == ring_size - 1)
-                       p->des01.etx.end_ring = 1;
-               p++;
-       }
-
-       return;
-}
-
-static int dwmac1000_get_tx_owner(struct dma_desc *p)
-{
-       return p->des01.etx.own;
-}
-
-static int dwmac1000_get_rx_owner(struct dma_desc *p)
-{
-       return p->des01.erx.own;
-}
-
-static void dwmac1000_set_tx_owner(struct dma_desc *p)
-{
-       p->des01.etx.own = 1;
-}
-
-static void dwmac1000_set_rx_owner(struct dma_desc *p)
-{
-       p->des01.erx.own = 1;
-}
-
-static int dwmac1000_get_tx_ls(struct dma_desc *p)
-{
-       return p->des01.etx.last_segment;
-}
-
-static void dwmac1000_release_tx_desc(struct dma_desc *p)
-{
-       int ter = p->des01.etx.end_ring;
-
-       memset(p, 0, sizeof(struct dma_desc));
-       p->des01.etx.end_ring = ter;
-
-       return;
-}
-
-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;
-       if (unlikely(len > BUF_SIZE_4KiB)) {
-               p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
-               p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
-       } else {
-               p->des01.etx.buffer1_size = len;
-       }
-       if (likely(csum_flag))
-               p->des01.etx.checksum_insertion = cic_full;
-}
-
-static void dwmac1000_clear_tx_ic(struct dma_desc *p)
-{
-       p->des01.etx.interrupt = 0;
-}
-
-static void dwmac1000_close_tx_desc(struct dma_desc *p)
-{
-       p->des01.etx.last_segment = 1;
-       p->des01.etx.interrupt = 1;
-}
-
-static int dwmac1000_get_rx_frame_len(struct dma_desc *p)
-{
-       return p->des01.erx.frame_length;
 }
 
 struct stmmac_dma_ops dwmac1000_dma_ops = {
@@ -454,21 +144,3 @@ struct stmmac_dma_ops dwmac1000_dma_ops = {
        .stop_rx = dwmac_dma_stop_rx,
        .dma_interrupt = dwmac_dma_interrupt,
 };
-
-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/dwmac100_core.c b/drivers/net/stmmac/dwmac100_core.c
new file mode 100644 (file)
index 0000000..6f270a0
--- /dev/null
@@ -0,0 +1,196 @@
+/*******************************************************************************
+  This is the driver for the MAC 10/100 on-chip Ethernet controller
+  currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
+
+  DWC Ether MAC 10/100 Universal version 4.0 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 "dwmac100.h"
+
+static void dwmac100_core_init(unsigned long ioaddr)
+{
+       u32 value = readl(ioaddr + MAC_CONTROL);
+
+       writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
+
+#ifdef STMMAC_VLAN_TAG_USED
+       writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
+#endif
+}
+
+static void dwmac100_dump_mac_regs(unsigned long ioaddr)
+{
+       pr_info("\t----------------------------------------------\n"
+               "\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));
+       pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", 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));
+       pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
+               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));
+       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));
+       pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", 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));
+       pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
+               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));
+       pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
+               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));
+}
+
+static void dwmac100_irq_status(unsigned long ioaddr)
+{
+       return;
+}
+
+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 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 dwmac100_set_filter(struct net_device *dev)
+{
+       unsigned long ioaddr = dev->base_addr;
+       u32 value = readl(ioaddr + MAC_CONTROL);
+
+       if (dev->flags & IFF_PROMISC) {
+               value |= MAC_CONTROL_PR;
+               value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
+                          MAC_CONTROL_HP);
+       } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
+                  || (dev->flags & IFF_ALLMULTI)) {
+               value |= MAC_CONTROL_PM;
+               value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
+               writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
+               writel(0xffffffff, ioaddr + MAC_HASH_LOW);
+       } else if (netdev_mc_empty(dev)) {      /* no multicast */
+               value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
+                          MAC_CONTROL_HO | MAC_CONTROL_HP);
+       } else {
+               u32 mc_filter[2];
+               struct netdev_hw_addr *ha;
+
+               /* 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);
+
+               memset(mc_filter, 0, sizeof(mc_filter));
+               netdev_for_each_mc_addr(ha, dev) {
+                       /* The upper 6 bits of the calculated CRC are used to
+                        * index the contens of the hash table */
+                       int bit_nr =
+                           ether_crc(ETH_ALEN, ha->addr) >> 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 + MAC_HASH_LOW);
+               writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
+       }
+
+       writel(value, ioaddr + MAC_CONTROL);
+
+       CHIP_DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
+           "HI 0x%08x, LO 0x%08x\n",
+           __func__, readl(ioaddr + MAC_CONTROL),
+           readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
+}
+
+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;
+
+       if (duplex)
+               flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
+       writel(flow, ioaddr + MAC_FLOW_CTRL);
+}
+
+/* No PMT module supported for this Ethernet Controller.
+ * Tested on ST platforms only.
+ */
+static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
+{
+       return;
+}
+
+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 *dwmac100_setup(unsigned long ioaddr)
+{
+       struct mac_device_info *mac;
+
+       mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+
+       pr_info("\tDWMAC100\n");
+
+       mac->mac = &dwmac100_ops;
+       mac->dma = &dwmac100_dma_ops;
+
+       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;
+}
diff --git a/drivers/net/stmmac/dwmac100_dma.c b/drivers/net/stmmac/dwmac100_dma.c
new file mode 100644 (file)
index 0000000..2fece7b
--- /dev/null
@@ -0,0 +1,134 @@
+/*******************************************************************************
+  This is the driver for the MAC 10/100 on-chip Ethernet controller
+  currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
+
+  DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
+  this code.
+
+  This contains the functions to handle the dma.
+
+  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 "dwmac100.h"
+#include "dwmac_dma.h"
+
+static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+                            u32 dma_rx)
+{
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
+       /* DMA SW reset */
+       value |= DMA_BUS_MODE_SFT_RESET;
+       writel(value, ioaddr + DMA_BUS_MODE);
+       do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
+
+       /* Enable Application Access by writing to DMA CSR0 */
+       writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
+              ioaddr + DMA_BUS_MODE);
+
+       /* Mask interrupts by writing to CSR7 */
+       writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+
+       /* The base address of the RX/TX descriptor lists must be written into
+        * DMA CSR3 and CSR4, respectively. */
+       writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
+       writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
+
+       return 0;
+}
+
+/* Store and Forward capability is not used at all..
+ * The transmit threshold can be programmed by
+ * setting the TTC bits in the DMA control register.*/
+static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
+                                       int rxmode)
+{
+       u32 csr6 = readl(ioaddr + DMA_CONTROL);
+
+       if (txmode <= 32)
+               csr6 |= DMA_CONTROL_TTC_32;
+       else if (txmode <= 64)
+               csr6 |= DMA_CONTROL_TTC_64;
+       else
+               csr6 |= DMA_CONTROL_TTC_128;
+
+       writel(csr6, ioaddr + DMA_CONTROL);
+}
+
+static void dwmac100_dump_dma_regs(unsigned long ioaddr)
+{
+       int i;
+
+       CHIP_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),
+                      readl(ioaddr + DMA_BUS_MODE + i * 4));
+       CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
+           DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
+       CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
+           DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
+}
+
+/* DMA controller has two counters to track the number of
+ * the receive missed frames. */
+static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
+                                      unsigned long ioaddr)
+{
+       struct net_device_stats *stats = (struct net_device_stats *)data;
+       u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
+
+       if (unlikely(csr8)) {
+               if (csr8 & DMA_MISSED_FRAME_OVE) {
+                       stats->rx_over_errors += 0x800;
+                       x->rx_overflow_cntr += 0x800;
+               } else {
+                       unsigned int ove_cntr;
+                       ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
+                       stats->rx_over_errors += ove_cntr;
+                       x->rx_overflow_cntr += ove_cntr;
+               }
+
+               if (csr8 & DMA_MISSED_FRAME_OVE_M) {
+                       stats->rx_missed_errors += 0xffff;
+                       x->rx_missed_cntr += 0xffff;
+               } else {
+                       unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
+                       stats->rx_missed_errors += miss_f;
+                       x->rx_missed_cntr += miss_f;
+               }
+       }
+}
+
+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,
+};
index de848d9f6060acbb685eea19f91bde3d492c3301..7b815a1b7b8cb82e8a9d6e85302f1ee8ac07bc4b 100644 (file)
@@ -95,6 +95,7 @@
 #define DMA_STATUS_TU  0x00000004      /* Transmit Buffer Unavailable */
 #define DMA_STATUS_TPS 0x00000002      /* Transmit Process Stopped */
 #define DMA_STATUS_TI  0x00000001      /* Transmit Interrupt */
+#define DMA_CONTROL_FTF                0x00100000 /* Flush transmit FIFO */
 
 extern void dwmac_enable_dma_transmission(unsigned long ioaddr);
 extern void dwmac_enable_dma_irq(unsigned long ioaddr);
index d4adb1eaa447a6da2488618c04a709ea94e6835a..a85415216ef4e326a3ae21afa833c03be1ca6e52 100644 (file)
@@ -52,7 +52,6 @@ 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)
@@ -60,7 +59,6 @@ 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)
@@ -68,8 +66,6 @@ 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)
@@ -77,8 +73,6 @@ 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
@@ -111,7 +105,6 @@ static void show_tx_process_state(unsigned int status)
        default:
                break;
        }
-       return;
 }
 
 static void show_rx_process_state(unsigned int status)
@@ -149,7 +142,6 @@ static void show_rx_process_state(unsigned int status)
        default:
                break;
        }
-       return;
 }
 #endif
 
@@ -227,6 +219,13 @@ int dwmac_dma_interrupt(unsigned long ioaddr,
        return ret;
 }
 
+void dwmac_dma_flush_tx_fifo(unsigned long ioaddr)
+{
+       u32 csr6 = readl(ioaddr + DMA_CONTROL);
+       writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
+
+       do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
+}
 
 void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
                         unsigned int high, unsigned int low)
@@ -237,8 +236,6 @@ void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
        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,
@@ -257,7 +254,5 @@ void stmmac_get_mac_addr(unsigned long ioaddr, unsigned char *addr,
        addr[3] = (lo_addr >> 24) & 0xff;
        addr[4] = hi_addr & 0xff;
        addr[5] = (hi_addr >> 8) & 0xff;
-
-       return;
 }
 
diff --git a/drivers/net/stmmac/enh_desc.c b/drivers/net/stmmac/enh_desc.c
new file mode 100644 (file)
index 0000000..3c18ebe
--- /dev/null
@@ -0,0 +1,337 @@
+/*******************************************************************************
+  This contains the functions to handle the enhanced descriptors.
+
+  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 "common.h"
+
+static int enh_desc_get_tx_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;
+
+       if (unlikely(p->des01.etx.error_summary)) {
+               CHIP_DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
+               if (unlikely(p->des01.etx.jabber_timeout)) {
+                       CHIP_DBG(KERN_ERR "\tjabber_timeout error\n");
+                       x->tx_jabber++;
+               }
+
+               if (unlikely(p->des01.etx.frame_flushed)) {
+                       CHIP_DBG(KERN_ERR "\tframe_flushed error\n");
+                       x->tx_frame_flushed++;
+                       dwmac_dma_flush_tx_fifo(ioaddr);
+               }
+
+               if (unlikely(p->des01.etx.loss_carrier)) {
+                       CHIP_DBG(KERN_ERR "\tloss_carrier error\n");
+                       x->tx_losscarrier++;
+                       stats->tx_carrier_errors++;
+               }
+               if (unlikely(p->des01.etx.no_carrier)) {
+                       CHIP_DBG(KERN_ERR "\tno_carrier error\n");
+                       x->tx_carrier++;
+                       stats->tx_carrier_errors++;
+               }
+               if (unlikely(p->des01.etx.late_collision)) {
+                       CHIP_DBG(KERN_ERR "\tlate_collision error\n");
+                       stats->collisions += p->des01.etx.collision_count;
+               }
+               if (unlikely(p->des01.etx.excessive_collisions)) {
+                       CHIP_DBG(KERN_ERR "\texcessive_collisions\n");
+                       stats->collisions += p->des01.etx.collision_count;
+               }
+               if (unlikely(p->des01.etx.excessive_deferral)) {
+                       CHIP_DBG(KERN_INFO "\texcessive tx_deferral\n");
+                       x->tx_deferred++;
+               }
+
+               if (unlikely(p->des01.etx.underflow_error)) {
+                       CHIP_DBG(KERN_ERR "\tunderflow error\n");
+                       dwmac_dma_flush_tx_fifo(ioaddr);
+                       x->tx_underflow++;
+               }
+
+               if (unlikely(p->des01.etx.ip_header_error)) {
+                       CHIP_DBG(KERN_ERR "\tTX IP header csum error\n");
+                       x->tx_ip_header_error++;
+               }
+
+               if (unlikely(p->des01.etx.payload_error)) {
+                       CHIP_DBG(KERN_ERR "\tAddr/Payload csum error\n");
+                       x->tx_payload_error++;
+                       dwmac_dma_flush_tx_fifo(ioaddr);
+               }
+
+               ret = -1;
+       }
+
+       if (unlikely(p->des01.etx.deferred)) {
+               CHIP_DBG(KERN_INFO "GMAC TX status: tx deferred\n");
+               x->tx_deferred++;
+       }
+#ifdef STMMAC_VLAN_TAG_USED
+       if (p->des01.etx.vlan_frame) {
+               CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
+               x->tx_vlan++;
+       }
+#endif
+
+       return ret;
+}
+
+static int enh_desc_get_tx_len(struct dma_desc *p)
+{
+       return p->des01.etx.buffer1_size;
+}
+
+static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
+{
+       int ret = good_frame;
+       u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
+
+       /* bits 5 7 0 | Frame status
+        * ----------------------------------------------------------
+        *      0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
+        *      1 0 0 | IPv4/6 No CSUM errorS.
+        *      1 0 1 | IPv4/6 CSUM PAYLOAD error
+        *      1 1 0 | IPv4/6 CSUM IP HR error
+        *      1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
+        *      0 0 1 | IPv4/6 unsupported IP PAYLOAD
+        *      0 1 1 | COE bypassed.. no IPv4/6 frame
+        *      0 1 0 | Reserved.
+        */
+       if (status == 0x0) {
+               CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
+               ret = good_frame;
+       } else if (status == 0x4) {
+               CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
+               ret = good_frame;
+       } else if (status == 0x5) {
+               CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
+               ret = csum_none;
+       } else if (status == 0x6) {
+               CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
+               ret = csum_none;
+       } else if (status == 0x7) {
+               CHIP_DBG(KERN_ERR
+                   "RX Des0 status: IPv4/6 Header and Payload Error.\n");
+               ret = csum_none;
+       } else if (status == 0x1) {
+               CHIP_DBG(KERN_ERR
+                   "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
+               ret = discard_frame;
+       } else if (status == 0x3) {
+               CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
+               ret = discard_frame;
+       }
+       return ret;
+}
+
+static int enh_desc_get_rx_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;
+
+       if (unlikely(p->des01.erx.error_summary)) {
+               CHIP_DBG(KERN_ERR "GMAC RX Error Summary 0x%08x\n",
+                                 p->des01.erx);
+               if (unlikely(p->des01.erx.descriptor_error)) {
+                       CHIP_DBG(KERN_ERR "\tdescriptor error\n");
+                       x->rx_desc++;
+                       stats->rx_length_errors++;
+               }
+               if (unlikely(p->des01.erx.overflow_error)) {
+                       CHIP_DBG(KERN_ERR "\toverflow error\n");
+                       x->rx_gmac_overflow++;
+               }
+
+               if (unlikely(p->des01.erx.ipc_csum_error))
+                       CHIP_DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
+
+               if (unlikely(p->des01.erx.late_collision)) {
+                       CHIP_DBG(KERN_ERR "\tlate_collision error\n");
+                       stats->collisions++;
+                       stats->collisions++;
+               }
+               if (unlikely(p->des01.erx.receive_watchdog)) {
+                       CHIP_DBG(KERN_ERR "\treceive_watchdog error\n");
+                       x->rx_watchdog++;
+               }
+               if (unlikely(p->des01.erx.error_gmii)) {
+                       CHIP_DBG(KERN_ERR "\tReceive Error\n");
+                       x->rx_mii++;
+               }
+               if (unlikely(p->des01.erx.crc_error)) {
+                       CHIP_DBG(KERN_ERR "\tCRC error\n");
+                       x->rx_crc++;
+                       stats->rx_crc_errors++;
+               }
+               ret = discard_frame;
+       }
+
+       /* After a payload csum error, the ES bit is set.
+        * 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 = enh_desc_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)) {
+               CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
+               ret = discard_frame;
+       }
+       if (unlikely(p->des01.erx.sa_filter_fail)) {
+               CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
+               x->sa_rx_filter_fail++;
+               ret = discard_frame;
+       }
+       if (unlikely(p->des01.erx.da_filter_fail)) {
+               CHIP_DBG(KERN_ERR "GMAC RX : Dest Address filter fail\n");
+               x->da_rx_filter_fail++;
+               ret = discard_frame;
+       }
+       if (unlikely(p->des01.erx.length_error)) {
+               CHIP_DBG(KERN_ERR "GMAC RX: length_error error\n");
+               x->rx_length++;
+               ret = discard_frame;
+       }
+#ifdef STMMAC_VLAN_TAG_USED
+       if (p->des01.erx.vlan_tag) {
+               CHIP_DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
+               x->rx_vlan++;
+       }
+#endif
+       return ret;
+}
+
+static void enh_desc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+                                 int disable_rx_ic)
+{
+       int i;
+       for (i = 0; i < ring_size; i++) {
+               p->des01.erx.own = 1;
+               p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
+               /* To support jumbo frames */
+               p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
+               if (i == ring_size - 1)
+                       p->des01.erx.end_ring = 1;
+               if (disable_rx_ic)
+                       p->des01.erx.disable_ic = 1;
+               p++;
+       }
+}
+
+static void enh_desc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+{
+       int i;
+
+       for (i = 0; i < ring_size; i++) {
+               p->des01.etx.own = 0;
+               if (i == ring_size - 1)
+                       p->des01.etx.end_ring = 1;
+               p++;
+       }
+}
+
+static int enh_desc_get_tx_owner(struct dma_desc *p)
+{
+       return p->des01.etx.own;
+}
+
+static int enh_desc_get_rx_owner(struct dma_desc *p)
+{
+       return p->des01.erx.own;
+}
+
+static void enh_desc_set_tx_owner(struct dma_desc *p)
+{
+       p->des01.etx.own = 1;
+}
+
+static void enh_desc_set_rx_owner(struct dma_desc *p)
+{
+       p->des01.erx.own = 1;
+}
+
+static int enh_desc_get_tx_ls(struct dma_desc *p)
+{
+       return p->des01.etx.last_segment;
+}
+
+static void enh_desc_release_tx_desc(struct dma_desc *p)
+{
+       int ter = p->des01.etx.end_ring;
+
+       memset(p, 0, sizeof(struct dma_desc));
+       p->des01.etx.end_ring = ter;
+}
+
+static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+                                    int csum_flag)
+{
+       p->des01.etx.first_segment = is_fs;
+       if (unlikely(len > BUF_SIZE_4KiB)) {
+               p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
+               p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
+       } else {
+               p->des01.etx.buffer1_size = len;
+       }
+       if (likely(csum_flag))
+               p->des01.etx.checksum_insertion = cic_full;
+}
+
+static void enh_desc_clear_tx_ic(struct dma_desc *p)
+{
+       p->des01.etx.interrupt = 0;
+}
+
+static void enh_desc_close_tx_desc(struct dma_desc *p)
+{
+       p->des01.etx.last_segment = 1;
+       p->des01.etx.interrupt = 1;
+}
+
+static int enh_desc_get_rx_frame_len(struct dma_desc *p)
+{
+       return p->des01.erx.frame_length;
+}
+
+struct stmmac_desc_ops enh_desc_ops = {
+       .tx_status = enh_desc_get_tx_status,
+       .rx_status = enh_desc_get_rx_status,
+       .get_tx_len = enh_desc_get_tx_len,
+       .init_rx_desc = enh_desc_init_rx_desc,
+       .init_tx_desc = enh_desc_init_tx_desc,
+       .get_tx_owner = enh_desc_get_tx_owner,
+       .get_rx_owner = enh_desc_get_rx_owner,
+       .release_tx_desc = enh_desc_release_tx_desc,
+       .prepare_tx_desc = enh_desc_prepare_tx_desc,
+       .clear_tx_ic = enh_desc_clear_tx_ic,
+       .close_tx_desc = enh_desc_close_tx_desc,
+       .get_tx_ls = enh_desc_get_tx_ls,
+       .set_tx_owner = enh_desc_set_tx_owner,
+       .set_rx_owner = enh_desc_set_rx_owner,
+       .get_rx_frame_len = enh_desc_get_rx_frame_len,
+};
diff --git a/drivers/net/stmmac/norm_desc.c b/drivers/net/stmmac/norm_desc.c
new file mode 100644 (file)
index 0000000..31ad536
--- /dev/null
@@ -0,0 +1,236 @@
+/*******************************************************************************
+  This contains the functions to handle the normal descriptors.
+
+  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 "common.h"
+
+static int ndesc_get_tx_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;
+
+       if (unlikely(p->des01.tx.error_summary)) {
+               if (unlikely(p->des01.tx.underflow_error)) {
+                       x->tx_underflow++;
+                       stats->tx_fifo_errors++;
+               }
+               if (unlikely(p->des01.tx.no_carrier)) {
+                       x->tx_carrier++;
+                       stats->tx_carrier_errors++;
+               }
+               if (unlikely(p->des01.tx.loss_carrier)) {
+                       x->tx_losscarrier++;
+                       stats->tx_carrier_errors++;
+               }
+               if (unlikely((p->des01.tx.excessive_deferral) ||
+                            (p->des01.tx.excessive_collisions) ||
+                            (p->des01.tx.late_collision)))
+                       stats->collisions += p->des01.tx.collision_count;
+               ret = -1;
+       }
+       if (unlikely(p->des01.tx.heartbeat_fail)) {
+               x->tx_heartbeat++;
+               stats->tx_heartbeat_errors++;
+               ret = -1;
+       }
+       if (unlikely(p->des01.tx.deferred))
+               x->tx_deferred++;
+
+       return ret;
+}
+
+static int ndesc_get_tx_len(struct dma_desc *p)
+{
+       return p->des01.tx.buffer1_size;
+}
+
+/* This function verifies if each incoming frame has some errors
+ * 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 ndesc_get_rx_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("ndesc Error: Oversized Ethernet "
+                          "frame spanned multiple buffers\n");
+               stats->rx_length_errors++;
+               return discard_frame;
+       }
+
+       if (unlikely(p->des01.rx.error_summary)) {
+               if (unlikely(p->des01.rx.descriptor_error))
+                       x->rx_desc++;
+               if (unlikely(p->des01.rx.partial_frame_error))
+                       x->rx_partial++;
+               if (unlikely(p->des01.rx.run_frame))
+                       x->rx_runt++;
+               if (unlikely(p->des01.rx.frame_too_long))
+                       x->rx_toolong++;
+               if (unlikely(p->des01.rx.collision)) {
+                       x->rx_collision++;
+                       stats->collisions++;
+               }
+               if (unlikely(p->des01.rx.crc_error)) {
+                       x->rx_crc++;
+                       stats->rx_crc_errors++;
+               }
+               ret = discard_frame;
+       }
+       if (unlikely(p->des01.rx.dribbling))
+               ret = discard_frame;
+
+       if (unlikely(p->des01.rx.length_error)) {
+               x->rx_length++;
+               ret = discard_frame;
+       }
+       if (unlikely(p->des01.rx.mii_error)) {
+               x->rx_mii++;
+               ret = discard_frame;
+       }
+       if (p->des01.rx.multicast_frame) {
+               x->rx_multicast++;
+               stats->multicast++;
+       }
+       return ret;
+}
+
+static void ndesc_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+                              int disable_rx_ic)
+{
+       int i;
+       for (i = 0; i < ring_size; i++) {
+               p->des01.rx.own = 1;
+               p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
+               if (i == ring_size - 1)
+                       p->des01.rx.end_ring = 1;
+               if (disable_rx_ic)
+                       p->des01.rx.disable_ic = 1;
+               p++;
+       }
+}
+
+static void ndesc_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+{
+       int i;
+       for (i = 0; i < ring_size; i++) {
+               p->des01.tx.own = 0;
+               if (i == ring_size - 1)
+                       p->des01.tx.end_ring = 1;
+               p++;
+       }
+}
+
+static int ndesc_get_tx_owner(struct dma_desc *p)
+{
+       return p->des01.tx.own;
+}
+
+static int ndesc_get_rx_owner(struct dma_desc *p)
+{
+       return p->des01.rx.own;
+}
+
+static void ndesc_set_tx_owner(struct dma_desc *p)
+{
+       p->des01.tx.own = 1;
+}
+
+static void ndesc_set_rx_owner(struct dma_desc *p)
+{
+       p->des01.rx.own = 1;
+}
+
+static int ndesc_get_tx_ls(struct dma_desc *p)
+{
+       return p->des01.tx.last_segment;
+}
+
+static void ndesc_release_tx_desc(struct dma_desc *p)
+{
+       int ter = p->des01.tx.end_ring;
+
+       /* clean field used within the xmit */
+       p->des01.tx.first_segment = 0;
+       p->des01.tx.last_segment = 0;
+       p->des01.tx.buffer1_size = 0;
+
+       /* clean status reported */
+       p->des01.tx.error_summary = 0;
+       p->des01.tx.underflow_error = 0;
+       p->des01.tx.no_carrier = 0;
+       p->des01.tx.loss_carrier = 0;
+       p->des01.tx.excessive_deferral = 0;
+       p->des01.tx.excessive_collisions = 0;
+       p->des01.tx.late_collision = 0;
+       p->des01.tx.heartbeat_fail = 0;
+       p->des01.tx.deferred = 0;
+
+       /* set termination field */
+       p->des01.tx.end_ring = ter;
+}
+
+static void ndesc_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 ndesc_clear_tx_ic(struct dma_desc *p)
+{
+       p->des01.tx.interrupt = 0;
+}
+
+static void ndesc_close_tx_desc(struct dma_desc *p)
+{
+       p->des01.tx.last_segment = 1;
+       p->des01.tx.interrupt = 1;
+}
+
+static int ndesc_get_rx_frame_len(struct dma_desc *p)
+{
+       return p->des01.rx.frame_length;
+}
+
+struct stmmac_desc_ops ndesc_ops = {
+       .tx_status = ndesc_get_tx_status,
+       .rx_status = ndesc_get_rx_status,
+       .get_tx_len = ndesc_get_tx_len,
+       .init_rx_desc = ndesc_init_rx_desc,
+       .init_tx_desc = ndesc_init_tx_desc,
+       .get_tx_owner = ndesc_get_tx_owner,
+       .get_rx_owner = ndesc_get_rx_owner,
+       .release_tx_desc = ndesc_release_tx_desc,
+       .prepare_tx_desc = ndesc_prepare_tx_desc,
+       .clear_tx_ic = ndesc_clear_tx_ic,
+       .close_tx_desc = ndesc_close_tx_desc,
+       .get_tx_ls = ndesc_get_tx_ls,
+       .set_tx_owner = ndesc_set_tx_owner,
+       .set_rx_owner = ndesc_set_rx_owner,
+       .get_rx_frame_len = ndesc_get_rx_frame_len,
+};
index ba35e6943cf4e956d4c94e54fbddd3c93bb31a6e..ebebc644b1b8cf7b503fb07ef137cdf323d70a2c 100644 (file)
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#define DRV_MODULE_VERSION     "Jan_2010"
+#define DRV_MODULE_VERSION     "Apr_2010"
 #include <linux/stmmac.h>
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-#define STMMAC_VLAN_TAG_USED
-#include <linux/if_vlan.h>
-#endif
-
 #include "common.h"
 #ifdef CONFIG_STMMAC_TIMER
 #include "stmmac_timer.h"
@@ -93,6 +88,7 @@ struct stmmac_priv {
 #ifdef STMMAC_VLAN_TAG_USED
        struct vlan_group *vlgrp;
 #endif
+       int enh_desc;
 };
 
 #ifdef CONFIG_STM_DRIVERS
@@ -120,3 +116,5 @@ static inline int stmmac_claim_resource(struct platform_device *pdev)
 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);
+extern struct stmmac_desc_ops enh_desc_ops;
+extern struct stmmac_desc_ops ndesc_ops;
index c021eaa3ca69662a6fa5e32cc218f73f591455cf..f080509923f03eae4f787e9fc5615e1f9e03f2f5 100644 (file)
@@ -102,7 +102,6 @@ void stmmac_ethtool_getdrvinfo(struct net_device *dev,
        strcpy(info->version, DRV_MODULE_VERSION);
        info->fw_version[0] = '\0';
        info->n_stats = STMMAC_STATS_LEN;
-       return;
 }
 
 int stmmac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -194,8 +193,6 @@ void stmmac_ethtool_gregs(struct net_device *dev,
                        reg_space[i + 55] =
                            readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
        }
-
-       return;
 }
 
 int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
@@ -233,7 +230,6 @@ stmmac_get_pauseparam(struct net_device *netdev,
                pause->tx_pause = 1;
 
        spin_unlock(&priv->lock);
-       return;
 }
 
 static int
@@ -292,8 +288,6 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
                data[i] = (stmmac_gstrings_stats[i].sizeof_stat ==
                sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
        }
-
-       return;
 }
 
 static int stmmac_get_sset_count(struct net_device *netdev, int sset)
@@ -323,7 +317,6 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
                WARN_ON(1);
                break;
        }
-       return;
 }
 
 /* Currently only support WOL through Magic packet. */
index 4111a85ec80eb0030f5570b3fc1aaba957e6c21c..a31d580f306d90c206bc6b90e56cf9bd82a597d9 100644 (file)
@@ -169,8 +169,6 @@ static void stmmac_verify_args(void)
                flow_ctrl = FLOW_OFF;
        if (unlikely((pause < 0) || (pause > 0xffff)))
                pause = PAUSE_TIME;
-
-       return;
 }
 
 #if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
@@ -184,7 +182,6 @@ static void print_pkt(unsigned char *buf, int len)
                pr_info(" %02x", buf[j]);
        }
        pr_info("\n");
-       return;
 }
 #endif
 
@@ -514,7 +511,6 @@ static void init_dma_desc_rings(struct net_device *dev)
                pr_info("TX descriptor ring:\n");
                display_ring(priv->dma_tx, txsize);
        }
-       return;
 }
 
 static void dma_free_rx_skbufs(struct stmmac_priv *priv)
@@ -529,7 +525,6 @@ static void dma_free_rx_skbufs(struct stmmac_priv *priv)
                }
                priv->rx_skbuff[i] = NULL;
        }
-       return;
 }
 
 static void dma_free_tx_skbufs(struct stmmac_priv *priv)
@@ -547,7 +542,6 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
                        priv->tx_skbuff[i] = NULL;
                }
        }
-       return;
 }
 
 static void free_dma_desc_resources(struct stmmac_priv *priv)
@@ -567,8 +561,6 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
        kfree(priv->rx_skbuff_dma);
        kfree(priv->rx_skbuff);
        kfree(priv->tx_skbuff);
-
-       return;
 }
 
 /**
@@ -598,8 +590,6 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
                }
        }
        tx_coe = priv->tx_coe;
-
-       return;
 }
 
 /**
@@ -675,7 +665,6 @@ static void stmmac_tx(struct stmmac_priv *priv)
                }
                netif_tx_unlock(priv->dev);
        }
-       return;
 }
 
 static inline void stmmac_enable_irq(struct stmmac_priv *priv)
@@ -731,8 +720,6 @@ void stmmac_schedule(struct net_device *dev)
        priv->xstats.sched_timer_n++;
 
        _stmmac_schedule(priv);
-
-       return;
 }
 
 static void stmmac_no_timer_started(unsigned int x)
@@ -763,8 +750,6 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 
        priv->dev->stats.tx_errors++;
        netif_wake_queue(priv->dev);
-
-       return;
 }
 
 
@@ -788,8 +773,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
                stmmac_tx_err(priv);
        } else if (unlikely(status == tx_hard_error))
                stmmac_tx_err(priv);
-
-       return;
 }
 
 /**
@@ -837,7 +820,7 @@ static int stmmac_open(struct net_device *dev)
 #ifdef CONFIG_STMMAC_TIMER
        priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
        if (unlikely(priv->tm == NULL)) {
-               pr_err("%s: ERROR: timer memory alloc failed \n", __func__);
+               pr_err("%s: ERROR: timer memory alloc failed\n", __func__);
                return -ENOMEM;
        }
        priv->tm->freq = tmrate;
@@ -1197,7 +1180,6 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
                }
                priv->hw->desc->set_rx_owner(p + entry);
        }
-       return;
 }
 
 static int stmmac_rx(struct stmmac_priv *priv, int limit)
@@ -1280,7 +1262,6 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
 
                        priv->dev->stats.rx_packets++;
                        priv->dev->stats.rx_bytes += frame_len;
-                       priv->dev->last_rx = jiffies;
                }
                entry = next_entry;
                p = p_next;     /* use prefetched values */
@@ -1332,7 +1313,6 @@ static void stmmac_tx_timeout(struct net_device *dev)
 
        /* Clear Tx resources and restart transmitting again */
        stmmac_tx_err(priv);
-       return;
 }
 
 /* Configuration changes (passed on by ifconfig) */
@@ -1374,7 +1354,6 @@ static void stmmac_multicast_list(struct net_device *dev)
        spin_lock(&priv->lock);
        priv->hw->mac->set_filter(dev);
        spin_unlock(&priv->lock);
-       return;
 }
 
 /**
@@ -1490,8 +1469,6 @@ static void stmmac_vlan_rx_register(struct net_device *dev,
        spin_lock(&priv->lock);
        priv->vlgrp = grp;
        spin_unlock(&priv->lock);
-
-       return;
 }
 #endif
 
@@ -1587,6 +1564,12 @@ static int stmmac_mac_device_setup(struct net_device *dev)
        else
                device = dwmac100_setup(ioaddr);
 
+       if (priv->enh_desc) {
+               device->desc = &enh_desc_ops;
+               pr_info("\tEnhanced descriptor structure\n");
+       } else
+               device->desc = &ndesc_ops;
+
        if (!device)
                return -ENOMEM;
 
@@ -1727,6 +1710,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
        priv->bus_id = plat_dat->bus_id;
        priv->pbl = plat_dat->pbl;      /* TLI */
        priv->is_gmac = plat_dat->has_gmac;     /* GMAC is on board */
+       priv->enh_desc = plat_dat->enh_desc;
 
        platform_set_drvdata(pdev, ndev);
 
index 679f61ffb1f868254f75381e652112ae97d8b83b..2a0e1abde7e73eeea25c9c457999765b5315a01f 100644 (file)
@@ -31,8 +31,6 @@ static void stmmac_timer_handler(void *data)
        struct net_device *dev = (struct net_device *)data;
 
        stmmac_schedule(dev);
-
-       return;
 }
 
 #define STMMAC_TIMER_MSG(timer, freq) \
@@ -47,13 +45,11 @@ static void stmmac_rtc_start(unsigned int new_freq)
 {
        rtc_irq_set_freq(stmmac_rtc, &stmmac_task, new_freq);
        rtc_irq_set_state(stmmac_rtc, &stmmac_task, 1);
-       return;
 }
 
 static void stmmac_rtc_stop(void)
 {
        rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
-       return;
 }
 
 int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
@@ -102,13 +98,11 @@ static void stmmac_tmu_start(unsigned int new_freq)
 {
        clk_set_rate(timer_clock, new_freq);
        clk_enable(timer_clock);
-       return;
 }
 
 static void stmmac_tmu_stop(void)
 {
        clk_disable(timer_clock);
-       return;
 }
 
 int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
index 87a6b8eabc672355fd9ee12ae6aa738c8e8d3c0c..d85f0a84bc7bc0c2a993d72a591114a2f43bb29f 100644 (file)
@@ -280,7 +280,6 @@ stnic_init (struct net_device *dev)
 {
   stnic_reset (dev);
   NS8390_init (dev, 0);
-  return;
 }
 
 static void __exit stnic_cleanup(void)
index 8b28c89a9a77c50566ddb39601f37ed2d765a5b5..151312342243d3c784613ed07e2dd2f7aec2ac1f 100644 (file)
@@ -412,7 +412,7 @@ static int init586(struct net_device *dev)
        volatile struct iasetup_cmd_struct *ias_cmd;
        volatile struct tdr_cmd_struct *tdr_cmd;
        volatile struct mcsetup_cmd_struct *mc_cmd;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        int num_addrs=netdev_mc_count(dev);
 
        ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
@@ -536,9 +536,9 @@ static int init586(struct net_device *dev)
                mc_cmd->mc_cnt = swab16(num_addrs * 6);
 
                i = 0;
-               netdev_for_each_mc_addr(dmi, dev)
+               netdev_for_each_mc_addr(ha, dev)
                        memcpy((char *) mc_cmd->mc_list[i++],
-                              dmi->dmi_addr, ETH_ALEN);
+                              ha->addr, ETH_ALEN);
 
                p->scb->cbl_offset = make16(mc_cmd);
                p->scb->cmd_cuc = CUC_START;
@@ -985,7 +985,7 @@ static void sun3_82586_timeout(struct net_device *dev)
                p->scb->cmd_cuc = CUC_START;
                sun3_attn586();
                WAIT_4_SCB_CMD();
-               dev->trans_start = jiffies;
+               dev->trans_start = jiffies; /* prevent tx timeout */
                return 0;
        }
 #endif
@@ -998,7 +998,7 @@ static void sun3_82586_timeout(struct net_device *dev)
                sun3_82586_close(dev);
                sun3_82586_open(dev);
        }
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 /******************************************************
@@ -1062,7 +1062,6 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
                        }
 
                        sun3_attn586();
-                       dev->trans_start = jiffies;
                        if(!i)
                                dev_kfree_skb(skb);
                        WAIT_4_SCB_CMD();
@@ -1082,7 +1081,6 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
                p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
 
                p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
-               dev->trans_start = jiffies;
                p->nop_point = next_nop;
                dev_kfree_skb(skb);
 #      endif
@@ -1097,7 +1095,6 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
                p->nop_cmds[next_nop]->cmd_status = 0;
 
                p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
-               dev->trans_start = jiffies;
                p->xmit_count = next_nop;
 
                {
index 1694ca5bfb41a4f85c5ebee6e1b067938e982130..358c22f9acbef8e4978cf8cc0969123dbe9c3974 100644 (file)
@@ -523,8 +523,8 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
 
        /* Transmitter timeout, serious problems. */
        if (netif_queue_stopped(dev)) {
-               int tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < 20)
+               int tickssofar = jiffies - dev_trans_start(dev);
+               if (tickssofar < HZ/5)
                        return NETDEV_TX_BUSY;
 
                DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
@@ -559,7 +559,6 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
                REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
 
                netif_start_queue(dev);
-               dev->trans_start = jiffies;
 
                return NETDEV_TX_OK;
        }
@@ -637,8 +636,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
        AREG = CSR0;
        DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n",
                                  dev->name, DREG ));
-       dev->trans_start = jiffies;
-       dev_kfree_skb( skb );
+       dev_kfree_skb(skb);
 
        lp->lock = 0;
        if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
index ed7865a0b5b2efeacebda8db16aff1cab2aa5058..4591fe9bf0b9dd5fe875f5e6aecc5f877b0cc119 100644 (file)
@@ -362,7 +362,7 @@ static void bigmac_tcvr_write(struct bigmac *bp, void __iomem *tregs,
        default:
                printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");
                return;
-       };
+       }
 
        idle_transceiver(tregs);
        write_tcvr_bit(bp, tregs, 0);
@@ -401,7 +401,7 @@ static unsigned short bigmac_tcvr_read(struct bigmac *bp,
        default:
                printk(KERN_ERR "bigmac_tcvr_read: Whoops, no known transceiver type.\n");
                return 0xffff;
-       };
+       }
 
        idle_transceiver(tregs);
        write_tcvr_bit(bp, tregs, 0);
@@ -982,8 +982,6 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        sbus_writel(CREG_CTRL_TWAKEUP, bp->creg + CREG_CTRL);
 
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -999,7 +997,7 @@ static void bigmac_set_multicast(struct net_device *dev)
 {
        struct bigmac *bp = netdev_priv(dev);
        void __iomem *bregs = bp->bregs;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        int i;
        u32 tmp, crc;
@@ -1028,8 +1026,8 @@ static void bigmac_set_multicast(struct net_device *dev)
                for (i = 0; i < 4; i++)
                        hash_table[i] = 0;
 
-               netdev_for_each_mc_addr(dmi, dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
index 8249a394a4e16b68df683f52acbac224f9ef2649..2678588ea4b201bdd6a1c9395f5abeeae9d9216f 100644 (file)
@@ -788,7 +788,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
                iowrite8(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
                mdio_delay();
        }
-       return;
 }
 
 static int mdio_wait_link(struct net_device *dev, int wait)
@@ -972,7 +971,7 @@ static void tx_timeout(struct net_device *dev)
 
        dev->if_port = 0;
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
        if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
                netif_wake_queue(dev);
@@ -1022,7 +1021,6 @@ static void init_ring(struct net_device *dev)
                np->tx_skbuff[i] = NULL;
                np->tx_ring[i].status = 0;
        }
-       return;
 }
 
 static void tx_poll (unsigned long data)
@@ -1049,7 +1047,6 @@ static void tx_poll (unsigned long data)
        if (ioread32 (np->base + TxListPtr) == 0)
                iowrite32 (np->tx_ring_dma + head * sizeof(struct netdev_desc),
                        np->base + TxListPtr);
-       return;
 }
 
 static netdev_tx_t
@@ -1084,7 +1081,6 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
        } else {
                netif_stop_queue (dev);
        }
-       dev->trans_start = jiffies;
        if (netif_msg_tx_queued(np)) {
                printk (KERN_DEBUG
                        "%s: Transmit frame #%d queued in slot %d.\n",
@@ -1379,7 +1375,6 @@ not_done:
        if (np->budget <= 0)
                np->budget = RX_BUDGET;
        tasklet_schedule(&np->rx_tasklet);
-       return;
 }
 
 static void refill_rx (struct net_device *dev)
@@ -1410,7 +1405,6 @@ static void refill_rx (struct net_device *dev)
                np->rx_ring[entry].status = 0;
                cnt++;
        }
-       return;
 }
 static void netdev_error(struct net_device *dev, int intr_status)
 {
@@ -1522,13 +1516,13 @@ static void set_rx_mode(struct net_device *dev)
                memset(mc_filter, 0xff, sizeof(mc_filter));
                rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
        } else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                int bit;
                int index;
                int crc;
                memset (mc_filter, 0, sizeof (mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       crc = ether_crc_le(ETH_ALEN, ha->addr);
                        for (index=0, bit=0; bit < 6; bit++, crc <<= 1)
                                if (crc & 0x80000000) index |= 1 << bit;
                        mc_filter[index/16] |= (1 << (index % 16));
index e6880f1c4e8cf872320656761aa416ec75a3a3d7..434f9d735333663919c199b3e929dd74de924549 100644 (file)
@@ -1136,7 +1136,7 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
        writel(gp->tx_new, gp->regs + TXDMA_KICK);
        spin_unlock_irqrestore(&gp->tx_lock, flags);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
 
        return NETDEV_TX_OK;
 }
@@ -1846,12 +1846,12 @@ static u32 gem_setup_multicast(struct gem *gp)
        } else {
                u16 hash_table[16];
                u32 crc;
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                int i;
 
                memset(hash_table, 0, sizeof(hash_table));
-               netdev_for_each_mc_addr(dmi, gp->dev) {
-                       char *addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, gp->dev) {
+                       char *addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
@@ -2923,7 +2923,6 @@ static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
        dev_addr[1] = 0x00;
        dev_addr[2] = 0x20;
        get_random_bytes(dev_addr + 3, 3);
-       return;
 }
 #endif /* not Sparc and not PPC */
 
index b17dbb11bd678b9cc6227830003d95e2abb6a600..915c5909c7a8bb90e4c6fe22617f5dbee032552c 100644 (file)
@@ -855,7 +855,7 @@ static void happy_meal_timer(unsigned long data)
                hp->timer_ticks = 0;
                hp->timer_state = asleep; /* foo on you */
                break;
-       };
+       }
 
        if (restart_timer) {
                hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
@@ -1488,7 +1488,7 @@ static int happy_meal_init(struct happy_meal *hp)
                HMD(("external, disable MII, "));
                hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB);
                break;
-       };
+       }
 
        if (happy_meal_tcvr_reset(hp, tregs))
                return -EAGAIN;
@@ -1523,13 +1523,13 @@ static int happy_meal_init(struct happy_meal *hp)
                hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff);
        } else if ((hp->dev->flags & IFF_PROMISC) == 0) {
                u16 hash_table[4];
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                char *addrs;
                u32 crc;
 
                memset(hash_table, 0, sizeof(hash_table));
-               netdev_for_each_mc_addr(dmi, hp->dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, hp->dev) {
+                       addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
@@ -1734,7 +1734,7 @@ static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
        case external:
                hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB);
                break;
-       };
+       }
        if (happy_meal_tcvr_reset(hp, tregs))
                return;
 
@@ -2341,8 +2341,6 @@ static netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb,
 
        spin_unlock_irq(&hp->happy_lock);
 
-       dev->trans_start = jiffies;
-
        tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
        return NETDEV_TX_OK;
 }
@@ -2362,7 +2360,7 @@ static void happy_meal_set_multicast(struct net_device *dev)
 {
        struct happy_meal *hp = netdev_priv(dev);
        void __iomem *bregs = hp->bigmacregs;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        u32 crc;
 
@@ -2380,8 +2378,8 @@ static void happy_meal_set_multicast(struct net_device *dev)
                u16 hash_table[4];
 
                memset(hash_table, 0, sizeof(hash_table));
-               netdev_for_each_mc_addr(dmi, dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
@@ -2945,7 +2943,6 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
        dev_addr[1] = 0x00;
        dev_addr[2] = 0x20;
        get_random_bytes(&dev_addr[3], 3);
-       return;
 }
 #endif /* !(CONFIG_SPARC) */
 
@@ -3004,7 +3001,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
        dev->base_addr = (long) pdev;
 
        hp = netdev_priv(dev);
-       memset(hp, 0, sizeof(*hp));
 
        hp->happy_dev = pdev;
        hp->dma_dev = &pdev->dev;
index 0c21653ff9f90d3022d8e6e4e83d1bb03ee9f874..386af7bbe6783914f3fd683bc12d28a84b770e1a 100644 (file)
@@ -1003,7 +1003,7 @@ static int lance_reset(struct net_device *dev)
        }
        lp->init_ring(dev);
        load_csrs(lp);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        status = init_restart_lance(lp);
        return status;
 }
@@ -1054,7 +1054,7 @@ static void lance_piocopy_from_skb(void __iomem *dest, unsigned char *src, int l
                }
                src = (char *) p16;
                break;
-       };
+       }
        if (len >= 2) {
                u16 val = src[0] << 8 | src[1];
                sbus_writew(val, piobuf);
@@ -1160,7 +1160,6 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irq(&lp->lock);
 
-       dev->trans_start = jiffies;
        dev_kfree_skb(skb);
 
        return NETDEV_TX_OK;
@@ -1170,7 +1169,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void lance_load_multicast(struct net_device *dev)
 {
        struct lance_private *lp = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        char *addrs;
        u32 crc;
        u32 val;
@@ -1195,8 +1194,8 @@ static void lance_load_multicast(struct net_device *dev)
                return;
 
        /* Add addresses */
-       netdev_for_each_mc_addr(dmi, dev) {
-               addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrs = ha->addr;
 
                /* multicast address? */
                if (!(*addrs & 1))
index be637dce944c03efa7b134726a63058f97544edf..a7542d25c8451f31b0420e586fd96b74e77eced4 100644 (file)
@@ -602,7 +602,6 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
        qep->tx_new = NEXT_TX(entry);
 
        /* Get it going. */
-       dev->trans_start = jiffies;
        sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL);
 
        dev->stats.tx_packets++;
@@ -627,7 +626,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void qe_set_multicast(struct net_device *dev)
 {
        struct sunqe *qep = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        u8 new_mconfig = qep->mconfig;
        char *addrs;
        int i;
@@ -651,8 +650,8 @@ static void qe_set_multicast(struct net_device *dev)
                u8 *hbytes = (unsigned char *) &hash_table[0];
 
                memset(hash_table, 0, sizeof(hash_table));
-               netdev_for_each_mc_addr(dmi, dev) {
-                       addrs = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       addrs = ha->addr;
 
                        if (!(*addrs & 1))
                                continue;
index 6b1b7cea7f6b7fef75d2804254c6300a392fce86..d281a7b34701060d4ab23f3f2c764b684bf7bb0d 100644 (file)
@@ -717,7 +717,6 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 
 out_dropped_unlock:
@@ -763,12 +762,12 @@ static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
 
 static void __update_mc_list(struct vnet *vp, struct net_device *dev)
 {
-       struct dev_addr_list *p;
+       struct netdev_hw_addr *ha;
 
-       netdev_for_each_mc_addr(p, dev) {
+       netdev_for_each_mc_addr(ha, dev) {
                struct vnet_mcast_entry *m;
 
-               m = __vnet_mc_find(vp, p->dmi_addr);
+               m = __vnet_mc_find(vp, ha->addr);
                if (m) {
                        m->hit = 1;
                        continue;
@@ -778,7 +777,7 @@ static void __update_mc_list(struct vnet *vp, struct net_device *dev)
                        m = kzalloc(sizeof(*m), GFP_ATOMIC);
                        if (!m)
                                continue;
-                       memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+                       memcpy(m->addr, ha->addr, ETH_ALEN);
                        m->hit = 1;
 
                        m->next = vp->mcast_list;
index 49bd84c0d583e4ebaf8f3df7e4de8ddd4992671f..be08b75dbc15a3d2d6adaf8d76c6d1de83c4d362 100644 (file)
@@ -1357,8 +1357,6 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
        }
        lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
 
-       dev->trans_start = jiffies;
-
        /* If we just used up the very last entry in the
         * TX ring on this device, tell the queueing
         * layer to send no more.
@@ -1954,16 +1952,16 @@ tc35815_set_multicast_list(struct net_device *dev)
                /* Disable promiscuous mode, use normal mode. */
                tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
        } else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *cur_addr;
+               struct netdev_hw_addr *ha;
                int i;
                int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
 
                tc_writel(0, &tr->CAM_Ctl);
                /* Walk the address list, and load the filter */
                i = 0;
-               netdev_for_each_mc_addr(cur_addr, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        /* entry 0,1 is reserved. */
-                       tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
+                       tc35815_set_cam_entry(dev, i + 2, ha->addr);
                        ena_bits |= CAM_Ena_Bit(i + 2);
                        i++;
                }
index f5493092521acd159f750fe18072aba812dd2816..20ab161923253835b7ee760f8fc027bdcc8aa82c 100644 (file)
@@ -808,7 +808,7 @@ static void bdx_setmulti(struct net_device *ndev)
                        WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0);
        } else if (!netdev_mc_empty(ndev)) {
                u8 hash;
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                u32 reg, val;
 
                /* set IMF to deny all multicast frames */
@@ -825,10 +825,10 @@ static void bdx_setmulti(struct net_device *ndev)
                 * into RX_MAC_MCST regs. we skip this phase now and accept ALL
                 * multicast frames throu IMF */
                /* accept the rest of addresses throu IMF */
-               netdev_for_each_mc_addr(mclist, ndev) {
+               netdev_for_each_mc_addr(ha, ndev) {
                        hash = 0;
                        for (i = 0; i < ETH_ALEN; i++)
-                               hash ^= mclist->dmi_addr[i];
+                               hash ^= ha->addr[i];
                        reg = regRX_MCST_HASH0 + ((hash >> 5) << 2);
                        val = READ_REG(priv, reg);
                        val |= (1 << (hash % 32));
@@ -1303,7 +1303,6 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
                priv->net_stats.rx_bytes += len;
 
                skb_put(skb, len);
-               skb->dev = priv->ndev;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb->protocol = eth_type_trans(skb, priv->ndev);
 
@@ -1509,7 +1508,7 @@ bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb,
        int nr_frags = skb_shinfo(skb)->nr_frags;
        int i;
 
-       db->wptr->len = skb->len - skb->data_len;
+       db->wptr->len = skb_headlen(skb);
        db->wptr->addr.dma = pci_map_single(priv->pdev, skb->data,
                                            db->wptr->len, PCI_DMA_TODEVICE);
        pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
@@ -2034,7 +2033,6 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /************** priv ****************/
                priv = nic->priv[port] = netdev_priv(ndev);
 
-               memset(priv, 0, sizeof(struct bdx_priv));
                priv->pBdxRegs = nic->regs + port * 0x8000;
                priv->port = port;
                priv->pdev = pdev;
index ecc41cffb470d3d16b97e5fe61768f57c4822d65..573054ae7b58687dbe52eee0be849f0436159e1c 100644 (file)
@@ -67,8 +67,8 @@
 #include "tg3.h"
 
 #define DRV_MODULE_NAME                "tg3"
-#define DRV_MODULE_VERSION     "3.108"
-#define DRV_MODULE_RELDATE     "February 17, 2010"
+#define DRV_MODULE_VERSION     "3.110"
+#define DRV_MODULE_RELDATE     "April 9, 2010"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
 #define TG3_DEF_RX_RING_PENDING                200
 #define TG3_RX_JUMBO_RING_SIZE         256
 #define TG3_DEF_RX_JUMBO_RING_PENDING  100
-#define TG3_RSS_INDIR_TBL_SIZE 128
+#define TG3_RSS_INDIR_TBL_SIZE         128
 
 /* Do not place this n-ring entries value into the tp struct itself,
  * we really want to expose these constants to GCC so that modulo et
                                 TG3_TX_RING_SIZE)
 #define NEXT_TX(N)             (((N) + 1) & (TG3_TX_RING_SIZE - 1))
 
+#define TG3_RX_DMA_ALIGN               16
+#define TG3_RX_HEADROOM                        ALIGN(VLAN_HLEN, TG3_RX_DMA_ALIGN)
+
 #define TG3_DMA_BYTE_ENAB              64
 
 #define TG3_RX_STD_DMA_SZ              1536
 #define TG3_RX_JMB_BUFF_RING_SIZE \
        (sizeof(struct ring_info) * TG3_RX_JUMBO_RING_SIZE)
 
+#define TG3_RSS_MIN_NUM_MSIX_VECS      2
+
+/* Due to a hardware bug, the 5701 can only DMA to memory addresses
+ * that are at least dword aligned when used in PCIX mode.  The driver
+ * works around this bug by double copying the packet.  This workaround
+ * is built into the normal double copy length check for efficiency.
+ *
+ * However, the double copy is only necessary on those architectures
+ * where unaligned memory accesses are inefficient.  For those architectures
+ * where unaligned memory accesses incur little penalty, we can reintegrate
+ * the 5701 in the normal rx path.  Doing so saves a device structure
+ * dereference by hardcoding the double copy threshold in place.
+ */
+#define TG3_RX_COPY_THRESHOLD          256
+#if NET_IP_ALIGN == 0 || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+       #define TG3_RX_COPY_THRESH(tp)  TG3_RX_COPY_THRESHOLD
+#else
+       #define TG3_RX_COPY_THRESH(tp)  ((tp)->rx_copy_thresh)
+#endif
+
 /* minimum number of free TX descriptors required to wake up TX process */
 #define TG3_TX_WAKEUP_THRESH(tnapi)            ((tnapi)->tx_pending / 4)
 
 
 #define TG3_NUM_TEST           6
 
+#define TG3_FW_UPDATE_TIMEOUT_SEC      5
+
 #define FIRMWARE_TG3           "tigon/tg3.bin"
 #define FIRMWARE_TG3TSO                "tigon/tg3_tso.bin"
 #define FIRMWARE_TG3TSO5       "tigon/tg3_tso5.bin"
@@ -167,8 +192,6 @@ MODULE_FIRMWARE(FIRMWARE_TG3);
 MODULE_FIRMWARE(FIRMWARE_TG3TSO);
 MODULE_FIRMWARE(FIRMWARE_TG3TSO5);
 
-#define TG3_RSS_MIN_NUM_MSIX_VECS      2
-
 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");
@@ -360,7 +383,7 @@ static void tg3_write32(struct tg3 *tp, u32 off, u32 val)
 
 static u32 tg3_read32(struct tg3 *tp, u32 off)
 {
-       return (readl(tp->regs + off));
+       return readl(tp->regs + off);
 }
 
 static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
@@ -370,7 +393,7 @@ static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
 
 static u32 tg3_ape_read32(struct tg3 *tp, u32 off)
 {
-       return (readl(tp->aperegs + off));
+       return readl(tp->aperegs + off);
 }
 
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
@@ -488,7 +511,7 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
 
 static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off)
 {
-       return (readl(tp->regs + off + GRCMBOX_BASE));
+       return readl(tp->regs + off + GRCMBOX_BASE);
 }
 
 static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
@@ -496,16 +519,16 @@ static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
        writel(val, tp->regs + off + GRCMBOX_BASE);
 }
 
-#define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val)
+#define tw32_mailbox(reg, val)         tp->write32_mbox(tp, reg, val)
 #define tw32_mailbox_f(reg, val)       tw32_mailbox_flush(tp, (reg), (val))
-#define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val)
-#define tw32_tx_mbox(reg, val) tp->write32_tx_mbox(tp, reg, val)
-#define tr32_mailbox(reg)      tp->read32_mbox(tp, reg)
+#define tw32_rx_mbox(reg, val)         tp->write32_rx_mbox(tp, reg, val)
+#define tw32_tx_mbox(reg, val)         tp->write32_tx_mbox(tp, reg, val)
+#define tr32_mailbox(reg)              tp->read32_mbox(tp, reg)
 
-#define tw32(reg,val)          tp->write32(tp, reg, val)
-#define tw32_f(reg,val)                _tw32_flush(tp,(reg),(val), 0)
-#define tw32_wait_f(reg,val,us)        _tw32_flush(tp,(reg),(val), (us))
-#define tr32(reg)              tp->read32(tp, reg)
+#define tw32(reg, val)                 tp->write32(tp, reg, val)
+#define tw32_f(reg, val)               _tw32_flush(tp, (reg), (val), 0)
+#define tw32_wait_f(reg, val, us)      _tw32_flush(tp, (reg), (val), (us))
+#define tr32(reg)                      tp->read32(tp, reg)
 
 static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
 {
@@ -579,11 +602,11 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
                return 0;
 
        switch (locknum) {
-               case TG3_APE_LOCK_GRC:
-               case TG3_APE_LOCK_MEM:
-                       break;
-               default:
-                       return -EINVAL;
+       case TG3_APE_LOCK_GRC:
+       case TG3_APE_LOCK_MEM:
+               break;
+       default:
+               return -EINVAL;
        }
 
        off = 4 * locknum;
@@ -617,11 +640,11 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
                return;
 
        switch (locknum) {
-               case TG3_APE_LOCK_GRC:
-               case TG3_APE_LOCK_MEM:
-                       break;
-               default:
-                       return;
+       case TG3_APE_LOCK_GRC:
+       case TG3_APE_LOCK_MEM:
+               break;
+       default:
+               return;
        }
 
        off = 4 * locknum;
@@ -651,6 +674,7 @@ static void tg3_enable_ints(struct tg3 *tp)
        tp->coal_now = tp->coalesce_mode | HOSTCC_MODE_ENABLE;
        for (i = 0; i < tp->irq_cnt; i++) {
                struct tg3_napi *tnapi = &tp->napi[i];
+
                tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
                if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
                        tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
@@ -1098,7 +1122,7 @@ static int tg3_mdio_init(struct tg3 *tp)
 
        i = mdiobus_register(tp->mdio_bus);
        if (i) {
-               netdev_warn(tp->dev, "mdiobus_reg failed (0x%x)\n", i);
+               dev_warn(&tp->pdev->dev, "mdiobus_reg failed (0x%x)\n", i);
                mdiobus_free(tp->mdio_bus);
                return i;
        }
@@ -1106,7 +1130,7 @@ static int tg3_mdio_init(struct tg3 *tp)
        phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
 
        if (!phydev || !phydev->drv) {
-               netdev_warn(tp->dev, "No PHY devices\n");
+               dev_warn(&tp->pdev->dev, "No PHY devices\n");
                mdiobus_unregister(tp->mdio_bus);
                mdiobus_free(tp->mdio_bus);
                return -ENODEV;
@@ -1437,7 +1461,7 @@ static void tg3_adjust_link(struct net_device *dev)
            phydev->speed != tp->link_config.active_speed ||
            phydev->duplex != tp->link_config.active_duplex ||
            oldflowctrl != tp->link_config.active_flowctrl)
-           linkmesg = 1;
+               linkmesg = 1;
 
        tp->link_config.active_speed = phydev->speed;
        tp->link_config.active_duplex = phydev->duplex;
@@ -1464,7 +1488,7 @@ static int tg3_phy_init(struct tg3 *tp)
        phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link,
                             phydev->dev_flags, phydev->interface);
        if (IS_ERR(phydev)) {
-               netdev_err(tp->dev, "Could not attach to PHY\n");
+               dev_err(&tp->pdev->dev, "Could not attach to PHY\n");
                return PTR_ERR(phydev);
        }
 
@@ -1855,8 +1879,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
                /* Set Extended packet length bit for jumbo frames */
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400);
-       }
-       else {
+       } else {
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
        }
 
@@ -1974,8 +1997,7 @@ out:
                tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x401f);
                tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x14e2);
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
-       }
-       else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
+       } else if (tp->tg3_flags2 & TG3_FLG2_PHY_JITTER_BUG) {
                tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
                tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
                if (tp->tg3_flags2 & TG3_FLG2_PHY_ADJUST_TRIM) {
@@ -2007,8 +2029,8 @@ out:
                u32 phy_reg;
 
                if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &phy_reg))
-                   tg3_writephy(tp, MII_TG3_EXT_CTRL,
-                                phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
+                       tg3_writephy(tp, MII_TG3_EXT_CTRL,
+                                    phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
        }
 
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -3425,7 +3447,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
        ap->rxconfig = rx_cfg_reg;
        ret = ANEG_OK;
 
-       switch(ap->state) {
+       switch (ap->state) {
        case ANEG_STATE_UNKNOWN:
                if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
                        ap->state = ANEG_STATE_AN_ENABLE;
@@ -3463,11 +3485,10 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
                /* fallthru */
        case ANEG_STATE_RESTART:
                delta = ap->cur_time - ap->link_time;
-               if (delta > ANEG_STATE_SETTLE_TIME) {
+               if (delta > ANEG_STATE_SETTLE_TIME)
                        ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
-               } else {
+               else
                        ret = ANEG_TIMER_ENAB;
-               }
                break;
 
        case ANEG_STATE_DISABLE_LINK_OK:
@@ -3491,9 +3512,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
                break;
 
        case ANEG_STATE_ABILITY_DETECT:
-               if (ap->ability_match != 0 && ap->rxconfig != 0) {
+               if (ap->ability_match != 0 && ap->rxconfig != 0)
                        ap->state = ANEG_STATE_ACK_DETECT_INIT;
-               }
                break;
 
        case ANEG_STATE_ACK_DETECT_INIT:
@@ -4171,9 +4191,9 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
                                        current_duplex = DUPLEX_FULL;
                                else
                                        current_duplex = DUPLEX_HALF;
-                       }
-                       else
+                       } else {
                                current_link_up = 0;
+                       }
                }
        }
 
@@ -4211,6 +4231,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
                tp->serdes_counter--;
                return;
        }
+
        if (!netif_carrier_ok(tp->dev) &&
            (tp->link_config.autoneg == AUTONEG_ENABLE)) {
                u32 bmcr;
@@ -4240,10 +4261,9 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
                                tp->tg3_flags2 |= TG3_FLG2_PARALLEL_DETECT;
                        }
                }
-       }
-       else if (netif_carrier_ok(tp->dev) &&
-                (tp->link_config.autoneg == AUTONEG_ENABLE) &&
-                (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
+       } else if (netif_carrier_ok(tp->dev) &&
+                  (tp->link_config.autoneg == AUTONEG_ENABLE) &&
+                  (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) {
                u32 phy2;
 
                /* Select expansion interrupt status register */
@@ -4266,13 +4286,12 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
 {
        int err;
 
-       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
                err = tg3_setup_fiber_phy(tp, force_reset);
-       } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
+       else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
                err = tg3_setup_fiber_mii_phy(tp, force_reset);
-       } else {
+       else
                err = tg3_setup_copper_phy(tp, force_reset);
-       }
 
        if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
                u32 val, scale;
@@ -4335,8 +4354,11 @@ static void tg3_tx_recover(struct tg3 *tp)
        BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) ||
               tp->write32_tx_mbox == tg3_write_indirect_mbox);
 
-       netdev_warn(tp->dev, "The system may be re-ordering memory-mapped I/O cycles to the network device, attempting to recover\n"
-                   "Please report the problem to the driver maintainer and include system chipset information.\n");
+       netdev_warn(tp->dev,
+                   "The system may be re-ordering memory-mapped I/O "
+                   "cycles to the network device, attempting to recover. "
+                   "Please report the problem to the driver maintainer "
+                   "and include system chipset information.\n");
 
        spin_lock(&tp->lock);
        tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING;
@@ -4378,7 +4400,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
                }
 
                pci_unmap_single(tp->pdev,
-                                pci_unmap_addr(ri, mapping),
+                                dma_unmap_addr(ri, mapping),
                                 skb_headlen(skb),
                                 PCI_DMA_TODEVICE);
 
@@ -4392,7 +4414,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
                                tx_bug = 1;
 
                        pci_unmap_page(tp->pdev,
-                                      pci_unmap_addr(ri, mapping),
+                                      dma_unmap_addr(ri, mapping),
                                       skb_shinfo(skb)->frags[i].size,
                                       PCI_DMA_TODEVICE);
                        sw_idx = NEXT_TX(sw_idx);
@@ -4430,7 +4452,7 @@ static void tg3_rx_skb_free(struct tg3 *tp, struct ring_info *ri, u32 map_sz)
        if (!ri->skb)
                return;
 
-       pci_unmap_single(tp->pdev, pci_unmap_addr(ri, mapping),
+       pci_unmap_single(tp->pdev, dma_unmap_addr(ri, mapping),
                         map_sz, PCI_DMA_FROMDEVICE);
        dev_kfree_skb_any(ri->skb);
        ri->skb = NULL;
@@ -4496,7 +4518,7 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, struct tg3_rx_prodring_set *tpr,
        }
 
        map->skb = skb;
-       pci_unmap_addr_set(map, mapping, mapping);
+       dma_unmap_addr_set(map, mapping, mapping);
 
        desc->addr_hi = ((u64)mapping >> 32);
        desc->addr_lo = ((u64)mapping & 0xffffffff);
@@ -4516,8 +4538,8 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
        struct tg3 *tp = tnapi->tp;
        struct tg3_rx_buffer_desc *src_desc, *dest_desc;
        struct ring_info *src_map, *dest_map;
-       int dest_idx;
        struct tg3_rx_prodring_set *spr = &tp->prodring[0];
+       int dest_idx;
 
        switch (opaque_key) {
        case RXD_OPAQUE_RING_STD:
@@ -4541,8 +4563,8 @@ static void tg3_recycle_rx(struct tg3_napi *tnapi,
        }
 
        dest_map->skb = src_map->skb;
-       pci_unmap_addr_set(dest_map, mapping,
-                          pci_unmap_addr(src_map, mapping));
+       dma_unmap_addr_set(dest_map, mapping,
+                          dma_unmap_addr(src_map, mapping));
        dest_desc->addr_hi = src_desc->addr_hi;
        dest_desc->addr_lo = src_desc->addr_lo;
 
@@ -4605,18 +4627,20 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                struct sk_buff *skb;
                dma_addr_t dma_addr;
                u32 opaque_key, desc_idx, *post_ptr;
+               bool hw_vlan __maybe_unused = false;
+               u16 vtag __maybe_unused = 0;
 
                desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
                opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
                if (opaque_key == RXD_OPAQUE_RING_STD) {
                        ri = &tp->prodring[0].rx_std_buffers[desc_idx];
-                       dma_addr = pci_unmap_addr(ri, mapping);
+                       dma_addr = dma_unmap_addr(ri, mapping);
                        skb = ri->skb;
                        post_ptr = &std_prod_idx;
                        rx_std_posted++;
                } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
                        ri = &tp->prodring[0].rx_jmb_buffers[desc_idx];
-                       dma_addr = pci_unmap_addr(ri, mapping);
+                       dma_addr = dma_unmap_addr(ri, mapping);
                        skb = ri->skb;
                        post_ptr = &jmb_prod_idx;
                } else
@@ -4638,12 +4662,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) -
                      ETH_FCS_LEN;
 
-               if (len > RX_COPY_THRESHOLD &&
-                   tp->rx_offset == NET_IP_ALIGN) {
-                   /* rx_offset will likely not equal NET_IP_ALIGN
-                    * if this is a 5701 card running in PCI-X mode
-                    * [see tg3_get_invariants()]
-                    */
+               if (len > TG3_RX_COPY_THRESH(tp)) {
                        int skb_size;
 
                        skb_size = tg3_alloc_rx_skb(tp, tpr, opaque_key,
@@ -4668,12 +4687,12 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
 
-                       copy_skb = netdev_alloc_skb(tp->dev,
-                                                   len + TG3_RAW_IP_ALIGN);
+                       copy_skb = netdev_alloc_skb(tp->dev, len + VLAN_HLEN +
+                                                   TG3_RAW_IP_ALIGN);
                        if (copy_skb == NULL)
                                goto drop_it_no_recycle;
 
-                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN);
+                       skb_reserve(copy_skb, TG3_RAW_IP_ALIGN + VLAN_HLEN);
                        skb_put(copy_skb, len);
                        pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
                        skb_copy_from_linear_data(skb, copy_skb->data, len);
@@ -4699,12 +4718,29 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
                        goto next_pkt;
                }
 
+               if (desc->type_flags & RXD_FLAG_VLAN &&
+                   !(tp->rx_mode & RX_MODE_KEEP_VLAN_TAG)) {
+                       vtag = desc->err_vlan & RXD_VLAN_MASK;
 #if TG3_VLAN_TAG_USED
-               if (tp->vlgrp != NULL &&
-                   desc->type_flags & RXD_FLAG_VLAN) {
-                       vlan_gro_receive(&tnapi->napi, tp->vlgrp,
-                                        desc->err_vlan & RXD_VLAN_MASK, skb);
-               } else
+                       if (tp->vlgrp)
+                               hw_vlan = true;
+                       else
+#endif
+                       {
+                               struct vlan_ethhdr *ve = (struct vlan_ethhdr *)
+                                                   __skb_push(skb, VLAN_HLEN);
+
+                               memmove(ve, skb->data + VLAN_HLEN,
+                                       ETH_ALEN * 2);
+                               ve->h_vlan_proto = htons(ETH_P_8021Q);
+                               ve->h_vlan_TCI = htons(vtag);
+                       }
+               }
+
+#if TG3_VLAN_TAG_USED
+               if (hw_vlan)
+                       vlan_gro_receive(&tnapi->napi, tp->vlgrp, vtag, skb);
+               else
 #endif
                        napi_gro_receive(&tnapi->napi, skb);
 
@@ -4978,7 +5014,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
                if (unlikely(work_done >= budget))
                        break;
 
-               /* tp->last_tag is used in tg3_restart_ints() below
+               /* tp->last_tag is used in tg3_int_reenable() below
                 * to tell the hw how much work has been processed,
                 * so we must read it before checking for more work.
                 */
@@ -4987,8 +5023,8 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
                rmb();
 
                /* check for RX/TX work to do */
-               if (sblk->idx[0].tx_consumer == tnapi->tx_cons &&
-                   *(tnapi->rx_rcb_prod_idx) == tnapi->rx_rcb_ptr) {
+               if (likely(sblk->idx[0].tx_consumer == tnapi->tx_cons &&
+                          *(tnapi->rx_rcb_prod_idx) == tnapi->rx_rcb_ptr)) {
                        napi_complete(napi);
                        /* Reenable interrupts. */
                        tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24);
@@ -5260,7 +5296,8 @@ static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
 
        err = tg3_init_hw(tp, reset_phy);
        if (err) {
-               netdev_err(tp->dev, "Failed to re-initialize device, aborting\n");
+               netdev_err(tp->dev,
+                          "Failed to re-initialize device, aborting\n");
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                tg3_full_unlock(tp);
                del_timer_sync(&tp->timer);
@@ -5437,12 +5474,12 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                        len = skb_shinfo(skb)->frags[i-1].size;
 
                pci_unmap_single(tp->pdev,
-                                pci_unmap_addr(&tnapi->tx_buffers[entry],
+                                dma_unmap_addr(&tnapi->tx_buffers[entry],
                                                mapping),
                                 len, PCI_DMA_TODEVICE);
                if (i == 0) {
                        tnapi->tx_buffers[entry].skb = new_skb;
-                       pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
+                       dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
                                           new_addr);
                } else {
                        tnapi->tx_buffers[entry].skb = NULL;
@@ -5492,7 +5529,6 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
        struct netdev_queue *txq;
        unsigned int i, last;
 
-
        txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
        tnapi = &tp->napi[skb_get_queue_mapping(skb)];
        if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
@@ -5508,7 +5544,8 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
                        netif_tx_stop_queue(txq);
 
                        /* This is a hard error, log it. */
-                       netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
+                       netdev_err(dev,
+                                  "BUG! Tx Ring full when queue awake!\n");
                }
                return NETDEV_TX_BUSY;
        }
@@ -5552,9 +5589,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
 
                tcp_hdr(skb)->check = 0;
 
-       }
-       else if (skb->ip_summed == CHECKSUM_PARTIAL)
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                base_flags |= TXD_FLAG_TCPUDP_CSUM;
+       }
+
 #if TG3_VLAN_TAG_USED
        if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
@@ -5571,7 +5609,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
        }
 
        tnapi->tx_buffers[entry].skb = skb;
-       pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
+       dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
 
        if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
            !mss && skb->len > ETH_DATA_LEN)
@@ -5597,7 +5635,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
                                goto dma_error;
 
                        tnapi->tx_buffers[entry].skb = NULL;
-                       pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
+                       dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
                                           mapping);
 
                        tg3_set_txd(tnapi, entry, mapping, len,
@@ -5627,7 +5665,7 @@ dma_error:
        entry = tnapi->tx_prod;
        tnapi->tx_buffers[entry].skb = NULL;
        pci_unmap_single(tp->pdev,
-                        pci_unmap_addr(&tnapi->tx_buffers[entry], mapping),
+                        dma_unmap_addr(&tnapi->tx_buffers[entry], mapping),
                         skb_headlen(skb),
                         PCI_DMA_TODEVICE);
        for (i = 0; i <= last; i++) {
@@ -5635,7 +5673,7 @@ dma_error:
                entry = NEXT_TX(entry);
 
                pci_unmap_page(tp->pdev,
-                              pci_unmap_addr(&tnapi->tx_buffers[entry],
+                              dma_unmap_addr(&tnapi->tx_buffers[entry],
                                              mapping),
                               frag->size, PCI_DMA_TODEVICE);
        }
@@ -5695,7 +5733,6 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
        struct netdev_queue *txq;
        unsigned int i, last;
 
-
        txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
        tnapi = &tp->napi[skb_get_queue_mapping(skb)];
        if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
@@ -5711,7 +5748,8 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
                        netif_tx_stop_queue(txq);
 
                        /* This is a hard error, log it. */
-                       netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
+                       netdev_err(dev,
+                                  "BUG! Tx Ring full when queue awake!\n");
                }
                return NETDEV_TX_BUSY;
        }
@@ -5737,7 +5775,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
                hdr_len = ip_tcp_len + tcp_opt_len;
                if (unlikely((ETH_HLEN + hdr_len) > 80) &&
                             (tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
-                       return (tg3_tso_bug(tp, skb));
+                       return tg3_tso_bug(tp, skb);
 
                base_flags |= (TXD_FLAG_CPU_PRE_DMA |
                               TXD_FLAG_CPU_POST_DMA);
@@ -5797,7 +5835,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
        }
 
        tnapi->tx_buffers[entry].skb = skb;
-       pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
+       dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
 
        would_hit_hwbug = 0;
 
@@ -5833,7 +5871,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
                                               len, PCI_DMA_TODEVICE);
 
                        tnapi->tx_buffers[entry].skb = NULL;
-                       pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
+                       dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
                                           mapping);
                        if (pci_dma_mapping_error(tp->pdev, mapping))
                                goto dma_error;
@@ -5898,7 +5936,7 @@ dma_error:
        entry = tnapi->tx_prod;
        tnapi->tx_buffers[entry].skb = NULL;
        pci_unmap_single(tp->pdev,
-                        pci_unmap_addr(&tnapi->tx_buffers[entry], mapping),
+                        dma_unmap_addr(&tnapi->tx_buffers[entry], mapping),
                         skb_headlen(skb),
                         PCI_DMA_TODEVICE);
        for (i = 0; i <= last; i++) {
@@ -5906,7 +5944,7 @@ dma_error:
                entry = NEXT_TX(entry);
 
                pci_unmap_page(tp->pdev,
-                              pci_unmap_addr(&tnapi->tx_buffers[entry],
+                              dma_unmap_addr(&tnapi->tx_buffers[entry],
                                              mapping),
                               frag->size, PCI_DMA_TODEVICE);
        }
@@ -5924,9 +5962,9 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
                if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
                        tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
                        ethtool_op_set_tso(dev, 0);
-               }
-               else
+               } else {
                        tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
+               }
        } else {
                if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
                        tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
@@ -6007,7 +6045,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
        }
 }
 
-/* Initialize tx/rx rings for packet processing.
+/* Initialize rx rings for packet processing.
  *
  * The chip has been shut down and the driver detached from
  * the networking, so no interrupts or new tx packets will
@@ -6058,8 +6096,10 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
        /* Now allocate fresh SKBs for each rx ring. */
        for (i = 0; i < tp->rx_pending; i++) {
                if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_STD, i) < 0) {
-                       netdev_warn(tp->dev, "Using a smaller RX standard ring, only %d out of %d buffers were allocated successfully\n",
-                                   i, tp->rx_pending);
+                       netdev_warn(tp->dev,
+                                   "Using a smaller RX standard ring. Only "
+                                   "%d out of %d buffers were allocated "
+                                   "successfully\n", i, tp->rx_pending);
                        if (i == 0)
                                goto initfail;
                        tp->rx_pending = i;
@@ -6088,8 +6128,10 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
 
        for (i = 0; i < tp->rx_jumbo_pending; i++) {
                if (tg3_alloc_rx_skb(tp, tpr, RXD_OPAQUE_RING_JUMBO, i) < 0) {
-                       netdev_warn(tp->dev, "Using a smaller RX jumbo ring, only %d out of %d buffers were allocated successfully\n",
-                                   i, tp->rx_jumbo_pending);
+                       netdev_warn(tp->dev,
+                                   "Using a smaller RX jumbo ring. Only %d "
+                                   "out of %d buffers were allocated "
+                                   "successfully\n", i, tp->rx_jumbo_pending);
                        if (i == 0)
                                goto initfail;
                        tp->rx_jumbo_pending = i;
@@ -6187,7 +6229,7 @@ static void tg3_free_rings(struct tg3 *tp)
                        }
 
                        pci_unmap_single(tp->pdev,
-                                        pci_unmap_addr(txp, mapping),
+                                        dma_unmap_addr(txp, mapping),
                                         skb_headlen(skb),
                                         PCI_DMA_TODEVICE);
                        txp->skb = NULL;
@@ -6197,7 +6239,7 @@ static void tg3_free_rings(struct tg3 *tp)
                        for (k = 0; k < skb_shinfo(skb)->nr_frags; k++) {
                                txp = &tnapi->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
                                pci_unmap_page(tp->pdev,
-                                              pci_unmap_addr(txp, mapping),
+                                              dma_unmap_addr(txp, mapping),
                                               skb_shinfo(skb)->frags[k].size,
                                               PCI_DMA_TODEVICE);
                                i++;
@@ -6433,8 +6475,9 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
        }
 
        if (i == MAX_WAIT_CNT && !silent) {
-               pr_err("tg3_stop_block timed out, ofs=%lx enable_bit=%x\n",
-                      ofs, enable_bit);
+               dev_err(&tp->pdev->dev,
+                       "tg3_stop_block timed out, ofs=%lx enable_bit=%x\n",
+                       ofs, enable_bit);
                return -ENODEV;
        }
 
@@ -6480,8 +6523,9 @@ static int tg3_abort_hw(struct tg3 *tp, int silent)
                        break;
        }
        if (i >= MAX_WAIT_CNT) {
-               netdev_err(tp->dev, "%s timed out, TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n",
-                          __func__, tr32(MAC_TX_MODE));
+               dev_err(&tp->pdev->dev,
+                       "%s timed out, TX_MODE_ENABLE will not clear "
+                       "MAC_TX_MODE=%08x\n", __func__, tr32(MAC_TX_MODE));
                err |= -ENODEV;
        }
 
@@ -6551,35 +6595,35 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
                return;
 
        switch (kind) {
-               case RESET_KIND_INIT:
-                       tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
-                                       APE_HOST_SEG_SIG_MAGIC);
-                       tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
-                                       APE_HOST_SEG_LEN_MAGIC);
-                       apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
-                       tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
-                       tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
-                                       APE_HOST_DRIVER_ID_MAGIC);
-                       tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
-                                       APE_HOST_BEHAV_NO_PHYLOCK);
-
-                       event = APE_EVENT_STATUS_STATE_START;
-                       break;
-               case RESET_KIND_SHUTDOWN:
-                       /* With the interface we are currently using,
-                        * APE does not track driver state.  Wiping
-                        * out the HOST SEGMENT SIGNATURE forces
-                        * the APE to assume OS absent status.
-                        */
-                       tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
+       case RESET_KIND_INIT:
+               tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
+                               APE_HOST_SEG_SIG_MAGIC);
+               tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
+                               APE_HOST_SEG_LEN_MAGIC);
+               apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
+               tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
+               tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
+                               APE_HOST_DRIVER_ID_MAGIC);
+               tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
+                               APE_HOST_BEHAV_NO_PHYLOCK);
+
+               event = APE_EVENT_STATUS_STATE_START;
+               break;
+       case RESET_KIND_SHUTDOWN:
+               /* With the interface we are currently using,
+                * APE does not track driver state.  Wiping
+                * out the HOST SEGMENT SIGNATURE forces
+                * the APE to assume OS absent status.
+                */
+               tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
 
-                       event = APE_EVENT_STATUS_STATE_UNLOAD;
-                       break;
-               case RESET_KIND_SUSPEND:
-                       event = APE_EVENT_STATUS_STATE_SUSPEND;
-                       break;
-               default:
-                       return;
+               event = APE_EVENT_STATUS_STATE_UNLOAD;
+               break;
+       case RESET_KIND_SUSPEND:
+               event = APE_EVENT_STATUS_STATE_SUSPEND;
+               break;
+       default:
+               return;
        }
 
        event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
@@ -7156,7 +7200,8 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
 
        if (cpu_base == TX_CPU_BASE &&
            (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
-               netdev_err(tp->dev, "%s: Trying to load TX cpu firmware which is 5705\n",
+               netdev_err(tp->dev,
+                          "%s: Trying to load TX cpu firmware which is 5705\n",
                           __func__);
                return -EINVAL;
        }
@@ -7236,7 +7281,8 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
                udelay(1000);
        }
        if (i >= 5) {
-               netdev_err(tp->dev, "tg3_load_firmware fails to set RX CPU PC, is %08x should be %08x\n",
+               netdev_err(tp->dev, "%s fails to set RX CPU PC, is %08x "
+                          "should be %08x\n", __func__,
                           tr32(RX_CPU_BASE + CPU_PC), info.fw_base);
                return -ENODEV;
        }
@@ -7300,7 +7346,8 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
                udelay(1000);
        }
        if (i >= 5) {
-               netdev_err(tp->dev, "%s fails to set CPU PC, is %08x should be %08x\n",
+               netdev_err(tp->dev,
+                          "%s fails to set CPU PC, is %08x should be %08x\n",
                           __func__, tr32(cpu_base + CPU_PC), info.fw_base);
                return -ENODEV;
        }
@@ -7568,9 +7615,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
 
        tg3_write_sig_pre_reset(tp, RESET_KIND_INIT);
 
-       if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
+       if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
                tg3_abort_hw(tp, 1);
-       }
 
        if (reset_phy)
                tg3_phy_reset(tp);
@@ -7631,6 +7677,25 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(GRC_MODE, grc_mode);
        }
 
+       if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0) {
+               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_PHYCTL5);
+               tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_PL_LO_PHYCTL5,
+                    val | TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ);
+
+               tw32(GRC_MODE, grc_mode);
+
+               val = tr32(TG3_CPMU_LSPD_10MB_CLK);
+               val &= ~CPMU_LSPD_10MB_MACCLK_MASK;
+               val |= CPMU_LSPD_10MB_MACCLK_6_25;
+               tw32(TG3_CPMU_LSPD_10MB_CLK, val);
+       }
+
        /* 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
@@ -7679,6 +7744,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
                val = tr32(TG3PCI_DMA_RW_CTRL) &
                      ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
+               if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
+                       val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK;
                tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl);
        } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
                   GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
@@ -7723,8 +7790,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                        tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
                tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
                tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
-       }
-       else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+       } else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
                int fw_len;
 
                fw_len = tp->fw_len;
@@ -7839,9 +7905,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
                    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
                        val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) |
-                             (RX_STD_MAX_SIZE << 2);
+                             (TG3_RX_STD_DMA_SZ << 2);
                else
-                       val = RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT;
+                       val = TG3_RX_STD_DMA_SZ << BDINFO_FLAGS_MAXLEN_SHIFT;
        } else
                val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT;
 
@@ -8476,8 +8542,8 @@ static void tg3_timer(unsigned long __opaque)
                        tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
                                      FWCMD_NICDRV_ALIVE3);
                        tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
-                       /* 5 seconds timeout */
-                       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
+                       tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX,
+                                     TG3_FW_UPDATE_TIMEOUT_SEC);
 
                        tg3_generate_fw_event(tp);
                }
@@ -8625,8 +8691,9 @@ static int tg3_test_msi(struct tg3 *tp)
                return err;
 
        /* MSI test failed, go back to INTx mode */
-       netdev_warn(tp->dev, "No interrupt was generated using MSI, switching to INTx mode\n"
-                   "Please report this failure to the PCI maintainer and include system chipset information\n");
+       netdev_warn(tp->dev, "No interrupt was generated using MSI. Switching "
+                   "to INTx mode. Please report this failure to the PCI "
+                   "maintainer and include system chipset information\n");
 
        free_irq(tp->napi[0].irq_vec, &tp->napi[0]);
 
@@ -8739,7 +8806,8 @@ static void tg3_ints_init(struct tg3 *tp)
                /* All MSI supporting chips should support tagged
                 * status.  Assert that this is the case.
                 */
-               netdev_warn(tp->dev, "MSI without TAGGED? Not using MSI\n");
+               netdev_warn(tp->dev,
+                           "MSI without TAGGED_STATUS? Not using MSI\n");
                goto defcfg;
        }
 
@@ -8914,236 +8982,6 @@ err_out1:
        return err;
 }
 
-#if 0
-/*static*/ void tg3_dump_state(struct tg3 *tp)
-{
-       u32 val32, val32_2, val32_3, val32_4, val32_5;
-       u16 val16;
-       int i;
-       struct tg3_hw_status *sblk = tp->napi[0]->hw_status;
-
-       pci_read_config_word(tp->pdev, PCI_STATUS, &val16);
-       pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &val32);
-       printk("DEBUG: PCI status [%04x] TG3PCI state[%08x]\n",
-              val16, val32);
-
-       /* MAC block */
-       printk("DEBUG: MAC_MODE[%08x] MAC_STATUS[%08x]\n",
-              tr32(MAC_MODE), tr32(MAC_STATUS));
-       printk("       MAC_EVENT[%08x] MAC_LED_CTRL[%08x]\n",
-              tr32(MAC_EVENT), tr32(MAC_LED_CTRL));
-       printk("DEBUG: MAC_TX_MODE[%08x] MAC_TX_STATUS[%08x]\n",
-              tr32(MAC_TX_MODE), tr32(MAC_TX_STATUS));
-       printk("       MAC_RX_MODE[%08x] MAC_RX_STATUS[%08x]\n",
-              tr32(MAC_RX_MODE), tr32(MAC_RX_STATUS));
-
-       /* Send data initiator control block */
-       printk("DEBUG: SNDDATAI_MODE[%08x] SNDDATAI_STATUS[%08x]\n",
-              tr32(SNDDATAI_MODE), tr32(SNDDATAI_STATUS));
-       printk("       SNDDATAI_STATSCTRL[%08x]\n",
-              tr32(SNDDATAI_STATSCTRL));
-
-       /* Send data completion control block */
-       printk("DEBUG: SNDDATAC_MODE[%08x]\n", tr32(SNDDATAC_MODE));
-
-       /* Send BD ring selector block */
-       printk("DEBUG: SNDBDS_MODE[%08x] SNDBDS_STATUS[%08x]\n",
-              tr32(SNDBDS_MODE), tr32(SNDBDS_STATUS));
-
-       /* Send BD initiator control block */
-       printk("DEBUG: SNDBDI_MODE[%08x] SNDBDI_STATUS[%08x]\n",
-              tr32(SNDBDI_MODE), tr32(SNDBDI_STATUS));
-
-       /* Send BD completion control block */
-       printk("DEBUG: SNDBDC_MODE[%08x]\n", tr32(SNDBDC_MODE));
-
-       /* Receive list placement control block */
-       printk("DEBUG: RCVLPC_MODE[%08x] RCVLPC_STATUS[%08x]\n",
-              tr32(RCVLPC_MODE), tr32(RCVLPC_STATUS));
-       printk("       RCVLPC_STATSCTRL[%08x]\n",
-              tr32(RCVLPC_STATSCTRL));
-
-       /* Receive data and receive BD initiator control block */
-       printk("DEBUG: RCVDBDI_MODE[%08x] RCVDBDI_STATUS[%08x]\n",
-              tr32(RCVDBDI_MODE), tr32(RCVDBDI_STATUS));
-
-       /* Receive data completion control block */
-       printk("DEBUG: RCVDCC_MODE[%08x]\n",
-              tr32(RCVDCC_MODE));
-
-       /* Receive BD initiator control block */
-       printk("DEBUG: RCVBDI_MODE[%08x] RCVBDI_STATUS[%08x]\n",
-              tr32(RCVBDI_MODE), tr32(RCVBDI_STATUS));
-
-       /* Receive BD completion control block */
-       printk("DEBUG: RCVCC_MODE[%08x] RCVCC_STATUS[%08x]\n",
-              tr32(RCVCC_MODE), tr32(RCVCC_STATUS));
-
-       /* Receive list selector control block */
-       printk("DEBUG: RCVLSC_MODE[%08x] RCVLSC_STATUS[%08x]\n",
-              tr32(RCVLSC_MODE), tr32(RCVLSC_STATUS));
-
-       /* Mbuf cluster free block */
-       printk("DEBUG: MBFREE_MODE[%08x] MBFREE_STATUS[%08x]\n",
-              tr32(MBFREE_MODE), tr32(MBFREE_STATUS));
-
-       /* Host coalescing control block */
-       printk("DEBUG: HOSTCC_MODE[%08x] HOSTCC_STATUS[%08x]\n",
-              tr32(HOSTCC_MODE), tr32(HOSTCC_STATUS));
-       printk("DEBUG: HOSTCC_STATS_BLK_HOST_ADDR[%08x%08x]\n",
-              tr32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH),
-              tr32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW));
-       printk("DEBUG: HOSTCC_STATUS_BLK_HOST_ADDR[%08x%08x]\n",
-              tr32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH),
-              tr32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW));
-       printk("DEBUG: HOSTCC_STATS_BLK_NIC_ADDR[%08x]\n",
-              tr32(HOSTCC_STATS_BLK_NIC_ADDR));
-       printk("DEBUG: HOSTCC_STATUS_BLK_NIC_ADDR[%08x]\n",
-              tr32(HOSTCC_STATUS_BLK_NIC_ADDR));
-
-       /* Memory arbiter control block */
-       printk("DEBUG: MEMARB_MODE[%08x] MEMARB_STATUS[%08x]\n",
-              tr32(MEMARB_MODE), tr32(MEMARB_STATUS));
-
-       /* Buffer manager control block */
-       printk("DEBUG: BUFMGR_MODE[%08x] BUFMGR_STATUS[%08x]\n",
-              tr32(BUFMGR_MODE), tr32(BUFMGR_STATUS));
-       printk("DEBUG: BUFMGR_MB_POOL_ADDR[%08x] BUFMGR_MB_POOL_SIZE[%08x]\n",
-              tr32(BUFMGR_MB_POOL_ADDR), tr32(BUFMGR_MB_POOL_SIZE));
-       printk("DEBUG: BUFMGR_DMA_DESC_POOL_ADDR[%08x] "
-              "BUFMGR_DMA_DESC_POOL_SIZE[%08x]\n",
-              tr32(BUFMGR_DMA_DESC_POOL_ADDR),
-              tr32(BUFMGR_DMA_DESC_POOL_SIZE));
-
-       /* Read DMA control block */
-       printk("DEBUG: RDMAC_MODE[%08x] RDMAC_STATUS[%08x]\n",
-              tr32(RDMAC_MODE), tr32(RDMAC_STATUS));
-
-       /* Write DMA control block */
-       printk("DEBUG: WDMAC_MODE[%08x] WDMAC_STATUS[%08x]\n",
-              tr32(WDMAC_MODE), tr32(WDMAC_STATUS));
-
-       /* DMA completion block */
-       printk("DEBUG: DMAC_MODE[%08x]\n",
-              tr32(DMAC_MODE));
-
-       /* GRC block */
-       printk("DEBUG: GRC_MODE[%08x] GRC_MISC_CFG[%08x]\n",
-              tr32(GRC_MODE), tr32(GRC_MISC_CFG));
-       printk("DEBUG: GRC_LOCAL_CTRL[%08x]\n",
-              tr32(GRC_LOCAL_CTRL));
-
-       /* TG3_BDINFOs */
-       printk("DEBUG: RCVDBDI_JUMBO_BD[%08x%08x:%08x:%08x]\n",
-              tr32(RCVDBDI_JUMBO_BD + 0x0),
-              tr32(RCVDBDI_JUMBO_BD + 0x4),
-              tr32(RCVDBDI_JUMBO_BD + 0x8),
-              tr32(RCVDBDI_JUMBO_BD + 0xc));
-       printk("DEBUG: RCVDBDI_STD_BD[%08x%08x:%08x:%08x]\n",
-              tr32(RCVDBDI_STD_BD + 0x0),
-              tr32(RCVDBDI_STD_BD + 0x4),
-              tr32(RCVDBDI_STD_BD + 0x8),
-              tr32(RCVDBDI_STD_BD + 0xc));
-       printk("DEBUG: RCVDBDI_MINI_BD[%08x%08x:%08x:%08x]\n",
-              tr32(RCVDBDI_MINI_BD + 0x0),
-              tr32(RCVDBDI_MINI_BD + 0x4),
-              tr32(RCVDBDI_MINI_BD + 0x8),
-              tr32(RCVDBDI_MINI_BD + 0xc));
-
-       tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x0, &val32);
-       tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x4, &val32_2);
-       tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x8, &val32_3);
-       tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0xc, &val32_4);
-       printk("DEBUG: SRAM_SEND_RCB_0[%08x%08x:%08x:%08x]\n",
-              val32, val32_2, val32_3, val32_4);
-
-       tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x0, &val32);
-       tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x4, &val32_2);
-       tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x8, &val32_3);
-       tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0xc, &val32_4);
-       printk("DEBUG: SRAM_RCV_RET_RCB_0[%08x%08x:%08x:%08x]\n",
-              val32, val32_2, val32_3, val32_4);
-
-       tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x0, &val32);
-       tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x4, &val32_2);
-       tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x8, &val32_3);
-       tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0xc, &val32_4);
-       tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x10, &val32_5);
-       printk("DEBUG: SRAM_STATUS_BLK[%08x:%08x:%08x:%08x:%08x]\n",
-              val32, val32_2, val32_3, val32_4, val32_5);
-
-       /* SW status block */
-       printk(KERN_DEBUG
-        "Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n",
-              sblk->status,
-              sblk->status_tag,
-              sblk->rx_jumbo_consumer,
-              sblk->rx_consumer,
-              sblk->rx_mini_consumer,
-              sblk->idx[0].rx_producer,
-              sblk->idx[0].tx_consumer);
-
-       /* SW statistics block */
-       printk("DEBUG: Host statistics block [%08x:%08x:%08x:%08x]\n",
-              ((u32 *)tp->hw_stats)[0],
-              ((u32 *)tp->hw_stats)[1],
-              ((u32 *)tp->hw_stats)[2],
-              ((u32 *)tp->hw_stats)[3]);
-
-       /* Mailboxes */
-       printk("DEBUG: SNDHOST_PROD[%08x%08x] SNDNIC_PROD[%08x%08x]\n",
-              tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + 0x0),
-              tr32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + 0x4),
-              tr32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + 0x0),
-              tr32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + 0x4));
-
-       /* NIC side send descriptors. */
-       for (i = 0; i < 6; i++) {
-               unsigned long txd;
-
-               txd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_TX_BUFFER_DESC
-                       + (i * sizeof(struct tg3_tx_buffer_desc));
-               printk("DEBUG: NIC TXD(%d)[%08x:%08x:%08x:%08x]\n",
-                      i,
-                      readl(txd + 0x0), readl(txd + 0x4),
-                      readl(txd + 0x8), readl(txd + 0xc));
-       }
-
-       /* NIC side RX descriptors. */
-       for (i = 0; i < 6; i++) {
-               unsigned long rxd;
-
-               rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_BUFFER_DESC
-                       + (i * sizeof(struct tg3_rx_buffer_desc));
-               printk("DEBUG: NIC RXD_STD(%d)[0][%08x:%08x:%08x:%08x]\n",
-                      i,
-                      readl(rxd + 0x0), readl(rxd + 0x4),
-                      readl(rxd + 0x8), readl(rxd + 0xc));
-               rxd += (4 * sizeof(u32));
-               printk("DEBUG: NIC RXD_STD(%d)[1][%08x:%08x:%08x:%08x]\n",
-                      i,
-                      readl(rxd + 0x0), readl(rxd + 0x4),
-                      readl(rxd + 0x8), readl(rxd + 0xc));
-       }
-
-       for (i = 0; i < 6; i++) {
-               unsigned long rxd;
-
-               rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_JUMBO_BUFFER_DESC
-                       + (i * sizeof(struct tg3_rx_buffer_desc));
-               printk("DEBUG: NIC RXD_JUMBO(%d)[0][%08x:%08x:%08x:%08x]\n",
-                      i,
-                      readl(rxd + 0x0), readl(rxd + 0x4),
-                      readl(rxd + 0x8), readl(rxd + 0xc));
-               rxd += (4 * sizeof(u32));
-               printk("DEBUG: NIC RXD_JUMBO(%d)[1][%08x:%08x:%08x:%08x]\n",
-                      i,
-                      readl(rxd + 0x0), readl(rxd + 0x4),
-                      readl(rxd + 0x8), readl(rxd + 0xc));
-       }
-}
-#endif
-
 static struct net_device_stats *tg3_get_stats(struct net_device *);
 static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *);
 
@@ -9162,9 +9000,6 @@ static int tg3_close(struct net_device *dev)
        tg3_phy_stop(tp);
 
        tg3_full_lock(tp, 1);
-#if 0
-       tg3_dump_state(tp);
-#endif
 
        tg3_disable_ints(tp);
 
@@ -9406,9 +9241,8 @@ static inline u32 calc_crc(unsigned char *buf, int len)
 
                        reg >>= 1;
 
-                       if (tmp) {
+                       if (tmp)
                                reg ^= 0xedb88320;
-                       }
                }
        }
 
@@ -9452,20 +9286,20 @@ static void __tg3_set_rx_mode(struct net_device *dev)
                rx_mode |= RX_MODE_PROMISC;
        } else if (dev->flags & IFF_ALLMULTI) {
                /* Accept all multicast. */
-               tg3_set_multi (tp, 1);
+               tg3_set_multi(tp, 1);
        } else if (netdev_mc_empty(dev)) {
                /* Reject all multicast. */
-               tg3_set_multi (tp, 0);
+               tg3_set_multi(tp, 0);
        } else {
                /* Accept one or more multicast(s). */
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                u32 mc_filter[4] = { 0, };
                u32 regidx;
                u32 bit;
                u32 crc;
 
-               netdev_for_each_mc_addr(mclist, dev) {
-                       crc = calc_crc (mclist->dmi_addr, ETH_ALEN);
+               netdev_for_each_mc_addr(ha, dev) {
+                       crc = calc_crc(ha->addr, ETH_ALEN);
                        bit = ~crc & 0x7f;
                        regidx = (bit & 0x60) >> 5;
                        bit &= 0x1f;
@@ -9618,7 +9452,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                memcpy(data, ((char*)&val) + b_offset, b_count);
                len -= b_count;
                offset += b_count;
-               eeprom->len += b_count;
+               eeprom->len += b_count;
        }
 
        /* read bytes upto the last 4 byte boundary */
@@ -10166,8 +10000,8 @@ static int tg3_set_rx_csum(struct net_device *dev, u32 data)
        if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
                if (data != 0)
                        return -EINVAL;
-               return 0;
-       }
+               return 0;
+       }
 
        spin_lock_bh(&tp->lock);
        if (data)
@@ -10186,8 +10020,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
        if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
                if (data != 0)
                        return -EINVAL;
-               return 0;
-       }
+               return 0;
+       }
 
        if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
                ethtool_op_set_tx_ipv6_csum(dev, data);
@@ -10197,7 +10031,7 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
        return 0;
 }
 
-static int tg3_get_sset_count (struct net_device *dev, int sset)
+static int tg3_get_sset_count(struct net_device *dev, int sset)
 {
        switch (sset) {
        case ETH_SS_TEST:
@@ -10209,7 +10043,7 @@ static int tg3_get_sset_count (struct net_device *dev, int sset)
        }
 }
 
-static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
+static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 {
        switch (stringset) {
        case ETH_SS_STATS:
@@ -10256,7 +10090,7 @@ static int tg3_phys_id(struct net_device *dev, u32 data)
        return 0;
 }
 
-static void tg3_get_ethtool_stats (struct net_device *dev,
+static void tg3_get_ethtool_stats(struct net_device *dev,
                                   struct ethtool_stats *estats, u64 *tmp_stats)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -10362,8 +10196,7 @@ static int tg3_test_nvram(struct tg3 *tp)
                                for (l = 0, msk = 0x80; l < 7; l++, msk >>= 1)
                                        parity[k++] = buf8[i] & msk;
                                i++;
-                       }
-                       else if (i == 16) {
+                       } else if (i == 16) {
                                int l;
                                u8 msk;
 
@@ -10461,7 +10294,7 @@ static int tg3_test_registers(struct tg3 *tp)
                { MAC_ADDR_0_HIGH, 0x0000,
                        0x00000000, 0x0000ffff },
                { MAC_ADDR_0_LOW, 0x0000,
-                       0x00000000, 0xffffffff },
+                       0x00000000, 0xffffffff },
                { MAC_RX_MTU_SIZE, 0x0000,
                        0x00000000, 0x0000ffff },
                { MAC_TX_MODE, 0x0000,
@@ -10649,7 +10482,8 @@ static int tg3_test_registers(struct tg3 *tp)
 
 out:
        if (netif_msg_hw(tp))
-               pr_err("Register test failed at offset %x\n", offset);
+               netdev_err(tp->dev,
+                          "Register test failed at offset %x\n", offset);
        tw32(offset, save_val);
        return -EIO;
 }
@@ -10825,9 +10659,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
                                     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
                }
                tw32(MAC_MODE, mac_mode);
-       }
-       else
+       } else {
                return -EINVAL;
+       }
 
        err = -EIO;
 
@@ -10909,7 +10743,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
 
        rx_skb = tpr->rx_std_buffers[desc_idx].skb;
 
-       map = pci_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping);
+       map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping);
        pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE);
 
        for (i = 14; i < tx_len; i++) {
@@ -11083,7 +10917,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                return phy_mii_ioctl(phydev, data, cmd);
        }
 
-       switch(cmd) {
+       switch (cmd) {
        case SIOCGMIIPHY:
                data->phy_id = tp->phy_addr;
 
@@ -11776,7 +11610,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
                tp->tg3_flags |= TG3_FLAG_NVRAM;
 
                if (tg3_nvram_lock(tp)) {
-                       netdev_warn(tp->dev, "Cannot get nvram lock, %s failed\n",
+                       netdev_warn(tp->dev,
+                                   "Cannot get nvram lock, %s failed\n",
                                    __func__);
                        return;
                }
@@ -11895,7 +11730,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                if (ret)
                        break;
 
-               page_off = offset & pagemask;
+               page_off = offset & pagemask;
                size = pagesize;
                if (len < size)
                        size = len;
@@ -11923,7 +11758,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR |
                        NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE;
 
-               if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+               if (tg3_nvram_exec_cmd(tp, nvram_cmd))
                        break;
 
                /* Issue another write enable to start the write. */
@@ -11977,7 +11812,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
                memcpy(&data, buf + i, 4);
                tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
-               page_off = offset % tp->nvram_pagesize;
+               page_off = offset % tp->nvram_pagesize;
 
                phy_addr = tg3_nvram_phys_addr(tp, offset);
 
@@ -11985,7 +11820,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
 
                nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
 
-               if ((page_off == 0) || (i == 0))
+               if (page_off == 0 || i == 0)
                        nvram_cmd |= NVRAM_CMD_FIRST;
                if (page_off == (tp->nvram_pagesize - 4))
                        nvram_cmd |= NVRAM_CMD_LAST;
@@ -12028,8 +11863,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 
        if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) {
                ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
-       }
-       else {
+       } else {
                u32 grc_mode;
 
                ret = tg3_nvram_lock(tp);
@@ -12049,8 +11883,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 
                        ret = tg3_nvram_write_block_buffered(tp, offset, len,
                                buf);
-               }
-               else {
+               } else {
                        ret = tg3_nvram_write_block_unbuffered(tp, offset, len,
                                buf);
                }
@@ -12545,11 +12378,11 @@ skip_phy_reset:
        return err;
 }
 
-static void __devinit tg3_read_partno(struct tg3 *tp)
+static void __devinit tg3_read_vpd(struct tg3 *tp)
 {
-       unsigned char vpd_data[TG3_NVM_VPD_LEN];   /* in little-endian format */
+       u8 vpd_data[TG3_NVM_VPD_LEN];
        unsigned int block_end, rosize, len;
-       int i = 0;
+       int j, i = 0;
        u32 magic;
 
        if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
@@ -12598,6 +12431,32 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
        if (block_end > TG3_NVM_VPD_LEN)
                goto out_not_found;
 
+       j = pci_vpd_find_info_keyword(vpd_data, i, rosize,
+                                     PCI_VPD_RO_KEYWORD_MFR_ID);
+       if (j > 0) {
+               len = pci_vpd_info_field_size(&vpd_data[j]);
+
+               j += PCI_VPD_INFO_FLD_HDR_SIZE;
+               if (j + len > block_end || len != 4 ||
+                   memcmp(&vpd_data[j], "1028", 4))
+                       goto partno;
+
+               j = pci_vpd_find_info_keyword(vpd_data, i, rosize,
+                                             PCI_VPD_RO_KEYWORD_VENDOR0);
+               if (j < 0)
+                       goto partno;
+
+               len = pci_vpd_info_field_size(&vpd_data[j]);
+
+               j += PCI_VPD_INFO_FLD_HDR_SIZE;
+               if (j + len > block_end)
+                       goto partno;
+
+               memcpy(tp->fw_ver, &vpd_data[j], len);
+               strncat(tp->fw_ver, " bc ", TG3_NVM_VPD_LEN - len - 1);
+       }
+
+partno:
        i = pci_vpd_find_info_keyword(vpd_data, i, rosize,
                                      PCI_VPD_RO_KEYWORD_PARTNO);
        if (i < 0)
@@ -12667,7 +12526,7 @@ static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
 static void __devinit tg3_read_bc_ver(struct tg3 *tp)
 {
        u32 val, offset, start, ver_offset;
-       int i;
+       int i, dst_off;
        bool newver = false;
 
        if (tg3_nvram_read(tp, 0xc, &offset) ||
@@ -12687,8 +12546,11 @@ static void __devinit tg3_read_bc_ver(struct tg3 *tp)
                        newver = true;
        }
 
+       dst_off = strlen(tp->fw_ver);
+
        if (newver) {
-               if (tg3_nvram_read(tp, offset + 8, &ver_offset))
+               if (TG3_VER_SIZE - dst_off < 16 ||
+                   tg3_nvram_read(tp, offset + 8, &ver_offset))
                        return;
 
                offset = offset + ver_offset - start;
@@ -12697,7 +12559,7 @@ static void __devinit tg3_read_bc_ver(struct tg3 *tp)
                        if (tg3_nvram_read_be32(tp, offset + i, &v))
                                return;
 
-                       memcpy(tp->fw_ver + i, &v, sizeof(v));
+                       memcpy(tp->fw_ver + dst_off + i, &v, sizeof(v));
                }
        } else {
                u32 major, minor;
@@ -12708,7 +12570,8 @@ static void __devinit tg3_read_bc_ver(struct tg3 *tp)
                major = (ver_offset & TG3_NVM_BCVER_MAJMSK) >>
                        TG3_NVM_BCVER_MAJSFT;
                minor = ver_offset & TG3_NVM_BCVER_MINMSK;
-               snprintf(&tp->fw_ver[0], 32, "v%d.%02d", major, minor);
+               snprintf(&tp->fw_ver[dst_off], TG3_VER_SIZE - dst_off,
+                        "v%d.%02d", major, minor);
        }
 }
 
@@ -12732,9 +12595,7 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
 {
        u32 offset, major, minor, build;
 
-       tp->fw_ver[0] = 's';
-       tp->fw_ver[1] = 'b';
-       tp->fw_ver[2] = '\0';
+       strncat(tp->fw_ver, "sb", TG3_VER_SIZE - strlen(tp->fw_ver) - 1);
 
        if ((val & TG3_EEPROM_SB_FORMAT_MASK) != TG3_EEPROM_SB_FORMAT_1)
                return;
@@ -12771,11 +12632,14 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
        if (minor > 99 || build > 26)
                return;
 
-       snprintf(&tp->fw_ver[2], 30, " v%d.%02d", major, minor);
+       offset = strlen(tp->fw_ver);
+       snprintf(&tp->fw_ver[offset], TG3_VER_SIZE - offset,
+                " v%d.%02d", major, minor);
 
        if (build > 0) {
-               tp->fw_ver[8] = 'a' + build - 1;
-               tp->fw_ver[9] = '\0';
+               offset = strlen(tp->fw_ver);
+               if (offset < TG3_VER_SIZE - 1)
+                       tp->fw_ver[offset] = 'a' + build - 1;
        }
 }
 
@@ -12862,12 +12726,13 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp)
 static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 {
        u32 val;
+       bool vpd_vers = false;
 
-       if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) {
-               tp->fw_ver[0] = 's';
-               tp->fw_ver[1] = 'b';
-               tp->fw_ver[2] = '\0';
+       if (tp->fw_ver[0] != 0)
+               vpd_vers = true;
 
+       if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) {
+               strcat(tp->fw_ver, "sb");
                return;
        }
 
@@ -12884,11 +12749,12 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
                return;
 
        if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
-            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
-               return;
+            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) || vpd_vers)
+               goto done;
 
        tg3_read_mgmtfw_ver(tp);
 
+done:
        tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
 
@@ -12898,9 +12764,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 {
        static struct pci_device_id write_reorder_chipsets[] = {
                { PCI_DEVICE(PCI_VENDOR_ID_AMD,
-                            PCI_DEVICE_ID_AMD_FE_GATE_700C) },
+                            PCI_DEVICE_ID_AMD_FE_GATE_700C) },
                { PCI_DEVICE(PCI_VENDOR_ID_AMD,
-                            PCI_DEVICE_ID_AMD_8131_BRIDGE) },
+                            PCI_DEVICE_ID_AMD_8131_BRIDGE) },
                { PCI_DEVICE(PCI_VENDOR_ID_VIA,
                             PCI_DEVICE_ID_VIA_8385_0) },
                { },
@@ -13066,8 +12932,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tp->tg3_flags2 |= TG3_FLG2_5780_CLASS;
                tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
                tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
-       }
-       else {
+       } else {
                struct pci_dev *bridge = NULL;
 
                do {
@@ -13129,6 +12994,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tp->dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
                if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
                        tp->dev->features |= NETIF_F_IPV6_CSUM;
+               tp->dev->features |= NETIF_F_GRO;
        }
 
        /* Determine TSO capabilities */
@@ -13189,8 +13055,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG;
 
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
-            (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
-                (tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG))
+           (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+           (tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG))
                tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE;
 
        pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
@@ -13224,7 +13090,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                   (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
                tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
                if (!tp->pcix_cap) {
-                       pr_err("Cannot find PCI-X capability, aborting\n");
+                       dev_err(&tp->pdev->dev,
+                               "Cannot find PCI-X capability, aborting\n");
                        return -EIO;
                }
 
@@ -13421,7 +13288,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        /* Force the chip into D0. */
        err = tg3_set_power_state(tp, PCI_D0);
        if (err) {
-               pr_err("(%s) transition to D0 failed\n", pci_name(tp->pdev));
+               dev_err(&tp->pdev->dev, "Transition to D0 failed\n");
                return err;
        }
 
@@ -13595,13 +13462,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
 
        err = tg3_phy_probe(tp);
        if (err) {
-               pr_err("(%s) phy probe failed, err %d\n",
-                      pci_name(tp->pdev), err);
+               dev_err(&tp->pdev->dev, "phy probe failed, err %d\n", err);
                /* ... but do not return immediately ... */
                tg3_mdio_fini(tp);
        }
 
-       tg3_read_partno(tp);
+       tg3_read_vpd(tp);
        tg3_read_fw_ver(tp);
 
        if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
@@ -13639,10 +13505,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        else
                tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
 
-       tp->rx_offset = NET_IP_ALIGN;
+       tp->rx_offset = NET_IP_ALIGN + TG3_RX_HEADROOM;
+       tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
        if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
-           (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
-               tp->rx_offset = 0;
+           (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
+               tp->rx_offset -= NET_IP_ALIGN;
+#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
+               tp->rx_copy_thresh = ~(u16)0;
+#endif
+       }
 
        tp->rx_std_max_post = TG3_RX_RING_SIZE;
 
@@ -13965,11 +13836,10 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm
        }
        pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
 
-       if (to_device) {
+       if (to_device)
                tw32(FTQ_DMA_HIGH_READ_FIFO_ENQDEQ, sram_dma_descs);
-       } else {
+       else
                tw32(FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ, sram_dma_descs);
-       }
 
        ret = -ENODEV;
        for (i = 0; i < 40; i++) {
@@ -14105,8 +13975,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
                /* Send the buffer to the chip. */
                ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1);
                if (ret) {
-                       pr_err("tg3_test_dma() Write the buffer failed %d\n",
-                              ret);
+                       dev_err(&tp->pdev->dev,
+                               "%s: Buffer write failed. err = %d\n",
+                               __func__, ret);
                        break;
                }
 
@@ -14116,8 +13987,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
                        u32 val;
                        tg3_read_mem(tp, 0x2100 + (i*4), &val);
                        if (le32_to_cpu(val) != p[i]) {
-                               pr_err("  tg3_test_dma()  Card buffer corrupted on write! (%d != %d)\n",
-                                      val, i);
+                               dev_err(&tp->pdev->dev,
+                                       "%s: Buffer corrupted on device! "
+                                       "(%d != %d)\n", __func__, val, i);
                                /* ret = -ENODEV here? */
                        }
                        p[i] = 0;
@@ -14126,9 +13998,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
                /* Now read it back. */
                ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
                if (ret) {
-                       pr_err("tg3_test_dma() Read the buffer failed %d\n",
-                              ret);
-
+                       dev_err(&tp->pdev->dev, "%s: Buffer read failed. "
+                               "err = %d\n", __func__, ret);
                        break;
                }
 
@@ -14144,8 +14015,9 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
                                tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
                                break;
                        } else {
-                               pr_err("tg3_test_dma() buffer corrupted on read back! (%d != %d)\n",
-                                      p[i], i);
+                               dev_err(&tp->pdev->dev,
+                                       "%s: Buffer corrupted on read back! "
+                                       "(%d != %d)\n", __func__, p[i], i);
                                ret = -ENODEV;
                                goto out;
                        }
@@ -14172,10 +14044,10 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
                if (pci_dev_present(dma_wait_state_chipsets)) {
                        tp->dma_rwctrl &= ~DMA_RWCTRL_WRITE_BNDRY_MASK;
                        tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
-               }
-               else
+               } else {
                        /* Safe to use the calculated DMA boundary. */
                        tp->dma_rwctrl = saved_dma_rwctrl;
+               }
 
                tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
        }
@@ -14437,13 +14309,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               pr_err("Cannot enable PCI device, aborting\n");
+               dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
                return err;
        }
 
        err = pci_request_regions(pdev, DRV_MODULE_NAME);
        if (err) {
-               pr_err("Cannot obtain PCI resources, aborting\n");
+               dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
                goto err_out_disable_pdev;
        }
 
@@ -14452,14 +14324,15 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        /* Find power-management capability. */
        pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
        if (pm_cap == 0) {
-               pr_err("Cannot find PowerManagement capability, aborting\n");
+               dev_err(&pdev->dev,
+                       "Cannot find Power Management capability, aborting\n");
                err = -EIO;
                goto err_out_free_res;
        }
 
        dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS);
        if (!dev) {
-               pr_err("Etherdev alloc failed, aborting\n");
+               dev_err(&pdev->dev, "Etherdev alloc failed, aborting\n");
                err = -ENOMEM;
                goto err_out_free_res;
        }
@@ -14509,7 +14382,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        tp->regs = pci_ioremap_bar(pdev, BAR_0);
        if (!tp->regs) {
-               netdev_err(dev, "Cannot map device registers, aborting\n");
+               dev_err(&pdev->dev, "Cannot map device registers, aborting\n");
                err = -ENOMEM;
                goto err_out_free_dev;
        }
@@ -14525,7 +14398,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        err = tg3_get_invariants(tp);
        if (err) {
-               netdev_err(dev, "Problem fetching invariants of chip, aborting\n");
+               dev_err(&pdev->dev,
+                       "Problem fetching invariants of chip, aborting\n");
                goto err_out_iounmap;
        }
 
@@ -14560,7 +14434,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                        err = pci_set_consistent_dma_mask(pdev,
                                                          persist_dma_mask);
                        if (err < 0) {
-                               netdev_err(dev, "Unable to obtain 64 bit DMA for consistent allocations\n");
+                               dev_err(&pdev->dev, "Unable to obtain 64 bit "
+                                       "DMA for consistent allocations\n");
                                goto err_out_iounmap;
                        }
                }
@@ -14568,7 +14443,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        if (err || dma_mask == DMA_BIT_MASK(32)) {
                err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
-                       netdev_err(dev, "No usable DMA configuration, aborting\n");
+                       dev_err(&pdev->dev,
+                               "No usable DMA configuration, aborting\n");
                        goto err_out_iounmap;
                }
        }
@@ -14617,14 +14493,16 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        err = tg3_get_device_address(tp);
        if (err) {
-               netdev_err(dev, "Could not obtain valid ethernet address, aborting\n");
+               dev_err(&pdev->dev,
+                       "Could not obtain valid ethernet address, aborting\n");
                goto err_out_iounmap;
        }
 
        if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
                tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
                if (!tp->aperegs) {
-                       netdev_err(dev, "Cannot map APE registers, aborting\n");
+                       dev_err(&pdev->dev,
+                               "Cannot map APE registers, aborting\n");
                        err = -ENOMEM;
                        goto err_out_iounmap;
                }
@@ -14648,7 +14526,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        err = tg3_test_dma(tp);
        if (err) {
-               netdev_err(dev, "DMA engine test failed, aborting\n");
+               dev_err(&pdev->dev, "DMA engine test failed, aborting\n");
                goto err_out_apeunmap;
        }
 
@@ -14709,7 +14587,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        err = register_netdev(dev);
        if (err) {
-               netdev_err(dev, "Cannot register net device, aborting\n");
+               dev_err(&pdev->dev, "Cannot register net device, aborting\n");
                goto err_out_apeunmap;
        }
 
@@ -14722,11 +14600,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
        if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) {
                struct phy_device *phydev;
                phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR];
-               netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+               netdev_info(dev,
+                           "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
                            phydev->drv->name, dev_name(&phydev->dev));
        } else
-               netdev_info(dev, "attached PHY is %s (%s Ethernet) (WireSpeed[%d])\n",
-                           tg3_phy_string(tp),
+               netdev_info(dev, "attached PHY is %s (%s Ethernet) "
+                           "(WireSpeed[%d])\n", tg3_phy_string(tp),
                            ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" :
                             ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" :
                              "10/100/1000Base-T")),
index 574a1cc4d3535fd878d100acf0aeb83d36a8531d..ce9c4918c3181cbaf2de835b3e42411d65d71f18 100644 (file)
 #define TG3_BDINFO_NIC_ADDR            0xcUL /* 32-bit */
 #define TG3_BDINFO_SIZE                        0x10UL
 
-#define RX_COPY_THRESHOLD              256
-
 #define TG3_RX_INTERNAL_RING_SZ_5906   32
 
-#define RX_STD_MAX_SIZE                        1536
 #define RX_STD_MAX_SIZE_5705           512
 #define RX_JUMBO_MAX_SIZE              0xdeadbeef /* XXX */
 
 #define   METAL_REV_B2                  0x02
 #define TG3PCI_DMA_RW_CTRL             0x0000006c
 #define  DMA_RWCTRL_DIS_CACHE_ALIGNMENT  0x00000001
+#define  DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK 0x00000380
 #define  DMA_RWCTRL_READ_BNDRY_MASK     0x00000700
 #define  DMA_RWCTRL_READ_BNDRY_DISAB    0x00000000
 #define  DMA_RWCTRL_READ_BNDRY_16       0x00000100
 /* 0x94 --> 0x98 unused */
 #define TG3PCI_STD_RING_PROD_IDX       0x00000098 /* 64-bit */
 #define TG3PCI_RCV_RET_RING_CON_IDX    0x000000a0 /* 64-bit */
-/* 0xa0 --> 0xb8 unused */
+/* 0xa8 --> 0xb8 unused */
 #define TG3PCI_DUAL_MAC_CTRL           0x000000b8
 #define  DUAL_MAC_CTRL_CH_MASK          0x00000003
 #define  DUAL_MAC_CTRL_ID               0x00000004
 #define TG3_PCIE_TLDLPL_PORT           0x00007c00
 #define TG3_PCIE_PL_LO_PHYCTL1          0x00000004
 #define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN        0x00001000
+#define TG3_PCIE_PL_LO_PHYCTL5          0x00000014
+#define TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ      0x80000000
 
 /* OTP bit definitions */
 #define TG3_OTP_AGCTGT_MASK            0x000000e0
 #define MII_TG3_DSP_AADJ1CH0           0x001f
 #define MII_TG3_DSP_AADJ1CH3           0x601f
 #define  MII_TG3_DSP_AADJ1CH3_ADCCKADJ 0x0002
-#define MII_TG3_DSP_EXP8               0x0708
+#define MII_TG3_DSP_EXP8               0x0f08
 #define  MII_TG3_DSP_EXP8_REJ2MHz      0x0001
 #define  MII_TG3_DSP_EXP8_AEDW         0x0200
 #define MII_TG3_DSP_EXP75              0x0f75
@@ -2512,7 +2512,7 @@ struct tg3_hw_stats {
  */
 struct ring_info {
        struct sk_buff                  *skb;
-       DECLARE_PCI_UNMAP_ADDR(mapping)
+       DEFINE_DMA_UNMAP_ADDR(mapping);
 };
 
 struct tg3_config_info {
@@ -2561,7 +2561,7 @@ struct tg3_bufmgr_config {
 
 struct tg3_ethtool_stats {
        /* Statistics maintained by Receive MAC. */
-       u64             rx_octets;
+       u64             rx_octets;
        u64             rx_fragments;
        u64             rx_ucast_packets;
        u64             rx_mcast_packets;
@@ -2751,9 +2751,11 @@ struct tg3 {
        struct tg3_napi                 napi[TG3_IRQ_MAX_VECS];
        void                            (*write32_rx_mbox) (struct tg3 *, u32,
                                                            u32);
+       u32                             rx_copy_thresh;
        u32                             rx_pending;
        u32                             rx_jumbo_pending;
        u32                             rx_std_max_post;
+       u32                             rx_offset;
        u32                             rx_pkt_map_sz;
 #if TG3_VLAN_TAG_USED
        struct vlan_group               *vlgrp;
@@ -2773,7 +2775,6 @@ struct tg3 {
        unsigned long                   last_event_jiffies;
        };
 
-       u32                             rx_offset;
        u32                             tg3_flags;
 #define TG3_FLAG_TAGGED_STATUS         0x00000001
 #define TG3_FLAG_TXD_MBOX_HWBUG                0x00000002
index 390540c101c7913ad2655eb44a4776f5b9fd603f..ccee3eddc5f4c24b4afcdf6cb4dcaf8759165b7a 100644 (file)
@@ -1034,7 +1034,7 @@ static void TLan_tx_timeout(struct net_device *dev)
        TLan_ResetLists( dev );
        TLan_ReadAndClearStats( dev, TLAN_IGNORE );
        TLan_ResetAdapter( dev );
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue( dev );
 
 }
@@ -1147,7 +1147,6 @@ static netdev_tx_t TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
 
        CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
 
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 
 } /* TLan_StartTx */
@@ -1314,7 +1313,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
 
 static void TLan_SetMulticastList( struct net_device *dev )
 {
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        u32                     hash1 = 0;
        u32                     hash2 = 0;
        int                     i;
@@ -1336,12 +1335,12 @@ static void TLan_SetMulticastList( struct net_device *dev )
                        TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
                } else {
                        i = 0;
-                       netdev_for_each_mc_addr(dmi, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                if ( i < 3 ) {
                                        TLan_SetMac( dev, i + 1,
-                                                    (char *) &dmi->dmi_addr );
+                                                    (char *) &ha->addr);
                                } else {
-                                       offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
+                                       offset = TLan_HashFunc((u8 *)&ha->addr);
                                        if ( offset < 32 )
                                                hash1 |= ( 1 << offset );
                                        else
@@ -2464,7 +2463,7 @@ static void TLan_PhyPrint( struct net_device *dev )
                printk( "TLAN:   Device %s, Unmanaged PHY.\n", dev->name );
        } else if ( phy <= TLAN_PHY_MAX_ADDR ) {
                printk( "TLAN:   Device %s, PHY 0x%02x.\n", dev->name, phy );
-               printk( "TLAN:      Off.  +0     +1     +2     +3 \n" );
+               printk( "TLAN:      Off.  +0     +1     +2     +3\n" );
                 for ( i = 0; i < 0x20; i+= 4 ) {
                        printk( "TLAN:      0x%02x", i );
                        TLan_MiiReadReg( dev, phy, i, &data0 );
index 7d7f3eef1ab3e4d71aad3fa6cf2d3c934dda5536..10800f16a2316c60e60ec9f4ca73f04711713d89 100644 (file)
@@ -77,7 +77,7 @@ static char version[] __devinitdata  =
 
 #define FW_NAME                "3com/3C359.bin"
 MODULE_AUTHOR("Mike Phillips <mikep@linuxtr.net>") ; 
-MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ;
+MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver\n") ;
 MODULE_FIRMWARE(FW_NAME);
 
 /* Module parameters */
@@ -163,19 +163,19 @@ static void print_tx_state(struct net_device *dev)
        u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
        int i ; 
 
-       printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d \n",xl_priv->tx_ring_head, 
+       printk("tx_ring_head: %d, tx_ring_tail: %d, free_ent: %d\n",xl_priv->tx_ring_head,
                xl_priv->tx_ring_tail, xl_priv->free_ring_entries) ; 
-       printk("Ring    , Address ,   FSH  , DnNextPtr, Buffer, Buffer_Len \n"); 
+       printk("Ring    , Address ,   FSH  , DnNextPtr, Buffer, Buffer_Len\n");
        for (i = 0; i < 16; i++) {
                txd = &(xl_priv->xl_tx_ring[i]) ; 
-               printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(txd), 
+               printk("%d, %08lx, %08x, %08x, %08x, %08x\n", i, virt_to_bus(txd),
                        txd->framestartheader, txd->dnnextptr, txd->buffer, txd->buffer_length ) ; 
        }
 
-       printk("DNLISTPTR = %04x \n", readl(xl_mmio + MMIO_DNLISTPTR) ); 
+       printk("DNLISTPTR = %04x\n", readl(xl_mmio + MMIO_DNLISTPTR) );
        
-       printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); 
-       printk("Queue status = %0x \n",netif_running(dev) ) ; 
+       printk("DmaCtl = %04x\n", readl(xl_mmio + MMIO_DMA_CTRL) );
+       printk("Queue status = %0x\n",netif_running(dev) ) ;
 }
 
 static void print_rx_state(struct net_device *dev)
@@ -186,19 +186,19 @@ static void print_rx_state(struct net_device *dev)
        u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
        int i ; 
 
-       printk("rx_ring_tail: %d \n", xl_priv->rx_ring_tail) ; 
-       printk("Ring    , Address ,   FrameState  , UPNextPtr, FragAddr, Frag_Len \n"); 
+       printk("rx_ring_tail: %d\n", xl_priv->rx_ring_tail);
+       printk("Ring    , Address ,   FrameState  , UPNextPtr, FragAddr, Frag_Len\n");
        for (i = 0; i < 16; i++) { 
                /* rxd = (struct xl_rx_desc *)xl_priv->rx_ring_dma_addr + (i * sizeof(struct xl_rx_desc)) ; */
                rxd = &(xl_priv->xl_rx_ring[i]) ; 
-               printk("%d, %08lx, %08x, %08x, %08x, %08x \n", i, virt_to_bus(rxd), 
+               printk("%d, %08lx, %08x, %08x, %08x, %08x\n", i, virt_to_bus(rxd),
                        rxd->framestatus, rxd->upnextptr, rxd->upfragaddr, rxd->upfraglen ) ; 
        }
 
-       printk("UPLISTPTR = %04x \n", readl(xl_mmio + MMIO_UPLISTPTR) ); 
+       printk("UPLISTPTR = %04x\n", readl(xl_mmio + MMIO_UPLISTPTR));
        
-       printk("DmaCtl = %04x \n", readl(xl_mmio + MMIO_DMA_CTRL) ); 
-       printk("Queue status = %0x \n",netif_running(dev) ) ;
+       printk("DmaCtl = %04x\n", readl(xl_mmio + MMIO_DMA_CTRL));
+       printk("Queue status = %0x\n",netif_running(dev));
 } 
 #endif
 
@@ -391,7 +391,7 @@ static int __devinit xl_init(struct net_device *dev)
        struct xl_private *xl_priv = netdev_priv(dev);
        int err;
 
-       printk(KERN_INFO "%s \n", version);
+       printk(KERN_INFO "%s\n", version);
        printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n",
                xl_priv->xl_card_name, (unsigned int)dev->base_addr ,xl_priv->xl_mmio, dev->irq);
 
@@ -463,7 +463,7 @@ static int xl_hw_reset(struct net_device *dev)
        writel( (IO_WORD_READ | PMBAR),xl_mmio + MMIO_MAC_ACCESS_CMD);  
 
 #if XL_DEBUG
-       printk(KERN_INFO "Read from PMBAR = %04x \n", readw(xl_mmio + MMIO_MACDATA)) ; 
+       printk(KERN_INFO "Read from PMBAR = %04x\n", readw(xl_mmio + MMIO_MACDATA));
 #endif
 
        if ( readw( (xl_mmio + MMIO_MACDATA))  & PMB_CPHOLD ) { 
@@ -591,9 +591,9 @@ static int xl_hw_reset(struct net_device *dev)
 #if XL_DEBUG
        writel(IO_WORD_READ | SWITCHSETTINGS, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 
        if ( readw(xl_mmio + MMIO_MACDATA) & 2) { 
-               printk(KERN_INFO "Default ring speed 4 mbps \n") ;
+               printk(KERN_INFO "Default ring speed 4 mbps\n");
        } else {
-               printk(KERN_INFO "Default ring speed 16 mbps \n") ; 
+               printk(KERN_INFO "Default ring speed 16 mbps\n");
        } 
        printk(KERN_INFO "%s: xl_priv->srb = %04x\n",xl_priv->xl_card_name, xl_priv->srb);
 #endif
@@ -651,7 +651,7 @@ static int xl_open(struct net_device *dev)
 
        if (open_err != 0) { /* Something went wrong with the open command */
                if (open_err & 0x07) { /* Wrong speed, retry at different speed */
-                       printk(KERN_WARNING "%s: Open Error, retrying at different ringspeed \n", dev->name) ; 
+                       printk(KERN_WARNING "%s: Open Error, retrying at different ringspeed\n", dev->name);
                        switchsettings = switchsettings ^ 2 ; 
                        xl_ee_write(dev,0x08,switchsettings) ; 
                        xl_hw_reset(dev) ; 
@@ -703,7 +703,7 @@ static int xl_open(struct net_device *dev)
        }
 
        if (i==0) { 
-               printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; 
+               printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name);
                free_irq(dev->irq,dev) ; 
                kfree(xl_priv->xl_tx_ring);
                kfree(xl_priv->xl_rx_ring);
@@ -853,7 +853,7 @@ static int xl_open_hw(struct net_device *dev)
  
                writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 12, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 
                xl_priv->arb = swab16(readw(xl_mmio + MMIO_MACDATA)) ;
-               printk(", ARB: %04x \n",xl_priv->arb ) ; 
+               printk(", ARB: %04x\n",xl_priv->arb );
                writel( (MEM_WORD_READ | 0xD0000 | xl_priv->srb) + 14, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 
                vsoff = swab16(readw(xl_mmio + MMIO_MACDATA)) ;
 
@@ -867,7 +867,7 @@ static int xl_open_hw(struct net_device *dev)
                        ver_str[i] = readb(xl_mmio + MMIO_MACDATA) ; 
                }
                ver_str[i] = '\0' ; 
-               printk(KERN_INFO "%s: Microcode version String: %s \n",dev->name,ver_str); 
+               printk(KERN_INFO "%s: Microcode version String: %s\n",dev->name,ver_str);
        }       
        
        /*
@@ -991,7 +991,7 @@ static void xl_rx(struct net_device *dev)
                        skb = dev_alloc_skb(xl_priv->pkt_buf_sz) ; 
 
                        if (skb==NULL) { /* Still need to fix the rx ring */
-                               printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer \n",dev->name) ; 
+                               printk(KERN_WARNING "%s: dev_alloc_skb failed in rx, single buffer\n",dev->name);
                                adv_rx_ring(dev) ; 
                                dev->stats.rx_dropped++ ; 
                                writel(ACK_INTERRUPT | UPCOMPACK | LATCH_ACK , xl_mmio + MMIO_COMMAND) ; 
@@ -1092,7 +1092,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
         */
        if (intstatus == 0x0001) {  
                writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ;
-               printk(KERN_INFO "%s: 00001 int received \n",dev->name) ;  
+               printk(KERN_INFO "%s: 00001 int received\n",dev->name);
        } else {  
                if (intstatus & (HOSTERRINT | SRBRINT | ARBCINT | UPCOMPINT | DNCOMPINT | HARDERRINT | (1<<8) | TXUNDERRUN | ASBFINT)) { 
                        
@@ -1103,9 +1103,9 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
                         */
 
                        if (intstatus & HOSTERRINT) {
-                               printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x \n",dev->name,intstatus) ; 
+                               printk(KERN_WARNING "%s: Host Error, performing global reset, intstatus = %04x\n",dev->name,intstatus);
                                writew( GLOBAL_RESET, xl_mmio + MMIO_COMMAND ) ;
-                               printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); 
+                               printk(KERN_WARNING "%s: Resetting hardware:\n", dev->name);
                                netif_stop_queue(dev) ;
                                xl_freemem(dev) ; 
                                free_irq(dev->irq,dev);         
@@ -1128,7 +1128,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
                                        Must put a timeout check here ! */
                                        /* Empty Loop */
                                } 
-                               printk(KERN_WARNING "%s: TX Underrun received \n",dev->name) ;
+                               printk(KERN_WARNING "%s: TX Underrun received\n",dev->name);
                                writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; 
                        } /* TxUnderRun */
        
@@ -1157,13 +1157,13 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
                                macstatus = readw(xl_mmio + MMIO_MACDATA) ; 
                                printk(KERN_WARNING "%s: MacStatusError, details: ", dev->name);
                                if (macstatus & (1<<14)) 
-                                       printk(KERN_WARNING "tchk error: Unrecoverable error \n") ; 
+                                       printk(KERN_WARNING "tchk error: Unrecoverable error\n");
                                if (macstatus & (1<<3))
-                                       printk(KERN_WARNING "eint error: Internal watchdog timer expired \n") ;
+                                       printk(KERN_WARNING "eint error: Internal watchdog timer expired\n");
                                if (macstatus & (1<<2))
-                                       printk(KERN_WARNING "aint error: Host tried to perform invalid operation \n") ; 
+                                       printk(KERN_WARNING "aint error: Host tried to perform invalid operation\n");
                                printk(KERN_WARNING "Instatus = %02x, macstatus = %02x\n",intstatus,macstatus) ; 
-                               printk(KERN_WARNING "%s: Resetting hardware: \n", dev->name); 
+                               printk(KERN_WARNING "%s: Resetting hardware:\n", dev->name);
                                netif_stop_queue(dev) ;
                                xl_freemem(dev) ; 
                                free_irq(dev->irq,dev); 
@@ -1175,7 +1175,7 @@ static irqreturn_t xl_interrupt(int irq, void *dev_id)
                                return IRQ_HANDLED;
                        }
                } else { 
-                       printk(KERN_WARNING "%s: Received Unknown interrupt : %04x \n", dev->name, intstatus) ;
+                       printk(KERN_WARNING "%s: Received Unknown interrupt : %04x\n", dev->name, intstatus);
                        writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ;     
                }
        } 
@@ -1350,11 +1350,11 @@ static int xl_close(struct net_device *dev)
 
        writel(MEM_BYTE_READ | 0xd0000 | xl_priv->srb, xl_mmio + MMIO_MAC_ACCESS_CMD);
        if (readb(xl_mmio + MMIO_MACDATA) != CLOSE_NIC) { 
-               printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response \n",dev->name) ; 
+               printk(KERN_INFO "%s: CLOSE_NIC did not get a CLOSE_NIC response\n",dev->name);
        } else { 
                writel((MEM_BYTE_READ | 0xd0000 | xl_priv->srb) +2, xl_mmio + MMIO_MAC_ACCESS_CMD) ;
                if (readb(xl_mmio + MMIO_MACDATA)==0) { 
-                       printk(KERN_INFO "%s: Adapter has been closed \n",dev->name) ;
+                       printk(KERN_INFO "%s: Adapter has been closed\n",dev->name);
                        writew(ACK_INTERRUPT | SRBRACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; 
 
                        xl_freemem(dev) ; 
@@ -1391,7 +1391,7 @@ static int xl_close(struct net_device *dev)
 static void xl_set_rx_mode(struct net_device *dev) 
 {
        struct xl_private *xl_priv = netdev_priv(dev);
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned char dev_mc_address[4] ; 
        u16 options ; 
 
@@ -1408,11 +1408,11 @@ static void xl_set_rx_mode(struct net_device *dev)
 
        dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
 
-       netdev_for_each_mc_addr(dmi, dev) {
-                dev_mc_address[0] |= dmi->dmi_addr[2] ;
-                dev_mc_address[1] |= dmi->dmi_addr[3] ;
-                dev_mc_address[2] |= dmi->dmi_addr[4] ;
-                dev_mc_address[3] |= dmi->dmi_addr[5] ;
+       netdev_for_each_mc_addr(ha, dev) {
+               dev_mc_address[0] |= ha->addr[2];
+               dev_mc_address[1] |= ha->addr[3];
+               dev_mc_address[2] |= ha->addr[4];
+               dev_mc_address[3] |= ha->addr[5];
         }
 
        if (memcmp(xl_priv->xl_functional_addr,dev_mc_address,4) != 0) { /* Options have changed, run the command */
@@ -1447,11 +1447,11 @@ static void xl_srb_bh(struct net_device *dev)
                printk(KERN_INFO "%s: Command: %d - Invalid Command code\n",dev->name,srb_cmd) ; 
                break ; 
        case 4:
-               printk(KERN_INFO "%s: Command: %d - Adapter is closed, must be open for this command \n",dev->name,srb_cmd) ; 
+               printk(KERN_INFO "%s: Command: %d - Adapter is closed, must be open for this command\n",dev->name,srb_cmd);
                break ;
        
        case 6:
-               printk(KERN_INFO "%s: Command: %d - Options Invalid for command \n",dev->name,srb_cmd) ;
+               printk(KERN_INFO "%s: Command: %d - Options Invalid for command\n",dev->name,srb_cmd);
                break ;
 
        case 0: /* Successful command execution */ 
@@ -1472,11 +1472,11 @@ static void xl_srb_bh(struct net_device *dev)
                        break ; 
                case SET_FUNC_ADDRESS:
                        if(xl_priv->xl_message_level) 
-                               printk(KERN_INFO "%s: Functional Address Set \n",dev->name) ;  
+                               printk(KERN_INFO "%s: Functional Address Set\n",dev->name);
                        break ; 
                case CLOSE_NIC:
                        if(xl_priv->xl_message_level)
-                               printk(KERN_INFO "%s: Received CLOSE_NIC interrupt in interrupt handler \n",dev->name) ;        
+                               printk(KERN_INFO "%s: Received CLOSE_NIC interrupt in interrupt handler\n",dev->name);
                        break ; 
                case SET_MULTICAST_MODE:
                        if(xl_priv->xl_message_level)
@@ -1485,9 +1485,9 @@ static void xl_srb_bh(struct net_device *dev)
                case SET_RECEIVE_MODE:
                        if(xl_priv->xl_message_level) {  
                                if (xl_priv->xl_copy_all_options == 0x0004) 
-                                       printk(KERN_INFO "%s: Entering promiscuous mode \n", dev->name) ; 
+                                       printk(KERN_INFO "%s: Entering promiscuous mode\n", dev->name);
                                else
-                                       printk(KERN_INFO "%s: Entering normal receive mode \n",dev->name) ; 
+                                       printk(KERN_INFO "%s: Entering normal receive mode\n",dev->name);
                        }
                        break ; 
  
@@ -1557,20 +1557,20 @@ static void xl_arb_cmd(struct net_device *dev)
                        xl_freemem(dev) ; 
                        free_irq(dev->irq,dev);
                        
-                       printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
+                       printk(KERN_WARNING "%s: Adapter has been closed\n", dev->name);
                } /* If serious error */
                
                if (xl_priv->xl_message_level) { 
                        if (lan_status_diff & LSC_SIG_LOSS) 
-                                       printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; 
+                                       printk(KERN_WARNING "%s: No receive signal detected\n", dev->name);
                        if (lan_status_diff & LSC_HARD_ERR)
-                                       printk(KERN_INFO "%s: Beaconing \n",dev->name);
+                                       printk(KERN_INFO "%s: Beaconing\n",dev->name);
                        if (lan_status_diff & LSC_SOFT_ERR)
-                                       printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name);
+                                       printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name);
                        if (lan_status_diff & LSC_TRAN_BCN) 
                                        printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
                        if (lan_status_diff & LSC_SS) 
-                                       printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
+                                       printk(KERN_INFO "%s: Single Station on the ring\n", dev->name);
                        if (lan_status_diff & LSC_RING_REC)
                                        printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name);
                        if (lan_status_diff & LSC_FDX_MODE)
@@ -1579,7 +1579,7 @@ static void xl_arb_cmd(struct net_device *dev)
                
                if (lan_status_diff & LSC_CO) { 
                                if (xl_priv->xl_message_level) 
-                                       printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
+                                       printk(KERN_INFO "%s: Counter Overflow\n", dev->name);
                                /* Issue READ.LOG command */
                                xl_srb_cmd(dev, READ_LOG) ;     
                }
@@ -1595,7 +1595,7 @@ static void xl_arb_cmd(struct net_device *dev)
        }  /* Lan.change.status */
        else if ( arb_cmd == RECEIVE_DATA) { /* Received.Data */
 #if XL_DEBUG
-               printk(KERN_INFO "Received.Data \n") ; 
+               printk(KERN_INFO "Received.Data\n");
 #endif                 
                writel( ((MEM_WORD_READ | 0xD0000 | xl_priv->arb) + 6), xl_mmio + MMIO_MAC_ACCESS_CMD) ;
                xl_priv->mac_buffer = swab16(readw(xl_mmio + MMIO_MACDATA)) ;
@@ -1630,7 +1630,7 @@ static void xl_arb_cmd(struct net_device *dev)
                xl_asb_cmd(dev) ; 
                
        } else {
-               printk(KERN_WARNING "%s: Received unknown arb (xl_priv) command: %02x \n",dev->name,arb_cmd) ; 
+               printk(KERN_WARNING "%s: Received unknown arb (xl_priv) command: %02x\n",dev->name,arb_cmd);
        }
 
        /* Acknowledge the arb interrupt */
@@ -1687,13 +1687,13 @@ static void xl_asb_bh(struct net_device *dev)
        ret_code = readb(xl_mmio + MMIO_MACDATA) ; 
        switch (ret_code) { 
                case 0x01:
-                       printk(KERN_INFO "%s: ASB Command, unrecognized command code \n",dev->name) ;
+                       printk(KERN_INFO "%s: ASB Command, unrecognized command code\n",dev->name);
                        break ;
                case 0x26:
-                       printk(KERN_INFO "%s: ASB Command, unexpected receive buffer \n", dev->name) ; 
+                       printk(KERN_INFO "%s: ASB Command, unexpected receive buffer\n", dev->name);
                        break ; 
                case 0x40:
-                       printk(KERN_INFO "%s: ASB Command, Invalid Station ID \n", dev->name) ; 
+                       printk(KERN_INFO "%s: ASB Command, Invalid Station ID\n", dev->name);
                        break ;  
        }
        xl_priv->asb_queued = 0 ; 
index 1a0967246e2f01dbc6bf72c5aac4e8ce4f8c70ca..91e6c78271a3a09f4b8a5e4aba0b508e6f1ee134 100644 (file)
@@ -986,7 +986,7 @@ static void open_sap(unsigned char type, struct net_device *dev)
 static void tok_set_multicast_list(struct net_device *dev)
 {
        struct tok_info *ti = netdev_priv(dev);
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        unsigned char address[4];
 
        int i;
@@ -995,11 +995,11 @@ static void tok_set_multicast_list(struct net_device *dev)
        /*BMS ifconfig tr down or hot unplug a PCMCIA card ??hownowbrowncow*/
        if (/*BMSHELPdev->start == 0 ||*/ ti->open_status != OPEN) return;
        address[0] = address[1] = address[2] = address[3] = 0;
-       netdev_for_each_mc_addr(mclist, dev) {
-               address[0] |= mclist->dmi_addr[2];
-               address[1] |= mclist->dmi_addr[3];
-               address[2] |= mclist->dmi_addr[4];
-               address[3] |= mclist->dmi_addr[5];
+       netdev_for_each_mc_addr(ha, dev) {
+               address[0] |= ha->addr[2];
+               address[1] |= ha->addr[3];
+               address[2] |= ha->addr[4];
+               address[3] |= ha->addr[5];
        }
        SET_PAGE(ti->srb_page);
        for (i = 0; i < sizeof(struct srb_set_funct_addr); i++)
@@ -1041,7 +1041,6 @@ static netdev_tx_t tok_send_packet(struct sk_buff *skb,
        writew(ti->exsap_station_id, ti->srb + STATION_ID_OFST);
        writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
        spin_unlock_irqrestore(&(ti->lock), flags);
-       dev->trans_start = jiffies;
        return NETDEV_TX_OK;
 }
 
index 7a5fbf5a9d7136afa7bf39afa643dbcf788426e1..5bd140704533f353fa6b7ee05a6cbd9445aec7ad 100644 (file)
@@ -358,7 +358,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev,
        pcr |= PCI_COMMAND_SERR;
        pci_write_config_word (pdev, PCI_COMMAND, pcr);
 
-       printk("%s \n", version);
+       printk("%s\n", version);
        printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
                streamer_priv->streamer_card_name,
                (unsigned int) dev->base_addr,
@@ -651,7 +651,7 @@ static int streamer_open(struct net_device *dev)
 #if STREAMER_DEBUG
                writew(readw(streamer_mmio + LAPWWO),
                       streamer_mmio + LAPA);
-               printk("srb open request: \n");
+               printk("srb open request:\n");
                for (i = 0; i < 16; i++) {
                        printk("%x:", ntohs(readw(streamer_mmio + LAPDINC)));
                }
@@ -701,7 +701,7 @@ static int streamer_open(struct net_device *dev)
                if (srb_word != 0) {
                        if (srb_word == 0x07) {
                                if (!streamer_priv->streamer_ring_speed && open_finished) {     /* Autosense , first time around */
-                                       printk(KERN_WARNING "%s: Retrying at different ring speed \n",
+                                       printk(KERN_WARNING "%s: Retrying at different ring speed\n",
                                               dev->name);
                                        open_finished = 0;
                                } else {
@@ -717,7 +717,7 @@ static int streamer_open(struct net_device *dev)
                                            ((error_code & 0x0f) == 0x0d))
                                        {
                                                printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n", dev->name);
-                                               printk(KERN_WARNING "%s: Please try again with a specified ring speed \n", dev->name);
+                                               printk(KERN_WARNING "%s: Please try again with a specified ring speed\n", dev->name);
                                                free_irq(dev->irq, dev);
                                                return -EIO;
                                        }
@@ -923,7 +923,7 @@ static void streamer_rx(struct net_device *dev)
 
                if (rx_desc->status & 0x7E830000) {     /* errors */
                        if (streamer_priv->streamer_message_level) {
-                               printk(KERN_WARNING "%s: Rx Error %x \n",
+                               printk(KERN_WARNING "%s: Rx Error %x\n",
                                       dev->name, rx_desc->status);
                        }
                } else {        /* received without errors */
@@ -936,7 +936,7 @@ static void streamer_rx(struct net_device *dev)
 
                        if (skb == NULL) 
                        {
-                               printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n", dev->name);
+                               printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers.\n",  dev->name);
                                dev->stats.rx_dropped++;
                        } else {        /* we allocated an skb OK */
                                if (buffer_cnt == 1) {
@@ -1267,7 +1267,7 @@ static void streamer_set_rx_mode(struct net_device *dev)
            netdev_priv(dev);
        __u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
        __u8 options = 0;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned char dev_mc_address[5];
 
        writel(streamer_priv->srb, streamer_mmio + LAPA);
@@ -1303,11 +1303,11 @@ static void streamer_set_rx_mode(struct net_device *dev)
        writel(streamer_priv->srb,streamer_mmio+LAPA);
        dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; 
   
-       netdev_for_each_mc_addr(dmi, dev) {
-               dev_mc_address[0] |= dmi->dmi_addr[2] ; 
-               dev_mc_address[1] |= dmi->dmi_addr[3] ; 
-               dev_mc_address[2] |= dmi->dmi_addr[4] ; 
-               dev_mc_address[3] |= dmi->dmi_addr[5] ; 
+       netdev_for_each_mc_addr(ha, dev) {
+               dev_mc_address[0] |= ha->addr[2];
+               dev_mc_address[1] |= ha->addr[3];
+               dev_mc_address[2] |= ha->addr[4];
+               dev_mc_address[3] |= ha->addr[5];
        }
   
        writew(htons(SRB_SET_FUNC_ADDRESS << 8),streamer_mmio+LAPDINC);
@@ -1364,7 +1364,7 @@ static void streamer_srb_bh(struct net_device *dev)
                case 0x00:
                        break;
                case 0x01:
-                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name);
                        break;
                case 0x04:
                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name);
@@ -1392,13 +1392,13 @@ static void streamer_srb_bh(struct net_device *dev)
                case 0x00:
                        break;
                case 0x01:
-                       printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name);
                        break;
                case 0x04:
                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name);
                        break;
                case 0x39:      /* Must deal with this if individual multicast addresses used */
-                       printk(KERN_INFO "%s: Group address not found \n", dev->name);
+                       printk(KERN_INFO "%s: Group address not found\n", dev->name);
                        break;
                default:
                        break;
@@ -1414,10 +1414,10 @@ static void streamer_srb_bh(struct net_device *dev)
                switch (srb_word) {
                case 0x00:
                        if (streamer_priv->streamer_message_level)
-                               printk(KERN_INFO "%s: Functional Address Mask Set \n", dev->name);
+                               printk(KERN_INFO "%s: Functional Address Mask Set\n", dev->name);
                        break;
                case 0x01:
-                       printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name);
                        break;
                case 0x04:
                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name);
@@ -1448,7 +1448,7 @@ static void streamer_srb_bh(struct net_device *dev)
                        }
                        break;
                case 0x01:
-                       printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name);
                        break;
                case 0x04:
                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name);
@@ -1467,7 +1467,7 @@ static void streamer_srb_bh(struct net_device *dev)
                                printk(KERN_INFO "%s: Read Source Routing Counters issued\n", dev->name);
                        break;
                case 0x01:
-                       printk(KERN_WARNING "%s: Unrecognized srb command \n", dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized srb command\n", dev->name);
                        break;
                case 0x04:
                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n", dev->name);
@@ -1556,7 +1556,7 @@ static void streamer_arb_cmd(struct net_device *dev)
                                             (streamer_mmio + LAPDINC)));
                        }
 
-                       printk("next %04x, fs %02x, len %04x \n", next,
+                       printk("next %04x, fs %02x, len %04x\n", next,
                               status, len);
                }
 #endif
@@ -1593,7 +1593,7 @@ static void streamer_arb_cmd(struct net_device *dev)
 
                mac_frame->protocol = tr_type_trans(mac_frame, dev);
 #if STREAMER_NETWORK_MONITOR
-               printk(KERN_WARNING "%s: Received MAC Frame, details: \n",
+               printk(KERN_WARNING "%s: Received MAC Frame, details:\n",
                       dev->name);
                mac_hdr = tr_hdr(mac_frame);
                printk(KERN_WARNING
@@ -1669,15 +1669,15 @@ drop_frame:
                /* If serious error */
                if (streamer_priv->streamer_message_level) {
                        if (lan_status_diff & LSC_SIG_LOSS)
-                               printk(KERN_WARNING "%s: No receive signal detected \n", dev->name);
+                               printk(KERN_WARNING "%s: No receive signal detected\n", dev->name);
                        if (lan_status_diff & LSC_HARD_ERR) 
-                               printk(KERN_INFO "%s: Beaconing \n", dev->name);
+                               printk(KERN_INFO "%s: Beaconing\n", dev->name);
                        if (lan_status_diff & LSC_SOFT_ERR)
-                               printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n", dev->name);
+                               printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n", dev->name);
                        if (lan_status_diff & LSC_TRAN_BCN)
                                printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n", dev->name);
                        if (lan_status_diff & LSC_SS)
-                               printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
+                               printk(KERN_INFO "%s: Single Station on the ring\n", dev->name);
                        if (lan_status_diff & LSC_RING_REC)
                                printk(KERN_INFO "%s: Ring recovery ongoing\n", dev->name);
                        if (lan_status_diff & LSC_FDX_MODE)
@@ -1686,7 +1686,7 @@ drop_frame:
 
                if (lan_status_diff & LSC_CO) {
                        if (streamer_priv->streamer_message_level)
-                               printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
+                               printk(KERN_INFO "%s: Counter Overflow\n", dev->name);
 
                        /* Issue READ.LOG command */
 
@@ -1716,7 +1716,7 @@ drop_frame:
                streamer_priv->streamer_lan_status = lan_status;
        } /* Lan.change.status */
        else
-               printk(KERN_WARNING "%s: Unknown arb command \n", dev->name);
+               printk(KERN_WARNING "%s: Unknown arb command\n", dev->name);
 }
 
 static void streamer_asb_bh(struct net_device *dev)
@@ -1747,10 +1747,10 @@ static void streamer_asb_bh(struct net_device *dev)
                rc=ntohs(readw(streamer_mmio+LAPD)) >> 8;
                switch (rc) {
                case 0x01:
-                       printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized command code\n", dev->name);
                        break;
                case 0x26:
-                       printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name);
+                       printk(KERN_WARNING "%s: Unrecognized buffer address\n", dev->name);
                        break;
                case 0xFF:
                        /* Valid response, everything should be ok again */
index 53f631ebb162d55021739a4bd4898b023eda5c8d..785ad1a2157be971cf684ef99f0c27319d94d8f3 100644 (file)
@@ -109,7 +109,6 @@ static void madgemc_sifwriteb(struct net_device *dev, unsigned short val, unsign
                SIFWRITEB(val, reg);
                madgemc_setregpage(dev, 0);
        }
-       return;
 }
 
 /*
@@ -140,7 +139,6 @@ static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsign
                SIFWRITEW(val, reg);
                madgemc_setregpage(dev, 0);
        }
-       return;
 }
 
 static struct net_device_ops madgemc_netdev_ops __read_mostly;
@@ -505,8 +503,6 @@ static void madgemc_setregpage(struct net_device *dev, int page)
                     dev->base_addr + MC_CONTROL_REG1);
        }
        reg1 = inb(dev->base_addr + MC_CONTROL_REG1);
-
-       return;
 }
 
 /*
@@ -527,8 +523,6 @@ static void madgemc_setsifsel(struct net_device *dev, int val)
                     dev->base_addr + MC_CONTROL_REG0);
        }       
        reg0 = inb(dev->base_addr + MC_CONTROL_REG0);
-
-       return;
 }
 
 /*
@@ -550,8 +544,6 @@ static void madgemc_setint(struct net_device *dev, int val)
                outb(reg1 | MC_CONTROL_REG1_SINTEN, 
                     dev->base_addr + MC_CONTROL_REG1);
        }
-
-       return;
 }
 
 /*
@@ -594,8 +586,6 @@ static void madgemc_chipset_close(struct net_device *dev)
        madgemc_setint(dev, 0);
        /* unmap SIF registers */
        madgemc_setsifsel(dev, 0);
-
-       return;
 }
 
 /*
@@ -656,8 +646,6 @@ static void madgemc_read_rom(struct net_device *dev, struct card_info *card)
        /* Restore original register values */
        outb(reg0, ioaddr + MC_CONTROL_REG0);
        outb(reg1, ioaddr + MC_CONTROL_REG1);
-       
-       return;
 }
 
 static int madgemc_open(struct net_device *dev)
index 3a25e0434ae2a62590a77d5303c6c6ecbdcde562..3d2fbe60b46e07f57e97f418ad62a903e908b26f 100644 (file)
@@ -302,7 +302,7 @@ static int olympic_init(struct net_device *dev)
        olympic_priv=netdev_priv(dev);
        olympic_mmio=olympic_priv->olympic_mmio;
 
-       printk("%s \n", version);
+       printk("%s\n", version);
        printk("%s. I/O at %hx, MMIO at %p, LAP at %p, using irq %d\n", olympic_priv->olympic_card_name, (unsigned int) dev->base_addr,olympic_priv->olympic_mmio, olympic_priv->olympic_lap, dev->irq);
 
        writel(readl(olympic_mmio+BCTL) | BCTL_SOFTRESET,olympic_mmio+BCTL);
@@ -468,7 +468,7 @@ static int olympic_open(struct net_device *dev)
 #if OLYMPIC_DEBUG
        printk("LAPWWO: %x, LAPA: %x\n",readw(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
        printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
-       printk("Before the open command \n");
+       printk("Before the open command\n");
 #endif 
        do {
                memset_io(init_srb,0,SRB_COMMAND_SIZE);
@@ -520,7 +520,7 @@ static int olympic_open(struct net_device *dev)
                                break;
                        }
                        if (time_after(jiffies, t + 10*HZ)) {
-                               printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; 
+                               printk(KERN_WARNING "%s: SRB timed out.\n",dev->name);
                                olympic_priv->srb_queued=0;
                                break ; 
                        } 
@@ -549,7 +549,7 @@ static int olympic_open(struct net_device *dev)
                        break;
                case 0x07:
                        if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */
-                               printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); 
+                               printk(KERN_WARNING "%s: Retrying at different ring speed\n", dev->name);
                                open_finished = 0 ;  
                                continue;
                        }
@@ -558,7 +558,7 @@ static int olympic_open(struct net_device *dev)
 
                        if (!olympic_priv->olympic_ring_speed && ((err & 0x0f) == 0x0d)) { 
                                printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name);
-                               printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name);
+                               printk(KERN_WARNING "%s: Please try again with a specified ring speed\n",dev->name);
                        } else {
                                printk(KERN_WARNING "%s: %s - %s\n", dev->name,
                                        open_maj_error[(err & 0xf0) >> 4],
@@ -759,7 +759,7 @@ static void olympic_rx(struct net_device *dev)
                olympic_priv->rx_status_last_received++ ;
                olympic_priv->rx_status_last_received &= (OLYMPIC_RX_RING_SIZE -1);
 #if OLYMPIC_DEBUG
-               printk("rx status: %x rx len: %x \n", le32_to_cpu(rx_status->status_buffercnt), le32_to_cpu(rx_status->fragmentcnt_framelen));
+               printk("rx status: %x rx len: %x\n", le32_to_cpu(rx_status->status_buffercnt), le32_to_cpu(rx_status->fragmentcnt_framelen));
 #endif
                length = le32_to_cpu(rx_status->fragmentcnt_framelen) & 0xffff;
                buffer_cnt = le32_to_cpu(rx_status->status_buffercnt) & 0xffff; 
@@ -774,15 +774,15 @@ static void olympic_rx(struct net_device *dev)
                        if (l_status_buffercnt & 0x3B000000) {
                                if (olympic_priv->olympic_message_level) {
                                        if (l_status_buffercnt & (1<<29))  /* Rx Frame Truncated */
-                                               printk(KERN_WARNING "%s: Rx Frame Truncated \n",dev->name);
+                                               printk(KERN_WARNING "%s: Rx Frame Truncated\n",dev->name);
                                        if (l_status_buffercnt & (1<<28)) /*Rx receive overrun */
-                                               printk(KERN_WARNING "%s: Rx Frame Receive overrun \n",dev->name);
+                                               printk(KERN_WARNING "%s: Rx Frame Receive overrun\n",dev->name);
                                        if (l_status_buffercnt & (1<<27)) /* No receive buffers */
-                                               printk(KERN_WARNING "%s: No receive buffers \n",dev->name);
+                                               printk(KERN_WARNING "%s: No receive buffers\n",dev->name);
                                        if (l_status_buffercnt & (1<<25)) /* Receive frame error detect */
-                                               printk(KERN_WARNING "%s: Receive frame error detect \n",dev->name);
+                                               printk(KERN_WARNING "%s: Receive frame error detect\n",dev->name);
                                        if (l_status_buffercnt & (1<<24)) /* Received Error Detect */
-                                               printk(KERN_WARNING "%s: Received Error Detect \n",dev->name);
+                                               printk(KERN_WARNING "%s: Received Error Detect\n",dev->name);
                                } 
                                olympic_priv->rx_ring_last_received += i ; 
                                olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1) ; 
@@ -796,7 +796,7 @@ static void olympic_rx(struct net_device *dev)
                                }
 
                                if (skb == NULL) {
-                                       printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers. \n",dev->name) ;
+                                       printk(KERN_WARNING "%s: Not enough memory to copy packet to upper layers.\n",dev->name) ;
                                        dev->stats.rx_dropped++;
                                        /* Update counters even though we don't transfer the frame */
                                        olympic_priv->rx_ring_last_received += i ; 
@@ -1101,7 +1101,7 @@ static int olympic_close(struct net_device *dev)
                }
 
                if (t == 0) { 
-                       printk(KERN_WARNING "%s: SRB timed out. May not be fatal. \n",dev->name) ; 
+                       printk(KERN_WARNING "%s: SRB timed out. May not be fatal.\n",dev->name);
                } 
                olympic_priv->srb_queued=0;
        }
@@ -1139,7 +1139,7 @@ static void olympic_set_rx_mode(struct net_device *dev)
        u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; 
        u8 options = 0; 
        u8 __iomem *srb;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        unsigned char dev_mc_address[4] ; 
 
        writel(olympic_priv->srb,olympic_mmio+LAPA);
@@ -1177,11 +1177,11 @@ static void olympic_set_rx_mode(struct net_device *dev)
 
        dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ; 
 
-       netdev_for_each_mc_addr(dmi, dev) {
-               dev_mc_address[0] |= dmi->dmi_addr[2] ; 
-               dev_mc_address[1] |= dmi->dmi_addr[3] ; 
-               dev_mc_address[2] |= dmi->dmi_addr[4] ; 
-               dev_mc_address[3] |= dmi->dmi_addr[5] ; 
+       netdev_for_each_mc_addr(ha, dev) {
+               dev_mc_address[0] |= ha->addr[2];
+               dev_mc_address[1] |= ha->addr[3];
+               dev_mc_address[2] |= ha->addr[4];
+               dev_mc_address[3] |= ha->addr[5];
        }
 
        writeb(SRB_SET_FUNC_ADDRESS,srb+0);
@@ -1239,7 +1239,7 @@ static void olympic_srb_bh(struct net_device *dev)
                                case 0x00:
                                        break ; 
                                case 0x01:
-                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name);
                                        break ;
                                case 0x04:
                                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name); 
@@ -1266,13 +1266,13 @@ static void olympic_srb_bh(struct net_device *dev)
                                case 0x00:
                                        break ; 
                                case 0x01:
-                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name);
                                        break ; 
                                case 0x04:
                                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
                                        break ; 
                                case 0x39: /* Must deal with this if individual multicast addresses used */
-                                       printk(KERN_INFO "%s: Group address not found \n",dev->name); 
+                                       printk(KERN_INFO "%s: Group address not found\n",dev->name);
                                        break ;
                                default:
                                        break ; 
@@ -1287,10 +1287,10 @@ static void olympic_srb_bh(struct net_device *dev)
                        switch (readb(srb+2)) { 
                                case 0x00:
                                        if (olympic_priv->olympic_message_level)
-                                               printk(KERN_INFO "%s: Functional Address Mask Set \n",dev->name) ; 
+                                               printk(KERN_INFO "%s: Functional Address Mask Set\n",dev->name);
                                        break ;
                                case 0x01:
-                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name);
                                        break ; 
                                case 0x04:
                                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
@@ -1310,7 +1310,7 @@ static void olympic_srb_bh(struct net_device *dev)
                                                printk(KERN_INFO "%s: Read Log issued\n",dev->name) ; 
                                        break ; 
                                case 0x01:
-                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name);
                                        break ; 
                                case 0x04:
                                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
@@ -1328,7 +1328,7 @@ static void olympic_srb_bh(struct net_device *dev)
                                                printk(KERN_INFO "%s: Read Source Routing Counters issued\n",dev->name) ; 
                                        break ; 
                                case 0x01:
-                                       printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ; 
+                                       printk(KERN_WARNING "%s: Unrecognized srb command\n",dev->name);
                                        break ; 
                                case 0x04:
                                        printk(KERN_WARNING "%s: Adapter must be open for this operation, doh!!\n",dev->name) ; 
@@ -1404,7 +1404,7 @@ static void olympic_arb_cmd(struct net_device *dev)
                        printk("Loc %d = %02x\n",i,readb(frame_data + i)); 
                }
 
-               printk("next %04x, fs %02x, len %04x \n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); 
+               printk("next %04x, fs %02x, len %04x\n",readw(buf_ptr+offsetof(struct mac_receive_buffer,next)), readb(buf_ptr+offsetof(struct mac_receive_buffer,frame_status)), readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length)));
 }
 #endif 
                mac_frame = dev_alloc_skb(frame_len) ; 
@@ -1426,7 +1426,7 @@ static void olympic_arb_cmd(struct net_device *dev)
 
                if (olympic_priv->olympic_network_monitor) { 
                        struct trh_hdr *mac_hdr;
-                       printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name);
+                       printk(KERN_WARNING "%s: Received MAC Frame, details:\n",dev->name);
                        mac_hdr = tr_hdr(mac_frame);
                        printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %pM\n",
                               dev->name, mac_hdr->daddr);
@@ -1489,20 +1489,20 @@ drop_frame:
                        writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
                        netif_stop_queue(dev);
                        olympic_priv->srb = readw(olympic_priv->olympic_lap + LAPWWO) ; 
-                       printk(KERN_WARNING "%s: Adapter has been closed \n", dev->name) ; 
+                       printk(KERN_WARNING "%s: Adapter has been closed\n", dev->name);
                } /* If serious error */
                
                if (olympic_priv->olympic_message_level) { 
                        if (lan_status_diff & LSC_SIG_LOSS) 
-                                       printk(KERN_WARNING "%s: No receive signal detected \n", dev->name) ; 
+                                       printk(KERN_WARNING "%s: No receive signal detected\n", dev->name);
                        if (lan_status_diff & LSC_HARD_ERR)
-                                       printk(KERN_INFO "%s: Beaconing \n",dev->name);
+                                       printk(KERN_INFO "%s: Beaconing\n",dev->name);
                        if (lan_status_diff & LSC_SOFT_ERR)
-                                       printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame \n",dev->name);
+                                       printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name);
                        if (lan_status_diff & LSC_TRAN_BCN) 
                                        printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name);
                        if (lan_status_diff & LSC_SS) 
-                                       printk(KERN_INFO "%s: Single Station on the ring \n", dev->name);
+                                       printk(KERN_INFO "%s: Single Station on the ring\n", dev->name);
                        if (lan_status_diff & LSC_RING_REC)
                                        printk(KERN_INFO "%s: Ring recovery ongoing\n",dev->name);
                        if (lan_status_diff & LSC_FDX_MODE)
@@ -1512,7 +1512,7 @@ drop_frame:
                if (lan_status_diff & LSC_CO) { 
                                        
                                if (olympic_priv->olympic_message_level) 
-                                       printk(KERN_INFO "%s: Counter Overflow \n", dev->name);
+                                       printk(KERN_INFO "%s: Counter Overflow\n", dev->name);
                                        
                                /* Issue READ.LOG command */
 
@@ -1551,7 +1551,7 @@ drop_frame:
        
        }  /* Lan.change.status */
        else
-               printk(KERN_WARNING "%s: Unknown arb command \n", dev->name);
+               printk(KERN_WARNING "%s: Unknown arb command\n", dev->name);
 }
 
 static void olympic_asb_bh(struct net_device *dev) 
@@ -1578,10 +1578,10 @@ static void olympic_asb_bh(struct net_device *dev)
        if (olympic_priv->asb_queued == 2) { 
                switch (readb(asb_block+2)) {
                        case 0x01:
-                               printk(KERN_WARNING "%s: Unrecognized command code \n", dev->name);
+                               printk(KERN_WARNING "%s: Unrecognized command code\n", dev->name);
                                break ;
                        case 0x26:
-                               printk(KERN_WARNING "%s: Unrecognized buffer address \n", dev->name);
+                               printk(KERN_WARNING "%s: Unrecognized buffer address\n", dev->name);
                                break ;
                        case 0xFF:
                                /* Valid response, everything should be ok again */
index e40560137c460938633c4750986d9b4a9d1cdd7c..0929fff5982c73e93902cc20ae02447e5bd26262 100644 (file)
@@ -4562,7 +4562,7 @@ static void smctr_timeout(struct net_device *dev)
          * fake transmission time and go on trying. Our own timeout
          * routine is in sktr_timer_chk()
          */
-        dev->trans_start = jiffies;
+        dev->trans_start = jiffies; /* prevent tx timeout */
         netif_wake_queue(dev);
 }
 
@@ -5147,8 +5147,6 @@ static void smctr_set_multicast_list(struct net_device *dev)
 {
         if(smctr_debug > 10)
                 printk(KERN_DEBUG "%s: smctr_set_multicast_list\n", dev->name);
-
-        return;
 }
 
 static int smctr_set_page(struct net_device *dev, __u8 *buf)
index 8b508c922410cf4e010aa6b1bcbe8cd72b634bb2..435ef7d5470fd8e8e6c4849c1d3dc930a13e1b3f 100644 (file)
@@ -325,8 +325,6 @@ static void tms380tr_timer_end_wait(unsigned long data)
                tp->Sleeping = 0;
                wake_up_interruptible(&tp->wait_for_tok_int);
        }
-
-       return;
 }
 
 /*
@@ -460,8 +458,6 @@ static void tms380tr_init_net_local(struct net_device *dev)
        tp->RplHead = &tp->Rpl[0];
        tp->RplTail = &tp->Rpl[RPL_NUM-1];
        tp->RplTail->Status = (RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ);
-
-       return;
 }
 
 /*
@@ -481,8 +477,6 @@ static void tms380tr_init_ipb(struct net_local *tp)
        tp->ipb.DMA_Abort_Thrhld = DMA_RETRIES;
        tp->ipb.SCB_Addr        = 0;
        tp->ipb.SSB_Addr        = 0;
-
-       return;
 }
 
 /*
@@ -527,8 +521,6 @@ static void tms380tr_init_opb(struct net_device *dev)
 
        tp->ocpl.ProdIDAddr[0]   = LOWORD(Addr);
        tp->ocpl.ProdIDAddr[1]   = HIWORD(Addr);
-
-       return;
 }
 
 /*
@@ -543,8 +535,6 @@ static void tms380tr_open_adapter(struct net_device *dev)
 
        tp->OpenCommandIssued = 1;
        tms380tr_exec_cmd(dev, OC_OPEN);
-
-       return;
 }
 
 /*
@@ -554,8 +544,6 @@ static void tms380tr_open_adapter(struct net_device *dev)
 static void tms380tr_disable_interrupts(struct net_device *dev)
 {
        SIFWRITEB(0, SIFACL);
-
-       return;
 }
 
 /*
@@ -565,8 +553,6 @@ static void tms380tr_disable_interrupts(struct net_device *dev)
 static void tms380tr_enable_interrupts(struct net_device *dev)
 {
        SIFWRITEB(ACL_SINTEN, SIFACL);
-
-       return;
 }
 
 /*
@@ -578,8 +564,6 @@ static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command)
 
        tp->CMDqueue |= Command;
        tms380tr_chk_outstanding_cmds(dev);
-
-       return;
 }
 
 static void tms380tr_timeout(struct net_device *dev)
@@ -592,7 +576,7 @@ static void tms380tr_timeout(struct net_device *dev)
         * fake transmission time and go on trying. Our own timeout
         * routine is in tms380tr_timer_chk()
         */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(dev);
 }
 
@@ -712,8 +696,6 @@ static void tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr)
        SRBit = frame[8] & 0x80;
        memcpy(&frame[8], hw_addr, 6);
        frame[8] |= SRBit;
-
-       return;
 }
 
 /*
@@ -743,8 +725,6 @@ static void tms380tr_timer_chk(unsigned long data)
                return;
        tp->ReOpenInProgress = 1;
        tms380tr_open_adapter(dev);
-
-       return;
 }
 
 /*
@@ -863,8 +843,6 @@ static void tms380tr_reset_interrupt(struct net_device *dev)
         * and clear STS_SYSTEM_IRQ bit: enable adapter for further interrupts.
         */
        tms380tr_exec_sifcmd(dev, CMD_SSB_CLEAR | CMD_CLEAR_SYSTEM_IRQ);
-
-       return;
 }
 
 /*
@@ -1119,8 +1097,6 @@ static void tms380tr_cmd_status_irq(struct net_device *dev)
                tp->MacStat.frequency_errors += tp->errorlogtable.Frequency_Error;
                tp->MacStat.internal_errors += tp->errorlogtable.Internal_Error;
        }
-
-       return;
 }
 
 /*
@@ -1211,17 +1187,17 @@ static void tms380tr_set_multicast_list(struct net_device *dev)
                }
                else
                {
-                       struct dev_mc_list *mclist;
+                       struct netdev_hw_addr *ha;
 
-                       netdev_for_each_mc_addr(mclist, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                ((char *)(&tp->ocpl.FunctAddr))[0] |=
-                                       mclist->dmi_addr[2];
+                                       ha->addr[2];
                                ((char *)(&tp->ocpl.FunctAddr))[1] |=
-                                       mclist->dmi_addr[3];
+                                       ha->addr[3];
                                ((char *)(&tp->ocpl.FunctAddr))[2] |=
-                                       mclist->dmi_addr[4];
+                                       ha->addr[4];
                                ((char *)(&tp->ocpl.FunctAddr))[3] |=
-                                       mclist->dmi_addr[5];
+                                       ha->addr[5];
                        }
                }
                tms380tr_exec_cmd(dev, OC_SET_FUNCT_ADDR);
@@ -1229,7 +1205,6 @@ static void tms380tr_set_multicast_list(struct net_device *dev)
        
        tp->ocpl.OPENOptions = OpenOptions;
        tms380tr_exec_cmd(dev, OC_MODIFY_OPEN_PARMS);
-       return;
 }
 
 /*
@@ -1247,7 +1222,6 @@ void tms380tr_wait(unsigned long time)
 #else
        udelay(time);
 #endif
-       return;
 }
 
 /*
@@ -1266,8 +1240,6 @@ static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue
                SifStsValue = SIFREADW(SIFSTS);
        } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--);
        SIFWRITEW(cmd, SIFCMD);
-
-       return;
 }
 
 /*
@@ -1390,7 +1362,7 @@ static int tms380tr_bringup_diags(struct net_device *dev)
                        Status &= STS_MASK;
 
                        if(tms380tr_debug > 3)
-                               printk(KERN_DEBUG " %04X \n", Status);
+                               printk(KERN_DEBUG " %04X\n", Status);
                        /* BUD successfully completed */
                        if(Status == STS_INITIALIZE)
                                return (1);
@@ -1700,8 +1672,6 @@ static void tms380tr_chk_outstanding_cmds(struct net_device *dev)
 
        /* Execute SCB and generate IRQ when done. */
        tms380tr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST);
-
-       return;
 }
 
 /*
@@ -1774,8 +1744,6 @@ static void tms380tr_ring_status_irq(struct net_device *dev)
                tp->AdapterOpenFlag = 0;
                tms380tr_open_adapter(dev);
        }
-
-       return;
 }
 
 /*
@@ -1846,7 +1814,7 @@ static void tms380tr_chk_irq(struct net_device *dev)
                        break;
 
                case DMA_WRITE_ABORT:
-                       printk(KERN_INFO "%s: DMA write operation aborted: \n",
+                       printk(KERN_INFO "%s: DMA write operation aborted:\n",
                                dev->name);
                        switch (AdapterCheckBlock[1])
                        {
@@ -1932,8 +1900,6 @@ static void tms380tr_chk_irq(struct net_device *dev)
                /* Restart of firmware successful */
                tp->AdapterOpenFlag = 1;
        }
-
-       return;
 }
 
 /*
@@ -1988,8 +1954,6 @@ static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data,
        /* Restore original values */
        SIFWRITEW(old_sifadx, SIFADX);
        SIFWRITEW(old_sifadr, SIFADR);
-
-       return;
 }
 
 /*
@@ -2021,8 +1985,6 @@ static void tms380tr_cancel_tx_queue(struct net_local* tp)
                        dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_any(tpl->Skb);
        }
-
-       return;
 }
 
 /*
@@ -2094,7 +2056,6 @@ static void tms380tr_tx_status_irq(struct net_device *dev)
 
        if(!tp->TplFree->NextTPLPtr->BusyFlag)
                netif_wake_queue(dev);
-       return;
 }
 
 /*
@@ -2255,8 +2216,6 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
                /* Inform adapter about RPL valid. */
                tms380tr_exec_sifcmd(dev, CMD_RX_VALID);
        }
-
-       return;
 }
 
 /*
@@ -2269,8 +2228,6 @@ static void tms380tr_rcv_status_irq(struct net_device *dev)
 static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status)
 {
        rpl->Status = Status;
-
-       return;
 }
 
 /*
@@ -2287,8 +2244,6 @@ static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPt
        /* Test functional bit */
        if(DataPtr[2] & GROUP_BIT)
                tp->MacStat.multicast++;
-
-       return;
 }
 
 static int tms380tr_set_mac_address(struct net_device *dev, void *addr)
@@ -2318,8 +2273,6 @@ static void tms380tr_dump(unsigned char *Data, int length)
                       Data[j+0],Data[j+1],Data[j+2],Data[j+3],
                       Data[j+4],Data[j+5],Data[j+6],Data[j+7]);
        }
-
-       return;
 }
 #endif
 
index 5b1fbb3c3b516871635d3a3aa6cd68c245ce0d76..a03730bd1da54aaee6073921e2a6ddd08a137e36 100644 (file)
@@ -263,7 +263,7 @@ static inline void tsi108_write_tbi(struct tsi108_prv_data *data,
                        return;
                udelay(10);
        }
-       printk(KERN_ERR "%s function time out \n", __func__);
+       printk(KERN_ERR "%s function time out\n", __func__);
 }
 
 static int mii_speed(struct mii_if_info *mii)
@@ -704,8 +704,8 @@ static int tsi108_send_packet(struct sk_buff * skb, struct net_device *dev)
 
                if (i == 0) {
                        data->txring[tx].buf0 = dma_map_single(NULL, skb->data,
-                                       skb->len - skb->data_len, DMA_TO_DEVICE);
-                       data->txring[tx].len = skb->len - skb->data_len;
+                                       skb_headlen(skb), DMA_TO_DEVICE);
+                       data->txring[tx].len = skb_headlen(skb);
                        misc |= TSI108_TX_SOF;
                } else {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
@@ -1056,7 +1056,7 @@ static void tsi108_stop_ethernet(struct net_device *dev)
                        return;
                udelay(10);
        }
-       printk(KERN_ERR "%s function time out \n", __func__);
+       printk(KERN_ERR "%s function time out\n", __func__);
 }
 
 static void tsi108_reset_ether(struct tsi108_prv_data * data)
@@ -1186,15 +1186,15 @@ static void tsi108_set_rx_mode(struct net_device *dev)
 
        if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) {
                int i;
-               struct dev_mc_list *mc;
+               struct netdev_hw_addr *ha;
                rxcfg |= TSI108_EC_RXCFG_MFE | TSI108_EC_RXCFG_MC_HASH;
 
                memset(data->mc_hash, 0, sizeof(data->mc_hash));
 
-               netdev_for_each_mc_addr(mc, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        u32 hash, crc;
 
-                       crc = ether_crc(6, mc->dmi_addr);
+                       crc = ether_crc(6, ha->addr);
                        hash = crc >> 23;
                        __set_bit(hash, &data->mc_hash[0]);
                }
@@ -1233,7 +1233,7 @@ static void tsi108_init_phy(struct net_device *dev)
                udelay(10);
        }
        if (i == 0)
-               printk(KERN_ERR "%s function time out \n", __func__);
+               printk(KERN_ERR "%s function time out\n", __func__);
 
        if (data->phy_type == TSI108_PHY_BCM54XX) {
                tsi108_write_mii(data, 0x09, 0x0300);
index 19cafc2b418dab716bebfab2005eee7efd61bb1e..c0e70006374e826930f8797b1c1c2a65710ea78c 100644 (file)
@@ -654,7 +654,6 @@ static netdev_tx_t de_start_xmit (struct sk_buff *skb,
 
        /* Trigger an immediate transmit demand. */
        dw32(TxPoll, NormalTxPoll);
-       dev->trans_start = jiffies;
 
        return NETDEV_TX_OK;
 }
@@ -671,15 +670,15 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
 {
        struct de_private *de = netdev_priv(dev);
        u16 hash_table[32];
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        int i;
        u16 *eaddrs;
 
        memset(hash_table, 0, sizeof(hash_table));
        set_bit_le(255, hash_table);                    /* Broadcast entry */
        /* This should work on big-endian machines as well. */
-       netdev_for_each_mc_addr(mclist, dev) {
-               int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
+       netdev_for_each_mc_addr(ha, dev) {
+               int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff;
 
                set_bit_le(index, hash_table);
        }
@@ -700,13 +699,13 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
 static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
 {
        struct de_private *de = netdev_priv(dev);
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        u16 *eaddrs;
 
        /* We have <= 14 addresses so we can use the wonderful
           16 address perfect filtering of the Tulip. */
-       netdev_for_each_mc_addr(mclist, dev) {
-               eaddrs = (u16 *)mclist->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               eaddrs = (u16 *) ha->addr;
                *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
                *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
                *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
index 09b57193a16a146784aca8f2ccae616242e11b24..75a64c88cf7aaf9294137e932c40918fff354234 100644 (file)
@@ -1337,7 +1337,7 @@ de4x5_open(struct net_device *dev)
     }
 
     lp->interrupt = UNMASK_INTERRUPTS;
-    dev->trans_start = jiffies;
+    dev->trans_start = jiffies; /* prevent tx timeout */
 
     START_DE4X5;
 
@@ -1507,7 +1507,6 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
            outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
 
            lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-           dev->trans_start = jiffies;
 
            if (TX_BUFFS_AVAIL) {
                netif_start_queue(dev);         /* Another pkt may be queued */
@@ -1884,8 +1883,6 @@ de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len)
     if (lp->pktStats.bins[0] == 0) { /* Reset counters */
         memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
     }
-
-    return;
 }
 
 /*
@@ -1937,7 +1934,7 @@ set_multicast_list(struct net_device *dev)
 
            lp->tx_new = (++lp->tx_new) % lp->txRingSize;
            outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
-           dev->trans_start = jiffies;
+           dev->trans_start = jiffies; /* prevent tx timeout */
        }
     }
 }
@@ -1951,7 +1948,7 @@ static void
 SetMulticastFilter(struct net_device *dev)
 {
     struct de4x5_private *lp = netdev_priv(dev);
-    struct dev_mc_list *dmi;
+    struct netdev_hw_addr *ha;
     u_long iobase = dev->base_addr;
     int i, bit, byte;
     u16 hashcode;
@@ -1966,8 +1963,8 @@ SetMulticastFilter(struct net_device *dev)
     if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 14)) {
        omr |= OMR_PM;                       /* Pass all multicasts */
     } else if (lp->setup_f == HASH_PERF) {   /* Hash Filtering */
-       netdev_for_each_mc_addr(dmi, dev) {
-           addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+           addrs = ha->addr;
            if ((*addrs & 0x01) == 1) {      /* multicast address? */
                crc = ether_crc_le(ETH_ALEN, addrs);
                hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
@@ -1983,8 +1980,8 @@ SetMulticastFilter(struct net_device *dev)
            }
        }
     } else {                                 /* Perfect filtering */
-       netdev_for_each_mc_addr(dmi, dev) {
-           addrs = dmi->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+           addrs = ha->addr;
            for (i=0; i<ETH_ALEN; i++) {
                *(pa + (i&1)) = *addrs++;
                if (i & 0x01) pa += 4;
@@ -1992,8 +1989,6 @@ SetMulticastFilter(struct net_device *dev)
        }
     }
     outl(omr, DE4X5_OMR);
-
-    return;
 }
 
 #ifdef CONFIG_EISA
@@ -2188,8 +2183,6 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
            return;
        }
     }
-
-    return;
 }
 
 /*
@@ -3292,8 +3285,6 @@ de4x5_init_connection(struct net_device *dev)
     outl(POLL_DEMAND, DE4X5_TPD);
 
     netif_wake_queue(dev);
-
-    return;
 }
 
 /*
@@ -3665,8 +3656,6 @@ de4x5_free_rx_buffs(struct net_device *dev)
        lp->rx_ring[i].status = 0;
        lp->rx_skb[i] = (struct sk_buff *)1;    /* Dummy entry */
     }
-
-    return;
 }
 
 static void
@@ -3709,8 +3698,6 @@ de4x5_save_skbs(struct net_device *dev)
        lp->cache.save_cnt++;
        START_DE4X5;
     }
-
-    return;
 }
 
 static void
@@ -3742,8 +3729,6 @@ de4x5_rst_desc_ring(struct net_device *dev)
        lp->cache.save_cnt--;
        START_DE4X5;
     }
-
-    return;
 }
 
 static void
@@ -3772,8 +3757,6 @@ de4x5_cache_state(struct net_device *dev, int flag)
        }
        break;
     }
-
-    return;
 }
 
 static void
@@ -3846,8 +3829,6 @@ de4x5_setup_intr(struct net_device *dev)
        outl(sts, DE4X5_STS);
        ENABLE_IRQs;
     }
-
-    return;
 }
 
 /*
@@ -3880,8 +3861,6 @@ reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15)
     outl(csr13, DE4X5_SICR);
 
     mdelay(10);
-
-    return;
 }
 
 /*
@@ -3902,8 +3881,6 @@ create_packet(struct net_device *dev, char *frame, int len)
 
     *buf++ = 0;                              /* Packet length (2 bytes) */
     *buf++ = 1;
-
-    return;
 }
 
 /*
@@ -4007,8 +3984,6 @@ DevicePresent(struct net_device *dev, u_long aprom_addr)
        }
        de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
     }
-
-    return;
 }
 
 /*
@@ -4046,8 +4021,6 @@ enet_addr_rst(u_long aprom_addr)
            }
        }
     }
-
-    return;
 }
 
 /*
@@ -4187,8 +4160,6 @@ srom_repair(struct net_device *dev, int card)
        lp->useSROM = true;
        break;
     }
-
-    return;
 }
 
 /*
@@ -4262,8 +4233,6 @@ srom_latch(u_int command, u_long addr)
     sendto_srom(command, addr);
     sendto_srom(command | DT_CLK, addr);
     sendto_srom(command, addr);
-
-    return;
 }
 
 static void
@@ -4272,8 +4241,6 @@ srom_command(u_int command, u_long addr)
     srom_latch(command, addr);
     srom_latch(command, addr);
     srom_latch((command & 0x0000ff00) | DT_CS, addr);
-
-    return;
 }
 
 static void
@@ -4288,8 +4255,6 @@ srom_address(u_int command, u_long addr, u_char offset)
     udelay(1);
 
     i = (getfrom_srom(addr) >> 3) & 0x01;
-
-    return;
 }
 
 static short
@@ -4323,8 +4288,6 @@ srom_busy(u_int command, u_long addr)
    }
 
    sendto_srom(command & 0x0000ff00, addr);
-
-   return;
 }
 */
 
@@ -4333,8 +4296,6 @@ sendto_srom(u_int command, u_long addr)
 {
     outl(command, addr);
     udelay(1);
-
-    return;
 }
 
 static int
@@ -4433,8 +4394,6 @@ srom_init(struct net_device *dev)
            p += ((*p & BLOCK_LEN) + 1);
        }
     }
-
-    return;
 }
 
 /*
@@ -4463,8 +4422,6 @@ srom_exec(struct net_device *dev, u_char *p)
        outl(lp->cache.csr14, DE4X5_STRR);
        outl(lp->cache.csr13, DE4X5_SICR);
     }
-
-    return;
 }
 
 /*
@@ -4889,8 +4846,6 @@ mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
     mii_ta(MII_STWR, ioaddr);              /* Turn around time - 2 MDC       */
     data = mii_swap(data, 16);             /* Swap data bit ordering         */
     mii_wdata(data, 16, ioaddr);           /* Write data                     */
-
-    return;
 }
 
 static int
@@ -4916,8 +4871,6 @@ mii_wdata(int data, int len, u_long ioaddr)
        sendto_mii(MII_MWR | MII_WR, data, ioaddr);
        data >>= 1;
     }
-
-    return;
 }
 
 static void
@@ -4930,8 +4883,6 @@ mii_address(u_char addr, u_long ioaddr)
        sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
        addr >>= 1;
     }
-
-    return;
 }
 
 static void
@@ -4943,8 +4894,6 @@ mii_ta(u_long rw, u_long ioaddr)
     } else {
        getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
     }
-
-    return;
 }
 
 static int
@@ -4971,8 +4920,6 @@ sendto_mii(u32 command, int data, u_long ioaddr)
     udelay(1);
     outl(command | MII_MDC | j, ioaddr);
     udelay(1);
-
-    return;
 }
 
 static int
@@ -5077,7 +5024,7 @@ mii_get_phy(struct net_device *dev)
            lp->phy[k].spd.value = GENERIC_VALUE;  /* TX & T4, H/F Duplex    */
            lp->mii_cnt++;
            lp->active++;
-           printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name);
+           printk("%s: Using generic MII device control. If the board doesn't operate,\nplease mail the following dump to the author:\n", dev->name);
            j = de4x5_debug;
            de4x5_debug |= DEBUG_MII;
            de4x5_dbg_mii(dev, k);
@@ -5186,8 +5133,6 @@ gep_wr(s32 data, struct net_device *dev)
     } else if ((lp->chipset & ~0x00ff) == DC2114x) {
        outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
     }
-
-    return;
 }
 
 static int
@@ -5247,8 +5192,6 @@ yawn(struct net_device *dev, int state)
            break;
        }
     }
-
-    return;
 }
 
 static void
@@ -5290,8 +5233,6 @@ de4x5_parse_params(struct net_device *dev)
        }
        *q = t;
     }
-
-    return;
 }
 
 static void
@@ -5337,12 +5278,10 @@ de4x5_dbg_open(struct net_device *dev)
            }
        }
        printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
-       printk("Ring size: \nRX: %d\nTX: %d\n",
+       printk("Ring size:\nRX: %d\nTX: %d\n",
               (short)lp->rxRingSize,
               (short)lp->txRingSize);
     }
-
-    return;
 }
 
 static void
@@ -5369,8 +5308,6 @@ de4x5_dbg_mii(struct net_device *dev, int k)
            printk("MII 20:  %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
        }
     }
-
-    return;
 }
 
 static void
@@ -5395,8 +5332,6 @@ de4x5_dbg_media(struct net_device *dev)
        }
        lp->c_media = lp->media;
     }
-
-    return;
 }
 
 static void
@@ -5417,8 +5352,6 @@ de4x5_dbg_srom(struct de4x5_srom *p)
            printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
        }
     }
-
-    return;
 }
 
 static void
@@ -5440,8 +5373,6 @@ de4x5_dbg_rx(struct sk_buff *skb, int len)
          printk("\n");
        }
     }
-
-    return;
 }
 
 /*
index 9568156dea982aa8058479774a2ad1e59c8c7846..29e6c63d39fd3de1e10f8af2412c5532f898bc93 100644 (file)
@@ -1118,7 +1118,6 @@ static void dmfe_ethtool_get_wol(struct net_device *dev,
 
        wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
        wolinfo->wolopts = db->wol_mode;
-       return;
 }
 
 
@@ -1180,11 +1179,11 @@ static void dmfe_timer(unsigned long data)
 
        /* TX polling kick monitor */
        if ( db->tx_packet_cnt &&
-            time_after(jiffies, dev->trans_start + DMFE_TX_KICK) ) {
+            time_after(jiffies, dev_trans_start(dev) + DMFE_TX_KICK) ) {
                outl(0x1, dev->base_addr + DCR1);   /* Tx polling again */
 
                /* TX Timeout */
-               if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) {
+               if (time_after(jiffies, dev_trans_start(dev) + DMFE_TX_TIMEOUT) ) {
                        db->reset_TXtimeout++;
                        db->wait_reset = 1;
                        dev_warn(&dev->dev, "Tx timeout - resetting\n");
@@ -1453,7 +1452,7 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
 
 static void dm9132_id_table(struct DEVICE *dev)
 {
-       struct dev_mc_list *mcptr;
+       struct netdev_hw_addr *ha;
        u16 * addrptr;
        unsigned long ioaddr = dev->base_addr+0xc0;             /* ID Table */
        u32 hash_val;
@@ -1477,8 +1476,8 @@ static void dm9132_id_table(struct DEVICE *dev)
        hash_table[3] = 0x8000;
 
        /* the multicast address in Hash Table : 64 bits */
-       netdev_for_each_mc_addr(mcptr, dev) {
-               hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+       netdev_for_each_mc_addr(ha, dev) {
+               hash_val = cal_CRC((char *) ha->addr, 6, 0) & 0x3f;
                hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
        }
 
@@ -1496,7 +1495,7 @@ static void dm9132_id_table(struct DEVICE *dev)
 static void send_filter_frame(struct DEVICE *dev)
 {
        struct dmfe_board_info *db = netdev_priv(dev);
-       struct dev_mc_list *mcptr;
+       struct netdev_hw_addr *ha;
        struct tx_desc *txptr;
        u16 * addrptr;
        u32 * suptr;
@@ -1519,8 +1518,8 @@ static void send_filter_frame(struct DEVICE *dev)
        *suptr++ = 0xffff;
 
        /* fit the multicast address */
-       netdev_for_each_mc_addr(mcptr, dev) {
-               addrptr = (u16 *) mcptr->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrptr = (u16 *) ha->addr;
                *suptr++ = addrptr[0];
                *suptr++ = addrptr[1];
                *suptr++ = addrptr[2];
index 68b170ae4d15a3c3c0e9d4d85e1ad53ff0eaf1b8..a0c770ee4b6475d0c56235585afc167aa3c84c65 100644 (file)
@@ -396,8 +396,6 @@ void tulip_select_media(struct net_device *dev, int startup)
        tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
 
        mdelay(1);
-
-       return;
 }
 
 /*
index 966efa1a27d70ca01c0c8cf3fb6458cd72c90bf0..a63e64b6863d852def7dc6c1a2a8c6b9b081fe73 100644 (file)
@@ -67,7 +67,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5)
                 */
                if (tulip_media_cap[dev->if_port] & MediaIsMII)
                        return;
-               if (! tp->nwayset  ||  time_after(jiffies, dev->trans_start + 1*HZ)) {
+               if (! tp->nwayset || time_after(jiffies, dev_trans_start(dev) + 1*HZ)) {
                        tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
                        iowrite32(tp->csr6, ioaddr + CSR6);
                        iowrite32(0x30, ioaddr + CSR12);
index 3810db9dc2de3a4ae17067b1ba087e32004fbc66..254643ed945e60e068336dc7d8218fada93798b3 100644 (file)
@@ -605,7 +605,7 @@ static void tulip_tx_timeout(struct net_device *dev)
 
 out_unlock:
        spin_unlock_irqrestore (&tp->lock, flags);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue (dev);
 }
 
@@ -707,8 +707,6 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&tp->lock, flags);
 
-       dev->trans_start = jiffies;
-
        return NETDEV_TX_OK;
 }
 
@@ -991,15 +989,15 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
 {
        struct tulip_private *tp = netdev_priv(dev);
        u16 hash_table[32];
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        int i;
        u16 *eaddrs;
 
        memset(hash_table, 0, sizeof(hash_table));
        set_bit_le(255, hash_table);                    /* Broadcast entry */
        /* This should work on big-endian machines as well. */
-       netdev_for_each_mc_addr(mclist, dev) {
-               int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
+       netdev_for_each_mc_addr(ha, dev) {
+               int index = ether_crc_le(ETH_ALEN, ha->addr) & 0x1ff;
 
                set_bit_le(index, hash_table);
        }
@@ -1019,13 +1017,13 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
 static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
 {
        struct tulip_private *tp = netdev_priv(dev);
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        u16 *eaddrs;
 
        /* We have <= 14 addresses so we can use the wonderful
           16 address perfect filtering of the Tulip. */
-       netdev_for_each_mc_addr(mclist, dev) {
-               eaddrs = (u16 *)mclist->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               eaddrs = (u16 *) ha->addr;
                *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
                *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
                *setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
@@ -1062,7 +1060,7 @@ static void set_rx_mode(struct net_device *dev)
        } else  if (tp->flags & MC_HASH_ONLY) {
                /* Some work-alikes have only a 64-entry hash filter table. */
                /* Should verify correctness on big-endian/__powerpc__ */
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                if (netdev_mc_count(dev) > 64) {
                        /* Arbitrary non-effective limit. */
                        tp->csr6 |= AcceptAllMulticast;
@@ -1070,18 +1068,21 @@ static void set_rx_mode(struct net_device *dev)
                } else {
                        u32 mc_filter[2] = {0, 0};               /* Multicast hash filter */
                        int filterbit;
-                       netdev_for_each_mc_addr(mclist, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                if (tp->flags & COMET_MAC_ADDR)
-                                       filterbit = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
+                                       filterbit = ether_crc_le(ETH_ALEN,
+                                                                ha->addr);
                                else
-                                       filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+                                       filterbit = ether_crc(ETH_ALEN,
+                                                             ha->addr) >> 26;
                                filterbit &= 0x3f;
                                mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
                                if (tulip_debug > 2)
                                        dev_info(&dev->dev,
                                                 "Added filter for %pM  %08x bit %d\n",
-                                                mclist->dmi_addr,
-                                                ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+                                                ha->addr,
+                                                ether_crc(ETH_ALEN, ha->addr),
+                                                filterbit);
                        }
                        if (mc_filter[0] == tp->mc_filter[0]  &&
                                mc_filter[1] == tp->mc_filter[1])
index a589dd34891ee646e279b7a8de15c42d5c49a393..96de5829b940806729f02fa26eeb7537713e821d 100644 (file)
@@ -1040,11 +1040,11 @@ static void uli526x_timer(unsigned long data)
 
        /* TX polling kick monitor */
        if ( db->tx_packet_cnt &&
-            time_after(jiffies, dev->trans_start + ULI526X_TX_KICK) ) {
+            time_after(jiffies, dev_trans_start(dev) + ULI526X_TX_KICK) ) {
                outl(0x1, dev->base_addr + DCR1);   // Tx polling again
 
                // TX Timeout
-               if ( time_after(jiffies, dev->trans_start + ULI526X_TX_TIMEOUT) ) {
+               if ( time_after(jiffies, dev_trans_start(dev) + ULI526X_TX_TIMEOUT) ) {
                        db->reset_TXtimeout++;
                        db->wait_reset = 1;
                        printk( "%s: Tx timeout - resetting\n",
@@ -1393,7 +1393,7 @@ static void update_cr6(u32 cr6_data, unsigned long ioaddr)
 static void send_filter_frame(struct net_device *dev, int mc_cnt)
 {
        struct uli526x_board_info *db = netdev_priv(dev);
-       struct dev_mc_list *mcptr;
+       struct netdev_hw_addr *ha;
        struct tx_desc *txptr;
        u16 * addrptr;
        u32 * suptr;
@@ -1416,8 +1416,8 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
        *suptr++ = 0xffff << FLT_SHIFT;
 
        /* fit the multicast address */
-       netdev_for_each_mc_addr(mcptr, dev) {
-               addrptr = (u16 *) mcptr->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addrptr = (u16 *) ha->addr;
                *suptr++ = addrptr[0] << FLT_SHIFT;
                *suptr++ = addrptr[1] << FLT_SHIFT;
                *suptr++ = addrptr[2] << FLT_SHIFT;
index 98dbf6cc1d683d5e6fc5746ae76b85d8ba696e01..608b279b921b20a033d906b28929f4711d77495a 100644 (file)
@@ -626,7 +626,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
                iowrite32(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
                mdio_delay(mdio_addr);
        }
-       return;
 }
 
 
@@ -969,9 +968,8 @@ static void tx_timeout(struct net_device *dev)
        enable_irq(dev->irq);
 
        netif_wake_queue(dev);
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        np->stats.tx_errors++;
-       return;
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -1055,8 +1053,6 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        }
        spin_unlock_irq(&np->lock);
 
-       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);
@@ -1366,13 +1362,15 @@ static u32 __set_rx_mode(struct net_device *dev)
                memset(mc_filter, 0xff, sizeof(mc_filter));
                rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int filterbit = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F;
-                       filterbit &= 0x3f;
-                       mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
+               netdev_for_each_mc_addr(ha, dev) {
+                       int filbit;
+
+                       filbit = (ether_crc(ETH_ALEN, ha->addr) >> 26) ^ 0x3F;
+                       filbit &= 0x3f;
+                       mc_filter[filbit >> 5] |= 1 << (filbit & 31);
                }
                rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
        }
index acfeeb980562d9a72df7f21f3e50c82be0f7280b..a439e93be22d24132f29e6b146b9d1a0af430178 100644 (file)
@@ -350,9 +350,9 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
 
 #ifdef DEBUG
        print_binary(status);
-       printk("tx status 0x%08x 0x%08x \n",
+       printk("tx status 0x%08x 0x%08x\n",
               card->tx_buffer[0], card->tx_buffer[4]);
-       printk("rx status 0x%08x 0x%08x \n",
+       printk("rx status 0x%08x 0x%08x\n",
               card->rx_buffer[0], card->rx_buffer[4]);
 #endif
        /* Handle shared irq and hotplug */
@@ -462,7 +462,7 @@ static int xircom_open(struct net_device *dev)
        struct xircom_private *xp = netdev_priv(dev);
        int retval;
        enter("xircom_open");
-       pr_info("xircom cardbus adaptor found, registering as %s, using irq %i \n",
+       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) {
index 43265207d46370c97789a4ac264acc2d4238dbad..97b25533e5fb1dd741bc7a2541ed598014707a99 100644 (file)
@@ -109,6 +109,9 @@ struct tun_struct {
 
        struct tap_filter       txflt;
        struct socket           socket;
+       struct socket_wq        wq;
+
+       int                     vnet_hdr_sz;
 
 #ifdef TUN_DEBUG
        int debug;
@@ -323,7 +326,7 @@ static void tun_net_uninit(struct net_device *dev)
        /* Inform the methods they need to stop using the dev.
         */
        if (tfile) {
-               wake_up_all(&tun->socket.wait);
+               wake_up_all(&tun->wq.wait);
                if (atomic_dec_and_test(&tfile->count))
                        __tun_detach(tun);
        }
@@ -393,12 +396,11 @@ static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Enqueue packet */
        skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb);
-       dev->trans_start = jiffies;
 
        /* Notify and wake up reader process */
        if (tun->flags & TUN_FASYNC)
                kill_fasync(&tun->fasync, SIGIO, POLL_IN);
-       wake_up_interruptible_poll(&tun->socket.wait, POLLIN |
+       wake_up_interruptible_poll(&tun->wq.wait, POLLIN |
                                   POLLRDNORM | POLLRDBAND);
        return NETDEV_TX_OK;
 
@@ -415,7 +417,6 @@ static void tun_net_mclist(struct net_device *dev)
         * _rx_ path and has nothing to do with the _tx_ path.
         * In rx path we always accept everything userspace gives us.
         */
-       return;
 }
 
 #define MIN_MTU 68
@@ -498,7 +499,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 
        DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
 
-       poll_wait(file, &tun->socket.wait, wait);
+       poll_wait(file, &tun->wq.wait, wait);
 
        if (!skb_queue_empty(&sk->sk_receive_queue))
                mask |= POLLIN | POLLRDNORM;
@@ -563,7 +564,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
        }
 
        if (tun->flags & TUN_VNET_HDR) {
-               if ((len -= sizeof(gso)) > count)
+               if ((len -= tun->vnet_hdr_sz) > count)
                        return -EINVAL;
 
                if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso)))
@@ -575,7 +576,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
 
                if (gso.hdr_len > len)
                        return -EINVAL;
-               offset += sizeof(gso);
+               offset += tun->vnet_hdr_sz;
        }
 
        if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
@@ -718,7 +719,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
 
        if (tun->flags & TUN_VNET_HDR) {
                struct virtio_net_hdr gso = { 0 }; /* no info leak */
-               if ((len -= sizeof(gso)) < 0)
+               if ((len -= tun->vnet_hdr_sz) < 0)
                        return -EINVAL;
 
                if (skb_is_gso(skb)) {
@@ -749,7 +750,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
                if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
                                               sizeof(gso))))
                        return -EFAULT;
-               total += sizeof(gso);
+               total += tun->vnet_hdr_sz;
        }
 
        len = min_t(int, skb->len, len);
@@ -773,7 +774,7 @@ static ssize_t tun_do_read(struct tun_struct *tun,
 
        DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
 
-       add_wait_queue(&tun->socket.wait, &wait);
+       add_wait_queue(&tun->wq.wait, &wait);
        while (len) {
                current->state = TASK_INTERRUPTIBLE;
 
@@ -804,7 +805,7 @@ static ssize_t tun_do_read(struct tun_struct *tun,
        }
 
        current->state = TASK_RUNNING;
-       remove_wait_queue(&tun->socket.wait, &wait);
+       remove_wait_queue(&tun->wq.wait, &wait);
 
        return ret;
 }
@@ -861,6 +862,7 @@ static struct rtnl_link_ops tun_link_ops __read_mostly = {
 static void tun_sock_write_space(struct sock *sk)
 {
        struct tun_struct *tun;
+       wait_queue_head_t *wqueue;
 
        if (!sock_writeable(sk))
                return;
@@ -868,8 +870,9 @@ static void tun_sock_write_space(struct sock *sk)
        if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
                return;
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+       wqueue = sk_sleep(sk);
+       if (wqueue && waitqueue_active(wqueue))
+               wake_up_interruptible_sync_poll(wqueue, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
 
        tun = tun_sk(sk)->tun;
@@ -1033,13 +1036,15 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                tun->dev = dev;
                tun->flags = flags;
                tun->txflt.count = 0;
+               tun->vnet_hdr_sz = sizeof(struct virtio_net_hdr);
 
                err = -ENOMEM;
                sk = sk_alloc(net, AF_UNSPEC, GFP_KERNEL, &tun_proto);
                if (!sk)
                        goto err_free_dev;
 
-               init_waitqueue_head(&tun->socket.wait);
+               tun->socket.wq = &tun->wq;
+               init_waitqueue_head(&tun->wq.wait);
                tun->socket.ops = &tun_socket_ops;
                sock_init_data(&tun->socket, sk);
                sk->sk_write_space = tun_sock_write_space;
@@ -1174,6 +1179,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        struct sock_fprog fprog;
        struct ifreq ifr;
        int sndbuf;
+       int vnet_hdr_sz;
        int ret;
 
        if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
@@ -1319,6 +1325,25 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
                tun->socket.sk->sk_sndbuf = sndbuf;
                break;
 
+       case TUNGETVNETHDRSZ:
+               vnet_hdr_sz = tun->vnet_hdr_sz;
+               if (copy_to_user(argp, &vnet_hdr_sz, sizeof(vnet_hdr_sz)))
+                       ret = -EFAULT;
+               break;
+
+       case TUNSETVNETHDRSZ:
+               if (copy_from_user(&vnet_hdr_sz, argp, sizeof(vnet_hdr_sz))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (vnet_hdr_sz < (int)sizeof(struct virtio_net_hdr)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               tun->vnet_hdr_sz = vnet_hdr_sz;
+               break;
+
        case TUNATTACHFILTER:
                /* Can be set only for TAPs */
                ret = -EINVAL;
@@ -1342,7 +1367,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
        default:
                ret = -EINVAL;
                break;
-       };
+       }
 
 unlock:
        rtnl_unlock();
index 98d818daa77ecae5f95b8ac8b4cfe0b7f6ca4d41..22bde49262c075de51aedc7ae75a4a9cefb79387 100644 (file)
@@ -881,8 +881,6 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
        wmb();
        iowrite32(txRing->lastWrite, tp->tx_ioaddr + txRing->writeRegister);
 
-       dev->trans_start = jiffies;
-
        /* If we don't have room to put the worst case packet on the
         * queue, then we must stop the queue. We need 2 extra
         * descriptors -- one to prevent ring wrap, and one for the
@@ -920,11 +918,11 @@ typhoon_set_rx_mode(struct net_device *dev)
                /* Too many to match, or accept all multicasts. */
                filter |= TYPHOON_RX_FILTER_ALL_MCAST;
        } else if (!netdev_mc_empty(dev)) {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit = ether_crc(ETH_ALEN, ha->addr) & 0x3f;
                        mc_filter[bit >> 5] |= 1 << (bit & 0x1f);
                }
 
index 1b0aef37e495a656a266eca8fa2a03a500a64a04..932602db54b39c09b1c7bbb9e62e6a663c356903 100644 (file)
@@ -1999,7 +1999,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
 static void ucc_geth_set_multi(struct net_device *dev)
 {
        struct ucc_geth_private *ugeth;
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
        struct ucc_fast __iomem *uf_regs;
        struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
 
@@ -2028,16 +2028,16 @@ static void ucc_geth_set_multi(struct net_device *dev)
                        out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
                        out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
 
-                       netdev_for_each_mc_addr(dmi, dev) {
+                       netdev_for_each_mc_addr(ha, dev) {
                                /* Only support group multicast for now.
                                 */
-                               if (!(dmi->dmi_addr[0] & 1))
+                               if (!(ha->addr[0] & 1))
                                        continue;
 
                                /* Ask CPM to run CRC and set bit in
                                 * filter mask.
                                 */
-                               hw_add_addr_in_hash(ugeth, dmi->dmi_addr);
+                               hw_add_addr_in_hash(ugeth, ha->addr);
                        }
                }
        }
@@ -3148,8 +3148,6 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* set bd status and length */
        out_be32((u32 __iomem *)bd, bd_status);
 
-       dev->trans_start = jiffies;
-
        /* Move to next BD in the ring */
        if (!(bd_status & T_W))
                bd += sizeof(struct qe_bd);
@@ -3883,7 +3881,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        }
 
        if (netif_msg_probe(&debug))
-               printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
+               printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d)\n",
                        ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
                        ug_info->uf_info.irq);
 
index 35f56fc828032090512658216b56b712bf035999..31b73310ec77db754d458fedeabd6ecea81ab4d1 100644 (file)
@@ -224,10 +224,9 @@ static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
                   cmd, value, index, size);
 
        if (data) {
-               buf = kmalloc(size, GFP_KERNEL);
+               buf = kmemdup(data, size, GFP_KERNEL);
                if (!buf)
                        goto out;
-               memcpy(buf, data, size);
        }
 
        err = usb_control_msg(
@@ -322,8 +321,29 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                /* get the packet length */
                size = (u16) (header & 0x0000ffff);
 
-               if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+               if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
+                       u8 alignment = (u32)skb->data & 0x3;
+                       if (alignment != 0x2) {
+                               /*
+                                * not 16bit aligned so use the room provided by
+                                * the 32 bit header to align the data
+                                *
+                                * note we want 16bit alignment as MAC header is
+                                * 14bytes thus ip header will be aligned on
+                                * 32bit boundary so accessing ipheader elements
+                                * using a cast to struct ip header wont cause
+                                * an unaligned accesses.
+                                */
+                               u8 realignment = (alignment + 2) & 0x3;
+                               memmove(skb->data - realignment,
+                                       skb->data,
+                                       size);
+                               skb->data -= realignment;
+                               skb_set_tail_pointer(skb, size);
+                       }
                        return 2;
+               }
+
                if (size > ETH_FRAME_LEN) {
                        netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
                                   size);
@@ -331,7 +351,18 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                }
                ax_skb = skb_clone(skb, GFP_ATOMIC);
                if (ax_skb) {
+                       u8 alignment = (u32)packet & 0x3;
                        ax_skb->len = size;
+
+                       if (alignment != 0x2) {
+                               /*
+                                * not 16bit aligned use the room provided by
+                                * the 32 bit header to align the data
+                                */
+                               u8 realignment = (alignment + 2) & 0x3;
+                               memmove(packet - realignment, packet, size);
+                               packet -= realignment;
+                       }
                        ax_skb->data = packet;
                        skb_set_tail_pointer(ax_skb, size);
                        usbnet_skb_return(dev, ax_skb);
@@ -558,16 +589,14 @@ static void asix_set_multicast(struct net_device *net)
                 * for our 8 byte filter buffer
                 * to avoid allocating memory that
                 * is tricky to free later */
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
                u32 crc_bits;
 
                memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
 
                /* Build the multicast hash filter. */
-               netdev_for_each_mc_addr(mc_list, net) {
-                       crc_bits =
-                           ether_crc(ETH_ALEN,
-                                     mc_list->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, net) {
+                       crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
                        data->multi_filter[crc_bits >> 3] |=
                            1 << (crc_bits & 7);
                }
@@ -794,16 +823,14 @@ static void ax88172_set_multicast(struct net_device *net)
                 * for our 8 byte filter buffer
                 * to avoid allocating memory that
                 * is tricky to free later */
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
                u32 crc_bits;
 
                memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
 
                /* Build the multicast hash filter. */
-               netdev_for_each_mc_addr(mc_list, net) {
-                       crc_bits =
-                           ether_crc(ETH_ALEN,
-                                     mc_list->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, net) {
+                       crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
                        data->multi_filter[crc_bits >> 3] |=
                            1 << (crc_bits & 7);
                }
index 602e123b2741672994755fa9884a57f167b39bda..97687d335903148d7edfa6ba9f55bbd4e02331b0 100644 (file)
@@ -629,7 +629,7 @@ static void catc_multicast(unsigned char *addr, u8 *multicast)
 static void catc_set_multicast_list(struct net_device *netdev)
 {
        struct catc *catc = netdev_priv(netdev);
-       struct dev_mc_list *mc;
+       struct netdev_hw_addr *ha;
        u8 broadcast[6];
        u8 rx = RxEnable | RxPolarity | RxMultiCast;
 
@@ -647,8 +647,8 @@ static void catc_set_multicast_list(struct net_device *netdev)
        if (netdev->flags & IFF_ALLMULTI) {
                memset(catc->multicast, 0xff, 64);
        } else {
-               netdev_for_each_mc_addr(mc, netdev) {
-                       u32 crc = ether_crc_le(6, mc->dmi_addr);
+               netdev_for_each_mc_addr(ha, netdev) {
+                       u32 crc = ether_crc_le(6, ha->addr);
                        if (!catc->is_f5u011) {
                                catc->multicast[(crc >> 3) & 0x3f] |= 1 << (crc & 7);
                        } else {
index 3547cf13d219c07ca56e7468ac2905b830c4959e..b3fe0de4046970dc27fbc31b478b9cce42cf9c63 100644 (file)
@@ -64,6 +64,11 @@ static int is_wireless_rndis(struct usb_interface_descriptor *desc)
 
 #endif
 
+static const u8 mbm_guid[16] = {
+       0xa3, 0x17, 0xa8, 0x8b, 0x04, 0x5e, 0x4f, 0x01,
+       0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a,
+};
+
 /*
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -79,6 +84,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
        int                             status;
        int                             rndis;
        struct usb_driver               *driver = driver_of(intf);
+       struct usb_cdc_mdlm_desc        *desc = NULL;
+       struct usb_cdc_mdlm_detail_desc *detail = NULL;
 
        if (sizeof dev->data < sizeof *info)
                return -EDOM;
@@ -229,6 +236,34 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                         * side link address we were given.
                         */
                        break;
+               case USB_CDC_MDLM_TYPE:
+                       if (desc) {
+                               dev_dbg(&intf->dev, "extra MDLM descriptor\n");
+                               goto bad_desc;
+                       }
+
+                       desc = (void *)buf;
+
+                       if (desc->bLength != sizeof(*desc))
+                               goto bad_desc;
+
+                       if (memcmp(&desc->bGUID, mbm_guid, 16))
+                               goto bad_desc;
+                       break;
+               case USB_CDC_MDLM_DETAIL_TYPE:
+                       if (detail) {
+                               dev_dbg(&intf->dev, "extra MDLM detail descriptor\n");
+                               goto bad_desc;
+                       }
+
+                       detail = (void *)buf;
+
+                       if (detail->bGuidDescriptorType == 0) {
+                               if (detail->bLength < (sizeof(*detail) + 1))
+                                       goto bad_desc;
+                       } else
+                               goto bad_desc;
+                       break;
                }
 next_desc:
                len -= buf [0]; /* bLength */
@@ -543,80 +578,10 @@ static const struct usb_device_id products [] = {
                        USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long) &cdc_info,
 }, {
-       /* Ericsson F3507g */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1900, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson F3507g ver. 2 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1902, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson F3607gw */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1904, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson F3607gw ver 2 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1905, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson F3607gw ver 3 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1906, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson F3307 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x190a, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson F3307 ver 2 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1909, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson C3607w */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1049, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Ericsson C3607w ver 2 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x190b, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Toshiba F3507g */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130b, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Toshiba F3607gw */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130c, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Toshiba F3607gw ver 2 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x1311, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Dell F3507g */
-       USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8147, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Dell F3607gw */
-       USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8183, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
-}, {
-       /* Dell F3607gw ver 2 */
-       USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x8184, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &mbm_info,
+       USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
+                       USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long)&mbm_info,
+
 },
        { },            // END
 };
index 5dfed9297b22fbe4f5b8aa568e20ed416ee8df72..02b622e3b9fb3b13a5457fe85d01bc1875125716 100644 (file)
@@ -93,10 +93,9 @@ static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data)
        netdev_dbg(dev->net, "dm_write() reg=0x%02x, length=%d\n", reg, length);
 
        if (data) {
-               buf = kmalloc(length, GFP_KERNEL);
+               buf = kmemdup(data, length, GFP_KERNEL);
                if (!buf)
                        goto out;
-               memcpy(buf, data, length);
        }
 
        err = usb_control_msg(dev->udev,
@@ -387,10 +386,10 @@ static void dm9601_set_multicast(struct net_device *net)
                   netdev_mc_count(net) > DM_MAX_MCAST) {
                rx_ctl |= 0x04;
        } else if (!netdev_mc_empty(net)) {
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
 
-               netdev_for_each_mc_addr(mc_list, net) {
-                       u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, net) {
+                       u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
                        hashes[crc >> 3] |= 1 << (crc & 0x7);
                }
        }
index be0cc99e881a6c4c41c8b8f502d0392f4be343e5..9964df199511879b4f5d73c0ca36014da972009e 100644 (file)
@@ -834,8 +834,6 @@ static netdev_tx_t hso_net_start_xmit(struct sk_buff *skb,
        } else {
                net->stats.tx_packets++;
                net->stats.tx_bytes += skb->len;
-               /* And tell the kernel when the last transmit started. */
-               net->trans_start = jiffies;
        }
        dev_kfree_skb(skb);
        /* we're done */
@@ -1474,7 +1472,6 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
        spin_unlock_irqrestore(&serial->serial_lock, flags);
 
        /* done */
-       return;
 }
 
 /* how many characters in the buffer */
@@ -1994,7 +1991,6 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
        hso_kick_transmit(serial);
 
        D1(" ");
-       return;
 }
 
 /* called for writing diag or CS serial port */
index c4c334d9770f9916f2f67c85661c6694fa5f4c25..46890dc625dcfb36a7692b277c7add70d63195dd 100644 (file)
@@ -856,7 +856,6 @@ skip:
        {
                kaweth->stats.tx_packets++;
                kaweth->stats.tx_bytes += skb->len;
-               net->trans_start = jiffies;
        }
 
        spin_unlock_irq(&kaweth->device_lock);
index 9f24e3f871e1ff67cdff9e9e4327cca53da3e867..a6281e3987b5c47d6a061e1bb45538000bd6745e 100644 (file)
@@ -142,12 +142,10 @@ static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, const void *
        int ret;
        void *buffer;
 
-       buffer = kmalloc(size, GFP_NOIO);
+       buffer = kmemdup(data, size, GFP_NOIO);
        if (buffer == NULL)
                return -ENOMEM;
 
-       memcpy(buffer, data, size);
-
        ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
                              MCS7830_WR_BMREQ, 0x0000, index, buffer,
                              size, MCS7830_CTRL_TIMEOUT);
@@ -453,12 +451,12 @@ static void mcs7830_data_set_multicast(struct net_device *net)
                 * for our 8 byte filter buffer
                 * to avoid allocating memory that
                 * is tricky to free later */
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
                u32 crc_bits;
 
                /* Build the multicast hash filter. */
-               netdev_for_each_mc_addr(mc_list, net) {
-                       crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, net) {
+                       crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
                        data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
                }
        }
index 41838773b568dca9674410a0c22c8390741941e6..974d17f0263e2229e5f64be97b2234ba684a7aea 100644 (file)
@@ -203,13 +203,12 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
        char *buffer;
        DECLARE_WAITQUEUE(wait, current);
 
-       buffer = kmalloc(size, GFP_KERNEL);
+       buffer = kmemdup(data, size, GFP_KERNEL);
        if (!buffer) {
                netif_warn(pegasus, drv, pegasus->net,
                           "out of memory in %s\n", __func__);
                return -ENOMEM;
        }
-       memcpy(buffer, data, size);
 
        add_wait_queue(&pegasus->ctrl_wait, &wait);
        set_current_state(TASK_UNINTERRUPTIBLE);
@@ -255,13 +254,12 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
        char *tmp;
        DECLARE_WAITQUEUE(wait, current);
 
-       tmp = kmalloc(1, GFP_KERNEL);
+       tmp = kmemdup(&data, 1, GFP_KERNEL);
        if (!tmp) {
                netif_warn(pegasus, drv, pegasus->net,
                           "out of memory in %s\n", __func__);
                return -ENOMEM;
        }
-       memcpy(tmp, &data, 1);
        add_wait_queue(&pegasus->ctrl_wait, &wait);
        set_current_state(TASK_UNINTERRUPTIBLE);
        while (pegasus->flags & ETH_REGS_CHANGED)
@@ -808,7 +806,7 @@ static void write_bulk_callback(struct urb *urb)
                break;
        }
 
-       net->trans_start = jiffies;
+       net->trans_start = jiffies; /* prevent tx timeout */
        netif_wake_queue(net);
 }
 
@@ -909,7 +907,6 @@ static netdev_tx_t pegasus_start_xmit(struct sk_buff *skb,
        } else {
                pegasus->stats.tx_packets++;
                pegasus->stats.tx_bytes += skb->len;
-               net->trans_start = jiffies;
        }
        dev_kfree_skb(skb);
 
index b90d8766ab744e4849e8524af510fca402944ea0..29f5211e645b0abcba70af272263a77b8ba12023 100644 (file)
@@ -256,7 +256,7 @@ PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
                DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
                DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "IO DATA USB ETX-US2", VENDOR_IODATA, 0x092a,
+PEGASUS_DEV( "IO DATA USB ETX-US2", VENDOR_IODATA, 0x093a,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
                DEFAULT_GPIO_RESET)
index dd8a4adf48cadf3d1c85507dc9c71c9d9c316004..28d3ee175e7bbffe697e00f0019c15636eeb6050 100644 (file)
@@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
 int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
 {
        struct cdc_state        *info = (void *) &dev->data;
+       struct usb_cdc_notification notification;
        int                     master_ifnum;
        int                     retval;
+       int                     partial;
        unsigned                count;
        __le32                  rsp;
        u32                     xid = 0, msg_len, request_id;
@@ -133,13 +135,17 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
        if (unlikely(retval < 0 || xid == 0))
                return retval;
 
-       // FIXME Seems like some devices discard responses when
-       // we time out and cancel our "get response" requests...
-       // so, this is fragile.  Probably need to poll for status.
+       /* Some devices don't respond on the control channel until
+        * polled on the status channel, so do that first. */
+       retval = usb_interrupt_msg(
+               dev->udev,
+               usb_rcvintpipe(dev->udev, dev->status->desc.bEndpointAddress),
+               &notification, sizeof(notification), &partial,
+               RNDIS_CONTROL_TIMEOUT_MS);
+       if (unlikely(retval < 0))
+               return retval;
 
-       /* ignore status endpoint, just poll the control channel;
-        * the request probably completed immediately
-        */
+       /* Poll the control channel; the request probably completed immediately */
        rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
        for (count = 0; count < 10; count++) {
                memset(buf, 0, CONTROL_BUFFER_SIZE);
index 35b98b1b79e479f8ecf9924fe16aa72dddba7b5e..753ee6eb7eddee40c44b52f1b3cfb15987c5467a 100644 (file)
@@ -445,14 +445,14 @@ static void smsc75xx_set_multicast(struct net_device *netdev)
                netif_dbg(dev, drv, dev->net, "receive all multicast enabled");
                pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF;
        } else if (!netdev_mc_empty(dev->net)) {
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
 
                netif_dbg(dev, drv, dev->net, "receive multicast hash filter");
 
                pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF;
 
-               netdev_for_each_mc_addr(mc_list, netdev) {
-                       u32 bitnum = smsc75xx_hash(mc_list->dmi_addr);
+               netdev_for_each_mc_addr(ha, netdev) {
+                       u32 bitnum = smsc75xx_hash(ha->addr);
                        pdata->multicast_hash_table[bitnum / 32] |=
                                (1 << (bitnum % 32));
                }
index 3135af63d3785f8ba38cfe3b516841bfdc2a1c92..12a3c88c52821fdfb44c05ca964ef3bb022ce3c4 100644 (file)
@@ -385,13 +385,13 @@ static void smsc95xx_set_multicast(struct net_device *netdev)
                pdata->mac_cr |= MAC_CR_MCPAS_;
                pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_HPFILT_);
        } else if (!netdev_mc_empty(dev->net)) {
-               struct dev_mc_list *mc_list;
+               struct netdev_hw_addr *ha;
 
                pdata->mac_cr |= MAC_CR_HPFILT_;
                pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_);
 
-               netdev_for_each_mc_addr(mc_list, netdev) {
-                       u32 bitnum = smsc95xx_hash(mc_list->dmi_addr);
+               netdev_for_each_mc_addr(ha, netdev) {
+                       u32 bitnum = smsc95xx_hash(ha->addr);
                        u32 mask = 0x01 << (bitnum & 0x1F);
                        if (bitnum & 0x20)
                                hash_hi |= mask;
index 7177abc78dc6b664fbe722a8bb18263ad7c3d1b1..a95c73de5824c67f7bd3ca471a4e8697c16ffd34 100644 (file)
@@ -1069,12 +1069,15 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
         * NOTE:  strictly conforming cdc-ether devices should expect
         * the ZLP here, but ignore the one-byte packet.
         */
-       if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) {
-               urb->transfer_buffer_length++;
-               if (skb_tailroom(skb)) {
-                       skb->data[skb->len] = 0;
-                       __skb_put(skb, 1);
-               }
+       if (length % dev->maxpacket == 0) {
+               if (!(info->flags & FLAG_SEND_ZLP)) {
+                       urb->transfer_buffer_length++;
+                       if (skb_tailroom(skb)) {
+                               skb->data[skb->len] = 0;
+                               __skb_put(skb, 1);
+                       }
+               } else
+                       urb->transfer_flags |= URB_ZERO_PACKET;
        }
 
        spin_lock_irqsave(&dev->txq.lock, flags);
index 388751aa66e05f287ec40422936a30bac95d4407..4930f9dbc493d50d2b46f7829d62541bc8b1e646 100644 (file)
@@ -1209,7 +1209,7 @@ static void rhine_reset_task(struct work_struct *work)
        spin_unlock_bh(&rp->lock);
        enable_irq(rp->pdev->irq);
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        dev->stats.tx_errors++;
        netif_wake_queue(dev);
 }
@@ -1294,8 +1294,6 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
        if (rp->cur_tx == rp->dirty_tx + TX_QUEUE_LEN)
                netif_stop_queue(dev);
 
-       dev->trans_start = jiffies;
-
        spin_unlock_irqrestore(&rp->lock, flags);
 
        if (debug > 4) {
@@ -1703,11 +1701,11 @@ static void rhine_set_rx_mode(struct net_device *dev)
                iowrite32(0xffffffff, ioaddr + MulticastFilter1);
                rx_mode = 0x0C;
        } else {
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
 
                memset(mc_filter, 0, sizeof(mc_filter));
-               netdev_for_each_mc_addr(mclist, dev) {
-                       int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+               netdev_for_each_mc_addr(ha, dev) {
+                       int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
 
                        mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
                }
index bc278d4ee89debb359c4d70ef21e06bfd7479ae3..42dffd3e5795b6737943170e0e6e4ccfe4043f62 100644 (file)
@@ -719,30 +719,30 @@ static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
        u32 status = 0;
        u16 ANAR;
 
-       if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+       if (!MII_REG_BITS_IS_ON(BMSR_LSTATUS, MII_BMSR, regs))
                status |= VELOCITY_LINK_FAIL;
 
-       if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+       if (MII_REG_BITS_IS_ON(ADVERTISE_1000FULL, MII_CTRL1000, regs))
                status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
-       else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+       else if (MII_REG_BITS_IS_ON(ADVERTISE_1000HALF, MII_CTRL1000, regs))
                status |= (VELOCITY_SPEED_1000);
        else {
-               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-               if (ANAR & ANAR_TXFD)
+               velocity_mii_read(regs, MII_ADVERTISE, &ANAR);
+               if (ANAR & ADVERTISE_100FULL)
                        status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
-               else if (ANAR & ANAR_TX)
+               else if (ANAR & ADVERTISE_100HALF)
                        status |= VELOCITY_SPEED_100;
-               else if (ANAR & ANAR_10FD)
+               else if (ANAR & ADVERTISE_10FULL)
                        status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
                else
                        status |= (VELOCITY_SPEED_10);
        }
 
-       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
-               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
-                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
-                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+       if (MII_REG_BITS_IS_ON(BMCR_ANENABLE, MII_BMCR, regs)) {
+               velocity_mii_read(regs, MII_ADVERTISE, &ANAR);
+               if ((ANAR & (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF))
+                   == (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF)) {
+                       if (MII_REG_BITS_IS_ON(ADVERTISE_1000HALF | ADVERTISE_1000FULL, MII_CTRL1000, regs))
                                status |= VELOCITY_AUTONEG_ENABLE;
                }
        }
@@ -801,23 +801,23 @@ static void set_mii_flow_control(struct velocity_info *vptr)
        /*Enable or Disable PAUSE in ANAR */
        switch (vptr->options.flow_cntl) {
        case FLOW_CNTL_TX:
-               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_OFF(ADVERTISE_PAUSE_CAP, MII_ADVERTISE, vptr->mac_regs);
+               MII_REG_BITS_ON(ADVERTISE_PAUSE_ASYM, MII_ADVERTISE, vptr->mac_regs);
                break;
 
        case FLOW_CNTL_RX:
-               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ADVERTISE_PAUSE_CAP, MII_ADVERTISE, vptr->mac_regs);
+               MII_REG_BITS_ON(ADVERTISE_PAUSE_ASYM, MII_ADVERTISE, vptr->mac_regs);
                break;
 
        case FLOW_CNTL_TX_RX:
-               MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON(ADVERTISE_PAUSE_CAP, MII_ADVERTISE, vptr->mac_regs);
+               MII_REG_BITS_OFF(ADVERTISE_PAUSE_ASYM, MII_ADVERTISE, vptr->mac_regs);
                break;
 
        case FLOW_CNTL_DISABLE:
-               MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_OFF(ADVERTISE_PAUSE_CAP, MII_ADVERTISE, vptr->mac_regs);
+               MII_REG_BITS_OFF(ADVERTISE_PAUSE_ASYM, MII_ADVERTISE, vptr->mac_regs);
                break;
        default:
                break;
@@ -832,10 +832,10 @@ static void set_mii_flow_control(struct velocity_info *vptr)
  */
 static void mii_set_auto_on(struct velocity_info *vptr)
 {
-       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
-               MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+       if (MII_REG_BITS_IS_ON(BMCR_ANENABLE, MII_BMCR, vptr->mac_regs))
+               MII_REG_BITS_ON(BMCR_ANRESTART, MII_BMCR, vptr->mac_regs);
        else
-               MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+               MII_REG_BITS_ON(BMCR_ANENABLE, MII_BMCR, vptr->mac_regs);
 }
 
 static u32 check_connection_type(struct mac_regs __iomem *regs)
@@ -860,11 +860,11 @@ static u32 check_connection_type(struct mac_regs __iomem *regs)
        else
                status |= VELOCITY_SPEED_100;
 
-       if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
-               velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
-               if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
-                   == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
-                       if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+       if (MII_REG_BITS_IS_ON(BMCR_ANENABLE, MII_BMCR, regs)) {
+               velocity_mii_read(regs, MII_ADVERTISE, &ANAR);
+               if ((ANAR & (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF))
+                   == (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF)) {
+                       if (MII_REG_BITS_IS_ON(ADVERTISE_1000HALF | ADVERTISE_1000FULL, MII_CTRL1000, regs))
                                status |= VELOCITY_AUTONEG_ENABLE;
                }
        }
@@ -905,7 +905,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
         */
 
        if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
-               MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+               MII_REG_BITS_ON(AUXCR_MDPPS, MII_NCONFIG, vptr->mac_regs);
 
        /*
         *      If connection type is AUTO
@@ -915,9 +915,9 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
                /* clear force MAC mode bit */
                BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
                /* set duplex mode of MAC according to duplex mode of MII */
-               MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
-               MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
-               MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+               MII_REG_BITS_ON(ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF, MII_ADVERTISE, vptr->mac_regs);
+               MII_REG_BITS_ON(ADVERTISE_1000FULL | ADVERTISE_1000HALF, MII_CTRL1000, vptr->mac_regs);
+               MII_REG_BITS_ON(BMCR_SPEED1000, MII_BMCR, vptr->mac_regs);
 
                /* enable AUTO-NEGO mode */
                mii_set_auto_on(vptr);
@@ -952,31 +952,31 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
                                BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
                }
 
-               MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+               MII_REG_BITS_OFF(ADVERTISE_1000FULL | ADVERTISE_1000HALF, MII_CTRL1000, vptr->mac_regs);
 
                if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
                        BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
                else
                        BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
 
-               /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
-               velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
-               ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+               /* MII_REG_BITS_OFF(BMCR_SPEED1000, MII_BMCR, vptr->mac_regs); */
+               velocity_mii_read(vptr->mac_regs, MII_ADVERTISE, &ANAR);
+               ANAR &= (~(ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | ADVERTISE_10HALF));
                if (mii_status & VELOCITY_SPEED_100) {
                        if (mii_status & VELOCITY_DUPLEX_FULL)
-                               ANAR |= ANAR_TXFD;
+                               ANAR |= ADVERTISE_100FULL;
                        else
-                               ANAR |= ANAR_TX;
+                               ANAR |= ADVERTISE_100HALF;
                } else {
                        if (mii_status & VELOCITY_DUPLEX_FULL)
-                               ANAR |= ANAR_10FD;
+                               ANAR |= ADVERTISE_10FULL;
                        else
-                               ANAR |= ANAR_10;
+                               ANAR |= ADVERTISE_10HALF;
                }
-               velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+               velocity_mii_write(vptr->mac_regs, MII_ADVERTISE, ANAR);
                /* enable AUTO-NEGO mode */
                mii_set_auto_on(vptr);
-               /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+               /* MII_REG_BITS_ON(BMCR_ANENABLE, MII_BMCR, vptr->mac_regs); */
        }
        /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
        /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
@@ -1126,7 +1126,7 @@ static void velocity_set_multi(struct net_device *dev)
        struct mac_regs __iomem *regs = vptr->mac_regs;
        u8 rx_mode;
        int i;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
 
        if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
                writel(0xffffffff, &regs->MARCAM[0]);
@@ -1142,8 +1142,8 @@ static void velocity_set_multi(struct net_device *dev)
                mac_get_cam_mask(regs, vptr->mCAMmask);
 
                i = 0;
-               netdev_for_each_mc_addr(mclist, dev) {
-                       mac_set_cam(regs, i + offset, mclist->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       mac_set_cam(regs, i + offset, ha->addr);
                        vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
                        i++;
                }
@@ -1178,36 +1178,36 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
                /*
                 *      Reset to hardware default
                 */
-               MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_OFF((ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP), MII_ADVERTISE, vptr->mac_regs);
                /*
                 *      Turn on ECHODIS bit in NWay-forced full mode and turn it
                 *      off it in NWay-forced half mode for NWay-forced v.s.
                 *      legacy-forced issue.
                 */
                if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_SREVISION, vptr->mac_regs);
                else
-                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_SREVISION, vptr->mac_regs);
                /*
                 *      Turn on Link/Activity LED enable bit for CIS8201
                 */
-               MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+               MII_REG_BITS_ON(PLED_LALBE, MII_TPISTATUS, vptr->mac_regs);
                break;
        case PHYID_VT3216_32BIT:
        case PHYID_VT3216_64BIT:
                /*
                 *      Reset to hardware default
                 */
-               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON((ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP), MII_ADVERTISE, vptr->mac_regs);
                /*
                 *      Turn on ECHODIS bit in NWay-forced full mode and turn it
                 *      off it in NWay-forced half mode for NWay-forced v.s.
                 *      legacy-forced issue
                 */
                if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
-                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+                       MII_REG_BITS_ON(TCSR_ECHODIS, MII_SREVISION, vptr->mac_regs);
                else
-                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+                       MII_REG_BITS_OFF(TCSR_ECHODIS, MII_SREVISION, vptr->mac_regs);
                break;
 
        case PHYID_MARVELL_1000:
@@ -1219,15 +1219,15 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
                /*
                 *      Reset to hardware default
                 */
-               MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+               MII_REG_BITS_ON((ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP), MII_ADVERTISE, vptr->mac_regs);
                break;
        default:
                ;
        }
-       velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
-       if (BMCR & BMCR_ISO) {
-               BMCR &= ~BMCR_ISO;
-               velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+       velocity_mii_read(vptr->mac_regs, MII_BMCR, &BMCR);
+       if (BMCR & BMCR_ISOLATE) {
+               BMCR &= ~BMCR_ISOLATE;
+               velocity_mii_write(vptr->mac_regs, MII_BMCR, BMCR);
        }
 }
 
@@ -2606,7 +2606,6 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
        td_ptr->td_buf[0].size |= TD_QUEUE;
        mac_tx_queue_wake(vptr->mac_regs, qnum);
 
-       dev->trans_start = jiffies;
        spin_unlock_irqrestore(&vptr->lock, flags);
 out:
        return NETDEV_TX_OK;
@@ -2953,13 +2952,13 @@ static int velocity_set_wol(struct velocity_info *vptr)
 
        if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
                if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
-                       MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+                       MII_REG_BITS_ON(AUXCR_MDPPS, MII_NCONFIG, vptr->mac_regs);
 
-               MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+               MII_REG_BITS_OFF(ADVERTISE_1000FULL | ADVERTISE_1000HALF, MII_CTRL1000, vptr->mac_regs);
        }
 
        if (vptr->mii_status & VELOCITY_SPEED_1000)
-               MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+               MII_REG_BITS_ON(BMCR_ANRESTART, MII_BMCR, vptr->mac_regs);
 
        BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
 
index ef4a0f64ba16b4634a717ff4ccb2b26357e9bfeb..c38191179fae3fa0f3f1d0ab38580b7ec0bd2728 100644 (file)
@@ -1240,86 +1240,16 @@ struct velocity_context {
        u32 pattern[8];
 };
 
-
-/*
- *     MII registers.
- */
-
-
 /*
  *     Registers in the MII (offset unit is WORD)
  */
 
-#define MII_REG_BMCR        0x00       // physical address
-#define MII_REG_BMSR        0x01       //
-#define MII_REG_PHYID1      0x02       // OUI
-#define MII_REG_PHYID2      0x03       // OUI + Module ID + REV ID
-#define MII_REG_ANAR        0x04       //
-#define MII_REG_ANLPAR      0x05       //
-#define MII_REG_G1000CR     0x09       //
-#define MII_REG_G1000SR     0x0A       //
-#define MII_REG_MODCFG      0x10       //
-#define MII_REG_TCSR        0x16       //
-#define MII_REG_PLED        0x1B       //
-// NS, MYSON only
-#define MII_REG_PCR         0x17       //
-// ESI only
-#define MII_REG_PCSR        0x17       //
-#define MII_REG_AUXCR       0x1C       //
-
 // Marvell 88E1000/88E1000S
 #define MII_REG_PSCR        0x10       // PHY specific control register
 
 //
-// Bits in the BMCR register
-//
-#define BMCR_RESET          0x8000     //
-#define BMCR_LBK            0x4000     //
-#define BMCR_SPEED100       0x2000     //
-#define BMCR_AUTO           0x1000     //
-#define BMCR_PD             0x0800     //
-#define BMCR_ISO            0x0400     //
-#define BMCR_REAUTO         0x0200     //
-#define BMCR_FDX            0x0100     //
-#define BMCR_SPEED1G        0x0040     //
-//
-// Bits in the BMSR register
-//
-#define BMSR_AUTOCM         0x0020     //
-#define BMSR_LNK            0x0004     //
-
-//
-// Bits in the ANAR register
-//
-#define ANAR_ASMDIR         0x0800     // Asymmetric PAUSE support
-#define ANAR_PAUSE          0x0400     // Symmetric PAUSE Support
-#define ANAR_T4             0x0200     //
-#define ANAR_TXFD           0x0100     //
-#define ANAR_TX             0x0080     //
-#define ANAR_10FD           0x0040     //
-#define ANAR_10             0x0020     //
-//
-// Bits in the ANLPAR register
-//
-#define ANLPAR_ASMDIR       0x0800     // Asymmetric PAUSE support
-#define ANLPAR_PAUSE        0x0400     // Symmetric PAUSE Support
-#define ANLPAR_T4           0x0200     //
-#define ANLPAR_TXFD         0x0100     //
-#define ANLPAR_TX           0x0080     //
-#define ANLPAR_10FD         0x0040     //
-#define ANLPAR_10           0x0020     //
-
-//
-// Bits in the G1000CR register
-//
-#define G1000CR_1000FD      0x0200     // PHY is 1000-T Full-duplex capable
-#define G1000CR_1000        0x0100     // PHY is 1000-T Half-duplex capable
-
-//
-// Bits in the G1000SR register
+// Bits in the Silicon revision register
 //
-#define G1000SR_1000FD      0x0800     // LP PHY is 1000-T Full-duplex capable
-#define G1000SR_1000        0x0400     // LP PHY is 1000-T Half-duplex capable
 
 #define TCSR_ECHODIS        0x2000     //
 #define AUXCR_MDPPS         0x0004     //
@@ -1338,7 +1268,6 @@ struct velocity_context {
 
 #define PHYID_REV_ID_MASK   0x0000000FUL
 
-#define PHYID_GET_PHY_REV_ID(i)     ((i) & PHYID_REV_ID_MASK)
 #define PHYID_GET_PHY_ID(i)         ((i) & ~PHYID_REV_ID_MASK)
 
 #define MII_REG_BITS_ON(x,i,p) do {\
@@ -1362,8 +1291,8 @@ struct velocity_context {
 
 #define MII_GET_PHY_ID(p) ({\
     u32 id;\
-    velocity_mii_read((p),MII_REG_PHYID2,(u16 *) &id);\
-    velocity_mii_read((p),MII_REG_PHYID1,((u16 *) &id)+1);\
+    velocity_mii_read((p),MII_PHYSID2,(u16 *) &id);\
+    velocity_mii_read((p),MII_PHYSID1,((u16 *) &id)+1);\
     (id);})
 
 /*
index b0577dd1a42dc838eae1e9ca6bb14bc018192b4d..b0a85d0387962b6ce2394637f9ae6dbbac5f6684 100644 (file)
@@ -40,8 +40,7 @@ module_param(gso, bool, 0444);
 
 #define VIRTNET_SEND_COMMAND_SG_MAX    2
 
-struct virtnet_info
-{
+struct virtnet_info {
        struct virtio_device *vdev;
        struct virtqueue *rvq, *svq, *cvq;
        struct net_device *dev;
@@ -62,6 +61,10 @@ struct virtnet_info
 
        /* Chain pages by the private ptr. */
        struct page *pages;
+
+       /* fragments + linear part + virtio header */
+       struct scatterlist rx_sg[MAX_SKB_FRAGS + 2];
+       struct scatterlist tx_sg[MAX_SKB_FRAGS + 2];
 };
 
 struct skb_vnet_hdr {
@@ -324,10 +327,8 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
 {
        struct sk_buff *skb;
        struct skb_vnet_hdr *hdr;
-       struct scatterlist sg[2];
        int err;
 
-       sg_init_table(sg, 2);
        skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
        if (unlikely(!skb))
                return -ENOMEM;
@@ -335,11 +336,11 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
        skb_put(skb, MAX_PACKET_LEN);
 
        hdr = skb_vnet_hdr(skb);
-       sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
+       sg_set_buf(vi->rx_sg, &hdr->hdr, sizeof hdr->hdr);
 
-       skb_to_sgvec(skb, sg + 1, 0, skb->len);
+       skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
 
-       err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 2, skb);
+       err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
        if (err < 0)
                dev_kfree_skb(skb);
 
@@ -348,13 +349,11 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
 
 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;
 
-       sg_init_table(sg, MAX_SKB_FRAGS + 2);
-       /* page in sg[MAX_SKB_FRAGS + 1] is list tail */
+       /* page in vi->rx_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) {
@@ -362,7 +361,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
                                give_pages(vi, list);
                        return -ENOMEM;
                }
-               sg_set_buf(&sg[i], page_address(first), PAGE_SIZE);
+               sg_set_buf(&vi->rx_sg[i], page_address(first), PAGE_SIZE);
 
                /* chain new page in list head to match sg */
                first->private = (unsigned long)list;
@@ -376,17 +375,17 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
        }
        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));
+       /* vi->rx_sg[0], vi->rx_sg[1] share the same page */
+       /* a separated vi->rx_sg[0] for virtio_net_hdr only due to QEMU bug */
+       sg_set_buf(&vi->rx_sg[0], p, sizeof(struct virtio_net_hdr));
 
-       /* sg[1] for data packet, from offset */
+       /* vi->rx_sg[1] for data packet, from offset */
        offset = sizeof(struct padded_vnet_hdr);
-       sg_set_buf(&sg[1], p + offset, PAGE_SIZE - offset);
+       sg_set_buf(&vi->rx_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,
+       err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
                                       first);
        if (err < 0)
                give_pages(vi, first);
@@ -397,16 +396,15 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
 static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
 {
        struct page *page;
-       struct scatterlist sg;
        int err;
 
        page = get_a_page(vi, gfp);
        if (!page)
                return -ENOMEM;
 
-       sg_init_one(&sg, page_address(page), PAGE_SIZE);
+       sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
 
-       err = vi->rvq->vq_ops->add_buf(vi->rvq, &sg, 0, 1, page);
+       err = vi->rvq->vq_ops->add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
        if (err < 0)
                give_pages(vi, page);
 
@@ -515,12 +513,9 @@ static unsigned int free_old_xmit_skbs(struct virtnet_info *vi)
 
 static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
 {
-       struct scatterlist sg[2+MAX_SKB_FRAGS];
        struct skb_vnet_hdr *hdr = skb_vnet_hdr(skb);
        const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
 
-       sg_init_table(sg, 2+MAX_SKB_FRAGS);
-
        pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -554,12 +549,13 @@ 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(vi->tx_sg, &hdr->mhdr, sizeof hdr->mhdr);
        else
-               sg_set_buf(sg, &hdr->hdr, sizeof hdr->hdr);
+               sg_set_buf(vi->tx_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);
+       hdr->num_sg = skb_to_sgvec(skb, vi->tx_sg + 1, 0, skb->len) + 1;
+       return vi->svq->vq_ops->add_buf(vi->svq, vi->tx_sg, hdr->num_sg,
+                                       0, skb);
 }
 
 static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -722,7 +718,6 @@ static void virtnet_set_rx_mode(struct net_device *dev)
        struct scatterlist sg[2];
        u8 promisc, allmulti;
        struct virtio_net_ctrl_mac *mac_data;
-       struct dev_addr_list *addr;
        struct netdev_hw_addr *ha;
        int uc_count;
        int mc_count;
@@ -779,8 +774,8 @@ static void virtnet_set_rx_mode(struct net_device *dev)
 
        mac_data->entries = mc_count;
        i = 0;
-       netdev_for_each_mc_addr(addr, dev)
-               memcpy(&mac_data->macs[i++][0], addr->da_addr, ETH_ALEN);
+       netdev_for_each_mc_addr(ha, dev)
+               memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
 
        sg_set_buf(&sg[1], mac_data,
                   sizeof(mac_data->entries) + (mc_count * ETH_ALEN));
@@ -942,6 +937,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        vdev->priv = vi;
        vi->pages = NULL;
        INIT_DELAYED_WORK(&vi->refill, refill_work);
+       sg_init_table(vi->rx_sg, ARRAY_SIZE(vi->rx_sg));
+       sg_init_table(vi->tx_sg, ARRAY_SIZE(vi->tx_sg));
 
        /* If we can receive ANY GSO packets, we must allocate large ones. */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
index cff3485d967364d1a5803ddd2468a2d302753470..989b742551ac4e44a2c6775c7c65cb1a796d3ba5 100644 (file)
@@ -992,7 +992,6 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_TXPROD,
                                       tq->tx_ring.next2fill);
        }
-       netdev->trans_start = jiffies;
 
        return NETDEV_TX_OK;
 
@@ -1174,7 +1173,6 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                                netif_receive_skb(skb);
                        }
 
-                       adapter->netdev->last_rx = jiffies;
                        ctx->skb = NULL;
                }
 
@@ -1371,13 +1369,12 @@ vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
 
        sz = sizeof(struct vmxnet3_rx_buf_info) * (rq->rx_ring[0].size +
                                                   rq->rx_ring[1].size);
-       bi = kmalloc(sz, GFP_KERNEL);
+       bi = kzalloc(sz, GFP_KERNEL);
        if (!bi) {
                printk(KERN_ERR "%s: failed to allocate rx bufinfo\n",
                       adapter->netdev->name);
                goto err;
        }
-       memset(bi, 0, sz);
        rq->buf_info[0] = bi;
        rq->buf_info[1] = bi + rq->rx_ring[0].size;
 
@@ -1675,11 +1672,11 @@ vmxnet3_copy_mc(struct net_device *netdev)
                /* We may be called with BH disabled */
                buf = kmalloc(sz, GFP_ATOMIC);
                if (buf) {
-                       struct dev_mc_list *mc;
+                       struct netdev_hw_addr *ha;
                        int i = 0;
 
-                       netdev_for_each_mc_addr(mc, netdev)
-                               memcpy(buf + i++ * ETH_ALEN, mc->dmi_addr,
+                       netdev_for_each_mc_addr(ha, netdev)
+                               memcpy(buf + i++ * ETH_ALEN, ha->addr,
                                       ETH_ALEN);
                }
        }
index a21a25d218b695c737a2647d6407c4acc448605d..297f0d2020735e4dffe20c689d2290c9d8716075 100644 (file)
@@ -183,8 +183,6 @@ __vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev)
        pci_write_config_word(hldev->pdev, PCI_COMMAND, cmd);
 
        pci_save_state(hldev->pdev);
-
-       return;
 }
 
 /*
@@ -342,8 +340,6 @@ void __vxge_hw_device_id_get(struct __vxge_hw_device *hldev)
 
        hldev->minor_revision =
                (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64);
-
-       return;
 }
 
 /*
@@ -357,8 +353,10 @@ __vxge_hw_device_access_rights_get(u32 host_type, u32 func_id)
 
        switch (host_type) {
        case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION:
-               access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
-                               VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+               if (func_id == 0) {
+                       access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+                                       VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+               }
                break;
        case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION:
                access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
@@ -426,8 +424,6 @@ void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
                hldev->first_vp_id = i;
                break;
        }
-
-       return;
 }
 
 /*
@@ -633,8 +629,10 @@ vxge_hw_device_initialize(
        __vxge_hw_device_pci_e_init(hldev);
 
        status = __vxge_hw_device_reg_addr_get(hldev);
-       if (status != VXGE_HW_OK)
+       if (status != VXGE_HW_OK) {
+               vfree(hldev);
                goto exit;
+       }
        __vxge_hw_device_id_get(hldev);
 
        __vxge_hw_device_host_info_get(hldev);
@@ -1213,19 +1211,16 @@ __vxge_hw_ring_mempool_item_alloc(struct vxge_hw_mempool *mempoolh,
                /* link this RxD block with previous one */
                __vxge_hw_ring_rxdblock_link(mempoolh, ring, index - 1, index);
        }
-
-       return;
 }
 
 /*
- * __vxge_hw_ring_initial_replenish - Initial replenish of RxDs
+ * __vxge_hw_ring_replenish - Initial replenish of RxDs
  * This function replenishes the RxDs from reserve array to work array
  */
 enum vxge_hw_status
-vxge_hw_ring_replenish(struct __vxge_hw_ring *ring, u16 min_flag)
+vxge_hw_ring_replenish(struct __vxge_hw_ring *ring)
 {
        void *rxd;
-       int i = 0;
        struct __vxge_hw_channel *channel;
        enum vxge_hw_status status = VXGE_HW_OK;
 
@@ -1246,11 +1241,6 @@ vxge_hw_ring_replenish(struct __vxge_hw_ring *ring, u16 min_flag)
                }
 
                vxge_hw_ring_rxd_post(ring, rxd);
-               if (min_flag) {
-                       i++;
-                       if (i == VXGE_HW_RING_MIN_BUFF_ALLOCATION)
-                               break;
-               }
        }
        status = VXGE_HW_OK;
 exit:
@@ -1355,7 +1345,7 @@ __vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp,
         * Currently we don't have a case when the 1) is done without the 2).
         */
        if (ring->rxd_init) {
-               status = vxge_hw_ring_replenish(ring, 1);
+               status = vxge_hw_ring_replenish(ring);
                if (status != VXGE_HW_OK) {
                        __vxge_hw_ring_delete(vp);
                        goto exit;
@@ -1417,7 +1407,7 @@ enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring)
                goto exit;
 
        if (ring->rxd_init) {
-               status = vxge_hw_ring_replenish(ring, 1);
+               status = vxge_hw_ring_replenish(ring);
                if (status != VXGE_HW_OK)
                        goto exit;
        }
@@ -2320,8 +2310,6 @@ __vxge_hw_fifo_mempool_item_alloc(
        txdl_priv->first_txdp = txdp;
        txdl_priv->next_txdl_priv = NULL;
        txdl_priv->alloc_frags = 0;
-
-       return;
 }
 
 /*
@@ -2578,7 +2566,6 @@ __vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg,
        writeq(dta_struct_sel, &vpath_reg->rts_access_steer_data0);
        writeq(0, &vpath_reg->rts_access_steer_data1);
        wmb();
-       return;
 }
 
 
@@ -3486,7 +3473,6 @@ __vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev, u32 vp_id)
                val64 &= ~VXGE_HW_PRC_CFG4_RTH_DISABLE;
 
        writeq(val64, &vp_reg->prc_cfg4);
-       return;
 }
 
 /*
@@ -3905,7 +3891,6 @@ vxge_hw_vpath_tti_ci_set(struct __vxge_hw_device *hldev, u32 vp_id)
                        &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]);
                }
        }
-       return;
 }
 /*
  * __vxge_hw_vpath_initialize
@@ -5039,8 +5024,6 @@ __vxge_hw_blockpool_free(struct __vxge_hw_device *devh,
                if (status == VXGE_HW_OK)
                        __vxge_hw_blockpool_blocks_remove(blockpool);
        }
-
-       return;
 }
 
 /*
@@ -5096,6 +5079,4 @@ __vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh,
        }
 
        __vxge_hw_blockpool_blocks_remove(blockpool);
-
-       return;
 }
index 13f5416307f8013ed5259137b5470fc99ce0445b..4ae2625d4d8f26001c81bc4ccf133169c5140693 100644 (file)
@@ -765,10 +765,18 @@ struct vxge_hw_device_hw_info {
 #define VXGE_HW_SR_VH_VIRTUAL_FUNCTION                         6
 #define VXGE_HW_VH_NORMAL_FUNCTION                             7
        u64             function_mode;
-#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION                   0
-#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION                  1
+#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION                  0
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION                   1
 #define VXGE_HW_FUNCTION_MODE_SRIOV                            2
 #define VXGE_HW_FUNCTION_MODE_MRIOV                            3
+#define VXGE_HW_FUNCTION_MODE_MRIOV_8                          4
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17                        5
+#define VXGE_HW_FUNCTION_MODE_SRIOV_8                          6
+#define VXGE_HW_FUNCTION_MODE_SRIOV_4                          7
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2                 8
+#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_4                 9
+#define VXGE_HW_FUNCTION_MODE_MRIOV_4                          10
+
        u32             func_id;
        u64             vpath_mask;
        struct vxge_hw_device_version fw_version;
@@ -1915,20 +1923,32 @@ static inline void *vxge_os_dma_malloc(struct pci_dev *pdev,
        gfp_t flags;
        void *vaddr;
        unsigned long misaligned = 0;
+       int realloc_flag = 0;
        *p_dma_acch = *p_dmah = NULL;
 
        if (in_interrupt())
                flags = GFP_ATOMIC | GFP_DMA;
        else
                flags = GFP_KERNEL | GFP_DMA;
-
-       size += VXGE_CACHE_LINE_SIZE;
-
+realloc:
        vaddr = kmalloc((size), flags);
        if (vaddr == NULL)
                return vaddr;
-       misaligned = (unsigned long)VXGE_ALIGN(*((u64 *)&vaddr),
+       misaligned = (unsigned long)VXGE_ALIGN((unsigned long)vaddr,
                                VXGE_CACHE_LINE_SIZE);
+       if (realloc_flag)
+               goto out;
+
+       if (misaligned) {
+               /* misaligned, free current one and try allocating
+                * size + VXGE_CACHE_LINE_SIZE memory
+                */
+               kfree((void *) vaddr);
+               size += VXGE_CACHE_LINE_SIZE;
+               realloc_flag = 1;
+               goto realloc;
+       }
+out:
        *(unsigned long *)p_dma_acch = misaligned;
        vaddr = (void *)((u8 *)vaddr + misaligned);
        return vaddr;
@@ -2254,4 +2274,6 @@ enum vxge_hw_status vxge_hw_vpath_rts_rth_set(
        struct vxge_hw_rth_hash_types *hash_type,
        u16 bucket_size);
 
+enum vxge_hw_status
+__vxge_hw_device_is_privilaged(u32 host_type, u32 func_id);
 #endif
index aaf374cfd322d641024c8e1921e3881b630888e3..cadef8549c0632820fc014fa84b0730044f88538 100644 (file)
@@ -109,7 +109,7 @@ static void vxge_ethtool_gregs(struct net_device *dev,
        int index, offset;
        enum vxge_hw_status status;
        u64 reg;
-       u8 *reg_space = (u8 *) space;
+       u64 *reg_space = (u64 *) space;
        struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev);
        struct __vxge_hw_device  *hldev = (struct __vxge_hw_device *)
                                        pci_get_drvdata(vdev->pdev);
@@ -129,8 +129,7 @@ static void vxge_ethtool_gregs(struct net_device *dev,
                                                __func__, __LINE__);
                                return;
                        }
-
-                       memcpy((reg_space + offset), &reg, 8);
+                       *reg_space++ = reg;
                }
        }
 }
index ba6d0da78c3019b111e537ef894ce66940fca324..b504bd56136210776fa0d31e87a5e00b687cb03b 100644 (file)
@@ -445,7 +445,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
                ring->ndev->name, __func__, __LINE__);
        ring->pkts_processed = 0;
 
-       vxge_hw_ring_replenish(ringh, 0);
+       vxge_hw_ring_replenish(ringh);
 
        do {
                prefetch((char *)dtr + L1_CACHE_BYTES);
@@ -1118,7 +1118,7 @@ vxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata)
  */
 static void vxge_set_multicast(struct net_device *dev)
 {
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        struct vxgedev *vdev;
        int i, mcast_cnt = 0;
        struct __vxge_hw_device  *hldev;
@@ -1218,8 +1218,8 @@ static void vxge_set_multicast(struct net_device *dev)
                }
 
                /* Add new ones */
-               netdev_for_each_mc_addr(mclist, dev) {
-                       memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN);
+               netdev_for_each_mc_addr(ha, dev) {
+                       memcpy(mac_info.macaddr, ha->addr, ETH_ALEN);
                        for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
                                        vpath_idx++) {
                                mac_info.vpath_no = vpath_idx;
@@ -1364,28 +1364,26 @@ static int vxge_set_mac_addr(struct net_device *dev, void *p)
 void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id)
 {
        struct vxge_vpath *vpath = &vdev->vpaths[vp_id];
-       int msix_id, alarm_msix_id;
-       int tim_msix_id[4] = {[0 ...3] = 0};
+       int msix_id = 0;
+       int tim_msix_id[4] = {0, 1, 0, 0};
+       int alarm_msix_id = VXGE_ALARM_MSIX_ID;
 
        vxge_hw_vpath_intr_enable(vpath->handle);
 
        if (vdev->config.intr_type == INTA)
                vxge_hw_vpath_inta_unmask_tx_rx(vpath->handle);
        else {
-               msix_id = vp_id * VXGE_HW_VPATH_MSIX_ACTIVE;
-               alarm_msix_id =
-                       VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
-
-               tim_msix_id[0] = msix_id;
-               tim_msix_id[1] = msix_id + 1;
                vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id,
                        alarm_msix_id);
 
+               msix_id = vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE;
                vxge_hw_vpath_msix_unmask(vpath->handle, msix_id);
                vxge_hw_vpath_msix_unmask(vpath->handle, msix_id + 1);
 
                /* enable the alarm vector */
-               vxge_hw_vpath_msix_unmask(vpath->handle, alarm_msix_id);
+               msix_id = (vpath->handle->vpath->hldev->first_vp_id *
+                       VXGE_HW_VPATH_MSIX_ACTIVE) + alarm_msix_id;
+               vxge_hw_vpath_msix_unmask(vpath->handle, msix_id);
        }
 }
 
@@ -1406,12 +1404,13 @@ void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id)
        if (vdev->config.intr_type == INTA)
                vxge_hw_vpath_inta_mask_tx_rx(vpath->handle);
        else {
-               msix_id = vp_id * VXGE_HW_VPATH_MSIX_ACTIVE;
+               msix_id = vpath->device_id * VXGE_HW_VPATH_MSIX_ACTIVE;
                vxge_hw_vpath_msix_mask(vpath->handle, msix_id);
                vxge_hw_vpath_msix_mask(vpath->handle, msix_id + 1);
 
                /* disable the alarm vector */
-               msix_id = VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+               msix_id = (vpath->handle->vpath->hldev->first_vp_id *
+                       VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID;
                vxge_hw_vpath_msix_mask(vpath->handle, msix_id);
        }
 }
@@ -1765,7 +1764,6 @@ static void vxge_netpoll(struct net_device *dev)
 
        vxge_debug_entryexit(VXGE_TRACE,
                "%s:%d  Exiting...", __func__, __LINE__);
-       return;
 }
 #endif
 
@@ -2224,19 +2222,18 @@ vxge_alarm_msix_handle(int irq, void *dev_id)
        enum vxge_hw_status status;
        struct vxge_vpath *vpath = (struct vxge_vpath *)dev_id;
        struct vxgedev *vdev = vpath->vdev;
-       int alarm_msix_id =
-               VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
+       int msix_id = (vpath->handle->vpath->vp_id *
+               VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID;
 
        for (i = 0; i < vdev->no_of_vpath; i++) {
-               vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle,
-                       alarm_msix_id);
+               vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle, msix_id);
 
                status = vxge_hw_vpath_alarm_process(vdev->vpaths[i].handle,
                        vdev->exec_mode);
                if (status == VXGE_HW_OK) {
 
                        vxge_hw_vpath_msix_unmask(vdev->vpaths[i].handle,
-                               alarm_msix_id);
+                                       msix_id);
                        continue;
                }
                vxge_debug_intr(VXGE_ERR,
@@ -2249,18 +2246,17 @@ vxge_alarm_msix_handle(int irq, void *dev_id)
 static int vxge_alloc_msix(struct vxgedev *vdev)
 {
        int j, i, ret = 0;
-       int intr_cnt = 0;
-       int alarm_msix_id = 0, msix_intr_vect = 0;
+       int msix_intr_vect = 0, temp;
        vdev->intr_cnt = 0;
 
+start:
        /* Tx/Rx MSIX Vectors count */
        vdev->intr_cnt = vdev->no_of_vpath * 2;
 
        /* Alarm MSIX Vectors count */
        vdev->intr_cnt++;
 
-       intr_cnt = (vdev->max_vpath_supported * 2) + 1;
-       vdev->entries = kzalloc(intr_cnt * sizeof(struct msix_entry),
+       vdev->entries = kzalloc(vdev->intr_cnt * sizeof(struct msix_entry),
                                                GFP_KERNEL);
        if (!vdev->entries) {
                vxge_debug_init(VXGE_ERR,
@@ -2269,8 +2265,9 @@ static int vxge_alloc_msix(struct vxgedev *vdev)
                return  -ENOMEM;
        }
 
-       vdev->vxge_entries = kzalloc(intr_cnt * sizeof(struct vxge_msix_entry),
-                                                       GFP_KERNEL);
+       vdev->vxge_entries =
+               kzalloc(vdev->intr_cnt * sizeof(struct vxge_msix_entry),
+                               GFP_KERNEL);
        if (!vdev->vxge_entries) {
                vxge_debug_init(VXGE_ERR, "%s: memory allocation failed",
                        VXGE_DRIVER_NAME);
@@ -2278,9 +2275,7 @@ static int vxge_alloc_msix(struct vxgedev *vdev)
                return -ENOMEM;
        }
 
-       /* Last vector in the list is used for alarm */
-       alarm_msix_id = VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
-       for (i = 0, j = 0; i < vdev->max_vpath_supported; i++) {
+       for (i = 0, j = 0; i < vdev->no_of_vpath; i++) {
 
                msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE;
 
@@ -2298,47 +2293,31 @@ static int vxge_alloc_msix(struct vxgedev *vdev)
        }
 
        /* Initialize the alarm vector */
-       vdev->entries[j].entry = alarm_msix_id;
-       vdev->vxge_entries[j].entry = alarm_msix_id;
+       vdev->entries[j].entry = VXGE_ALARM_MSIX_ID;
+       vdev->vxge_entries[j].entry = VXGE_ALARM_MSIX_ID;
        vdev->vxge_entries[j].in_use = 0;
 
-       ret = pci_enable_msix(vdev->pdev, vdev->entries, intr_cnt);
-       /* if driver request exceeeds available irq's, request with a small
-        * number.
-       */
-       if (ret > 0) {
-               vxge_debug_init(VXGE_ERR,
-                       "%s: MSI-X enable failed for %d vectors, available: %d",
-                       VXGE_DRIVER_NAME, intr_cnt, ret);
-               vdev->max_vpath_supported = vdev->no_of_vpath;
-               intr_cnt = (vdev->max_vpath_supported * 2) + 1;
-
-               /* Reset the alarm vector setting */
-               vdev->entries[j].entry = 0;
-               vdev->vxge_entries[j].entry = 0;
-
-               /* Initialize the alarm vector with new setting */
-               vdev->entries[intr_cnt - 1].entry = alarm_msix_id;
-               vdev->vxge_entries[intr_cnt - 1].entry = alarm_msix_id;
-               vdev->vxge_entries[intr_cnt - 1].in_use = 0;
-
-               ret = pci_enable_msix(vdev->pdev, vdev->entries, intr_cnt);
-               if (!ret)
-                       vxge_debug_init(VXGE_ERR,
-                               "%s: MSI-X enabled for %d vectors",
-                               VXGE_DRIVER_NAME, intr_cnt);
-       }
+       ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt);
 
-       if (ret) {
+       if (ret > 0) {
                vxge_debug_init(VXGE_ERR,
                        "%s: MSI-X enable failed for %d vectors, ret: %d",
-                       VXGE_DRIVER_NAME, intr_cnt, ret);
+                       VXGE_DRIVER_NAME, vdev->intr_cnt, ret);
                kfree(vdev->entries);
                kfree(vdev->vxge_entries);
                vdev->entries = NULL;
                vdev->vxge_entries = NULL;
+
+               if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3))
+                       return -ENODEV;
+               /* Try with less no of vector by reducing no of vpaths count */
+               temp = (ret - 1)/2;
+               vxge_close_vpaths(vdev, temp);
+               vdev->no_of_vpath = temp;
+               goto start;
+       } else if (ret < 0)
                return -ENODEV;
-       }
+
        return 0;
 }
 
@@ -2346,43 +2325,26 @@ static int vxge_enable_msix(struct vxgedev *vdev)
 {
 
        int i, ret = 0;
-       enum vxge_hw_status status;
        /* 0 - Tx, 1 - Rx  */
-       int tim_msix_id[4];
-       int alarm_msix_id = 0, msix_intr_vect = 0;
+       int tim_msix_id[4] = {0, 1, 0, 0};
+
        vdev->intr_cnt = 0;
 
        /* allocate msix vectors */
        ret = vxge_alloc_msix(vdev);
        if (!ret) {
-               /* Last vector in the list is used for alarm */
-               alarm_msix_id =
-                       VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2;
                for (i = 0; i < vdev->no_of_vpath; i++) {
 
                        /* If fifo or ring are not enabled
                           the MSIX vector for that should be set to 0
                           Hence initializeing this array to all 0s.
                        */
-                       memset(tim_msix_id, 0, sizeof(tim_msix_id));
-                       msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE;
-                       tim_msix_id[0] = msix_intr_vect;
-
-                       tim_msix_id[1] = msix_intr_vect + 1;
-                       vdev->vpaths[i].ring.rx_vector_no = tim_msix_id[1];
+                       vdev->vpaths[i].ring.rx_vector_no =
+                               (vdev->vpaths[i].device_id *
+                                       VXGE_HW_VPATH_MSIX_ACTIVE) + 1;
 
-                       status = vxge_hw_vpath_msix_set(
-                                               vdev->vpaths[i].handle,
-                                               tim_msix_id, alarm_msix_id);
-                       if (status != VXGE_HW_OK) {
-                               vxge_debug_init(VXGE_ERR,
-                                       "vxge_hw_vpath_msix_set "
-                                       "failed with status : %x", status);
-                               kfree(vdev->entries);
-                               kfree(vdev->vxge_entries);
-                               pci_disable_msix(vdev->pdev);
-                               return -ENODEV;
-                       }
+                       vxge_hw_vpath_msix_set(vdev->vpaths[i].handle,
+                                       tim_msix_id, VXGE_ALARM_MSIX_ID);
                }
        }
 
@@ -2393,7 +2355,7 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev)
 {
        int intr_cnt;
 
-       for (intr_cnt = 0; intr_cnt < (vdev->max_vpath_supported * 2 + 1);
+       for (intr_cnt = 0; intr_cnt < (vdev->no_of_vpath * 2 + 1);
                intr_cnt++) {
                if (vdev->vxge_entries[intr_cnt].in_use) {
                        synchronize_irq(vdev->entries[intr_cnt].vector);
@@ -2458,9 +2420,10 @@ static int vxge_add_isr(struct vxgedev *vdev)
                        switch (msix_idx) {
                        case 0:
                                snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
-                                       "%s:vxge fn: %d vpath: %d Tx MSI-X: %d",
-                                       vdev->ndev->name, pci_fun, vp_idx,
-                                       vdev->entries[intr_cnt].entry);
+                               "%s:vxge:MSI-X %d - Tx - fn:%d vpath:%d",
+                                       vdev->ndev->name,
+                                       vdev->entries[intr_cnt].entry,
+                                       pci_fun, vp_idx);
                                ret = request_irq(
                                    vdev->entries[intr_cnt].vector,
                                        vxge_tx_msix_handle, 0,
@@ -2472,9 +2435,10 @@ static int vxge_add_isr(struct vxgedev *vdev)
                                break;
                        case 1:
                                snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
-                                       "%s:vxge fn: %d vpath: %d Rx MSI-X: %d",
-                                       vdev->ndev->name, pci_fun, vp_idx,
-                                       vdev->entries[intr_cnt].entry);
+                               "%s:vxge:MSI-X %d - Rx - fn:%d vpath:%d",
+                                       vdev->ndev->name,
+                                       vdev->entries[intr_cnt].entry,
+                                       pci_fun, vp_idx);
                                ret = request_irq(
                                    vdev->entries[intr_cnt].vector,
                                        vxge_rx_msix_napi_handle,
@@ -2502,9 +2466,11 @@ static int vxge_add_isr(struct vxgedev *vdev)
                        if (irq_req) {
                                /* We requested for this msix interrupt */
                                vdev->vxge_entries[intr_cnt].in_use = 1;
+                               msix_idx +=  vdev->vpaths[vp_idx].device_id *
+                                       VXGE_HW_VPATH_MSIX_ACTIVE;
                                vxge_hw_vpath_msix_unmask(
                                        vdev->vpaths[vp_idx].handle,
-                                       intr_idx);
+                                       msix_idx);
                                intr_cnt++;
                        }
 
@@ -2514,16 +2480,17 @@ static int vxge_add_isr(struct vxgedev *vdev)
                                vp_idx++;
                }
 
-               intr_cnt = vdev->max_vpath_supported * 2;
+               intr_cnt = vdev->no_of_vpath * 2;
                snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN,
-                       "%s:vxge Alarm fn: %d MSI-X: %d",
-                       vdev->ndev->name, pci_fun,
-                       vdev->entries[intr_cnt].entry);
+                       "%s:vxge:MSI-X %d - Alarm - fn:%d",
+                       vdev->ndev->name,
+                       vdev->entries[intr_cnt].entry,
+                       pci_fun);
                /* For Alarm interrupts */
                ret = request_irq(vdev->entries[intr_cnt].vector,
                                        vxge_alarm_msix_handle, 0,
                                        vdev->desc[intr_cnt],
-                                       &vdev->vpaths[vp_idx]);
+                                       &vdev->vpaths[0]);
                if (ret) {
                        vxge_debug_init(VXGE_ERR,
                                "%s: MSIX - %d Registration failed",
@@ -2536,16 +2503,19 @@ static int vxge_add_isr(struct vxgedev *vdev)
                                goto INTA_MODE;
                }
 
+               msix_idx = (vdev->vpaths[0].handle->vpath->vp_id *
+                       VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID;
                vxge_hw_vpath_msix_unmask(vdev->vpaths[vp_idx].handle,
-                                       intr_idx - 2);
+                                       msix_idx);
                vdev->vxge_entries[intr_cnt].in_use = 1;
-               vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[vp_idx];
+               vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[0];
        }
 INTA_MODE:
 #endif
-       snprintf(vdev->desc[0], VXGE_INTR_STRLEN, "%s:vxge", vdev->ndev->name);
 
        if (vdev->config.intr_type == INTA) {
+               snprintf(vdev->desc[0], VXGE_INTR_STRLEN,
+                       "%s:vxge:INTA", vdev->ndev->name);
                vxge_hw_device_set_intr_type(vdev->devh,
                        VXGE_HW_INTR_MODE_IRQLINE);
                vxge_hw_vpath_tti_ci_set(vdev->devh,
@@ -2844,7 +2814,6 @@ static void vxge_napi_del_all(struct vxgedev *vdev)
                for (i = 0; i < vdev->no_of_vpath; i++)
                        netif_napi_del(&vdev->vpaths[i].ring.napi);
        }
-       return;
 }
 
 int do_vxge_close(struct net_device *dev, int do_io)
@@ -3529,8 +3498,6 @@ static void verify_bandwidth(void)
                for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++)
                        bw_percentage[i] = bw_percentage[0];
        }
-
-       return;
 }
 
 /*
@@ -3995,6 +3962,36 @@ static void vxge_io_resume(struct pci_dev *pdev)
        netif_device_attach(netdev);
 }
 
+static inline u32 vxge_get_num_vfs(u64 function_mode)
+{
+       u32 num_functions = 0;
+
+       switch (function_mode) {
+       case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
+       case VXGE_HW_FUNCTION_MODE_SRIOV_8:
+               num_functions = 8;
+               break;
+       case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
+               num_functions = 1;
+               break;
+       case VXGE_HW_FUNCTION_MODE_SRIOV:
+       case VXGE_HW_FUNCTION_MODE_MRIOV:
+       case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_17:
+               num_functions = 17;
+               break;
+       case VXGE_HW_FUNCTION_MODE_SRIOV_4:
+               num_functions = 4;
+               break;
+       case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2:
+               num_functions = 2;
+               break;
+       case VXGE_HW_FUNCTION_MODE_MRIOV_8:
+               num_functions = 8; /* TODO */
+               break;
+       }
+       return num_functions;
+}
+
 /**
  * vxge_probe
  * @pdev : structure containing the PCI related information of the device.
@@ -4022,14 +4019,19 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
        u8 *macaddr;
        struct vxge_mac_addrs *entry;
        static int bus = -1, device = -1;
+       u32 host_type;
        u8 new_device = 0;
+       enum vxge_hw_status is_privileged;
+       u32 function_mode;
+       u32 num_vfs = 0;
 
        vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__);
        attr.pdev = pdev;
 
-       if (bus != pdev->bus->number)
-               new_device = 1;
-       if (device != PCI_SLOT(pdev->devfn))
+       /* In SRIOV-17 mode, functions of the same adapter
+        * can be deployed on different buses */
+       if ((!pdev->is_virtfn) && ((bus != pdev->bus->number) ||
+               (device != PCI_SLOT(pdev->devfn))))
                new_device = 1;
 
        bus = pdev->bus->number;
@@ -4046,9 +4048,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                                driver_config->total_dev_cnt);
                driver_config->config_dev_cnt = 0;
                driver_config->total_dev_cnt = 0;
-               driver_config->g_no_cpus = 0;
        }
-
+       /* Now making the CPU based no of vpath calculation
+        * applicable for individual functions as well.
+        */
+       driver_config->g_no_cpus = 0;
        driver_config->vpath_per_dev = max_config_vpath;
 
        driver_config->total_dev_cnt++;
@@ -4161,6 +4165,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                "%s:%d  Vpath mask = %llx", __func__, __LINE__,
                (unsigned long long)vpath_mask);
 
+       function_mode = ll_config.device_hw_info.function_mode;
+       host_type = ll_config.device_hw_info.host_type;
+       is_privileged = __vxge_hw_device_is_privilaged(host_type,
+               ll_config.device_hw_info.func_id);
+
        /* Check how many vpaths are available */
        for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
                if (!((vpath_mask) & vxge_mBIT(i)))
@@ -4168,14 +4177,18 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
                max_vpath_supported++;
        }
 
+       if (new_device)
+               num_vfs = vxge_get_num_vfs(function_mode) - 1;
+
        /* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */
-       if ((VXGE_HW_FUNCTION_MODE_SRIOV ==
-               ll_config.device_hw_info.function_mode) &&
-               (max_config_dev > 1) && (pdev->is_physfn)) {
-                       ret = pci_enable_sriov(pdev, max_config_dev - 1);
-                       if (ret)
-                               vxge_debug_ll_config(VXGE_ERR,
-                                       "Failed to enable SRIOV: %d \n", ret);
+       if (is_sriov(function_mode) && (max_config_dev > 1) &&
+               (ll_config.intr_type != INTA) &&
+               (is_privileged == VXGE_HW_OK)) {
+               ret = pci_enable_sriov(pdev, ((max_config_dev - 1) < num_vfs)
+                       ? (max_config_dev - 1) : num_vfs);
+               if (ret)
+                       vxge_debug_ll_config(VXGE_ERR,
+                               "Failed in enabling SRIOV mode: %d\n", ret);
        }
 
        /*
index 7c83ba4be9d7866ecf685fdd03c109e84d0d05b1..60276b20fa5ecba7b348a37a32d292f464d35895 100644 (file)
@@ -31,6 +31,7 @@
 #define PCI_DEVICE_ID_TITAN_UNI                0x5833
 #define        VXGE_USE_DEFAULT                0xffffffff
 #define VXGE_HW_VPATH_MSIX_ACTIVE      4
+#define VXGE_ALARM_MSIX_ID             2
 #define VXGE_HW_RXSYNC_FREQ_CNT                4
 #define VXGE_LL_WATCH_DOG_TIMEOUT      (15 * HZ)
 #define VXGE_LL_RX_COPY_THRESHOLD      256
 
 #define VXGE_LL_MAX_FRAME_SIZE(dev) ((dev)->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE)
 
+#define is_sriov(function_mode) \
+       ((function_mode == VXGE_HW_FUNCTION_MODE_SRIOV) || \
+       (function_mode == VXGE_HW_FUNCTION_MODE_SRIOV_8) || \
+       (function_mode == VXGE_HW_FUNCTION_MODE_SRIOV_4))
+
 enum vxge_reset_event {
        /* reset events */
        VXGE_LL_VPATH_RESET     = 0,
index 2c012f4ce4651eed64a9f9e274fbb7791d783880..6cc1dd79b40b2a134f1d0044009a3ba9746ed2bb 100644 (file)
@@ -231,11 +231,8 @@ void vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channel, int msix_id)
 {
 
        __vxge_hw_pio_mem_write32_upper(
-               (u32)vxge_bVALn(vxge_mBIT(channel->first_vp_id+(msix_id/4)),
-                       0, 32),
+               (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
                &channel->common_reg->set_msix_mask_vect[msix_id%4]);
-
-       return;
 }
 
 /**
@@ -252,11 +249,8 @@ vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channel, int msix_id)
 {
 
        __vxge_hw_pio_mem_write32_upper(
-               (u32)vxge_bVALn(vxge_mBIT(channel->first_vp_id+(msix_id/4)),
-                       0, 32),
+               (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
                &channel->common_reg->clear_msix_mask_vect[msix_id%4]);
-
-       return;
 }
 
 /**
@@ -331,8 +325,6 @@ void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev)
        val64 = readq(&hldev->common_reg->titan_general_int_status);
 
        vxge_hw_device_unmask_all(hldev);
-
-       return;
 }
 
 /**
@@ -364,8 +356,6 @@ void vxge_hw_device_intr_disable(struct __vxge_hw_device *hldev)
                vxge_hw_vpath_intr_disable(
                        VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i]));
        }
-
-       return;
 }
 
 /**
@@ -385,8 +375,6 @@ void vxge_hw_device_mask_all(struct __vxge_hw_device *hldev)
 
        __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
                                &hldev->common_reg->titan_mask_all_int);
-
-       return;
 }
 
 /**
@@ -406,8 +394,6 @@ void vxge_hw_device_unmask_all(struct __vxge_hw_device *hldev)
 
        __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32),
                        &hldev->common_reg->titan_mask_all_int);
-
-       return;
 }
 
 /**
@@ -649,8 +635,6 @@ void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev)
                                 hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX]),
                                &hldev->common_reg->tim_int_status1);
        }
-
-       return;
 }
 
 /*
@@ -878,7 +862,7 @@ void vxge_hw_ring_rxd_post_post(struct __vxge_hw_ring *ring, void *rxdh)
 
        channel = &ring->channel;
 
-       rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
+       rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
 
        if (ring->stats->common_stats.usage_cnt > 0)
                ring->stats->common_stats.usage_cnt--;
@@ -902,7 +886,7 @@ void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring, void *rxdh)
        channel = &ring->channel;
 
        wmb();
-       rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
+       rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
 
        vxge_hw_channel_dtr_post(channel, rxdh);
 
@@ -966,6 +950,7 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
        struct __vxge_hw_channel *channel;
        struct vxge_hw_ring_rxd_1 *rxdp;
        enum vxge_hw_status status = VXGE_HW_OK;
+       u64 control_0, own;
 
        channel = &ring->channel;
 
@@ -977,8 +962,12 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
                goto exit;
        }
 
+       control_0 = rxdp->control_0;
+       own = control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER;
+       *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(control_0);
+
        /* check whether it is not the end */
-       if (!(rxdp->control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER)) {
+       if (!own || ((*t_code == VXGE_HW_RING_T_CODE_FRM_DROP) && own)) {
 
                vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control !=
                                0);
@@ -986,8 +975,6 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed(
                ++ring->cmpl_cnt;
                vxge_hw_channel_dtr_complete(channel);
 
-               *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(rxdp->control_0);
-
                vxge_assert(*t_code != VXGE_HW_RING_RXD_T_CODE_UNUSED);
 
                ring->stats->common_stats.usage_cnt++;
@@ -1035,12 +1022,13 @@ enum vxge_hw_status vxge_hw_ring_handle_tcode(
         * such as unknown UPV6 header), Drop it !!!
         */
 
-       if (t_code == 0 || t_code == 5) {
+       if (t_code ==  VXGE_HW_RING_T_CODE_OK ||
+               t_code == VXGE_HW_RING_T_CODE_L3_PKT_ERR) {
                status = VXGE_HW_OK;
                goto exit;
        }
 
-       if (t_code > 0xF) {
+       if (t_code > VXGE_HW_RING_T_CODE_MULTI_ERR) {
                status = VXGE_HW_ERR_INVALID_TCODE;
                goto exit;
        }
@@ -2216,29 +2204,24 @@ exit:
  * This API will associate a given MSIX vector numbers with the four TIM
  * interrupts and alarm interrupt.
  */
-enum vxge_hw_status
+void
 vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vp, int *tim_msix_id,
                       int alarm_msix_id)
 {
        u64 val64;
        struct __vxge_hw_virtualpath *vpath = vp->vpath;
        struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
-       u32 first_vp_id = vpath->hldev->first_vp_id;
+       u32 vp_id = vp->vpath->vp_id;
 
        val64 =  VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(
-                 (first_vp_id * 4) + tim_msix_id[0]) |
+                 (vp_id * 4) + tim_msix_id[0]) |
                 VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(
-                 (first_vp_id * 4) + tim_msix_id[1]) |
-                VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI(
-                       (first_vp_id * 4) + tim_msix_id[2]);
-
-               val64 |= VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI(
-                       (first_vp_id * 4) + tim_msix_id[3]);
+                 (vp_id * 4) + tim_msix_id[1]);
 
        writeq(val64, &vp_reg->interrupt_cfg0);
 
        writeq(VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(
-                       (first_vp_id * 4) + alarm_msix_id),
+                       (vpath->hldev->first_vp_id * 4) + alarm_msix_id),
                        &vp_reg->interrupt_cfg2);
 
        if (vpath->hldev->config.intr_mode ==
@@ -2258,8 +2241,6 @@ vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vp, int *tim_msix_id,
                                VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN,
                                0, 32), &vp_reg->one_shot_vect3_en);
        }
-
-       return VXGE_HW_OK;
 }
 
 /**
@@ -2279,11 +2260,8 @@ vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vp, int msix_id)
 {
        struct __vxge_hw_device *hldev = vp->vpath->hldev;
        __vxge_hw_pio_mem_write32_upper(
-               (u32) vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
-                       (msix_id  / 4)), 0, 32),
+               (u32) vxge_bVALn(vxge_mBIT(msix_id  >> 2), 0, 32),
                &hldev->common_reg->set_msix_mask_vect[msix_id % 4]);
-
-       return;
 }
 
 /**
@@ -2305,19 +2283,15 @@ vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id)
        if (hldev->config.intr_mode ==
                        VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) {
                __vxge_hw_pio_mem_write32_upper(
-                       (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
-                               (msix_id/4)), 0, 32),
+                       (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
                                &hldev->common_reg->
                                        clr_msix_one_shot_vec[msix_id%4]);
        } else {
                __vxge_hw_pio_mem_write32_upper(
-                       (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
-                               (msix_id/4)), 0, 32),
+                       (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
                                &hldev->common_reg->
                                        clear_msix_mask_vect[msix_id%4]);
        }
-
-       return;
 }
 
 /**
@@ -2337,11 +2311,8 @@ vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vp, int msix_id)
 {
        struct __vxge_hw_device *hldev = vp->vpath->hldev;
        __vxge_hw_pio_mem_write32_upper(
-                       (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id +
-                       (msix_id/4)), 0, 32),
+                       (u32)vxge_bVALn(vxge_mBIT(msix_id >> 2), 0, 32),
                        &hldev->common_reg->clear_msix_mask_vect[msix_id%4]);
-
-       return;
 }
 
 /**
@@ -2358,8 +2329,6 @@ vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vp)
        __vxge_hw_pio_mem_write32_upper(
                (u32)vxge_bVALn(vxge_mBIT(vp->vpath->vp_id), 0, 32),
                &vp->vpath->hldev->common_reg->set_msix_mask_all_vect);
-
-       return;
 }
 
 /**
@@ -2398,8 +2367,6 @@ void vxge_hw_vpath_inta_mask_tx_rx(struct __vxge_hw_vpath_handle *vp)
                        tim_int_mask1[VXGE_HW_VPATH_INTR_RX] | val64),
                        &hldev->common_reg->tim_int_mask1);
        }
-
-       return;
 }
 
 /**
@@ -2436,8 +2403,6 @@ void vxge_hw_vpath_inta_unmask_tx_rx(struct __vxge_hw_vpath_handle *vp)
                          tim_int_mask1[VXGE_HW_VPATH_INTR_RX])) & val64,
                        &hldev->common_reg->tim_int_mask1);
        }
-
-       return;
 }
 
 /**
index 861c853e3e8486e761c07edc2370506e4b521cb5..c252f3d3f65070a9e6d06499177462916e8b3e9b 100644 (file)
@@ -1866,6 +1866,51 @@ struct vxge_hw_ring_rxd_info {
        u32     rth_hash_type;
        u32     rth_value;
 };
+/**
+ * enum vxge_hw_ring_tcode - Transfer codes returned by adapter
+ * @VXGE_HW_RING_T_CODE_OK: Transfer ok.
+ * @VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH: Layer 3 checksum presentation
+ *             configuration mismatch.
+ * @VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH: Layer 4 checksum presentation
+ *             configuration mismatch.
+ * @VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH: Layer 3 and Layer 4 checksum
+ *             presentation configuration mismatch.
+ * @VXGE_HW_RING_T_CODE_L3_PKT_ERR: Layer 3 error unparseable packet,
+ *             such as unknown IPv6 header.
+ * @VXGE_HW_RING_T_CODE_L2_FRM_ERR: Layer 2 error frame integrity
+ *             error, such as FCS or ECC).
+ * @VXGE_HW_RING_T_CODE_BUF_SIZE_ERR: Buffer size error the RxD buffer(
+ *             s) were not appropriately sized and data loss occurred.
+ * @VXGE_HW_RING_T_CODE_INT_ECC_ERR: Internal ECC error RxD corrupted.
+ * @VXGE_HW_RING_T_CODE_BENIGN_OVFLOW: Benign overflow the contents of
+ *             Segment1 exceeded the capacity of Buffer1 and the remainder
+ *             was placed in Buffer2. Segment2 now starts in Buffer3.
+ *             No data loss or errors occurred.
+ * @VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF: Buffer size 0 one of the RxDs
+ *             assigned buffers has a size of 0 bytes.
+ * @VXGE_HW_RING_T_CODE_FRM_DROP: Frame dropped either due to
+ *             VPath Reset or because of a VPIN mismatch.
+ * @VXGE_HW_RING_T_CODE_UNUSED: Unused
+ * @VXGE_HW_RING_T_CODE_MULTI_ERR: Multiple errors more than one
+ *             transfer code condition occurred.
+ *
+ * Transfer codes returned by adapter.
+ */
+enum vxge_hw_ring_tcode {
+       VXGE_HW_RING_T_CODE_OK                          = 0x0,
+       VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH           = 0x1,
+       VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH           = 0x2,
+       VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH        = 0x3,
+       VXGE_HW_RING_T_CODE_L3_PKT_ERR                  = 0x5,
+       VXGE_HW_RING_T_CODE_L2_FRM_ERR                  = 0x6,
+       VXGE_HW_RING_T_CODE_BUF_SIZE_ERR                = 0x7,
+       VXGE_HW_RING_T_CODE_INT_ECC_ERR                 = 0x8,
+       VXGE_HW_RING_T_CODE_BENIGN_OVFLOW               = 0x9,
+       VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF               = 0xA,
+       VXGE_HW_RING_T_CODE_FRM_DROP                    = 0xC,
+       VXGE_HW_RING_T_CODE_UNUSED                      = 0xE,
+       VXGE_HW_RING_T_CODE_MULTI_ERR                   = 0xF
+};
 
 /**
  * enum enum vxge_hw_ring_hash_type - RTH hash types
@@ -1910,7 +1955,7 @@ vxge_hw_ring_rxd_post_post(
        void *rxdh);
 
 enum vxge_hw_status
-vxge_hw_ring_replenish(struct __vxge_hw_ring *ring_handle, u16 min_flag);
+vxge_hw_ring_replenish(struct __vxge_hw_ring *ring_handle);
 
 void
 vxge_hw_ring_rxd_post_post_wmb(
@@ -2042,7 +2087,6 @@ void vxge_hw_fifo_txdl_free(
 
 #define VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET (VXGE_HW_BLOCK_SIZE-8)
 #define VXGE_HW_RING_MEMBLOCK_IDX_OFFSET               (VXGE_HW_BLOCK_SIZE-16)
-#define VXGE_HW_RING_MIN_BUFF_ALLOCATION               64
 
 /*
  * struct __vxge_hw_ring_rxd_priv - Receive descriptor HW-private data.
@@ -2332,7 +2376,7 @@ enum vxge_hw_status vxge_hw_vpath_alarm_process(
        struct __vxge_hw_vpath_handle *vpath_handle,
        u32 skip_alarms);
 
-enum vxge_hw_status
+void
 vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vpath_handle,
                       int *tim_msix_id, int alarm_msix_id);
 
index 77c2a754b7b8572e674273bf9a242e8ab7896499..5da7ab1fd307638ea564b8aa750917d5370687f9 100644 (file)
@@ -17,7 +17,7 @@
 
 #define VXGE_VERSION_MAJOR     "2"
 #define VXGE_VERSION_MINOR     "0"
-#define VXGE_VERSION_FIX       "6"
-#define VXGE_VERSION_BUILD     "18937"
+#define VXGE_VERSION_FIX       "8"
+#define VXGE_VERSION_BUILD     "20182"
 #define VXGE_VERSION_FOR       "k"
 #endif
index cd8cb95c5bd78920c648b2b47831bd9e086bb701..cf9e15fd8d9106ad31ae2bb303459ac5883b4d79 100644 (file)
@@ -634,11 +634,12 @@ static netdev_tx_t cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
        }
        } else { /* chan->protocol == ETH_P_X25 */
                switch (skb->data[0]) {
-               case 0: break;
-               case 1: /* Connect request */
+               case X25_IFACE_DATA:
+                       break;
+               case X25_IFACE_CONNECT:
                        cycx_x25_chan_connect(dev);
                        goto free_packet;
-               case 2: /* Disconnect request */
+               case X25_IFACE_DISCONNECT:
                        cycx_x25_chan_disconnect(dev);
                        goto free_packet;
                default:
@@ -1406,7 +1407,8 @@ static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
                        reset_timer(dev);
 
                        if (chan->protocol == ETH_P_X25)
-                               cycx_x25_chan_send_event(dev, 1);
+                               cycx_x25_chan_send_event(dev,
+                                       X25_IFACE_CONNECT);
 
                        break;
                case WAN_CONNECTING:
@@ -1424,7 +1426,8 @@ static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
                        }
 
                        if (chan->protocol == ETH_P_X25)
-                               cycx_x25_chan_send_event(dev, 2);
+                               cycx_x25_chan_send_event(dev,
+                                       X25_IFACE_DISCONNECT);
 
                        netif_wake_queue(dev);
                        break;
index a4859f7a7cc0c9aa62ce537dcef3740999890b29..d45b08d1dbc939bc390ddbfc99c0a056f1e9582f 100644 (file)
@@ -1175,8 +1175,6 @@ static netdev_tx_t dscc4_start_xmit(struct sk_buff *skb,
        spin_unlock(&dpriv->lock);
 #endif
 
-       dev->trans_start = jiffies;
-
        if (debug > 2)
                dscc4_tx_print(dev, dpriv, "Xmit");
        /* To be cleaned(unsigned int)/optimized. Later, ok ? */
index 4dde2ea4a189d75ae6e7c3da6ec03469c13bc253..a3ea27ce04f236c54b420ff5bbb3f1f28933c975 100644 (file)
@@ -658,7 +658,6 @@ static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
 #endif
        writew(len, &desc->len);
        writeb(ST_TX_EOM, &desc->stat);
-       dev->trans_start = jiffies;
 
        port->txin = next_desc(port, port->txin, 1);
        sca_outw(desc_offset(port, port->txin, 1),
index aad9ed45c254c52af53510ba2158b2a11b22ced0..ea476cbd38b511039c8cb21ecdba7c61c1071ff1 100644 (file)
@@ -585,7 +585,6 @@ static netdev_tx_t sca_xmit(struct sk_buff *skb, struct net_device *dev)
 
        writew(len, &desc->len);
        writeb(ST_TX_EOM, &desc->stat);
-       dev->trans_start = jiffies;
 
        port->txin = (port->txin + 1) % card->tx_ring_buffers;
        sca_outl(desc_offset(port, port->txin, 1),
index c7adbb79f7cc34daf5c1b13f1398ff654d143b33..70527e5a54a2a83f130fcff2eb2f934cce2b59d7 100644 (file)
@@ -49,14 +49,14 @@ static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
 
 static void x25_connected(struct net_device *dev, int reason)
 {
-       x25_connect_disconnect(dev, reason, 1);
+       x25_connect_disconnect(dev, reason, X25_IFACE_CONNECT);
 }
 
 
 
 static void x25_disconnected(struct net_device *dev, int reason)
 {
-       x25_connect_disconnect(dev, reason, 2);
+       x25_connect_disconnect(dev, reason, X25_IFACE_DISCONNECT);
 }
 
 
@@ -71,7 +71,7 @@ static int x25_data_indication(struct net_device *dev, struct sk_buff *skb)
                return NET_RX_DROP;
 
        ptr  = skb->data;
-       *ptr = 0;
+       *ptr = X25_IFACE_DATA;
 
        skb->protocol = x25_type_trans(skb, dev);
        return netif_rx(skb);
@@ -94,13 +94,13 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* X.25 to LAPB */
        switch (skb->data[0]) {
-       case 0:         /* Data to be transmitted */
+       case X25_IFACE_DATA:    /* Data to be transmitted */
                skb_pull(skb, 1);
                if ((result = lapb_data_request(dev, skb)) != LAPB_OK)
                        dev_kfree_skb(skb);
                return NETDEV_TX_OK;
 
-       case 1:
+       case X25_IFACE_CONNECT:
                if ((result = lapb_connect_request(dev))!= LAPB_OK) {
                        if (result == LAPB_CONNECTED)
                                /* Send connect confirm. msg to level 3 */
@@ -112,7 +112,7 @@ static netdev_tx_t x25_xmit(struct sk_buff *skb, struct net_device *dev)
                }
                break;
 
-       case 2:
+       case X25_IFACE_DISCONNECT:
                if ((result = lapb_disconnect_request(dev)) != LAPB_OK) {
                        if (result == LAPB_NOTCONNECTED)
                                /* Send disconnect confirm. msg to level 3 */
index 0c2cdde686a03fd6f50efa58fa9d3538c2f8407a..88e363033e23a629101736b03d79c552759583fe 100644 (file)
@@ -891,7 +891,6 @@ static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
 
        wmb();
        queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc);
-       dev->trans_start = jiffies;
 
        if (qmgr_stat_below_low_watermark(txreadyq)) { /* empty */
 #if DEBUG_TX
index 98e2f99903d775e7ddfdd78ea93a56f9304ea77d..4d4dc38c72902e9ca62e8b7655cb9b70388a1a17 100644 (file)
@@ -139,7 +139,7 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
                return NET_RX_DROP;
 
        ptr  = skb->data;
-       *ptr = 0x00;
+       *ptr = X25_IFACE_DATA;
 
        skb->protocol = x25_type_trans(skb, dev);
        return netif_rx(skb);
@@ -161,14 +161,14 @@ static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
                goto drop;
 
        switch (skb->data[0]) {
-       case 0x00:
+       case X25_IFACE_DATA:
                break;
-       case 0x01:
+       case X25_IFACE_CONNECT:
                if ((err = lapb_connect_request(dev)) != LAPB_OK)
                        printk(KERN_ERR "lapbeth: lapb_connect_request "
                               "error: %d\n", err);
                goto drop;
-       case 0x02:
+       case X25_IFACE_DISCONNECT:
                if ((err = lapb_disconnect_request(dev)) != LAPB_OK)
                        printk(KERN_ERR "lapbeth: lapb_disconnect_request "
                               "err: %d\n", err);
@@ -225,7 +225,7 @@ static void lapbeth_connected(struct net_device *dev, int reason)
        }
 
        ptr  = skb_put(skb, 1);
-       *ptr = 0x01;
+       *ptr = X25_IFACE_CONNECT;
 
        skb->protocol = x25_type_trans(skb, dev);
        netif_rx(skb);
@@ -242,7 +242,7 @@ static void lapbeth_disconnected(struct net_device *dev, int reason)
        }
 
        ptr  = skb_put(skb, 1);
-       *ptr = 0x02;
+       *ptr = X25_IFACE_DISCONNECT;
 
        skb->protocol = x25_type_trans(skb, dev);
        netif_rx(skb);
index b278503771212dd02b59977dba0033957181a587..e2c6f7f4f51c16a36bea5d11daff068200ed125d 100644 (file)
@@ -1506,8 +1506,6 @@ static netdev_tx_t lmc_start_xmit(struct sk_buff *skb,
     /* send now! */
     LMC_CSR_WRITE (sc, csr_txpoll, 0);
 
-    dev->trans_start = jiffies;
-
     spin_unlock_irqrestore(&sc->lmc_lock, flags);
 
     lmc_trace(dev, "lmc_start_xmit_out");
@@ -2103,7 +2101,7 @@ static void lmc_driver_timeout(struct net_device *dev)
     printk("%s: Xmitter busy|\n", dev->name);
 
     sc->extra_stats.tx_tbusy_calls++;
-    if (jiffies - dev->trans_start < TX_TIMEOUT)
+    if (jiffies - dev_trans_start(dev) < TX_TIMEOUT)
            goto bug_out;
 
     /*
@@ -2135,7 +2133,7 @@ static void lmc_driver_timeout(struct net_device *dev)
     sc->lmc_device->stats.tx_errors++;
     sc->extra_stats.tx_ProcTimeout++; /* -baz */
 
-    dev->trans_start = jiffies;
+    dev->trans_start = jiffies; /* prevent tx timeout */
 
 bug_out:
 
index 3f744c6430946905cc312eb257d77eaef57c7878..c6aa66e5b52f34aedd5736e3c7e8c967870c24d2 100644 (file)
@@ -396,7 +396,7 @@ static void tx1_dma_buf_check(pc300_t * card, int ch)
        u16 next_bd = card->chan[ch].tx_next_bd;
        u32 scabase = card->hw.scabase;
 
-       printk ("\nnfree_tx_bd = %d \n", card->chan[ch].nfree_tx_bd);
+       printk ("\nnfree_tx_bd = %d\n", card->chan[ch].nfree_tx_bd);
        printk("#CH%d: f_bd = %d(0x%08x), n_bd = %d(0x%08x)\n", ch,
               first_bd, TX_BD_ADDR(ch, first_bd),
               next_bd, TX_BD_ADDR(ch, next_bd));
@@ -1790,7 +1790,7 @@ static void cpc_tx_timeout(struct net_device *dev)
                           cpc_readb(card->hw.falcbase + card->hw.cpld_reg2) &
                           ~(CPLD_REG2_FALC_LED1 << (2 * ch)));
        }
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
        CPC_UNLOCK(card, flags);
        netif_wake_queue(dev);
 }
@@ -1849,7 +1849,6 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev)
        if (d->trace_on) {
                cpc_trace(dev, skb, 'T');
        }
-       dev->trans_start = jiffies;
 
        /* Start transmission */
        CPC_LOCK(card, flags);
index 4917a94943bd9c1567bd63317b89043c3a08ccb3..4293889e287e7ff28a00020d7279c67b596a9d2a 100644 (file)
@@ -366,7 +366,7 @@ static void cpc_tty_close(struct tty_struct *tty, struct file *flip)
        int res;
 
        if (!tty || !tty->driver_data ) {
-               CPC_TTY_DBG("hdlx-tty: no TTY in close \n");
+               CPC_TTY_DBG("hdlx-tty: no TTY in close\n");
                return;
        }
 
index 31c41af2246d6cb4c5926ac7f7cec43b4e71c273..43ae6f440bfb179fbc4ee3ec59d20dfdd0a38331 100644 (file)
@@ -1352,7 +1352,7 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map)
                return(-EINVAL);
 
        if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){
-               printk(KERN_WARNING "SDLA: io-port 0x%04lx in use \n", dev->base_addr);
+               printk(KERN_WARNING "SDLA: io-port 0x%04lx in use\n", dev->base_addr);
                return(-EINVAL);
        }
        base = map->base_addr;
index 541c700dceef44b84d54f06db8c2797073bc3b3f..db73a7be199f0183fef7f40fa50c013b1db8d263 100644 (file)
@@ -298,7 +298,6 @@ static netdev_tx_t wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
        desc->stat = PACKET_FULL;
        writel(1 << (DOORBELL_TO_CARD_TX_0 + port->node),
               port->card->plx + PLX_DOORBELL_TO_CARD);
-       dev->trans_start = jiffies;
 
        port->tx_out = (port->tx_out + 1) % TX_BUFFERS;
 
index 80d5c5834a0bf976c0446a02e7a3050823158c4a..166e77dfffda9f9ec1b00c764d09b5b41b763506 100644 (file)
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
-#include <linux/x25.h>
 #include <linux/lapb.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/compat.h>
 #include <linux/slab.h>
+#include <net/x25device.h>
 #include "x25_asy.h"
 
 #include <net/x25device.h>
@@ -315,15 +315,15 @@ static netdev_tx_t x25_asy_xmit(struct sk_buff *skb,
        }
 
        switch (skb->data[0]) {
-       case 0x00:
+       case X25_IFACE_DATA:
                break;
-       case 0x01: /* Connection request .. do nothing */
+       case X25_IFACE_CONNECT: /* Connection request .. do nothing */
                err = lapb_connect_request(dev);
                if (err != LAPB_OK)
                        printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
                kfree_skb(skb);
                return NETDEV_TX_OK;
-       case 0x02: /* Disconnect request .. do nothing - hang up ?? */
+       case X25_IFACE_DISCONNECT: /* do nothing - hang up ?? */
                err = lapb_disconnect_request(dev);
                if (err != LAPB_OK)
                        printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
@@ -411,7 +411,7 @@ static void x25_asy_connected(struct net_device *dev, int reason)
        }
 
        ptr  = skb_put(skb, 1);
-       *ptr = 0x01;
+       *ptr = X25_IFACE_CONNECT;
 
        skb->protocol = x25_type_trans(skb, sl->dev);
        netif_rx(skb);
@@ -430,7 +430,7 @@ static void x25_asy_disconnected(struct net_device *dev, int reason)
        }
 
        ptr  = skb_put(skb, 1);
-       *ptr = 0x02;
+       *ptr = X25_IFACE_DISCONNECT;
 
        skb->protocol = x25_type_trans(skb, sl->dev);
        netif_rx(skb);
index d8322d2d1e2908b0412ad5b7220e8483a04aa3e9..746a5ee32f3356cf82de27fe583910f3053526e2 100644 (file)
@@ -395,7 +395,6 @@ wd_reset_8390(struct net_device *dev)
                outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
 
        if (ei_debug > 1) printk("reset done\n");
-       return;
 }
 
 /* Grab the 8390 specific header. Similar to the block_input routine, but
index 6180772dcc092011bf98f995048b45b81df2efa5..d86e8f31e7fcfc8b0b3bc1e1a46cc6f35cb8bfdb 100644 (file)
 #define D_SUBMODULE control
 #include "debug-levels.h"
 
+static int i2400m_idle_mode_disabled;/* 0 (idle mode enabled) by default */
+module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
+MODULE_PARM_DESC(idle_mode_disabled,
+                "If true, the device will not enable idle mode negotiation "
+                "with the base station (when connected) to save power.");
+
+/* 0 (power saving enabled) by default */
+static int i2400m_power_save_disabled;
+module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
+MODULE_PARM_DESC(power_save_disabled,
+                "If true, the driver will not tell the device to enter "
+                "power saving mode when it reports it is ready for it. "
+                "False by default (so the device is told to do power "
+                "saving).");
+
 int i2400m_passive_mode;       /* 0 (passive mode disabled) by default */
 module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
 MODULE_PARM_DESC(passive_mode,
@@ -346,7 +361,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
                        i2400m_state);
                i2400m_reset(i2400m, I2400M_RT_WARM);
                break;
-       };
+       }
        d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
                i2400m, ss, i2400m_state);
 }
@@ -395,7 +410,7 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
        default:
                dev_err(dev, "HW BUG? unknown media status %u\n",
                        status);
-       };
+       }
        d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
                i2400m, ms, status);
 }
@@ -524,7 +539,7 @@ void i2400m_report_hook(struct i2400m *i2400m,
                        }
                }
                break;
-       };
+       }
        d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n",
                i2400m, l3l4_hdr, size);
 }
@@ -567,8 +582,7 @@ void i2400m_msg_ack_hook(struct i2400m *i2400m,
                                         size);
                }
                break;
-       };
-       return;
+       }
 }
 
 
@@ -740,7 +754,7 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
                break;
        default:
                ack_timeout = HZ;
-       };
+       }
 
        if (unlikely(i2400m->trace_msg_from_user))
                wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
@@ -1419,5 +1433,4 @@ void i2400m_dev_shutdown(struct i2400m *i2400m)
 
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
-       return;
 }
index 94dc83c3969d7498d7a625d48685741c1642a788..9c8b78d4abd2f2b416c15cf3511f3bcdc11ca25e 100644 (file)
 #include "debug-levels.h"
 
 
-int i2400m_idle_mode_disabled; /* 0 (idle mode enabled) by default */
-module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
-MODULE_PARM_DESC(idle_mode_disabled,
-                "If true, the device will not enable idle mode negotiation "
-                "with the base station (when connected) to save power.");
-
-int i2400m_rx_reorder_disabled;        /* 0 (rx reorder enabled) by default */
-module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
-MODULE_PARM_DESC(rx_reorder_disabled,
-                "If true, RX reordering will be disabled.");
-
-int i2400m_power_save_disabled;        /* 0 (power saving enabled) by default */
-module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
-MODULE_PARM_DESC(power_save_disabled,
-                "If true, the driver will not tell the device to enter "
-                "power saving mode when it reports it is ready for it. "
-                "False by default (so the device is told to do power "
-                "saving).");
-
 static char i2400m_debug_params[128];
 module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params),
                    0644);
@@ -395,6 +376,16 @@ retry:
        result = i2400m_dev_initialize(i2400m);
        if (result < 0)
                goto error_dev_initialize;
+
+       /* We don't want any additional unwanted error recovery triggered
+        * from any other context so if anything went wrong before we come
+        * here, let's keep i2400m->error_recovery untouched and leave it to
+        * dev_reset_handle(). See dev_reset_handle(). */
+
+       atomic_dec(&i2400m->error_recovery);
+       /* Every thing works so far, ok, now we are ready to
+        * take error recovery if it's required. */
+
        /* At this point, reports will come for the device and set it
         * to the right state if it is different than UNINITIALIZED */
        d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
@@ -403,10 +394,10 @@ retry:
 
 error_dev_initialize:
 error_check_mac_addr:
+error_fw_check:
        i2400m->ready = 0;
        wmb();          /* see i2400m->ready's documentation  */
        flush_workqueue(i2400m->work_queue);
-error_fw_check:
        if (i2400m->bus_dev_stop)
                i2400m->bus_dev_stop(i2400m);
 error_bus_dev_start:
@@ -436,7 +427,8 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
                result = __i2400m_dev_start(i2400m, bm_flags);
                if (result >= 0) {
                        i2400m->updown = 1;
-                       wmb();  /* see i2400m->updown's documentation */
+                       i2400m->alive = 1;
+                       wmb();/* see i2400m->updown and i2400m->alive's doc */
                }
        }
        mutex_unlock(&i2400m->init_mutex);
@@ -497,7 +489,8 @@ void i2400m_dev_stop(struct i2400m *i2400m)
        if (i2400m->updown) {
                __i2400m_dev_stop(i2400m);
                i2400m->updown = 0;
-               wmb();  /* see i2400m->updown's documentation  */
+               i2400m->alive = 0;
+               wmb();  /* see i2400m->updown and i2400m->alive's doc */
        }
        mutex_unlock(&i2400m->init_mutex);
 }
@@ -617,12 +610,12 @@ int i2400m_post_reset(struct i2400m *i2400m)
 error_dev_start:
        if (i2400m->bus_release)
                i2400m->bus_release(i2400m);
-error_bus_setup:
        /* even if the device was up, it could not be recovered, so we
         * mark it as down. */
        i2400m->updown = 0;
        wmb();          /* see i2400m->updown's documentation  */
        mutex_unlock(&i2400m->init_mutex);
+error_bus_setup:
        d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
        return result;
 }
@@ -669,6 +662,9 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
 
        d_fnstart(3, dev, "(ws %p i2400m %p reason %s)\n", ws, i2400m, reason);
 
+       i2400m->boot_mode = 1;
+       wmb();          /* Make sure i2400m_msg_to_dev() sees boot_mode */
+
        result = 0;
        if (mutex_trylock(&i2400m->init_mutex) == 0) {
                /* We are still in i2400m_dev_start() [let it fail] or
@@ -679,39 +675,68 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
                complete(&i2400m->msg_completion);
                goto out;
        }
-       if (i2400m->updown == 0)  {
-               dev_info(dev, "%s: device is down, doing nothing\n", reason);
-               goto out_unlock;
-       }
+
        dev_err(dev, "%s: reinitializing driver\n", reason);
-       __i2400m_dev_stop(i2400m);
-       result = __i2400m_dev_start(i2400m,
-                                   I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
-       if (result < 0) {
+       rmb();
+       if (i2400m->updown) {
+               __i2400m_dev_stop(i2400m);
                i2400m->updown = 0;
                wmb();          /* see i2400m->updown's documentation  */
-               dev_err(dev, "%s: cannot start the device: %d\n",
-                       reason, result);
-               result = -EUCLEAN;
        }
-out_unlock:
+
+       if (i2400m->alive) {
+               result = __i2400m_dev_start(i2400m,
+                                   I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
+               if (result < 0) {
+                       dev_err(dev, "%s: cannot start the device: %d\n",
+                               reason, result);
+                       result = -EUCLEAN;
+                       if (atomic_read(&i2400m->bus_reset_retries)
+                                       >= I2400M_BUS_RESET_RETRIES) {
+                               result = -ENODEV;
+                               dev_err(dev, "tried too many times to "
+                                       "reset the device, giving up\n");
+                       }
+               }
+       }
+
        if (i2400m->reset_ctx) {
                ctx->result = result;
                complete(&ctx->completion);
        }
        mutex_unlock(&i2400m->init_mutex);
        if (result == -EUCLEAN) {
+               /*
+                * We come here because the reset during operational mode
+                * wasn't successully done and need to proceed to a bus
+                * reset. For the dev_reset_handle() to be able to handle
+                * the reset event later properly, we restore boot_mode back
+                * to the state before previous reset. ie: just like we are
+                * issuing the bus reset for the first time
+                */
+               i2400m->boot_mode = 0;
+               wmb();
+
+               atomic_inc(&i2400m->bus_reset_retries);
                /* ops, need to clean up [w/ init_mutex not held] */
                result = i2400m_reset(i2400m, I2400M_RT_BUS);
                if (result >= 0)
                        result = -ENODEV;
+       } else {
+               rmb();
+               if (i2400m->alive) {
+                       /* great, we expect the device state up and
+                        * dev_start() actually brings the device state up */
+                       i2400m->updown = 1;
+                       wmb();
+                       atomic_set(&i2400m->bus_reset_retries, 0);
+               }
        }
 out:
        i2400m_put(i2400m);
        kfree(iw);
        d_fnend(3, dev, "(ws %p i2400m %p reason %s) = void\n",
                ws, i2400m, reason);
-       return;
 }
 
 
@@ -729,14 +754,72 @@ out:
  */
 int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason)
 {
-       i2400m->boot_mode = 1;
-       wmb();          /* Make sure i2400m_msg_to_dev() sees boot_mode */
        return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
                                    GFP_ATOMIC, &reason, sizeof(reason));
 }
 EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle);
 
 
+ /*
+ * The actual work of error recovery.
+ *
+ * The current implementation of error recovery is to trigger a bus reset.
+ */
+static
+void __i2400m_error_recovery(struct work_struct *ws)
+{
+       struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws);
+       struct i2400m *i2400m = iw->i2400m;
+
+       i2400m_reset(i2400m, I2400M_RT_BUS);
+
+       i2400m_put(i2400m);
+       kfree(iw);
+       return;
+}
+
+/*
+ * Schedule a work struct for error recovery.
+ *
+ * The intention of error recovery is to bring back the device to some
+ * known state whenever TX sees -110 (-ETIMEOUT) on copying the data to
+ * the device. The TX failure could mean a device bus stuck, so the current
+ * error recovery implementation is to trigger a bus reset to the device
+ * and hopefully it can bring back the device.
+ *
+ * The actual work of error recovery has to be in a thread context because
+ * it is kicked off in the TX thread (i2400ms->tx_workqueue) which is to be
+ * destroyed by the error recovery mechanism (currently a bus reset).
+ *
+ * Also, there may be already a queue of TX works that all hit
+ * the -ETIMEOUT error condition because the device is stuck already.
+ * Since bus reset is used as the error recovery mechanism and we don't
+ * want consecutive bus resets simply because the multiple TX works
+ * in the queue all hit the same device erratum, the flag "error_recovery"
+ * is introduced for preventing unwanted consecutive bus resets.
+ *
+ * Error recovery shall only be invoked again if previous one was completed.
+ * The flag error_recovery is set when error recovery mechanism is scheduled,
+ * and is checked when we need to schedule another error recovery. If it is
+ * in place already, then we shouldn't schedule another one.
+ */
+void i2400m_error_recovery(struct i2400m *i2400m)
+{
+       struct device *dev = i2400m_dev(i2400m);
+
+       if (atomic_add_return(1, &i2400m->error_recovery) == 1) {
+               if (i2400m_schedule_work(i2400m, __i2400m_error_recovery,
+                       GFP_ATOMIC, NULL, 0) < 0) {
+                       dev_err(dev, "run out of memory for "
+                               "scheduling an error recovery ?\n");
+                       atomic_dec(&i2400m->error_recovery);
+               }
+       } else
+               atomic_dec(&i2400m->error_recovery);
+       return;
+}
+EXPORT_SYMBOL_GPL(i2400m_error_recovery);
+
 /*
  * Alloc the command and ack buffers for boot mode
  *
@@ -803,6 +886,13 @@ void i2400m_init(struct i2400m *i2400m)
 
        mutex_init(&i2400m->init_mutex);
        /* wake_tx_ws is initialized in i2400m_tx_setup() */
+       atomic_set(&i2400m->bus_reset_retries, 0);
+
+       i2400m->alive = 0;
+
+       /* initialize error_recovery to 1 for denoting we
+        * are not yet ready to take any error recovery */
+       atomic_set(&i2400m->error_recovery, 1);
 }
 EXPORT_SYMBOL_GPL(i2400m_init);
 
@@ -996,7 +1086,6 @@ void __exit i2400m_driver_exit(void)
        /* for scheds i2400m_dev_reset_handle() */
        flush_scheduled_work();
        i2400m_barker_db_exit();
-       return;
 }
 module_exit(i2400m_driver_exit);
 
index b9c4bed3b457cf52087d3848040153ee325e108c..360d4fb195f475aff73e9880d64bc1c212c0fb9f 100644 (file)
@@ -99,7 +99,10 @@ enum {
  *
  * @tx_workqueue: workqeueue used for data TX; we don't use the
  *     system's workqueue as that might cause deadlocks with code in
- *     the bus-generic driver.
+ *     the bus-generic driver. The read/write operation to the queue
+ *     is protected with spinlock (tx_lock in struct i2400m) to avoid
+ *     the queue being destroyed in the middle of a the queue read/write
+ *     operation.
  *
  * @debugfs_dentry: dentry for the SDIO specific debugfs files
  *
index 820b128705ecf69f2493eb0a628cbc71f88a8a30..fa74777fd65f6cc79e9d59dbe679373a886ed91e 100644 (file)
 #include <linux/wimax/i2400m.h>
 #include <asm/byteorder.h>
 
+enum {
+/* netdev interface */
+       /*
+        * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size
+        *
+        * The MTU is 1400 or less
+        */
+       I2400M_MAX_MTU = 1400,
+};
+
 /* Misc constants */
 enum {
        /* Size of the Boot Mode Command buffer */
@@ -167,6 +177,11 @@ enum {
        I2400M_BM_ACK_BUF_SIZE = 256,
 };
 
+enum {
+       /* Maximum number of bus reset can be retried */
+       I2400M_BUS_RESET_RETRIES = 3,
+};
+
 /**
  * struct i2400m_poke_table - Hardware poke table for the Intel 2400m
  *
@@ -227,6 +242,11 @@ struct i2400m_barker_db;
  *     so we have a tx_blk_size variable that the bus layer sets to
  *     tell the engine how much of that we need.
  *
+ * @bus_tx_room_min: [fill] Minimum room required while allocating
+ *     TX queue's buffer space for message header. SDIO requires
+ *     224 bytes and USB 16 bytes. Refer bus specific driver code
+ *     for details.
+ *
  * @bus_pl_size_max: [fill] Maximum payload size.
  *
  * @bus_setup: [optional fill] Function called by the bus-generic code
@@ -397,7 +417,7 @@ struct i2400m_barker_db;
  *
  * @tx_size_max: biggest TX message sent.
  *
- * @rx_lock: spinlock to protect RX members
+ * @rx_lock: spinlock to protect RX members and rx_roq_refcount.
  *
  * @rx_pl_num: total number of payloads received
  *
@@ -421,6 +441,10 @@ struct i2400m_barker_db;
  *     delivered. Then the driver can release them to the host. See
  *     drivers/net/i2400m/rx.c for details.
  *
+ * @rx_roq_refcount: refcount rx_roq. This refcounts any access to
+ *     rx_roq thus preventing rx_roq being destroyed when rx_roq
+ *     is being accessed. rx_roq_refcount is protected by rx_lock.
+ *
  * @rx_reports: reports received from the device that couldn't be
  *     processed because the driver wasn't still ready; when ready,
  *     they are pulled from here and chewed.
@@ -507,6 +531,38 @@ struct i2400m_barker_db;
  *     same.
  *
  * @pm_notifier: used to register for PM events
+ *
+ * @bus_reset_retries: counter for the number of bus resets attempted for
+ *     this boot. It's not for tracking the number of bus resets during
+ *     the whole driver life cycle (from insmod to rmmod) but for the
+ *     number of dev_start() executed until dev_start() returns a success
+ *     (ie: a good boot means a dev_stop() followed by a successful
+ *     dev_start()). dev_reset_handler() increments this counter whenever
+ *     it is triggering a bus reset. It checks this counter to decide if a
+ *     subsequent bus reset should be retried. dev_reset_handler() retries
+ *     the bus reset until dev_start() succeeds or the counter reaches
+ *     I2400M_BUS_RESET_RETRIES. The counter is cleared to 0 in
+ *     dev_reset_handle() when dev_start() returns a success,
+ *     ie: a successul boot is completed.
+ *
+ * @alive: flag to denote if the device *should* be alive. This flag is
+ *     everything like @updown (see doc for @updown) except reflecting
+ *     the device state *we expect* rather than the actual state as denoted
+ *     by @updown. It is set 1 whenever @updown is set 1 in dev_start().
+ *     Then the device is expected to be alive all the time
+ *     (i2400m->alive remains 1) until the driver is removed. Therefore
+ *     all the device reboot events detected can be still handled properly
+ *     by either dev_reset_handle() or .pre_reset/.post_reset as long as
+ *     the driver presents. It is set 0 along with @updown in dev_stop().
+ *
+ * @error_recovery: flag to denote if we are ready to take an error recovery.
+ *     0 for ready to take an error recovery; 1 for not ready. It is
+ *     initialized to 1 while probe() since we don't tend to take any error
+ *     recovery during probe(). It is decremented by 1 whenever dev_start()
+ *     succeeds to indicate we are ready to take error recovery from now on.
+ *     It is checked every time we wanna schedule an error recovery. If an
+ *     error recovery is already in place (error_recovery was set 1), we
+ *     should not schedule another one until the last one is done.
  */
 struct i2400m {
        struct wimax_dev wimax_dev;     /* FIRST! See doc */
@@ -522,6 +578,7 @@ struct i2400m {
        wait_queue_head_t state_wq;     /* Woken up when on state updates */
 
        size_t bus_tx_block_size;
+       size_t bus_tx_room_min;
        size_t bus_pl_size_max;
        unsigned bus_bm_retries;
 
@@ -550,10 +607,12 @@ struct i2400m {
                tx_num, tx_size_acc, tx_size_min, tx_size_max;
 
        /* RX stuff */
-       spinlock_t rx_lock;             /* protect RX state */
+       /* protect RX state and rx_roq_refcount */
+       spinlock_t rx_lock;
        unsigned rx_pl_num, rx_pl_max, rx_pl_min,
                rx_num, rx_size_acc, rx_size_min, rx_size_max;
-       struct i2400m_roq *rx_roq;      /* not under rx_lock! */
+       struct i2400m_roq *rx_roq;      /* access is refcounted */
+       struct kref rx_roq_refcount;    /* refcount access to rx_roq */
        u8 src_mac_addr[ETH_HLEN];
        struct list_head rx_reports;    /* under rx_lock! */
        struct work_struct rx_report_ws;
@@ -581,6 +640,16 @@ struct i2400m {
        struct i2400m_barker_db *barker;
 
        struct notifier_block pm_notifier;
+
+       /* counting bus reset retries in this boot */
+       atomic_t bus_reset_retries;
+
+       /* if the device is expected to be alive */
+       unsigned alive;
+
+       /* 0 if we are ready for error recovery; 1 if not ready  */
+       atomic_t error_recovery;
+
 };
 
 
@@ -803,6 +872,7 @@ void i2400m_put(struct i2400m *i2400m)
 extern int i2400m_dev_reset_handle(struct i2400m *, const char *);
 extern int i2400m_pre_reset(struct i2400m *);
 extern int i2400m_post_reset(struct i2400m *);
+extern void i2400m_error_recovery(struct i2400m *);
 
 /*
  * _setup()/_release() are called by the probe/disconnect functions of
@@ -815,7 +885,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *);
 extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *);
 extern void i2400m_tx_msg_sent(struct i2400m *);
 
-extern int i2400m_power_save_disabled;
 
 /*
  * Utility functions
@@ -922,10 +991,5 @@ extern int i2400m_barker_db_init(const char *);
 extern void i2400m_barker_db_exit(void);
 
 
-/* Module parameters */
-
-extern int i2400m_idle_mode_disabled;
-extern int i2400m_rx_reorder_disabled;
-
 
 #endif /* #ifndef __I2400M_H__ */
index b811c2f1f5e978dc42e8cacea806307a6cff70c7..94742e1eafe079d4dd99a33e1e144642f3cb6ad7 100644 (file)
 
 enum {
 /* netdev interface */
-       /*
-        * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size
-        *
-        * The MTU is 1400 or less
-        */
-       I2400M_MAX_MTU = 1400,
        /* 20 secs? yep, this is the maximum timeout that the device
         * might take to get out of IDLE / negotiate it with the base
         * station. We add 1sec for good measure. */
        I2400M_TX_TIMEOUT = 21 * HZ,
-       I2400M_TX_QLEN = 5,
+       /*
+        * Experimentation has determined that, 20 to be a good value
+        * for minimizing the jitter in the throughput.
+        */
+       I2400M_TX_QLEN = 20,
 };
 
 
@@ -255,7 +253,6 @@ void i2400m_net_wake_stop(struct i2400m *i2400m)
                kfree_skb(wake_tx_skb);
        }
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
-       return;
 }
 
 
@@ -434,7 +431,6 @@ void i2400m_tx_timeout(struct net_device *net_dev)
         * this, there might be data pending to be sent or not...
         */
        net_dev->stats.tx_errors++;
-       return;
 }
 
 
index fa2e11e5b4b9cb32718bb827f41ecbe1c3c580ef..6537593fae66cfc6cfc02c4b5dc95c7b35d4e572 100644 (file)
 #define D_SUBMODULE rx
 #include "debug-levels.h"
 
+static int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */
+module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
+MODULE_PARM_DESC(rx_reorder_disabled,
+                "If true, RX reordering will be disabled.");
+
 struct i2400m_report_hook_args {
        struct sk_buff *skb_rx;
        const struct i2400m_l3l4_hdr *l3l4_hdr;
@@ -300,20 +305,18 @@ void i2400m_rx_ctl_ack(struct i2400m *i2400m,
                d_printf(1, dev, "Huh? waiter for command reply cancelled\n");
                goto error_waiter_cancelled;
        }
-       if (ack_skb == NULL) {
+       if (IS_ERR(ack_skb))
                dev_err(dev, "CMD/GET/SET ack: cannot allocate SKB\n");
-               i2400m->ack_skb = ERR_PTR(-ENOMEM);
-       } else
-               i2400m->ack_skb = ack_skb;
+       i2400m->ack_skb = ack_skb;
        spin_unlock_irqrestore(&i2400m->rx_lock, flags);
        complete(&i2400m->msg_completion);
        return;
 
 error_waiter_cancelled:
-       kfree_skb(ack_skb);
+       if (!IS_ERR(ack_skb))
+               kfree_skb(ack_skb);
 error_no_waiter:
        spin_unlock_irqrestore(&i2400m->rx_lock, flags);
-       return;
 }
 
 
@@ -718,7 +721,6 @@ void __i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
 out:
        d_fnend(4, dev, "(i2400m %p roq %p skb %p sn %u nsn %d) = void\n",
                i2400m, roq, skb, sn, nsn);
-       return;
 }
 
 
@@ -743,12 +745,12 @@ unsigned __i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
        unsigned new_nws, nsn_itr;
 
        new_nws = __i2400m_roq_nsn(roq, sn);
-       if (unlikely(new_nws >= 1024) && d_test(1)) {
-               dev_err(dev, "SW BUG? __update_ws new_nws %u (sn %u ws %u)\n",
-                       new_nws, sn, roq->ws);
-               WARN_ON(1);
-               i2400m_roq_log_dump(i2400m, roq);
-       }
+       /*
+        * For type 2(update_window_start) rx messages, there is no
+        * need to check if the normalized sequence number is greater 1023.
+        * Simply insert and deliver all packets to the host up to the
+        * window start.
+        */
        skb_queue_walk_safe(&roq->queue, skb_itr, tmp_itr) {
                roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
                nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn);
@@ -798,7 +800,6 @@ void i2400m_roq_reset(struct i2400m *i2400m, struct i2400m_roq *roq)
        }
        roq->ws = 0;
        d_fnend(2, dev, "(i2400m %p roq %p) = void\n", i2400m, roq);
-       return;
 }
 
 
@@ -837,7 +838,6 @@ void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
        }
        d_fnend(2, dev, "(i2400m %p roq %p skb %p lbn %u) = void\n",
                i2400m, roq, skb, lbn);
-       return;
 }
 
 
@@ -863,7 +863,6 @@ void i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
        i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_WS,
                             old_ws, len, sn, nsn, roq->ws);
        d_fnstart(2, dev, "(i2400m %p roq %p sn %u) = void\n", i2400m, roq, sn);
-       return;
 }
 
 
@@ -890,32 +889,51 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
                  i2400m, roq, skb, sn);
        len = skb_queue_len(&roq->queue);
        nsn = __i2400m_roq_nsn(roq, sn);
+       /*
+        * For type 3(queue_update_window_start) rx messages, there is no
+        * need to check if the normalized sequence number is greater 1023.
+        * Simply insert and deliver all packets to the host up to the
+        * window start.
+        */
        old_ws = roq->ws;
-       if (unlikely(nsn >= 1024)) {
-               dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n",
-                       nsn, sn, roq->ws);
-               i2400m_roq_log_dump(i2400m, roq);
-               i2400m_reset(i2400m, I2400M_RT_WARM);
-       } else {
-               /* if the queue is empty, don't bother as we'd queue
-                * it and inmediately unqueue it -- just deliver it */
-               if (len == 0) {
-                       struct i2400m_roq_data *roq_data;
-                       roq_data = (struct i2400m_roq_data *) &skb->cb;
-                       i2400m_net_erx(i2400m, skb, roq_data->cs);
-               }
-               else
-                       __i2400m_roq_queue(i2400m, roq, skb, sn, nsn);
-               __i2400m_roq_update_ws(i2400m, roq, sn + 1);
-               i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET_WS,
-                                  old_ws, len, sn, nsn, roq->ws);
-       }
+       /* If the queue is empty, don't bother as we'd queue
+        * it and immediately unqueue it -- just deliver it.
+        */
+       if (len == 0) {
+               struct i2400m_roq_data *roq_data;
+               roq_data = (struct i2400m_roq_data *) &skb->cb;
+               i2400m_net_erx(i2400m, skb, roq_data->cs);
+       } else
+               __i2400m_roq_queue(i2400m, roq, skb, sn, nsn);
+
+       __i2400m_roq_update_ws(i2400m, roq, sn + 1);
+       i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET_WS,
+                          old_ws, len, sn, nsn, roq->ws);
+
        d_fnend(2, dev, "(i2400m %p roq %p skb %p sn %u) = void\n",
                i2400m, roq, skb, sn);
-       return;
 }
 
 
+/*
+ * This routine destroys the memory allocated for rx_roq, when no
+ * other thread is accessing it. Access to rx_roq is refcounted by
+ * rx_roq_refcount, hence memory allocated must be destroyed when
+ * rx_roq_refcount becomes zero. This routine gets executed when
+ * rx_roq_refcount becomes zero.
+ */
+void i2400m_rx_roq_destroy(struct kref *ref)
+{
+       unsigned itr;
+       struct i2400m *i2400m
+                       = container_of(ref, struct i2400m, rx_roq_refcount);
+       for (itr = 0; itr < I2400M_RO_CIN + 1; itr++)
+               __skb_queue_purge(&i2400m->rx_roq[itr].queue);
+       kfree(i2400m->rx_roq[0].log);
+       kfree(i2400m->rx_roq);
+       i2400m->rx_roq = NULL;
+}
+
 /*
  * Receive and send up an extended data packet
  *
@@ -969,6 +987,7 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
        unsigned ro_needed, ro_type, ro_cin, ro_sn;
        struct i2400m_roq *roq;
        struct i2400m_roq_data *roq_data;
+       unsigned long flags;
 
        BUILD_BUG_ON(ETH_HLEN > sizeof(*hdr));
 
@@ -1007,7 +1026,16 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
                ro_cin = (reorder >> I2400M_RO_CIN_SHIFT) & I2400M_RO_CIN;
                ro_sn = (reorder >> I2400M_RO_SN_SHIFT) & I2400M_RO_SN;
 
+               spin_lock_irqsave(&i2400m->rx_lock, flags);
                roq = &i2400m->rx_roq[ro_cin];
+               if (roq == NULL) {
+                       kfree_skb(skb); /* rx_roq is already destroyed */
+                       spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+                       goto error;
+               }
+               kref_get(&i2400m->rx_roq_refcount);
+               spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+
                roq_data = (struct i2400m_roq_data *) &skb->cb;
                roq_data->sn = ro_sn;
                roq_data->cs = cs;
@@ -1034,6 +1062,10 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
                default:
                        dev_err(dev, "HW BUG? unknown reorder type %u\n", ro_type);
                }
+
+               spin_lock_irqsave(&i2400m->rx_lock, flags);
+               kref_put(&i2400m->rx_roq_refcount, i2400m_rx_roq_destroy);
+               spin_unlock_irqrestore(&i2400m->rx_lock, flags);
        }
        else
                i2400m_net_erx(i2400m, skb, cs);
@@ -1041,7 +1073,6 @@ error_skb_clone:
 error:
        d_fnend(2, dev, "(i2400m %p skb_rx %p single %u payload %p "
                "size %zu) = void\n", i2400m, skb_rx, single_last, payload, size);
-       return;
 }
 
 
@@ -1344,6 +1375,7 @@ int i2400m_rx_setup(struct i2400m *i2400m)
                        __i2400m_roq_init(&i2400m->rx_roq[itr]);
                        i2400m->rx_roq[itr].log = &rd[itr];
                }
+               kref_init(&i2400m->rx_roq_refcount);
        }
        return 0;
 
@@ -1357,12 +1389,12 @@ error_roq_alloc:
 /* Tear down the RX queue and infrastructure */
 void i2400m_rx_release(struct i2400m *i2400m)
 {
+       unsigned long flags;
+
        if (i2400m->rx_reorder) {
-               unsigned itr;
-               for(itr = 0; itr < I2400M_RO_CIN + 1; itr++)
-                       __skb_queue_purge(&i2400m->rx_roq[itr].queue);
-               kfree(i2400m->rx_roq[0].log);
-               kfree(i2400m->rx_roq);
+               spin_lock_irqsave(&i2400m->rx_lock, flags);
+               kref_put(&i2400m->rx_roq_refcount, i2400m_rx_roq_destroy);
+               spin_unlock_irqrestore(&i2400m->rx_lock, flags);
        }
        /* at this point, nothing can be received... */
        i2400m_report_hook_flush(i2400m);
index d619da33f20b9adad0642678545810a143d93aea..8b809c2ead6c928ce1d0a5143ae3e0d53756c73e 100644 (file)
@@ -197,7 +197,6 @@ error_alloc_skb:
 error_get_size:
 error_bad_size:
        d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret);
-       return;
 }
 
 
@@ -229,7 +228,6 @@ void i2400ms_irq(struct sdio_func *func)
        i2400ms_rx(i2400ms);
 error_no_irq:
        d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms);
-       return;
 }
 
 
index de66d068c9cbf2717a54c15254dfcfa96ffaac26..b53cd1c80e3e92900a85f81eb7cd85b538f78115 100644 (file)
@@ -98,6 +98,10 @@ void i2400ms_tx_submit(struct work_struct *ws)
                                tx_msg_size, result);
                }
 
+               if (result == -ETIMEDOUT) {
+                       i2400m_error_recovery(i2400m);
+                       break;
+               }
                d_printf(2, dev, "TX: %zub submitted\n", tx_msg_size);
        }
 
@@ -114,13 +118,17 @@ void i2400ms_bus_tx_kick(struct i2400m *i2400m)
 {
        struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
        struct device *dev = &i2400ms->func->dev;
+       unsigned long flags;
 
        d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
 
        /* schedule tx work, this is because tx may block, therefore
         * it has to run in a thread context.
         */
-       queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       if (i2400ms->tx_workqueue != NULL)
+               queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
 
        d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
 }
@@ -130,27 +138,40 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
        int result;
        struct device *dev = &i2400ms->func->dev;
        struct i2400m *i2400m = &i2400ms->i2400m;
+       struct workqueue_struct *tx_workqueue;
+       unsigned long flags;
 
        d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
 
        INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit);
        snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name),
                 "%s-tx", i2400m->wimax_dev.name);
-       i2400ms->tx_workqueue =
+       tx_workqueue =
                create_singlethread_workqueue(i2400ms->tx_wq_name);
-       if (NULL == i2400ms->tx_workqueue) {
+       if (tx_workqueue == NULL) {
                dev_err(dev, "TX: failed to create workqueue\n");
                result = -ENOMEM;
        } else
                result = 0;
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       i2400ms->tx_workqueue = tx_workqueue;
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
        d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
        return result;
 }
 
 void i2400ms_tx_release(struct i2400ms *i2400ms)
 {
-       if (i2400ms->tx_workqueue) {
-               destroy_workqueue(i2400ms->tx_workqueue);
-               i2400ms->tx_workqueue = NULL;
-       }
+       struct i2400m *i2400m = &i2400ms->i2400m;
+       struct workqueue_struct *tx_workqueue;
+       unsigned long flags;
+
+       tx_workqueue = i2400ms->tx_workqueue;
+
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       i2400ms->tx_workqueue = NULL;
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+       if (tx_workqueue)
+               destroy_workqueue(tx_workqueue);
 }
index 7632f80954e3e56620b95b474ccf79d4e90037c8..9bfc26e1bc6b92facf7ab32abec51e89ce6a9980 100644 (file)
@@ -483,6 +483,13 @@ int i2400ms_probe(struct sdio_func *func,
        sdio_set_drvdata(func, i2400ms);
 
        i2400m->bus_tx_block_size = I2400MS_BLK_SIZE;
+       /*
+        * Room required in the TX queue for SDIO message to accommodate
+        * a smallest payload while allocating header space is 224 bytes,
+        * which is the smallest message size(the block size 256 bytes)
+        * minus the smallest message header size(32 bytes).
+        */
+       i2400m->bus_tx_room_min = I2400MS_BLK_SIZE - I2400M_PL_ALIGN * 2;
        i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX;
        i2400m->bus_setup = i2400ms_bus_setup;
        i2400m->bus_dev_start = i2400ms_bus_dev_start;
index b0cb90624cf62f4f25d6f30732a00da538e558c2..3f819efc06b597b46f4f1a60b52cad88f9bf7e72 100644 (file)
@@ -258,8 +258,10 @@ enum {
         * Doc says maximum transaction is 16KiB. If we had 16KiB en
         * route and 16KiB being queued, it boils down to needing
         * 32KiB.
+        * 32KiB is insufficient for 1400 MTU, hence increasing
+        * tx buffer size to 64KiB.
         */
-       I2400M_TX_BUF_SIZE = 32768,
+       I2400M_TX_BUF_SIZE = 65536,
        /**
         * Message header and payload descriptors have to be 16
         * aligned (16 + 4 * N = 16 * M). If we take that average sent
@@ -270,10 +272,21 @@ enum {
         * at the end there are less, we pad up to the nearest
         * multiple of 16.
         */
-       I2400M_TX_PLD_MAX = 12,
+       /*
+        * According to Intel Wimax i3200, i5x50 and i6x50 specification
+        * documents, the maximum number of payloads per message can be
+        * up to 60. Increasing the number of payloads to 60 per message
+        * helps to accommodate smaller payloads in a single transaction.
+        */
+       I2400M_TX_PLD_MAX = 60,
        I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr)
        + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld),
        I2400M_TX_SKIP = 0x80000000,
+       /*
+        * According to Intel Wimax i3200, i5x50 and i6x50 specification
+        * documents, the maximum size of each message can be up to 16KiB.
+        */
+       I2400M_TX_MSG_SIZE = 16384,
 };
 
 #define TAIL_FULL ((void *)~(unsigned long)NULL)
@@ -328,6 +341,14 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
  * @padding: ensure that there is at least this many bytes of free
  *     contiguous space in the fifo. This is needed because later on
  *     we might need to add padding.
+ * @try_head: specify either to allocate head room or tail room space
+ *     in the TX FIFO. This boolean is required to avoids a system hang
+ *     due to an infinite loop caused by i2400m_tx_fifo_push().
+ *     The caller must always try to allocate tail room space first by
+ *     calling this routine with try_head = 0. In case if there
+ *     is not enough tail room space but there is enough head room space,
+ *     (i2400m_tx_fifo_push() returns TAIL_FULL) try to allocate head
+ *     room space, by calling this routine again with try_head = 1.
  *
  * Returns:
  *
@@ -359,6 +380,48 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
  * fail and return TAIL_FULL and let the caller figure out if we wants to
  * skip the tail room and try to allocate from the head.
  *
+ * There is a corner case, wherein i2400m_tx_new() can get into
+ * an infinite loop calling i2400m_tx_fifo_push().
+ * In certain situations, tx_in would have reached on the top of TX FIFO
+ * and i2400m_tx_tail_room() returns 0, as described below:
+ *
+ * N  ___________ tail room is zero
+ *   |<-  IN   ->|
+ *   |           |
+ *   |           |
+ *   |           |
+ *   |   data    |
+ *   |<-  OUT  ->|
+ *   |           |
+ *   |           |
+ *   | head room |
+ * 0  -----------
+ * During such a time, where tail room is zero in the TX FIFO and if there
+ * is a request to add a payload to TX FIFO, which calls:
+ * i2400m_tx()
+ *         ->calls i2400m_tx_close()
+ *         ->calls i2400m_tx_skip_tail()
+ *         goto try_new;
+ *         ->calls i2400m_tx_new()
+ *                    |----> [try_head:]
+ *     infinite loop  |     ->calls i2400m_tx_fifo_push()
+ *                    |                if (tail_room < needed)
+ *                    |                   if (head_room => needed)
+ *                    |                       return TAIL_FULL;
+ *                    |<----  goto try_head;
+ *
+ * i2400m_tx() calls i2400m_tx_close() to close the message, since there
+ * is no tail room to accommodate the payload and calls
+ * i2400m_tx_skip_tail() to skip the tail space. Now i2400m_tx() calls
+ * i2400m_tx_new() to allocate space for new message header calling
+ * i2400m_tx_fifo_push() that returns TAIL_FULL, since there is no tail space
+ * to accommodate the message header, but there is enough head space.
+ * The i2400m_tx_new() keeps re-retrying by calling i2400m_tx_fifo_push()
+ * ending up in a loop causing system freeze.
+ *
+ * This corner case is avoided by using a try_head boolean,
+ * as an argument to i2400m_tx_fifo_push().
+ *
  * Note:
  *
  *     Assumes i2400m->tx_lock is taken, and we use that as a barrier
@@ -367,7 +430,8 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
  *     pop data off the queue
  */
 static
-void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
+void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size,
+                         size_t padding, bool try_head)
 {
        struct device *dev = i2400m_dev(i2400m);
        size_t room, tail_room, needed_size;
@@ -382,9 +446,21 @@ void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
        }
        /* Is there space at the tail? */
        tail_room = __i2400m_tx_tail_room(i2400m);
-       if (tail_room < needed_size) {
-               if (i2400m->tx_out % I2400M_TX_BUF_SIZE
-                   < i2400m->tx_in % I2400M_TX_BUF_SIZE) {
+       if (!try_head && tail_room < needed_size) {
+               /*
+                * If the tail room space is not enough to push the message
+                * in the TX FIFO, then there are two possibilities:
+                * 1. There is enough head room space to accommodate
+                * this message in the TX FIFO.
+                * 2. There is not enough space in the head room and
+                * in tail room of the TX FIFO to accommodate the message.
+                * In the case (1), return TAIL_FULL so that the caller
+                * can figure out, if the caller wants to push the message
+                * into the head room space.
+                * In the case (2), return NULL, indicating that the TX FIFO
+                * cannot accommodate the message.
+                */
+               if (room - tail_room >= needed_size) {
                        d_printf(2, dev, "fifo push %zu/%zu: tail full\n",
                                 size, padding);
                        return TAIL_FULL;       /* There might be head space */
@@ -485,14 +561,25 @@ void i2400m_tx_new(struct i2400m *i2400m)
 {
        struct device *dev = i2400m_dev(i2400m);
        struct i2400m_msg_hdr *tx_msg;
+       bool try_head = 0;
        BUG_ON(i2400m->tx_msg != NULL);
+       /*
+        * In certain situations, TX queue might have enough space to
+        * accommodate the new message header I2400M_TX_PLD_SIZE, but
+        * might not have enough space to accommodate the payloads.
+        * Adding bus_tx_room_min padding while allocating a new TX message
+        * increases the possibilities of including at least one payload of the
+        * size <= bus_tx_room_min.
+        */
 try_head:
-       tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0);
+       tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE,
+                                    i2400m->bus_tx_room_min, try_head);
        if (tx_msg == NULL)
                goto out;
        else if (tx_msg == TAIL_FULL) {
                i2400m_tx_skip_tail(i2400m);
                d_printf(2, dev, "new TX message: tail full, trying head\n");
+               try_head = 1;
                goto try_head;
        }
        memset(tx_msg, 0, I2400M_TX_PLD_SIZE);
@@ -566,7 +653,7 @@ void i2400m_tx_close(struct i2400m *i2400m)
        aligned_size = ALIGN(tx_msg_moved->size, i2400m->bus_tx_block_size);
        padding = aligned_size - tx_msg_moved->size;
        if (padding > 0) {
-               pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0);
+               pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0, 0);
                if (unlikely(WARN_ON(pad_buf == NULL
                                     || pad_buf == TAIL_FULL))) {
                        /* This should not happen -- append should verify
@@ -632,6 +719,7 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
        unsigned long flags;
        size_t padded_len;
        void *ptr;
+       bool try_head = 0;
        unsigned is_singleton = pl_type == I2400M_PT_RESET_WARM
                || pl_type == I2400M_PT_RESET_COLD;
 
@@ -643,9 +731,11 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
         * current one is out of payload slots or we have a singleton,
         * close it and start a new one */
        spin_lock_irqsave(&i2400m->tx_lock, flags);
-       result = -ESHUTDOWN;
-       if (i2400m->tx_buf == NULL)
+       /* If tx_buf is NULL, device is shutdown */
+       if (i2400m->tx_buf == NULL) {
+               result = -ESHUTDOWN;
                goto error_tx_new;
+       }
 try_new:
        if (unlikely(i2400m->tx_msg == NULL))
                i2400m_tx_new(i2400m);
@@ -659,7 +749,13 @@ try_new:
        }
        if (i2400m->tx_msg == NULL)
                goto error_tx_new;
-       if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) {
+       /*
+        * Check if this skb will fit in the TX queue's current active
+        * TX message. The total message size must not exceed the maximum
+        * size of each message I2400M_TX_MSG_SIZE. If it exceeds,
+        * close the current message and push this skb into the new message.
+        */
+       if (i2400m->tx_msg->size + padded_len > I2400M_TX_MSG_SIZE) {
                d_printf(2, dev, "TX: message too big, going new\n");
                i2400m_tx_close(i2400m);
                i2400m_tx_new(i2400m);
@@ -669,11 +765,12 @@ try_new:
        /* So we have a current message header; now append space for
         * the message -- if there is not enough, try the head */
        ptr = i2400m_tx_fifo_push(i2400m, padded_len,
-                                 i2400m->bus_tx_block_size);
+                                 i2400m->bus_tx_block_size, try_head);
        if (ptr == TAIL_FULL) { /* Tail is full, try head */
                d_printf(2, dev, "pl append: tail full\n");
                i2400m_tx_close(i2400m);
                i2400m_tx_skip_tail(i2400m);
+               try_head = 1;
                goto try_new;
        } else if (ptr == NULL) {       /* All full */
                result = -ENOSPC;
@@ -689,7 +786,7 @@ try_new:
                         pl_type, buf_len);
                tx_msg->num_pls = le16_to_cpu(num_pls+1);
                tx_msg->size += padded_len;
-               d_printf(2, dev, "TX: appended %zu b (up to %u b) pl #%u \n",
+               d_printf(2, dev, "TX: appended %zu b (up to %u b) pl #%u\n",
                        padded_len, tx_msg->size, num_pls+1);
                d_printf(2, dev,
                         "TX: appended hdr @%zu %zu b pl #%u @%zu %zu/%zu b\n",
@@ -860,25 +957,43 @@ EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent);
  * i2400m_tx_setup - Initialize the TX queue and infrastructure
  *
  * Make sure we reset the TX sequence to zero, as when this function
- * is called, the firmware has been just restarted.
+ * is called, the firmware has been just restarted. Same rational
+ * for tx_in, tx_out, tx_msg_size and tx_msg. We reset them since
+ * the memory for TX queue is reallocated.
  */
 int i2400m_tx_setup(struct i2400m *i2400m)
 {
-       int result;
+       int result = 0;
+       void *tx_buf;
+       unsigned long flags;
 
        /* Do this here only once -- can't do on
         * i2400m_hard_start_xmit() as we'll cause race conditions if
         * the WS was scheduled on another CPU */
        INIT_WORK(&i2400m->wake_tx_ws, i2400m_wake_tx_work);
 
-       i2400m->tx_sequence = 0;
-       i2400m->tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_KERNEL);
-       if (i2400m->tx_buf == NULL)
+       tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_ATOMIC);
+       if (tx_buf == NULL) {
                result = -ENOMEM;
-       else
-               result = 0;
+               goto error_kmalloc;
+       }
+
+       /*
+        * Fail the build if we can't fit at least two maximum size messages
+        * on the TX FIFO [one being delivered while one is constructed].
+        */
+       BUILD_BUG_ON(2 * I2400M_TX_MSG_SIZE > I2400M_TX_BUF_SIZE);
+       spin_lock_irqsave(&i2400m->tx_lock, flags);
+       i2400m->tx_sequence = 0;
+       i2400m->tx_in = 0;
+       i2400m->tx_out = 0;
+       i2400m->tx_msg_size = 0;
+       i2400m->tx_msg = NULL;
+       i2400m->tx_buf = tx_buf;
+       spin_unlock_irqrestore(&i2400m->tx_lock, flags);
        /* Huh? the bus layer has to define this... */
        BUG_ON(i2400m->bus_tx_block_size == 0);
+error_kmalloc:
        return result;
 
 }
index 7b6a1d98bd74321af344c47916422dae6002108a..d44b545f4082b1ebb21ccfdf2e422723df8de4c0 100644 (file)
@@ -178,7 +178,6 @@ error_submit:
 out:
        d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n",
                urb, urb->status, urb->actual_length);
-       return;
 }
 
 
index d8c4d6497fdfb8dc4b4d97baafd55210833ea89a..16341ffc3df30de6bac85725b10be2a3b2fff95d 100644 (file)
@@ -82,6 +82,8 @@ MODULE_PARM_DESC(debug,
 
 /* Our firmware file name */
 static const char *i2400mu_bus_fw_names_5x50[] = {
+#define I2400MU_FW_FILE_NAME_v1_5 "i2400m-fw-usb-1.5.sbcf"
+       I2400MU_FW_FILE_NAME_v1_5,
 #define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf"
        I2400MU_FW_FILE_NAME_v1_4,
        NULL,
@@ -467,6 +469,13 @@ int i2400mu_probe(struct usb_interface *iface,
        usb_set_intfdata(iface, i2400mu);
 
        i2400m->bus_tx_block_size = I2400MU_BLK_SIZE;
+       /*
+        * Room required in the Tx queue for USB message to accommodate
+        * a smallest payload while allocating header space is 16 bytes.
+        * Adding this room  for the new tx message increases the
+        * possibilities of including any payload with size <= 16 bytes.
+        */
+       i2400m->bus_tx_room_min = I2400MU_BLK_SIZE;
        i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX;
        i2400m->bus_setup = NULL;
        i2400m->bus_dev_start = i2400mu_bus_dev_start;
@@ -778,4 +787,5 @@ MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
 MODULE_DESCRIPTION("Driver for USB based Intel Wireless WiMAX Connection 2400M "
                   "(5x50 & 6050)");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4);
+MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_5);
+MODULE_FIRMWARE(I6050U_FW_FILE_NAME_v1_5);
index 588943660755fa8e15e03a3543a2196464617c74..174e3442d5190df936544854787b919d3e0f4945 100644 (file)
@@ -5,6 +5,7 @@
 menuconfig WLAN
        bool "Wireless LAN"
        depends on !S390
+       depends on NET
        select WIRELESS
        default y
        ---help---
@@ -38,6 +39,12 @@ config LIBERTAS_THINFIRM
        ---help---
          A library for Marvell Libertas 8xxx devices using thinfirm.
 
+config LIBERTAS_THINFIRM_DEBUG
+       bool "Enable full debugging output in the Libertas thin firmware module."
+       depends on LIBERTAS_THINFIRM
+       ---help---
+         Debugging support.
+
 config LIBERTAS_THINFIRM_USB
        tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware"
        depends on LIBERTAS_THINFIRM && USB
@@ -210,90 +217,7 @@ config USB_NET_RNDIS_WLAN
 
          If you choose to build a module, it'll be called rndis_wlan.
 
-config RTL8180
-       tristate "Realtek 8180/8185 PCI support"
-       depends on MAC80211 && PCI && EXPERIMENTAL
-       select EEPROM_93CX6
-       ---help---
-         This is a driver for RTL8180 and RTL8185 based cards.
-         These are PCI based chips found in cards such as:
-
-         (RTL8185 802.11g)
-         A-Link WL54PC
-
-         (RTL8180 802.11b)
-         Belkin F5D6020 v3
-         Belkin F5D6020 v3
-         Dlink DWL-610
-         Dlink DWL-510
-         Netgear MA521
-         Level-One WPC-0101
-         Acer Aspire 1357 LMi
-         VCTnet PC-11B1
-         Ovislink AirLive WL-1120PCM
-         Mentor WL-PCI
-         Linksys WPC11 v4
-         TrendNET TEW-288PI
-         D-Link DWL-520 Rev D
-         Repotec RP-WP7126
-         TP-Link TL-WN250/251
-         Zonet ZEW1000
-         Longshine LCS-8031-R
-         HomeLine HLW-PCC200
-         GigaFast WF721-AEX
-         Planet WL-3553
-         Encore ENLWI-PCI1-NT
-         TrendNET TEW-266PC
-         Gigabyte GN-WLMR101
-         Siemens-fujitsu Amilo D1840W
-         Edimax EW-7126
-         PheeNet WL-11PCIR
-         Tonze PC-2100T
-         Planet WL-8303
-         Dlink DWL-650 v M1
-         Edimax EW-7106
-         Q-Tec 770WC
-         Topcom Skyr@cer 4011b
-         Roper FreeLan 802.11b (edition 2004)
-         Wistron Neweb Corp CB-200B
-         Pentagram HorNET
-         QTec 775WC
-         TwinMOS Booming B Series
-         Micronet SP906BB
-         Sweex LC700010
-         Surecom EP-9428
-         Safecom SWLCR-1100
-
-         Thanks to Realtek for their support!
-
-config RTL8187
-       tristate "Realtek 8187 and 8187B USB support"
-       depends on MAC80211 && USB
-       select EEPROM_93CX6
-       ---help---
-         This is a driver for RTL8187 and RTL8187B based cards.
-         These are USB based chips found in devices such as:
-
-         Netgear WG111v2
-         Level 1 WNC-0301USB
-         Micronet SP907GK V5
-         Encore ENUWI-G2
-         Trendnet TEW-424UB
-         ASUS P5B Deluxe/P5K Premium motherboards
-         Toshiba Satellite Pro series of laptops
-         Asus Wireless Link
-         Linksys WUSB54GC-EU v2
-           (v1 = rt73usb; v3 is rt2070-based,
-            use staging/rt3070 or try rt2800usb)
-
-         Thanks to Realtek for their support!
-
-# If possible, automatically enable LEDs for RTL8187.
-
-config RTL8187_LEDS
-       bool
-       depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
-       default y
+source "drivers/net/wireless/rtl818x/Kconfig"
 
 config ADM8211
        tristate "ADMtek ADM8211 support"
index ab61d2b558d6c944cb9f653f609e511256d90a6c..880ad9d170c2cae4687df80e3fc4e090db6120d8 100644 (file)
@@ -1318,21 +1318,19 @@ static void adm8211_bss_info_changed(struct ieee80211_hw *dev,
 }
 
 static u64 adm8211_prepare_multicast(struct ieee80211_hw *hw,
-                                    int mc_count, struct dev_addr_list *mclist)
+                                    struct netdev_hw_addr_list *mc_list)
 {
-       unsigned int bit_nr, i;
+       unsigned int bit_nr;
        u32 mc_filter[2];
+       struct netdev_hw_addr *ha;
 
        mc_filter[1] = mc_filter[0] = 0;
 
-       for (i = 0; i < mc_count; i++) {
-               if (!mclist)
-                       break;
-               bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+       netdev_hw_addr_list_for_each(ha, mc_list) {
+               bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
 
                bit_nr &= 0x3F;
                mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
-               mclist = mclist->next;
        }
 
        return mc_filter[0] | ((u64)(mc_filter[1]) << 32);
index dc5018a6d9edcc75a9de752c56e1f27bdbd2d7ee..a441aad922c254f50e06ebe99949cf4b8162ab87 100644 (file)
@@ -2876,7 +2876,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
        ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0;
        ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0;
 
-       airo_print_info(dev->name, "Firmware version %x.%x.%02x",
+       airo_print_info(dev->name, "Firmware version %x.%x.%02d",
                        ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF),
                        (le16_to_cpu(cap_rid.softVer) & 0xFF),
                        le16_to_cpu(cap_rid.softSubVer));
@@ -3193,19 +3193,26 @@ static void airo_print_status(const char *devname, u16 status)
 {
        u8 reason = status & 0xFF;
 
-       switch (status) {
+       switch (status & 0xFF00) {
        case STAT_NOBEACON:
-               airo_print_dbg(devname, "link lost (missed beacons)");
-               break;
-       case STAT_MAXRETRIES:
-       case STAT_MAXARL:
-               airo_print_dbg(devname, "link lost (max retries)");
-               break;
-       case STAT_FORCELOSS:
-               airo_print_dbg(devname, "link lost (local choice)");
-               break;
-       case STAT_TSFSYNC:
-               airo_print_dbg(devname, "link lost (TSF sync lost)");
+               switch (status) {
+               case STAT_NOBEACON:
+                       airo_print_dbg(devname, "link lost (missed beacons)");
+                       break;
+               case STAT_MAXRETRIES:
+               case STAT_MAXARL:
+                       airo_print_dbg(devname, "link lost (max retries)");
+                       break;
+               case STAT_FORCELOSS:
+                       airo_print_dbg(devname, "link lost (local choice)");
+                       break;
+               case STAT_TSFSYNC:
+                       airo_print_dbg(devname, "link lost (TSF sync lost)");
+                       break;
+               default:
+                       airo_print_dbg(devname, "unknow status %x\n", status);
+                       break;
+               }
                break;
        case STAT_DEAUTH:
                airo_print_dbg(devname, "deauthenticated (reason: %d)", reason);
@@ -3221,7 +3228,11 @@ static void airo_print_status(const char *devname, u16 status)
                airo_print_dbg(devname, "authentication failed (reason: %d)",
                               reason);
                break;
+       case STAT_ASSOC:
+       case STAT_REASSOC:
+               break;
        default:
+               airo_print_dbg(devname, "unknow status %x\n", status);
                break;
        }
 }
index 0fb419936dfff58e0b8780107c07c70d842d712b..8a2d4afc74f8dacbb2822b88c441fe0534711ef5 100644 (file)
@@ -1223,7 +1223,6 @@ static void at76_rx_callback(struct urb *urb)
 
        priv->rx_tasklet.data = (unsigned long)urb;
        tasklet_schedule(&priv->rx_tasklet);
-       return;
 }
 
 static int at76_submit_rx_urb(struct at76_priv *priv)
@@ -1889,6 +1888,7 @@ static void at76_dwork_hw_scan(struct work_struct *work)
 }
 
 static int at76_hw_scan(struct ieee80211_hw *hw,
+                       struct ieee80211_vif *vif,
                        struct cfg80211_scan_request *req)
 {
        struct at76_priv *priv = hw->priv;
index 4e7a7fd695c8e5aaa6d809642678f95d08580d84..0a75be027afaa5c7604cfc257093979a636653ab 100644 (file)
@@ -3,7 +3,7 @@ menuconfig ATH_COMMON
        depends on CFG80211
        ---help---
          This will enable the support for the Atheros wireless drivers.
-         ath5k, ath9k and ar9170 drivers share some common code, this option
+         ath5k, ath9k, ath9k_htc and ar9170 drivers share some common code, this option
          enables the common ath.ko module which shares common helpers.
 
          For more information and documentation on this module you can visit:
index dc662b76a1c897c4b3a8784ba445e12f3f60cfda..4f845f80c0984ea054481979d9e928dc5ce0f290 100644 (file)
@@ -109,41 +109,6 @@ struct ar9170_rxstream_mpdu_merge {
        bool has_plcp;
 };
 
-#define AR9170_NUM_TID 16
-#define WME_BA_BMP_SIZE         64
-#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
-
-#define WME_AC_BE   2
-#define WME_AC_BK   3
-#define WME_AC_VI   1
-#define WME_AC_VO   0
-
-#define TID_TO_WME_AC(_tid)                            \
-       ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
-        (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
-        (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
-        WME_AC_VO)
-
-#define BAW_WITHIN(_start, _bawsz, _seqno) \
-       ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
-
-enum ar9170_tid_state {
-       AR9170_TID_STATE_INVALID,
-       AR9170_TID_STATE_SHUTDOWN,
-       AR9170_TID_STATE_PROGRESS,
-       AR9170_TID_STATE_COMPLETE,
-};
-
-struct ar9170_sta_tid {
-       struct list_head list;
-       struct sk_buff_head queue;
-       u8 addr[ETH_ALEN];
-       u16 ssn;
-       u16 tid;
-       enum ar9170_tid_state state;
-       bool active;
-};
-
 struct ar9170_tx_queue_stats {
        unsigned int len;
        unsigned int limit;
@@ -152,14 +117,11 @@ struct ar9170_tx_queue_stats {
 
 #define AR9170_QUEUE_TIMEOUT           64
 #define AR9170_TX_TIMEOUT              8
-#define AR9170_BA_TIMEOUT              4
 #define AR9170_JANITOR_DELAY           128
 #define AR9170_TX_INVALID_RATE         0xffffffff
 
-#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)
+#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;
@@ -234,11 +196,6 @@ struct ar9170 {
        struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
        struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
        struct delayed_work tx_janitor;
-       /* tx ampdu */
-       struct sk_buff_head tx_status_ampdu;
-       spinlock_t tx_ampdu_list_lock;
-       struct list_head tx_ampdu_list;
-       atomic_t tx_ampdu_pending;
 
        /* rxstream mpdu merge */
        struct ar9170_rxstream_mpdu_merge rx_mpdu;
@@ -250,11 +207,6 @@ struct ar9170 {
        u8 global_ampdu_factor;
 };
 
-struct ar9170_sta_info {
-       struct ar9170_sta_tid agg[AR9170_NUM_TID];
-       unsigned int ampdu_max_len;
-};
-
 struct ar9170_tx_info {
        unsigned long timeout;
 };
index 826c45e6b2742e3ae97c8e174310a15c63ae0282..ec8134b4b949df2090e3cd230cbc2e5482bd8912 100644 (file)
@@ -79,7 +79,7 @@ __regwrite_out :                                                      \
        if (__nreg) {                                                   \
                if (IS_ACCEPTING_CMD(__ar))                             \
                        __err = ar->exec_cmd(__ar, AR9170_CMD_WREG,     \
-                                            8 * __nreg,                \
+                                            8 * __nreg,                \
                                             (u8 *) &__ar->cmdbuf[1],   \
                                             0, NULL);                  \
                __nreg = 0;                                             \
index d2c8cc83f1dd187630fe5a70e6f9774a1cc2b478..6c4663883423d725ddbcede12cc4086deecf99cd 100644 (file)
@@ -127,8 +127,8 @@ struct ar9170_eeprom {
        __le16  checksum;
        __le16  version;
        u8      operating_flags;
-#define AR9170_OPFLAG_5GHZ             1
-#define AR9170_OPFLAG_2GHZ             2
+#define AR9170_OPFLAG_5GHZ             1
+#define AR9170_OPFLAG_2GHZ             2
        u8      misc;
        __le16  reg_domain[2];
        u8      mac_address[6];
index 0a1d4c28e68a346e05a82c15c0599824bb5a4678..06f1f3c951a4daa136efbefcc3891e5b35b844a7 100644 (file)
@@ -425,5 +425,6 @@ enum ar9170_txq {
 
 #define AR9170_TXQ_DEPTH       32
 #define AR9170_TX_MAX_PENDING  128
+#define AR9170_RX_STREAM_MAX_SIZE 65535
 
 #endif /* __AR9170_HW_H */
index c53692980990153ca3b05562978cb3d010d6d215..2abc8757899418ab6875576dc556b703324624be 100644 (file)
@@ -50,10 +50,6 @@ static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
 
-static int modparam_ht;
-module_param_named(ht, modparam_ht, bool, S_IRUGO);
-MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
-
 #define RATE(_bitrate, _hw_rate, _txpidx, _flags) {    \
        .bitrate        = (_bitrate),                   \
        .flags          = (_flags),                     \
@@ -182,7 +178,6 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
 };
 
 static void ar9170_tx(struct ar9170 *ar);
-static bool ar9170_tx_ampdu(struct ar9170 *ar);
 
 static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
 {
@@ -195,21 +190,7 @@ 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;
-       return ar9170_get_tid_h((struct ieee80211_hdr *) txc->frame_data);
-}
-
-#define GET_NEXT_SEQ(seq)      ((seq + 1) & 0x0fff)
-#define GET_NEXT_SEQ_FROM_SKB(skb)     (GET_NEXT_SEQ(ar9170_get_seq(skb)))
-
-#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
+#ifdef AR9170_QUEUE_DEBUG
 static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ar9170_tx_control *txc = (void *) skb->data;
@@ -236,7 +217,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
               wiphy_name(ar->hw->wiphy), skb_queue_len(queue));
 
        skb_queue_walk(queue, skb) {
-               printk(KERN_DEBUG "index:%d => \n", i++);
+               printk(KERN_DEBUG "index:%d =>\n", i++);
                ar9170_print_txheader(ar, skb);
        }
        if (i != skb_queue_len(queue))
@@ -244,7 +225,7 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
                       "mismatch %d != %d\n", skb_queue_len(queue), i);
        printk(KERN_DEBUG "---[ end ]---\n");
 }
-#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#endif /* AR9170_QUEUE_DEBUG */
 
 #ifdef AR9170_QUEUE_DEBUG
 static void ar9170_dump_txqueue(struct ar9170 *ar,
@@ -275,20 +256,6 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
 }
 #endif /* AR9170_QUEUE_STOP_DEBUG */
 
-#ifdef AR9170_TXAGG_DEBUG
-static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
-       printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
-              wiphy_name(ar->hw->wiphy));
-       __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
-       spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
-}
-
-#endif /* AR9170_TXAGG_DEBUG */
-
 /* caller must guarantee exclusive access for _bin_ queue. */
 static void ar9170_recycle_expired(struct ar9170 *ar,
                                   struct sk_buff_head *queue,
@@ -308,7 +275,7 @@ static void ar9170_recycle_expired(struct ar9170 *ar,
                if (time_is_before_jiffies(arinfo->timeout)) {
 #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: [%ld > %ld] frame expired => "
-                              "recycle \n", wiphy_name(ar->hw->wiphy),
+                              "recycle\n", wiphy_name(ar->hw->wiphy),
                               jiffies, arinfo->timeout);
                        ar9170_print_txheader(ar, skb);
 #endif /* AR9170_QUEUE_DEBUG */
@@ -360,70 +327,6 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
        ieee80211_tx_status_irqsafe(ar->hw, skb);
 }
 
-static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
-{
-       struct sk_buff_head success;
-       struct sk_buff *skb;
-       unsigned int i;
-       unsigned long queue_bitmap = 0;
-
-       skb_queue_head_init(&success);
-
-       while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
-               __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
-
-       ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
-
-#ifdef AR9170_TXAGG_DEBUG
-       printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
-              wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
-       __ar9170_dump_txqueue(ar, &success);
-#endif /* AR9170_TXAGG_DEBUG */
-
-       while ((skb = __skb_dequeue(&success))) {
-               struct ieee80211_tx_info *txinfo;
-
-               queue_bitmap |= BIT(skb_get_queue_mapping(skb));
-
-               txinfo = IEEE80211_SKB_CB(skb);
-               ieee80211_tx_info_clear_status(txinfo);
-
-               txinfo->flags |= IEEE80211_TX_STAT_ACK;
-               txinfo->status.rates[0].count = 1;
-
-               skb_pull(skb, sizeof(struct ar9170_tx_control));
-               ieee80211_tx_status_irqsafe(ar->hw, skb);
-       }
-
-       for_each_set_bit(i, &queue_bitmap, BITS_PER_BYTE) {
-#ifdef AR9170_QUEUE_STOP_DEBUG
-               printk(KERN_DEBUG "%s: wake queue %d\n",
-                      wiphy_name(ar->hw->wiphy), i);
-               __ar9170_dump_txstats(ar);
-#endif /* AR9170_QUEUE_STOP_DEBUG */
-               ieee80211_wake_queue(ar->hw, i);
-       }
-
-       if (queue_bitmap)
-               ar9170_tx(ar);
-}
-
-static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
-{
-       struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
-       struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
-
-       arinfo->timeout = jiffies +
-                         msecs_to_jiffies(AR9170_BA_TIMEOUT);
-
-       skb_queue_tail(&ar->tx_status_ampdu, skb);
-       ar9170_tx_fake_ampdu_status(ar);
-
-       if (atomic_dec_and_test(&ar->tx_ampdu_pending) &&
-           !list_empty(&ar->tx_ampdu_list))
-               ar9170_tx_ampdu(ar);
-}
-
 void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -447,14 +350,10 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
        if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
                ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
        } else {
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       ar9170_tx_ampdu_callback(ar, skb);
-               } else {
-                       arinfo->timeout = jiffies +
-                                 msecs_to_jiffies(AR9170_TX_TIMEOUT);
+               arinfo->timeout = jiffies +
+                         msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
-                       skb_queue_tail(&ar->tx_status[queue], skb);
-               }
+               skb_queue_tail(&ar->tx_status[queue], skb);
        }
 
        if (!ar->tx_stats[queue].len &&
@@ -524,38 +423,6 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
        return NULL;
 }
 
-static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
-{
-       struct sk_buff *skb;
-       struct ieee80211_tx_info *txinfo;
-
-       while (count) {
-               skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
-               if (!skb)
-                       break;
-
-               txinfo = IEEE80211_SKB_CB(skb);
-               ieee80211_tx_info_clear_status(txinfo);
-
-               /* FIXME: maybe more ? */
-               txinfo->status.rates[0].count = 1;
-
-               skb_pull(skb, sizeof(struct ar9170_tx_control));
-               ieee80211_tx_status_irqsafe(ar->hw, skb);
-               count--;
-       }
-
-#ifdef AR9170_TXAGG_DEBUG
-       if (count) {
-               printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
-                      "suitable frames left in tx_status queue.\n",
-                      wiphy_name(ar->hw->wiphy), count);
-
-               ar9170_dump_tx_status_ampdu(ar);
-       }
-#endif /* AR9170_TXAGG_DEBUG */
-}
-
 /*
  * This worker tries to keeps an maintain tx_status queues.
  * So we can guarantee that incoming tx_status reports are
@@ -592,8 +459,6 @@ static void ar9170_tx_janitor(struct work_struct *work)
                        resched = true;
        }
 
-       ar9170_tx_fake_ampdu_status(ar);
-
        if (!resched)
                return;
 
@@ -673,10 +538,6 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 
        case 0xc5:
                /* BlockACK events */
-               ar9170_handle_block_ack(ar,
-                                       le16_to_cpu(cmd->ba_fail_cnt.failed),
-                                       le16_to_cpu(cmd->ba_fail_cnt.rate));
-               ar9170_tx_fake_ampdu_status(ar);
                break;
 
        case 0xc6:
@@ -689,7 +550,8 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 
        /* firmware debug */
        case 0xca:
-               printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4, (char *)buf + 4);
+               printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4,
+                               (char *)buf + 4);
                break;
        case 0xcb:
                len -= 4;
@@ -926,7 +788,6 @@ static void ar9170_rx_phy_status(struct ar9170 *ar,
 
        /* TODO: we could do something with phy_errors */
        status->signal = ar->noise[0] + phy->rssi_combined;
-       status->noise = ar->noise[0];
 }
 
 static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
@@ -1247,7 +1108,6 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
        ar->global_ampdu_density = 6;
        ar->global_ampdu_factor = 3;
 
-       atomic_set(&ar->tx_ampdu_pending, 0);
        ar->bad_hw_nagger = jiffies;
 
        err = ar->open(ar);
@@ -1310,40 +1170,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
                skb_queue_purge(&ar->tx_pending[i]);
                skb_queue_purge(&ar->tx_status[i]);
        }
-       skb_queue_purge(&ar->tx_status_ampdu);
 
        mutex_unlock(&ar->mutex);
 }
 
-static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
-{
-       struct ar9170_tx_control *txc = (void *) skb->data;
-
-       txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
-}
-
-static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
-                              struct sk_buff *src)
-{
-       struct ar9170_tx_control *dst_txc, *src_txc;
-       struct ieee80211_tx_info *dst_info, *src_info;
-       struct ar9170_tx_info *dst_arinfo, *src_arinfo;
-
-       src_txc = (void *) src->data;
-       src_info = IEEE80211_SKB_CB(src);
-       src_arinfo = (void *) src_info->rate_driver_data;
-
-       dst_txc = (void *) dst->data;
-       dst_info = IEEE80211_SKB_CB(dst);
-       dst_arinfo = (void *) dst_info->rate_driver_data;
-
-       dst_txc->phy_control = src_txc->phy_control;
-
-       /* same MCS for the whole aggregate */
-       memcpy(dst_info->driver_rates, src_info->driver_rates,
-              sizeof(dst_info->driver_rates));
-}
-
 static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
@@ -1420,14 +1250,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
                txc->phy_control |=
                        cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
 
-               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);
-               }
+               txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
        }
 
        return 0;
@@ -1537,158 +1360,6 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
        txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
 }
 
-static bool ar9170_tx_ampdu(struct ar9170 *ar)
-{
-       struct sk_buff_head agg;
-       struct ar9170_sta_tid *tid_info = NULL, *tmp;
-       struct sk_buff *skb, *first = NULL;
-       unsigned long flags, f2;
-       unsigned int i = 0;
-       u16 seq, queue, tmpssn;
-       bool run = false;
-
-       skb_queue_head_init(&agg);
-
-       spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-       if (list_empty(&ar->tx_ampdu_list)) {
-#ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: aggregation list is empty.\n",
-                      wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-               goto out_unlock;
-       }
-
-       list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
-               if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
-#ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
-                              wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-                       continue;
-               }
-
-               if (++i > 64) {
-#ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: enough frames aggregated.\n",
-                              wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-                       break;
-               }
-
-               queue = TID_TO_WME_AC(tid_info->tid);
-
-               if (skb_queue_len(&ar->tx_pending[queue]) >=
-                   AR9170_NUM_TX_AGG_MAX) {
-#ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: queue %d full.\n",
-                              wiphy_name(ar->hw->wiphy), queue);
-#endif /* AR9170_TXAGG_DEBUG */
-                       continue;
-               }
-
-               list_del_init(&tid_info->list);
-
-               spin_lock_irqsave(&tid_info->queue.lock, f2);
-               tmpssn = seq = tid_info->ssn;
-               first = skb_peek(&tid_info->queue);
-
-               if (likely(first))
-                       tmpssn = ar9170_get_seq(first);
-
-               if (unlikely(tmpssn != seq)) {
-#ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
-                              wiphy_name(ar->hw->wiphy), seq, tmpssn);
-#endif /* AR9170_TXAGG_DEBUG */
-                       tid_info->ssn = tmpssn;
-               }
-
-#ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
-                      "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
-                      tid_info->tid, tid_info->ssn,
-                      skb_queue_len(&tid_info->queue));
-               __ar9170_dump_txqueue(ar, &tid_info->queue);
-#endif /* AR9170_TXAGG_DEBUG */
-
-               while ((skb = skb_peek(&tid_info->queue))) {
-                       if (unlikely(ar9170_get_seq(skb) != seq))
-                               break;
-
-                       __skb_unlink(skb, &tid_info->queue);
-                       tid_info->ssn = seq = GET_NEXT_SEQ(seq);
-
-                       if (unlikely(skb_get_queue_mapping(skb) != queue)) {
-#ifdef AR9170_TXAGG_DEBUG
-                               printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
-                                      "!match.\n", wiphy_name(ar->hw->wiphy),
-                                      tid_info->tid,
-                                      TID_TO_WME_AC(tid_info->tid),
-                                      skb_get_queue_mapping(skb));
-#endif /* AR9170_TXAGG_DEBUG */
-                                       dev_kfree_skb_any(skb);
-                                       continue;
-                       }
-
-                       if (unlikely(first == skb)) {
-                               ar9170_tx_prepare_phy(ar, skb);
-                               __skb_queue_tail(&agg, skb);
-                               first = skb;
-                       } else {
-                               ar9170_tx_copy_phy(ar, skb, first);
-                               __skb_queue_tail(&agg, skb);
-                       }
-
-                       if (unlikely(skb_queue_len(&agg) ==
-                           AR9170_NUM_TX_AGG_MAX))
-                               break;
-               }
-
-               if (skb_queue_empty(&tid_info->queue))
-                       tid_info->active = false;
-               else
-                       list_add_tail(&tid_info->list,
-                                     &ar->tx_ampdu_list);
-
-               spin_unlock_irqrestore(&tid_info->queue.lock, f2);
-
-               if (unlikely(skb_queue_empty(&agg))) {
-#ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_DEBUG "%s: queued empty list!\n",
-                              wiphy_name(ar->hw->wiphy));
-#endif /* AR9170_TXAGG_DEBUG */
-                       continue;
-               }
-
-               /*
-                * tell the FW/HW that this is the last frame,
-                * that way it will wait for the immediate block ack.
-                */
-               ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
-
-#ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
-                      wiphy_name(ar->hw->wiphy));
-               __ar9170_dump_txqueue(ar, &agg);
-#endif /* AR9170_TXAGG_DEBUG */
-
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-
-               spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
-               skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
-               spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
-               run = true;
-
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-       }
-
-out_unlock:
-       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-       __skb_queue_purge(&agg);
-
-       return run;
-}
-
 static void ar9170_tx(struct ar9170 *ar)
 {
        struct sk_buff *skb;
@@ -1728,7 +1399,7 @@ static void ar9170_tx(struct ar9170 *ar)
                        printk(KERN_DEBUG "%s: queue %d full\n",
                               wiphy_name(ar->hw->wiphy), i);
 
-                       printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+                       printk(KERN_DEBUG "%s: stuck frames: ===>\n",
                               wiphy_name(ar->hw->wiphy));
                        ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
                        ar9170_dump_txqueue(ar, &ar->tx_status[i]);
@@ -1763,9 +1434,6 @@ static void ar9170_tx(struct ar9170 *ar)
                        arinfo->timeout = jiffies +
                                          msecs_to_jiffies(AR9170_TX_TIMEOUT);
 
-                       if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                               atomic_inc(&ar->tx_ampdu_pending);
-
 #ifdef AR9170_QUEUE_DEBUG
                        printk(KERN_DEBUG "%s: send frame q:%d =>\n",
                               wiphy_name(ar->hw->wiphy), i);
@@ -1774,9 +1442,6 @@ static void ar9170_tx(struct ar9170 *ar)
 
                        err = ar->tx(ar, skb);
                        if (unlikely(err)) {
-                               if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                                       atomic_dec(&ar->tx_ampdu_pending);
-
                                frames_failed++;
                                dev_kfree_skb_any(skb);
                        } else {
@@ -1823,94 +1488,11 @@ static void ar9170_tx(struct ar9170 *ar)
                                     msecs_to_jiffies(AR9170_JANITOR_DELAY));
 }
 
-static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
-{
-       struct ieee80211_tx_info *txinfo;
-       struct ar9170_sta_info *sta_info;
-       struct ar9170_sta_tid *agg;
-       struct sk_buff *iter;
-       unsigned long flags, f2;
-       unsigned int max;
-       u16 tid, seq, qseq;
-       bool run = false, queue = false;
-
-       tid = ar9170_get_tid(skb);
-       seq = ar9170_get_seq(skb);
-       txinfo = IEEE80211_SKB_CB(skb);
-       sta_info = (void *) txinfo->control.sta->drv_priv;
-       agg = &sta_info->agg[tid];
-       max = sta_info->ampdu_max_len;
-
-       spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-
-       if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
-#ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
-                      "for ESS:%pM tid:%d state:%d.\n",
-                      wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
-                      agg->state);
-#endif /* AR9170_TXAGG_DEBUG */
-               goto err_unlock;
-       }
-
-       if (!agg->active) {
-               agg->active = true;
-               agg->ssn = seq;
-               queue = true;
-       }
-
-       /* check if seq is within the BA window */
-       if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
-#ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
-                      "fit into BA window (%d - %d)\n",
-                      wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
-                      (agg->ssn + max) & 0xfff);
-#endif /* AR9170_TXAGG_DEBUG */
-               goto err_unlock;
-       }
-
-       spin_lock_irqsave(&agg->queue.lock, f2);
-
-       skb_queue_reverse_walk(&agg->queue, iter) {
-               qseq = ar9170_get_seq(iter);
-
-               if (GET_NEXT_SEQ(qseq) == seq) {
-                       __skb_queue_after(&agg->queue, iter, skb);
-                       goto queued;
-               }
-       }
-
-       __skb_queue_head(&agg->queue, skb);
-
-queued:
-       spin_unlock_irqrestore(&agg->queue.lock, f2);
-
-#ifdef AR9170_TXAGG_DEBUG
-       printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
-              wiphy_name(ar->hw->wiphy), skb);
-       __ar9170_dump_txqueue(ar, &agg->queue);
-#endif /* AR9170_TXAGG_DEBUG */
-
-       if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
-               run = true;
-
-       if (queue)
-               list_add_tail(&agg->list, &ar->tx_ampdu_list);
-
-       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-       return run;
-
-err_unlock:
-       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-       dev_kfree_skb_irq(skb);
-       return false;
-}
-
 int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ar9170 *ar = hw->priv;
        struct ieee80211_tx_info *info;
+       unsigned int queue;
 
        if (unlikely(!IS_STARTED(ar)))
                goto err_free;
@@ -1918,18 +1500,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        if (unlikely(ar9170_tx_prepare(ar, skb)))
                goto err_free;
 
+       queue = skb_get_queue_mapping(skb);
        info = IEEE80211_SKB_CB(skb);
-       if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-               bool run = ar9170_tx_ampdu_queue(ar, skb);
-
-               if (run || !atomic_read(&ar->tx_ampdu_pending))
-                       ar9170_tx_ampdu(ar);
-       } else {
-               unsigned int queue = skb_get_queue_mapping(skb);
-
-               ar9170_tx_prepare_phy(ar, skb);
-               skb_queue_tail(&ar->tx_pending[queue], skb);
-       }
+       ar9170_tx_prepare_phy(ar, skb);
+       skb_queue_tail(&ar->tx_pending[queue], skb);
 
        ar9170_tx(ar);
        return NETDEV_TX_OK;
@@ -2046,21 +1620,17 @@ out:
        return err;
 }
 
-static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
-                                      struct dev_addr_list *mclist)
+static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw,
+                                      struct netdev_hw_addr_list *mc_list)
 {
        u64 mchash;
-       int i;
+       struct netdev_hw_addr *ha;
 
        /* always get broadcast frames */
        mchash = 1ULL << (0xff >> 2);
 
-       for (i = 0; i < mc_count; i++) {
-               if (WARN_ON(!mclist))
-                       break;
-               mchash |= 1ULL << (mclist->dmi_addr[5] >> 2);
-               mclist = mclist->next;
-       }
+       netdev_hw_addr_list_for_each(ha, mc_list)
+               mchash |= 1ULL << (ha->addr[5] >> 2);
 
        return mchash;
 }
@@ -2330,57 +1900,6 @@ out:
        return err;
 }
 
-static int ar9170_sta_add(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif,
-                         struct ieee80211_sta *sta)
-{
-       struct ar9170 *ar = hw->priv;
-       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-       unsigned int i;
-
-       memset(sta_info, 0, sizeof(*sta_info));
-
-       if (!sta->ht_cap.ht_supported)
-               return 0;
-
-       if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
-               ar->global_ampdu_density = sta->ht_cap.ampdu_density;
-
-       if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
-               ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
-
-       for (i = 0; i < AR9170_NUM_TID; i++) {
-               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].tid = i;
-               INIT_LIST_HEAD(&sta_info->agg[i].list);
-               skb_queue_head_init(&sta_info->agg[i].queue);
-       }
-
-       sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
-
-       return 0;
-}
-
-static int ar9170_sta_remove(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            struct ieee80211_sta *sta)
-{
-       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-       unsigned int i;
-
-       if (!sta->ht_cap.ht_supported)
-               return 0;
-
-       for (i = 0; i < AR9170_NUM_TID; i++) {
-               sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
-               skb_queue_purge(&sta_info->agg[i].queue);
-       }
-
-       return 0;
-}
-
 static int ar9170_get_stats(struct ieee80211_hw *hw,
                            struct ieee80211_low_level_stats *stats)
 {
@@ -2423,55 +1942,7 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
                               enum ieee80211_ampdu_mlme_action action,
                               struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
-       struct ar9170 *ar = hw->priv;
-       struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
-       struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
-       unsigned long flags;
-
-       if (!modparam_ht)
-               return -EOPNOTSUPP;
-
        switch (action) {
-       case IEEE80211_AMPDU_TX_START:
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-               if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
-                   !list_empty(&tid_info->list)) {
-                       spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-#ifdef AR9170_TXAGG_DEBUG
-                       printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
-                              "is in a very bad state!\n",
-                              wiphy_name(hw->wiphy), sta->addr, tid);
-#endif /* AR9170_TXAGG_DEBUG */
-                       return -EBUSY;
-               }
-
-               *ssn = tid_info->ssn;
-               tid_info->state = AR9170_TID_STATE_PROGRESS;
-               tid_info->active = false;
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-               break;
-
-       case IEEE80211_AMPDU_TX_STOP:
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-               tid_info->state = AR9170_TID_STATE_SHUTDOWN;
-               list_del_init(&tid_info->list);
-               tid_info->active = false;
-               skb_queue_purge(&tid_info->queue);
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
-               break;
-
-       case IEEE80211_AMPDU_TX_OPERATIONAL:
-#ifdef AR9170_TXAGG_DEBUG
-               printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
-                      wiphy_name(hw->wiphy), sta->addr, tid);
-#endif /* AR9170_TXAGG_DEBUG */
-               spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
-               sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
-               spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
-               break;
-
        case IEEE80211_AMPDU_RX_START:
        case IEEE80211_AMPDU_RX_STOP:
                /* Handled by firmware */
@@ -2497,8 +1968,6 @@ static const struct ieee80211_ops ar9170_ops = {
        .bss_info_changed       = ar9170_op_bss_info_changed,
        .get_tsf                = ar9170_op_get_tsf,
        .set_key                = ar9170_set_key,
-       .sta_add                = ar9170_sta_add,
-       .sta_remove             = ar9170_sta_remove,
        .get_stats              = ar9170_get_stats,
        .ampdu_action           = ar9170_ampdu_action,
 };
@@ -2516,7 +1985,7 @@ void *ar9170_alloc(size_t priv_size)
         * tends to split the streams into separate rx descriptors.
         */
 
-       skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE, GFP_KERNEL);
+       skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
        if (!skb)
                goto err_nomem;
 
@@ -2531,8 +2000,6 @@ void *ar9170_alloc(size_t priv_size)
        mutex_init(&ar->mutex);
        spin_lock_init(&ar->cmdlock);
        spin_lock_init(&ar->tx_stats_lock);
-       spin_lock_init(&ar->tx_ampdu_list_lock);
-       skb_queue_head_init(&ar->tx_status_ampdu);
        for (i = 0; i < __AR9170_NUM_TXQ; i++) {
                skb_queue_head_init(&ar->tx_status[i]);
                skb_queue_head_init(&ar->tx_pending[i]);
@@ -2540,7 +2007,6 @@ void *ar9170_alloc(size_t priv_size)
        ar9170_rx_reset_rx_mpdu(ar);
        INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
        INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
-       INIT_LIST_HEAD(&ar->tx_ampdu_list);
 
        /* all hw supports 2.4 GHz, so set channel to 1 by default */
        ar->channel = &ar9170_2ghz_chantable[0];
@@ -2551,19 +2017,10 @@ void *ar9170_alloc(size_t priv_size)
                                         BIT(NL80211_IFTYPE_ADHOC);
        ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
                         IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                        IEEE80211_HW_SIGNAL_DBM |
-                        IEEE80211_HW_NOISE_DBM;
-
-       if (modparam_ht) {
-               ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
-       } else {
-               ar9170_band_2GHz.ht_cap.ht_supported = false;
-               ar9170_band_5GHz.ht_cap.ht_supported = false;
-       }
+                        IEEE80211_HW_SIGNAL_DBM;
 
        ar->hw->queues = __AR9170_NUM_TXQ;
        ar->hw->extra_tx_headroom = 8;
-       ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
 
        ar->hw->max_rates = 1;
        ar->hw->max_rate_tries = 3;
index e1c2fcaa8bed92889a3cc30d0dd8fcd6c3bffb00..abd083a357f5960f7d6fce43e2998d3977e3fc78 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/usb.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
+#include <linux/device.h>
 #include <net/mac80211.h>
 #include "ar9170.h"
 #include "cmd.h"
@@ -67,18 +68,28 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0cf3, 0x1001) },
        /* TP-Link TL-WN821N v2 */
        { USB_DEVICE(0x0cf3, 0x1002) },
+       /* 3Com Dual Band 802.11n USB Adapter */
+       { USB_DEVICE(0x0cf3, 0x1010) },
+       /* H3C Dual Band 802.11n USB Adapter */
+       { USB_DEVICE(0x0cf3, 0x1011) },
        /* Cace Airpcap NX */
        { USB_DEVICE(0xcace, 0x0300) },
        /* D-Link DWA 160 A1 */
        { USB_DEVICE(0x07d1, 0x3c10) },
        /* D-Link DWA 160 A2 */
        { USB_DEVICE(0x07d1, 0x3a09) },
+       /* Netgear WNA1000 */
+       { USB_DEVICE(0x0846, 0x9040) },
        /* Netgear WNDA3100 */
        { USB_DEVICE(0x0846, 0x9010) },
        /* Netgear WN111 v2 */
        { USB_DEVICE(0x0846, 0x9001) },
        /* Zydas ZD1221 */
        { USB_DEVICE(0x0ace, 0x1221) },
+       /* Proxim ORiNOCO 802.11n USB */
+       { USB_DEVICE(0x1435, 0x0804) },
+       /* WNC Generic 11n USB Dongle */
+       { USB_DEVICE(0x1435, 0x0326) },
        /* ZyXEL NWD271N */
        { USB_DEVICE(0x0586, 0x3417) },
        /* Z-Com UB81 BG */
@@ -99,6 +110,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
        { USB_DEVICE(0x0409, 0x0249) },
        /* AVM FRITZ!WLAN USB Stick N 2.4 */
        { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
+       /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
+       { USB_DEVICE(0x1668, 0x1200) },
 
        /* terminate */
        {}
@@ -731,10 +744,10 @@ static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
 
        /* unbind anything failed */
        if (parent)
-               down(&parent->sem);
+               device_lock(parent);
        device_release_driver(&aru->udev->dev);
        if (parent)
-               up(&parent->sem);
+               device_unlock(parent);
 
        usb_put_dev(aru->udev);
 }
index 71fc960814f0e26c77aed4278158addd011c6e58..d32f2828b098ee63241e3b1e83c82d96ab2944df 100644 (file)
@@ -48,6 +48,12 @@ enum ath_device_state {
        ATH_HW_INITIALIZED,
 };
 
+enum ath_bus_type {
+       ATH_PCI,
+       ATH_AHB,
+       ATH_USB,
+};
+
 struct reg_dmn_pair_mapping {
        u16 regDmnEnum;
        u16 reg_5ghz_ctl;
@@ -65,17 +71,30 @@ struct ath_regulatory {
        struct reg_dmn_pair_mapping *regpair;
 };
 
+/**
+ * struct ath_ops - Register read/write operations
+ *
+ * @read: Register read
+ * @write: Register write
+ * @enable_write_buffer: Enable multiple register writes
+ * @disable_write_buffer: Disable multiple register writes
+ * @write_flush: Flush buffered register writes
+ */
 struct ath_ops {
        unsigned int (*read)(void *, u32 reg_offset);
-        void (*write)(void *, u32 val, u32 reg_offset);
+       void (*write)(void *, u32 val, u32 reg_offset);
+       void (*enable_write_buffer)(void *);
+       void (*disable_write_buffer)(void *);
+       void (*write_flush) (void *);
 };
 
 struct ath_common;
 
 struct ath_bus_ops {
-       void            (*read_cachesize)(struct ath_common *common, int *csz);
-       bool            (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
-       void            (*bt_coex_prep)(struct ath_common *common);
+       enum ath_bus_type ath_bus_type;
+       void (*read_cachesize)(struct ath_common *common, int *csz);
+       bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+       void (*bt_coex_prep)(struct ath_common *common);
 };
 
 struct ath_common {
index 090dc6d268a3014cde3cdd863c0fd9e75b507ae4..cc09595b781ae3ee7248c8a84222f68c495d3103 100644 (file)
@@ -12,5 +12,6 @@ ath5k-y                               += attach.o
 ath5k-y                                += base.o
 ath5k-y                                += led.o
 ath5k-y                                += rfkill.o
+ath5k-y                                += ani.o
 ath5k-$(CONFIG_ATH5K_DEBUG)    += debug.o
 obj-$(CONFIG_ATH5K)            += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
new file mode 100644 (file)
index 0000000..f2311ab
--- /dev/null
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * 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 "ath5k.h"
+#include "base.h"
+#include "reg.h"
+#include "debug.h"
+#include "ani.h"
+
+/**
+ * DOC: Basic ANI Operation
+ *
+ * Adaptive Noise Immunity (ANI) controls five noise immunity parameters
+ * depending on the amount of interference in the environment, increasing
+ * or reducing sensitivity as necessary.
+ *
+ * The parameters are:
+ *   - "noise immunity"
+ *   - "spur immunity"
+ *   - "firstep level"
+ *   - "OFDM weak signal detection"
+ *   - "CCK weak signal detection"
+ *
+ * Basically we look at the amount of ODFM and CCK timing errors we get and then
+ * raise or lower immunity accordingly by setting one or more of these
+ * parameters.
+ * Newer chipsets have PHY error counters in hardware which will generate a MIB
+ * interrupt when they overflow. Older hardware has too enable PHY error frames
+ * by setting a RX flag and then count every single PHY error. When a specified
+ * threshold of errors has been reached we will raise immunity.
+ * Also we regularly check the amount of errors and lower or raise immunity as
+ * necessary.
+ */
+
+
+/*** ANI parameter control ***/
+
+/**
+ * ath5k_ani_set_noise_immunity_level() - Set noise immunity level
+ *
+ * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL
+ */
+void
+ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
+{
+       /* TODO:
+        * ANI documents suggest the following five levels to use, but the HAL
+        * and ath9k use only use the last two levels, making this
+        * essentially an on/off option. There *may* be a reason for this (???),
+        * so i stick with the HAL version for now...
+        */
+#if 0
+       const s8 hi[] = { -18, -18, -16, -14, -12 };
+       const s8 lo[] = { -52, -56, -60, -64, -70 };
+       const s8 sz[] = { -34, -41, -48, -55, -62 };
+       const s8 fr[] = { -70, -72, -75, -78, -80 };
+#else
+       const s8 sz[] = { -55, -62 };
+       const s8 lo[] = { -64, -70 };
+       const s8 hi[] = { -14, -12 };
+       const s8 fr[] = { -78, -80 };
+#endif
+       if (level < 0 || level >= ARRAY_SIZE(sz)) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "level out of range %d", level);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE,
+                               AR5K_PHY_DESIRED_SIZE_TOT, sz[level]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE,
+                               AR5K_PHY_AGCCOARSE_LO, lo[level]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE,
+                               AR5K_PHY_AGCCOARSE_HI, hi[level]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG,
+                               AR5K_PHY_SIG_FIRPWR, fr[level]);
+
+       ah->ah_sc->ani_state.noise_imm_level = level;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level);
+}
+
+
+/**
+ * ath5k_ani_set_spur_immunity_level() - Set spur immunity level
+ *
+ * @level: level between 0 and @max_spur_level (the maximum level is dependent
+ *     on the chip revision).
+ */
+void
+ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
+{
+       const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+
+       if (level < 0 || level >= ARRAY_SIZE(val) ||
+           level > ah->ah_sc->ani_state.max_spur_level) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "level out of range %d", level);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR,
+               AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, val[level]);
+
+       ah->ah_sc->ani_state.spur_level = level;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level);
+}
+
+
+/**
+ * ath5k_ani_set_firstep_level() - Set "firstep" level
+ *
+ * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL
+ */
+void
+ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
+{
+       const int val[] = { 0, 4, 8 };
+
+       if (level < 0 || level >= ARRAY_SIZE(val)) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "level out of range %d", level);
+               return;
+       }
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG,
+                               AR5K_PHY_SIG_FIRSTEP, val[level]);
+
+       ah->ah_sc->ani_state.firstep_level = level;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "new level %d", level);
+}
+
+
+/**
+ * ath5k_ani_set_ofdm_weak_signal_detection() - Control OFDM weak signal
+ *                                             detection
+ *
+ * @on: turn on or off
+ */
+void
+ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on)
+{
+       const int m1l[] = { 127, 50 };
+       const int m2l[] = { 127, 40 };
+       const int m1[] = { 127, 0x4d };
+       const int m2[] = { 127, 0x40 };
+       const int m2cnt[] = { 31, 16 };
+       const int m2lcnt[] = { 63, 48 };
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_M1, m1l[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_M2, m2l[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR,
+                               AR5K_PHY_WEAK_OFDM_HIGH_THR_M1, m1[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR,
+                               AR5K_PHY_WEAK_OFDM_HIGH_THR_M2, m2[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_HIGH_THR,
+                       AR5K_PHY_WEAK_OFDM_HIGH_THR_M2_COUNT, m2cnt[on]);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                       AR5K_PHY_WEAK_OFDM_LOW_THR_M2_COUNT, m2lcnt[on]);
+
+       if (on)
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN);
+       else
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_WEAK_OFDM_LOW_THR,
+                               AR5K_PHY_WEAK_OFDM_LOW_THR_SELFCOR_EN);
+
+       ah->ah_sc->ani_state.ofdm_weak_sig = on;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s",
+                         on ? "on" : "off");
+}
+
+
+/**
+ * ath5k_ani_set_cck_weak_signal_detection() - control CCK weak signal detection
+ *
+ * @on: turn on or off
+ */
+void
+ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on)
+{
+       const int val[] = { 8, 6 };
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_CCK_CROSSCORR,
+                               AR5K_PHY_CCK_CROSSCORR_WEAK_SIG_THR, val[on]);
+       ah->ah_sc->ani_state.cck_weak_sig = on;
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "turned %s",
+                         on ? "on" : "off");
+}
+
+
+/*** ANI algorithm ***/
+
+/**
+ * ath5k_ani_raise_immunity() - Increase noise immunity
+ *
+ * @ofdm_trigger: If this is true we are called because of too many OFDM errors,
+ *     the algorithm will tune more parameters then.
+ *
+ * Try to raise noise immunity (=decrease sensitivity) in several steps
+ * depending on the average RSSI of the beacons we received.
+ */
+static void
+ath5k_ani_raise_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as,
+                        bool ofdm_trigger)
+{
+       int rssi = ah->ah_beacon_rssi_avg.avg;
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "raise immunity (%s)",
+               ofdm_trigger ? "ODFM" : "CCK");
+
+       /* first: raise noise immunity */
+       if (as->noise_imm_level < ATH5K_ANI_MAX_NOISE_IMM_LVL) {
+               ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level + 1);
+               return;
+       }
+
+       /* only OFDM: raise spur immunity level */
+       if (ofdm_trigger &&
+           as->spur_level < ah->ah_sc->ani_state.max_spur_level) {
+               ath5k_ani_set_spur_immunity_level(ah, as->spur_level + 1);
+               return;
+       }
+
+       /* AP mode */
+       if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) {
+               if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL)
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level + 1);
+               return;
+       }
+
+       /* STA and IBSS mode */
+
+       /* TODO: for IBSS mode it would be better to keep a beacon RSSI average
+        * per each neighbour node and use the minimum of these, to make sure we
+        * don't shut out a remote node by raising immunity too high. */
+
+       if (rssi > ATH5K_ANI_RSSI_THR_HIGH) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                                 "beacon RSSI high");
+               /* only OFDM: beacon RSSI is high, we can disable ODFM weak
+                * signal detection */
+               if (ofdm_trigger && as->ofdm_weak_sig == true) {
+                       ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
+                       ath5k_ani_set_spur_immunity_level(ah, 0);
+                       return;
+               }
+               /* as a last resort or CCK: raise firstep level */
+               if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL) {
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level + 1);
+                       return;
+               }
+       } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) {
+               /* beacon RSSI in mid range, we need OFDM weak signal detect,
+                * but can raise firstep level */
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                                 "beacon RSSI mid");
+               if (ofdm_trigger && as->ofdm_weak_sig == false)
+                       ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
+               if (as->firstep_level < ATH5K_ANI_MAX_FIRSTEP_LVL)
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level + 1);
+               return;
+       } else if (ah->ah_current_channel->band == IEEE80211_BAND_2GHZ) {
+               /* beacon RSSI is low. in B/G mode turn of OFDM weak signal
+                * detect and zero firstep level to maximize CCK sensitivity */
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                                 "beacon RSSI low, 2GHz");
+               if (ofdm_trigger && as->ofdm_weak_sig == true)
+                       ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
+               if (as->firstep_level > 0)
+                       ath5k_ani_set_firstep_level(ah, 0);
+               return;
+       }
+
+       /* TODO: why not?:
+       if (as->cck_weak_sig == true) {
+               ath5k_ani_set_cck_weak_signal_detection(ah, false);
+       }
+       */
+}
+
+
+/**
+ * ath5k_ani_lower_immunity() - Decrease noise immunity
+ *
+ * Try to lower noise immunity (=increase sensitivity) in several steps
+ * depending on the average RSSI of the beacons we received.
+ */
+static void
+ath5k_ani_lower_immunity(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+{
+       int rssi = ah->ah_beacon_rssi_avg.avg;
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "lower immunity");
+
+       if (ah->ah_sc->opmode == NL80211_IFTYPE_AP) {
+               /* AP mode */
+               if (as->firstep_level > 0) {
+                       ath5k_ani_set_firstep_level(ah, as->firstep_level - 1);
+                       return;
+               }
+       } else {
+               /* STA and IBSS mode (see TODO above) */
+               if (rssi > ATH5K_ANI_RSSI_THR_HIGH) {
+                       /* beacon signal is high, leave OFDM weak signal
+                        * detection off or it may oscillate
+                        * TODO: who said it's off??? */
+               } else if (rssi > ATH5K_ANI_RSSI_THR_LOW) {
+                       /* beacon RSSI is mid-range: turn on ODFM weak signal
+                        * detection and next, lower firstep level */
+                       if (as->ofdm_weak_sig == false) {
+                               ath5k_ani_set_ofdm_weak_signal_detection(ah,
+                                                                        true);
+                               return;
+                       }
+                       if (as->firstep_level > 0) {
+                               ath5k_ani_set_firstep_level(ah,
+                                                       as->firstep_level - 1);
+                               return;
+                       }
+               } else {
+                       /* beacon signal is low: only reduce firstep level */
+                       if (as->firstep_level > 0) {
+                               ath5k_ani_set_firstep_level(ah,
+                                                       as->firstep_level - 1);
+                               return;
+                       }
+               }
+       }
+
+       /* all modes */
+       if (as->spur_level > 0) {
+               ath5k_ani_set_spur_immunity_level(ah, as->spur_level - 1);
+               return;
+       }
+
+       /* finally, reduce noise immunity */
+       if (as->noise_imm_level > 0) {
+               ath5k_ani_set_noise_immunity_level(ah, as->noise_imm_level - 1);
+               return;
+       }
+}
+
+
+/**
+ * ath5k_hw_ani_get_listen_time() - Calculate time spent listening
+ *
+ * Return an approximation of the time spent "listening" in milliseconds (ms)
+ * since the last call of this function by deducting the cycles spent
+ * transmitting and receiving from the total cycle count.
+ * Save profile count values for debugging/statistics and because we might want
+ * to use them later.
+ *
+ * We assume no one else clears these registers!
+ */
+static int
+ath5k_hw_ani_get_listen_time(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+{
+       int listen;
+
+       /* freeze */
+       ath5k_hw_reg_write(ah, AR5K_MIBC_FMC, AR5K_MIBC);
+       /* read */
+       as->pfc_cycles = ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE);
+       as->pfc_busy = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR);
+       as->pfc_tx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX);
+       as->pfc_rx = ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX);
+       /* clear */
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
+       ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
+       /* un-freeze */
+       ath5k_hw_reg_write(ah, 0, AR5K_MIBC);
+
+       /* TODO: where does 44000 come from? (11g clock rate?) */
+       listen = (as->pfc_cycles - as->pfc_rx - as->pfc_tx) / 44000;
+
+       if (as->pfc_cycles == 0 || listen < 0)
+               return 0;
+       return listen;
+}
+
+
+/**
+ * ath5k_ani_save_and_clear_phy_errors() - Clear and save PHY error counters
+ *
+ * Clear the PHY error counters as soon as possible, since this might be called
+ * from a MIB interrupt and we want to make sure we don't get interrupted again.
+ * Add the count of CCK and OFDM errors to our internal state, so it can be used
+ * by the algorithm later.
+ *
+ * Will be called from interrupt and tasklet context.
+ * Returns 0 if both counters are zero.
+ */
+static int
+ath5k_ani_save_and_clear_phy_errors(struct ath5k_hw *ah,
+                                   struct ath5k_ani_state *as)
+{
+       unsigned int ofdm_err, cck_err;
+
+       if (!ah->ah_capabilities.cap_has_phyerr_counters)
+               return 0;
+
+       ofdm_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1);
+       cck_err = ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2);
+
+       /* reset counters first, we might be in a hurry (interrupt) */
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH,
+                          AR5K_PHYERR_CNT1);
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH,
+                          AR5K_PHYERR_CNT2);
+
+       ofdm_err = ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - ofdm_err);
+       cck_err = ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX - cck_err);
+
+       /* sometimes both can be zero, especially when there is a superfluous
+        * second interrupt. detect that here and return an error. */
+       if (ofdm_err <= 0 && cck_err <= 0)
+               return 0;
+
+       /* avoid negative values should one of the registers overflow */
+       if (ofdm_err > 0) {
+               as->ofdm_errors += ofdm_err;
+               as->sum_ofdm_errors += ofdm_err;
+       }
+       if (cck_err > 0) {
+               as->cck_errors += cck_err;
+               as->sum_cck_errors += cck_err;
+       }
+       return 1;
+}
+
+
+/**
+ * ath5k_ani_period_restart() - Restart ANI period
+ *
+ * Just reset counters, so they are clear for the next "ani period".
+ */
+static void
+ath5k_ani_period_restart(struct ath5k_hw *ah, struct ath5k_ani_state *as)
+{
+       /* keep last values for debugging */
+       as->last_ofdm_errors = as->ofdm_errors;
+       as->last_cck_errors = as->cck_errors;
+       as->last_listen = as->listen_time;
+
+       as->ofdm_errors = 0;
+       as->cck_errors = 0;
+       as->listen_time = 0;
+}
+
+
+/**
+ * ath5k_ani_calibration() - The main ANI calibration function
+ *
+ * We count OFDM and CCK errors relative to the time where we did not send or
+ * receive ("listen" time) and raise or lower immunity accordingly.
+ * This is called regularly (every second) from the calibration timer, but also
+ * when an error threshold has been reached.
+ *
+ * In order to synchronize access from different contexts, this should be
+ * called only indirectly by scheduling the ANI tasklet!
+ */
+void
+ath5k_ani_calibration(struct ath5k_hw *ah)
+{
+       struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
+       int listen, ofdm_high, ofdm_low, cck_high, cck_low;
+
+       if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
+               return;
+
+       /* get listen time since last call and add it to the counter because we
+        * might not have restarted the "ani period" last time */
+       listen = ath5k_hw_ani_get_listen_time(ah, as);
+       as->listen_time += listen;
+
+       ath5k_ani_save_and_clear_phy_errors(ah, as);
+
+       ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000;
+       cck_high = as->listen_time * ATH5K_ANI_CCK_TRIG_HIGH / 1000;
+       ofdm_low = as->listen_time * ATH5K_ANI_OFDM_TRIG_LOW / 1000;
+       cck_low = as->listen_time * ATH5K_ANI_CCK_TRIG_LOW / 1000;
+
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+               "listen %d (now %d)", as->listen_time, listen);
+       ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+               "check high ofdm %d/%d cck %d/%d",
+               as->ofdm_errors, ofdm_high, as->cck_errors, cck_high);
+
+       if (as->ofdm_errors > ofdm_high || as->cck_errors > cck_high) {
+               /* too many PHY errors - we have to raise immunity */
+               bool ofdm_flag = as->ofdm_errors > ofdm_high ? true : false;
+               ath5k_ani_raise_immunity(ah, as, ofdm_flag);
+               ath5k_ani_period_restart(ah, as);
+
+       } else if (as->listen_time > 5 * ATH5K_ANI_LISTEN_PERIOD) {
+               /* If more than 5 (TODO: why 5?) periods have passed and we got
+                * relatively little errors we can try to lower immunity */
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "check low ofdm %d/%d cck %d/%d",
+                       as->ofdm_errors, ofdm_low, as->cck_errors, cck_low);
+
+               if (as->ofdm_errors <= ofdm_low && as->cck_errors <= cck_low)
+                       ath5k_ani_lower_immunity(ah, as);
+
+               ath5k_ani_period_restart(ah, as);
+       }
+}
+
+
+/*** INTERRUPT HANDLER ***/
+
+/**
+ * ath5k_ani_mib_intr() - Interrupt handler for ANI MIB counters
+ *
+ * Just read & reset the registers quickly, so they don't generate more
+ * interrupts, save the counters and schedule the tasklet to decide whether
+ * to raise immunity or not.
+ *
+ * We just need to handle PHY error counters, ath5k_hw_update_mib_counters()
+ * should take care of all "normal" MIB interrupts.
+ */
+void
+ath5k_ani_mib_intr(struct ath5k_hw *ah)
+{
+       struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
+
+       /* nothing to do here if HW does not have PHY error counters - they
+        * can't be the reason for the MIB interrupt then */
+       if (!ah->ah_capabilities.cap_has_phyerr_counters)
+               return;
+
+       /* not in use but clear anyways */
+       ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT);
+       ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
+
+       if (ah->ah_sc->ani_state.ani_mode != ATH5K_ANI_MODE_AUTO)
+               return;
+
+       /* if one of the errors triggered, we can get a superfluous second
+        * interrupt, even though we have already reset the register. the
+        * function detects that so we can return early */
+       if (ath5k_ani_save_and_clear_phy_errors(ah, as) == 0)
+               return;
+
+       if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH ||
+           as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH)
+               tasklet_schedule(&ah->ah_sc->ani_tasklet);
+}
+
+
+/**
+ * ath5k_ani_phy_error_report() - Used by older HW to report PHY errors
+ *
+ * This is used by hardware without PHY error counters to report PHY errors
+ * on a frame-by-frame basis, instead of the interrupt.
+ */
+void
+ath5k_ani_phy_error_report(struct ath5k_hw *ah,
+                          enum ath5k_phy_error_code phyerr)
+{
+       struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
+
+       if (phyerr == AR5K_RX_PHY_ERROR_OFDM_TIMING) {
+               as->ofdm_errors++;
+               if (as->ofdm_errors > ATH5K_ANI_OFDM_TRIG_HIGH)
+                       tasklet_schedule(&ah->ah_sc->ani_tasklet);
+       } else if (phyerr == AR5K_RX_PHY_ERROR_CCK_TIMING) {
+               as->cck_errors++;
+               if (as->cck_errors > ATH5K_ANI_CCK_TRIG_HIGH)
+                       tasklet_schedule(&ah->ah_sc->ani_tasklet);
+       }
+}
+
+
+/*** INIT ***/
+
+/**
+ * ath5k_enable_phy_err_counters() - Enable PHY error counters
+ *
+ * Enable PHY error counters for OFDM and CCK timing errors.
+ */
+static void
+ath5k_enable_phy_err_counters(struct ath5k_hw *ah)
+{
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_OFDM_TRIG_HIGH,
+                          AR5K_PHYERR_CNT1);
+       ath5k_hw_reg_write(ah, ATH5K_PHYERR_CNT_MAX - ATH5K_ANI_CCK_TRIG_HIGH,
+                          AR5K_PHYERR_CNT2);
+       ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_OFDM, AR5K_PHYERR_CNT1_MASK);
+       ath5k_hw_reg_write(ah, AR5K_PHY_ERR_FIL_CCK, AR5K_PHYERR_CNT2_MASK);
+
+       /* not in use */
+       ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT);
+       ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
+}
+
+
+/**
+ * ath5k_disable_phy_err_counters() - Disable PHY error counters
+ *
+ * Disable PHY error counters for OFDM and CCK timing errors.
+ */
+static void
+ath5k_disable_phy_err_counters(struct ath5k_hw *ah)
+{
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1);
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2);
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT1_MASK);
+       ath5k_hw_reg_write(ah, 0, AR5K_PHYERR_CNT2_MASK);
+
+       /* not in use */
+       ath5k_hw_reg_write(ah, 0, AR5K_OFDM_FIL_CNT);
+       ath5k_hw_reg_write(ah, 0, AR5K_CCK_FIL_CNT);
+}
+
+
+/**
+ * ath5k_ani_init() - Initialize ANI
+ * @mode: Which mode to use (auto, manual high, manual low, off)
+ *
+ * Initialize ANI according to mode.
+ */
+void
+ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode)
+{
+       /* ANI is only possible on 5212 and newer */
+       if (ah->ah_version < AR5K_AR5212)
+               return;
+
+       /* clear old state information */
+       memset(&ah->ah_sc->ani_state, 0, sizeof(ah->ah_sc->ani_state));
+
+       /* older hardware has more spur levels than newer */
+       if (ah->ah_mac_srev < AR5K_SREV_AR2414)
+               ah->ah_sc->ani_state.max_spur_level = 7;
+       else
+               ah->ah_sc->ani_state.max_spur_level = 2;
+
+       /* initial values for our ani parameters */
+       if (mode == ATH5K_ANI_MODE_OFF) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI off\n");
+       } else if  (mode == ATH5K_ANI_MODE_MANUAL_LOW) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "ANI manual low -> high sensitivity\n");
+               ath5k_ani_set_noise_immunity_level(ah, 0);
+               ath5k_ani_set_spur_immunity_level(ah, 0);
+               ath5k_ani_set_firstep_level(ah, 0);
+               ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
+               ath5k_ani_set_cck_weak_signal_detection(ah, true);
+       } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
+                       "ANI manual high -> low sensitivity\n");
+               ath5k_ani_set_noise_immunity_level(ah,
+                                       ATH5K_ANI_MAX_NOISE_IMM_LVL);
+               ath5k_ani_set_spur_immunity_level(ah,
+                                       ah->ah_sc->ani_state.max_spur_level);
+               ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
+               ath5k_ani_set_ofdm_weak_signal_detection(ah, false);
+               ath5k_ani_set_cck_weak_signal_detection(ah, false);
+       } else if (mode == ATH5K_ANI_MODE_AUTO) {
+               ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI, "ANI auto\n");
+               ath5k_ani_set_noise_immunity_level(ah, 0);
+               ath5k_ani_set_spur_immunity_level(ah, 0);
+               ath5k_ani_set_firstep_level(ah, 0);
+               ath5k_ani_set_ofdm_weak_signal_detection(ah, true);
+               ath5k_ani_set_cck_weak_signal_detection(ah, false);
+       }
+
+       /* newer hardware has PHY error counter registers which we can use to
+        * get OFDM and CCK error counts. older hardware has to set rxfilter and
+        * report every single PHY error by calling ath5k_ani_phy_error_report()
+        */
+       if (mode == ATH5K_ANI_MODE_AUTO) {
+               if (ah->ah_capabilities.cap_has_phyerr_counters)
+                       ath5k_enable_phy_err_counters(ah);
+               else
+                       ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) |
+                                                  AR5K_RX_FILTER_PHYERR);
+       } else {
+               if (ah->ah_capabilities.cap_has_phyerr_counters)
+                       ath5k_disable_phy_err_counters(ah);
+               else
+                       ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) &
+                                                  ~AR5K_RX_FILTER_PHYERR);
+       }
+
+       ah->ah_sc->ani_state.ani_mode = mode;
+}
+
+
+/*** DEBUG ***/
+
+#ifdef CONFIG_ATH5K_DEBUG
+
+void
+ath5k_ani_print_counters(struct ath5k_hw *ah)
+{
+       /* clears too */
+       printk(KERN_NOTICE "ACK fail\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_ACK_FAIL));
+       printk(KERN_NOTICE "RTS fail\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_RTS_FAIL));
+       printk(KERN_NOTICE "RTS success\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_RTS_OK));
+       printk(KERN_NOTICE "FCS error\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_FCS_FAIL));
+
+       /* no clear */
+       printk(KERN_NOTICE "tx\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_TX));
+       printk(KERN_NOTICE "rx\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_RX));
+       printk(KERN_NOTICE "busy\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_RXCLR));
+       printk(KERN_NOTICE "cycles\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PROFCNT_CYCLE));
+
+       printk(KERN_NOTICE "AR5K_PHYERR_CNT1\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT1));
+       printk(KERN_NOTICE "AR5K_PHYERR_CNT2\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_PHYERR_CNT2));
+       printk(KERN_NOTICE "AR5K_OFDM_FIL_CNT\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_OFDM_FIL_CNT));
+       printk(KERN_NOTICE "AR5K_CCK_FIL_CNT\t%d\n",
+               ath5k_hw_reg_read(ah, AR5K_CCK_FIL_CNT));
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h
new file mode 100644 (file)
index 0000000..55cf26d
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2010 Bruno Randolf <br1@einfach.org>
+ *
+ * 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.
+ */
+#ifndef ANI_H
+#define ANI_H
+
+/* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */
+#define ATH5K_ANI_LISTEN_PERIOD                100
+#define ATH5K_ANI_OFDM_TRIG_HIGH       500
+#define ATH5K_ANI_OFDM_TRIG_LOW                200
+#define ATH5K_ANI_CCK_TRIG_HIGH                200
+#define ATH5K_ANI_CCK_TRIG_LOW         100
+
+/* average beacon RSSI thresholds */
+#define ATH5K_ANI_RSSI_THR_HIGH                40
+#define ATH5K_ANI_RSSI_THR_LOW         7
+
+/* maximum availabe levels */
+#define ATH5K_ANI_MAX_FIRSTEP_LVL      2
+#define ATH5K_ANI_MAX_NOISE_IMM_LVL    1
+
+
+/**
+ * enum ath5k_ani_mode - mode for ANI / noise sensitivity
+ *
+ * @ATH5K_ANI_MODE_OFF: Turn ANI off. This can be useful to just stop the ANI
+ *     algorithm after it has been on auto mode.
+ * ATH5K_ANI_MODE_MANUAL_LOW: Manually set all immunity parameters to low,
+ *     maximizing sensitivity. ANI will not run.
+ * ATH5K_ANI_MODE_MANUAL_HIGH: Manually set all immunity parameters to high,
+ *     minimizing sensitivity. ANI will not run.
+ * ATH5K_ANI_MODE_AUTO: Automatically control immunity parameters based on the
+ *     amount of OFDM and CCK frame errors (default).
+ */
+enum ath5k_ani_mode {
+       ATH5K_ANI_MODE_OFF              = 0,
+       ATH5K_ANI_MODE_MANUAL_LOW       = 1,
+       ATH5K_ANI_MODE_MANUAL_HIGH      = 2,
+       ATH5K_ANI_MODE_AUTO             = 3
+};
+
+
+/**
+ * struct ath5k_ani_state - ANI state and associated counters
+ *
+ * @max_spur_level: the maximum spur level is chip dependent
+ */
+struct ath5k_ani_state {
+       enum ath5k_ani_mode     ani_mode;
+
+       /* state */
+       int                     noise_imm_level;
+       int                     spur_level;
+       int                     firstep_level;
+       bool                    ofdm_weak_sig;
+       bool                    cck_weak_sig;
+
+       int                     max_spur_level;
+
+       /* used by the algorithm */
+       unsigned int            listen_time;
+       unsigned int            ofdm_errors;
+       unsigned int            cck_errors;
+
+       /* debug/statistics only: numbers from last ANI calibration */
+       unsigned int            pfc_tx;
+       unsigned int            pfc_rx;
+       unsigned int            pfc_busy;
+       unsigned int            pfc_cycles;
+       unsigned int            last_listen;
+       unsigned int            last_ofdm_errors;
+       unsigned int            last_cck_errors;
+       unsigned int            sum_ofdm_errors;
+       unsigned int            sum_cck_errors;
+};
+
+void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode);
+void ath5k_ani_mib_intr(struct ath5k_hw *ah);
+void ath5k_ani_calibration(struct ath5k_hw *ah);
+void ath5k_ani_phy_error_report(struct ath5k_hw *ah,
+                               enum ath5k_phy_error_code phyerr);
+
+/* for manual control */
+void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level);
+void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level);
+void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level);
+void ath5k_ani_set_ofdm_weak_signal_detection(struct ath5k_hw *ah, bool on);
+void ath5k_ani_set_cck_weak_signal_detection(struct ath5k_hw *ah, bool on);
+
+void ath5k_ani_print_counters(struct ath5k_hw *ah);
+
+#endif /* ANI_H */
index ac67f02e26d88a7823dc3b736e0993c03a60a248..2785946f659a19efcbc2298126314b95dee721a7 100644 (file)
 #define AR5K_TUNE_MAX_TXPOWER                  63
 #define AR5K_TUNE_DEFAULT_TXPOWER              25
 #define AR5K_TUNE_TPC_TXPOWER                  false
-#define AR5K_TUNE_HWTXTRIES                    4
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL    10000   /* 10 sec */
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI    1000    /* 1 sec */
 
 #define AR5K_INIT_CARR_SENSE_EN                        1
 
@@ -614,28 +615,6 @@ struct ath5k_rx_status {
 #define AR5K_BEACON_ENA                0x00800000 /*enable beacon xmit*/
 #define AR5K_BEACON_RESET_TSF  0x01000000 /*force a TSF reset*/
 
-#if 0
-/**
- * struct ath5k_beacon_state - Per-station beacon timer state.
- * @bs_interval: in TU's, can also include the above flags
- * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a
- *     Point Coordination Function capable AP
- */
-struct ath5k_beacon_state {
-       u32     bs_next_beacon;
-       u32     bs_next_dtim;
-       u32     bs_interval;
-       u8      bs_dtim_period;
-       u8      bs_cfp_period;
-       u16     bs_cfp_max_duration;
-       u16     bs_cfp_du_remain;
-       u16     bs_tim_offset;
-       u16     bs_sleep_duration;
-       u16     bs_bmiss_threshold;
-       u32     bs_cfp_next;
-};
-#endif
-
 
 /*
  * TSF to TU conversion:
@@ -822,9 +801,9 @@ struct ath5k_athchan_2ghz {
  * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold
  *     We currently do increments on interrupt by
  *     (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2
- * @AR5K_INT_MIB: Indicates the Management Information Base counters should be
- *     checked. We should do this with ath5k_hw_update_mib_counters() but
- *     it seems we should also then do some noise immunity work.
+ * @AR5K_INT_MIB: Indicates the either Management Information Base counters or
+ *     one of the PHY error counters reached the maximum value and should be
+ *     read and cleared.
  * @AR5K_INT_RXPHY: RX PHY Error
  * @AR5K_INT_RXKCM: RX Key cache miss
  * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a
@@ -912,10 +891,11 @@ enum ath5k_int {
        AR5K_INT_NOCARD = 0xffffffff
 };
 
-/* Software interrupts used for calibration */
-enum ath5k_software_interrupt {
-       AR5K_SWI_FULL_CALIBRATION = 0x01,
-       AR5K_SWI_SHORT_CALIBRATION = 0x02,
+/* mask which calibration is active at the moment */
+enum ath5k_calibration_mask {
+       AR5K_CALIBRATION_FULL = 0x01,
+       AR5K_CALIBRATION_SHORT = 0x02,
+       AR5K_CALIBRATION_ANI = 0x04,
 };
 
 /*
@@ -1004,6 +984,8 @@ struct ath5k_capabilities {
        struct {
                u8      q_tx_num;
        } cap_queues;
+
+       bool cap_has_phyerr_counters;
 };
 
 /* size of noise floor history (keep it a power of two) */
@@ -1014,6 +996,15 @@ struct ath5k_nfcal_hist
        s16 nfval[ATH5K_NF_CAL_HIST_MAX];       /* last few noise floors */
 };
 
+/**
+ * struct avg_val - Helper structure for average calculation
+ * @avg: contains the actual average value
+ * @avg_weight: is used internally during calculation to prevent rounding errors
+ */
+struct ath5k_avg_val {
+       int avg;
+       int avg_weight;
+};
 
 /***************************************\
   HARDWARE ABSTRACTION LAYER STRUCTURE
@@ -1028,7 +1019,6 @@ struct ath5k_nfcal_hist
 
 /* TODO: Clean up and merge with ath5k_softc */
 struct ath5k_hw {
-       u32                     ah_magic;
        struct ath_common       common;
 
        struct ath5k_softc      *ah_sc;
@@ -1036,7 +1026,6 @@ struct ath5k_hw {
 
        enum ath5k_int          ah_imr;
 
-       enum nl80211_iftype     ah_op_mode;
        struct ieee80211_channel *ah_current_channel;
        bool                    ah_turbo;
        bool                    ah_calibration;
@@ -1049,7 +1038,6 @@ struct ath5k_hw {
        u32                     ah_phy;
        u32                     ah_mac_srev;
        u16                     ah_mac_version;
-       u16                     ah_mac_revision;
        u16                     ah_phy_revision;
        u16                     ah_radio_5ghz_revision;
        u16                     ah_radio_2ghz_revision;
@@ -1071,8 +1059,6 @@ struct ath5k_hw {
        u8                      ah_def_ant;
        bool                    ah_software_retry;
 
-       int                     ah_gpio_npins;
-
        struct ath5k_capabilities ah_capabilities;
 
        struct ath5k_txq_info   ah_txq[AR5K_NUM_TX_QUEUES];
@@ -1123,17 +1109,18 @@ struct ath5k_hw {
 
        struct ath5k_nfcal_hist ah_nfcal_hist;
 
+       /* average beacon RSSI in our BSS (used by ANI) */
+       struct ath5k_avg_val    ah_beacon_rssi_avg;
+
        /* noise floor from last periodic calibration */
        s32                     ah_noise_floor;
 
        /* Calibration timestamp */
-       unsigned long           ah_cal_tstamp;
-
-       /* Calibration interval (secs) */
-       u8                      ah_cal_intval;
+       unsigned long           ah_cal_next_full;
+       unsigned long           ah_cal_next_ani;
 
-       /* Software interrupt mask */
-       u8                      ah_swi_mask;
+       /* Calibration mask */
+       u8                      ah_cal_mask;
 
        /*
         * Function pointers
@@ -1141,9 +1128,9 @@ struct ath5k_hw {
        int (*ah_setup_rx_desc)(struct ath5k_hw *ah, struct ath5k_desc *desc,
                                u32 size, unsigned int flags);
        int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
-               unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int,
+               unsigned int, unsigned int, int, enum ath5k_pkt_type,
                unsigned int, unsigned int, unsigned int, unsigned int,
-               unsigned int, unsigned int, unsigned int);
+               unsigned int, unsigned int, unsigned int, unsigned int);
        int (*ah_setup_mrr_tx_desc)(struct ath5k_hw *, struct ath5k_desc *,
                unsigned int, unsigned int, unsigned int, unsigned int,
                unsigned int, unsigned int);
@@ -1158,158 +1145,145 @@ struct ath5k_hw {
  */
 
 /* Attach/Detach Functions */
-extern int ath5k_hw_attach(struct ath5k_softc *sc);
-extern void ath5k_hw_detach(struct ath5k_hw *ah);
+int ath5k_hw_attach(struct ath5k_softc *sc);
+void ath5k_hw_detach(struct ath5k_hw *ah);
 
 /* LED functions */
-extern int ath5k_init_leds(struct ath5k_softc *sc);
-extern void ath5k_led_enable(struct ath5k_softc *sc);
-extern void ath5k_led_off(struct ath5k_softc *sc);
-extern void ath5k_unregister_leds(struct ath5k_softc *sc);
+int ath5k_init_leds(struct ath5k_softc *sc);
+void ath5k_led_enable(struct ath5k_softc *sc);
+void ath5k_led_off(struct ath5k_softc *sc);
+void ath5k_unregister_leds(struct ath5k_softc *sc);
 
 /* Reset Functions */
-extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
-extern int ath5k_hw_on_hold(struct ath5k_hw *ah);
-extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
+int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
+int ath5k_hw_on_hold(struct ath5k_hw *ah);
+int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+                  struct ieee80211_channel *channel, bool change_channel);
+int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
+                             bool is_set);
 /* Power management functions */
-extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
 
 /* DMA Related Functions */
-extern void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
-extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
-extern u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
-extern void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
-extern int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-extern u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
+void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
+int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
+u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
+void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
+int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
+int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
                                u32 phys_addr);
-extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
+int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase);
 /* Interrupt handling */
-extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
-extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
-extern enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum
-ath5k_int new_mask);
-extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ieee80211_low_level_stats *stats);
+bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
+int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
+enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah);
 
 /* EEPROM access functions */
-extern int ath5k_eeprom_init(struct ath5k_hw *ah);
-extern void ath5k_eeprom_detach(struct ath5k_hw *ah);
-extern int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
-extern bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah);
+int ath5k_eeprom_init(struct ath5k_hw *ah);
+void ath5k_eeprom_detach(struct ath5k_hw *ah);
+int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
 
 /* 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);
+extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
+void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
 /* BSSID Functions */
-extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
-extern void ath5k_hw_set_associd(struct ath5k_hw *ah);
-extern void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
+int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
+void ath5k_hw_set_associd(struct ath5k_hw *ah);
+void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
 /* Receive start/stop functions */
-extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
-extern void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
 /* RX Filter functions */
-extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
-extern int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
-extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index);
-extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
-extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
+u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
+void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
 /* Beacon control functions */
-extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah);
-extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
-extern void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
-extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
-extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
-#if 0
-extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state);
-extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah);
-extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr);
-#endif
+u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
+void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
+void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
+void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
 /* ACK bit rate */
 void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
-/* ACK/CTS Timeouts */
-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);
-extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac);
-extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
+int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry);
+int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
+                    const struct ieee80211_key_conf *key, const u8 *mac);
+int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac);
 
 /* Queue Control Unit, DFS Control Unit Functions */
-extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info);
-extern int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
-                               const struct ath5k_txq_info *queue_info);
-extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
-                               enum ath5k_tx_queue queue_type,
-                               struct ath5k_txq_info *queue_info);
-extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
-extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
-extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
-extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah);
-extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+                              struct ath5k_txq_info *queue_info);
+int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
+                              const struct ath5k_txq_info *queue_info);
+int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
+                           enum ath5k_tx_queue queue_type,
+                           struct ath5k_txq_info *queue_info);
+u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
+int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
 
 /* Hardware Descriptor Functions */
-extern int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
+int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
 
 /* GPIO Functions */
-extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
-extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
-extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
-extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
-extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
-extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level);
+void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
+int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
+int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
+u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
+int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
+void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
+                           u32 interrupt_level);
 
 /* rfkill Functions */
-extern void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
-extern void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
+void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
+void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
 
 /* Misc functions */
 int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
-extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result);
-extern int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
-extern int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
+int ath5k_hw_get_capability(struct ath5k_hw *ah,
+                           enum ath5k_capability_type cap_type, u32 capability,
+                           u32 *result);
+int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
+int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
 
 /* Initial register settings functions */
-extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
 
 /* Initialize RF */
-extern int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
-                               struct ieee80211_channel *channel,
-                               unsigned int mode);
-extern int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
-extern enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
-extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
+int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+                        struct ieee80211_channel *channel,
+                        unsigned int mode);
+int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
+int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
 /* PHY/RF channel functions */
-extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
-extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
+bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
+int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
 /* PHY calibration */
 void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
-extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
-extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
-extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah);
-extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
+int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
+                          struct ieee80211_channel *channel);
 /* Spur mitigation */
 bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
-                               struct ieee80211_channel *channel);
+                                 struct ieee80211_channel *channel);
 void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
-                               struct ieee80211_channel *channel);
+                                        struct ieee80211_channel *channel);
 /* Misc PHY functions */
-extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
-extern int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+int ath5k_hw_phy_disable(struct ath5k_hw *ah);
 /* Antenna control */
-extern void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
-extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant);
-extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah);
+void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
 /* TX power setup */
-extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, u8 ee_mode, u8 txpower);
-extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
+int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+                    u8 ee_mode, u8 txpower);
+int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
 
 /*
  * Functions used internaly
@@ -1335,29 +1309,6 @@ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
        iowrite32(val, ah->ah_iobase + reg);
 }
 
-#if defined(_ATH5K_RESET) || defined(_ATH5K_PHY)
-/*
- * Check if a register write has been completed
- */
-static int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag,
-               u32 val, bool is_set)
-{
-       int i;
-       u32 data;
-
-       for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
-               data = ath5k_hw_reg_read(ah, reg);
-               if (is_set && (data & flag))
-                       break;
-               else if ((data & flag) == val)
-                       break;
-               udelay(15);
-       }
-
-       return (i <= 0) ? -EAGAIN : 0;
-}
-#endif
-
 static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
 {
        u32 retval = 0, bit, i;
@@ -1370,9 +1321,27 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
        return retval;
 }
 
-static inline int ath5k_pad_size(int hdrlen)
+#define AVG_SAMPLES    8
+#define AVG_FACTOR     1000
+
+/**
+ * ath5k_moving_average -  Exponentially weighted moving average
+ * @avg: average structure
+ * @val: current value
+ *
+ * This implementation make use of a struct ath5k_avg_val to prevent rounding
+ * errors.
+ */
+static inline struct ath5k_avg_val
+ath5k_moving_average(const struct ath5k_avg_val avg, const int val)
 {
-       return (hdrlen < 24) ? 0 : hdrlen & 3;
+       struct ath5k_avg_val new;
+       new.avg_weight = avg.avg_weight  ?
+               (((avg.avg_weight * ((AVG_SAMPLES) - 1)) +
+                       (val * (AVG_FACTOR))) / (AVG_SAMPLES)) :
+               (val * (AVG_FACTOR));
+       new.avg = new.avg_weight / (AVG_FACTOR);
+       return new;
 }
 
 #endif
index dc0786cc26393666f3d63ffdb56b5c4e11c4318f..e0c244b02f05d17cc1ee9fb7cc12dd9e0e01541e 100644 (file)
@@ -114,7 +114,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        /*
         * HW information
         */
-       ah->ah_op_mode = NL80211_IFTYPE_STATION;
        ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
        ah->ah_turbo = false;
        ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
@@ -124,6 +123,9 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        ah->ah_cw_min = AR5K_TUNE_CWMIN;
        ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
        ah->ah_software_retry = false;
+       ah->ah_ant_mode = AR5K_ANTMODE_DEFAULT;
+       ah->ah_noise_floor = -95;       /* until first NF calibration is run */
+       sc->ani_state.ani_mode = ATH5K_ANI_MODE_AUTO;
 
        /*
         * Find the mac version
@@ -149,7 +151,6 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        /* Get MAC, PHY and RADIO revisions */
        ah->ah_mac_srev = srev;
        ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
-       ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
        ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
                        0xffffffff;
        ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
@@ -328,7 +329,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
        memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN);
        ath5k_hw_set_associd(ah);
-       ath5k_hw_set_opmode(ah);
+       ath5k_hw_set_opmode(ah, sc->opmode);
 
        ath5k_hw_rfgain_opt_init(ah);
 
index 3abbe7513ab5602df918ae91d0702a2487c4d706..5f04cf38a5bc95548b07069bda31818a2438aa93 100644 (file)
@@ -59,8 +59,8 @@
 #include "base.h"
 #include "reg.h"
 #include "debug.h"
+#include "ani.h"
 
-static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
 static int modparam_nohwcrypt;
 module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
 MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -199,7 +199,7 @@ static void __devexit       ath5k_pci_remove(struct pci_dev *pdev);
 static int             ath5k_pci_suspend(struct device *dev);
 static int             ath5k_pci_resume(struct device *dev);
 
-SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
+static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
 #define ATH5K_PM_OPS   (&ath5k_pm_ops)
 #else
 #define ATH5K_PM_OPS   NULL
@@ -231,7 +231,7 @@ static void ath5k_remove_interface(struct ieee80211_hw *hw,
                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);
+                                  struct netdev_hw_addr_list *mc_list);
 static void ath5k_configure_filter(struct ieee80211_hw *hw,
                unsigned int changed_flags,
                unsigned int *new_flags,
@@ -242,6 +242,8 @@ static int ath5k_set_key(struct ieee80211_hw *hw,
                struct ieee80211_key_conf *key);
 static int ath5k_get_stats(struct ieee80211_hw *hw,
                struct ieee80211_low_level_stats *stats);
+static int ath5k_get_survey(struct ieee80211_hw *hw,
+               int idx, struct survey_info *survey);
 static u64 ath5k_get_tsf(struct ieee80211_hw *hw);
 static void ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf);
 static void ath5k_reset_tsf(struct ieee80211_hw *hw);
@@ -267,6 +269,7 @@ static const struct ieee80211_ops ath5k_hw_ops = {
        .configure_filter = ath5k_configure_filter,
        .set_key        = ath5k_set_key,
        .get_stats      = ath5k_get_stats,
+       .get_survey     = ath5k_get_survey,
        .conf_tx        = NULL,
        .get_tsf        = ath5k_get_tsf,
        .set_tsf        = ath5k_set_tsf,
@@ -308,7 +311,7 @@ static int  ath5k_rxbuf_setup(struct ath5k_softc *sc,
                                struct ath5k_buf *bf);
 static int     ath5k_txbuf_setup(struct ath5k_softc *sc,
                                struct ath5k_buf *bf,
-                               struct ath5k_txq *txq);
+                               struct ath5k_txq *txq, int padsize);
 static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
                                struct ath5k_buf *bf)
 {
@@ -365,6 +368,7 @@ static void         ath5k_beacon_send(struct ath5k_softc *sc);
 static void    ath5k_beacon_config(struct ath5k_softc *sc);
 static void    ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
 static void    ath5k_tasklet_beacon(unsigned long data);
+static void    ath5k_tasklet_ani(unsigned long data);
 
 static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
 {
@@ -544,8 +548,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
        SET_IEEE80211_DEV(hw, &pdev->dev);
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                   IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_SIGNAL_DBM;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
@@ -830,6 +833,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
        tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
        tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
+       tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);
 
        ret = ath5k_eeprom_read_mac(ah, mac);
        if (ret) {
@@ -1138,8 +1142,6 @@ ath5k_mode_setup(struct ath5k_softc *sc)
        struct ath5k_hw *ah = sc->ah;
        u32 rfilt;
 
-       ah->ah_op_mode = sc->opmode;
-
        /* configure rx filter */
        rfilt = sc->filter_flags;
        ath5k_hw_set_rx_filter(ah, rfilt);
@@ -1148,8 +1150,9 @@ ath5k_mode_setup(struct ath5k_softc *sc)
                ath5k_hw_set_bssid_mask(ah, sc->bssidmask);
 
        /* configure operational mode */
-       ath5k_hw_set_opmode(ah);
+       ath5k_hw_set_opmode(ah, sc->opmode);
 
+       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode);
        ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);
 }
 
@@ -1272,7 +1275,7 @@ static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb)
 
 static int
 ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
-                 struct ath5k_txq *txq)
+                 struct ath5k_txq *txq, int padsize)
 {
        struct ath5k_hw *ah = sc->ah;
        struct ath5k_desc *ds = bf->desc;
@@ -1324,7 +1327,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
                        sc->vif, pktlen, info));
        }
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
-               ieee80211_get_hdrlen_from_skb(skb),
+               ieee80211_get_hdrlen_from_skb(skb), padsize,
                get_hw_packet_type(skb),
                (sc->power_level * 2),
                hw_rate,
@@ -1636,7 +1639,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)
                                        sc->txqs[i].link);
                        }
        }
-       ieee80211_wake_queues(sc->hw); /* XXX move to callers */
 
        for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
                if (sc->txqs[i].setup)
@@ -1806,6 +1808,86 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
        }
 }
 
+static void
+ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi)
+{
+       struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+       struct ath5k_hw *ah = sc->ah;
+       struct ath_common *common = ath5k_hw_common(ah);
+
+       /* only beacons from our BSSID */
+       if (!ieee80211_is_beacon(mgmt->frame_control) ||
+           memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0)
+               return;
+
+       ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg,
+                                                     rssi);
+
+       /* in IBSS mode we should keep RSSI statistics per neighbour */
+       /* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */
+}
+
+/*
+ * Compute padding position. skb must contains an IEEE 802.11 frame
+ */
+static int ath5k_common_padpos(struct sk_buff *skb)
+{
+       struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 frame_control = hdr->frame_control;
+       int padpos = 24;
+
+       if (ieee80211_has_a4(frame_control)) {
+               padpos += ETH_ALEN;
+       }
+       if (ieee80211_is_data_qos(frame_control)) {
+               padpos += IEEE80211_QOS_CTL_LEN;
+       }
+
+       return padpos;
+}
+
+/*
+ * This function expects a 802.11 frame and returns the number of
+ * bytes added, or -1 if we don't have enought header room.
+ */
+
+static int ath5k_add_padding(struct sk_buff *skb)
+{
+       int padpos = ath5k_common_padpos(skb);
+       int padsize = padpos & 3;
+
+       if (padsize && skb->len>padpos) {
+
+               if (skb_headroom(skb) < padsize)
+                       return -1;
+
+               skb_push(skb, padsize);
+               memmove(skb->data, skb->data+padsize, padpos);
+               return padsize;
+       }
+
+       return 0;
+}
+
+/*
+ * This function expects a 802.11 frame and returns the number of
+ * bytes removed
+ */
+
+static int ath5k_remove_padding(struct sk_buff *skb)
+{
+       int padpos = ath5k_common_padpos(skb);
+       int padsize = padpos & 3;
+
+       if (padsize && skb->len>=padpos+padsize) {
+               memmove(skb->data + padsize, skb->data, padpos);
+               skb_pull(skb, padsize);
+               return padsize;
+       }
+
+       return 0;
+}
+
 static void
 ath5k_tasklet_rx(unsigned long data)
 {
@@ -1819,8 +1901,6 @@ ath5k_tasklet_rx(unsigned long data)
        struct ath5k_buf *bf;
        struct ath5k_desc *ds;
        int ret;
-       int hdrlen;
-       int padsize;
        int rx_flag;
 
        spin_lock(&sc->rxbuflock);
@@ -1845,18 +1925,24 @@ ath5k_tasklet_rx(unsigned long data)
                        break;
                else if (unlikely(ret)) {
                        ATH5K_ERR(sc, "error in processing rx descriptor\n");
+                       sc->stats.rxerr_proc++;
                        spin_unlock(&sc->rxbuflock);
                        return;
                }
 
-               if (unlikely(rs.rs_more)) {
-                       ATH5K_WARN(sc, "unsupported jumbo\n");
-                       goto next;
-               }
+               sc->stats.rx_all_count++;
 
                if (unlikely(rs.rs_status)) {
-                       if (rs.rs_status & AR5K_RXERR_PHY)
+                       if (rs.rs_status & AR5K_RXERR_CRC)
+                               sc->stats.rxerr_crc++;
+                       if (rs.rs_status & AR5K_RXERR_FIFO)
+                               sc->stats.rxerr_fifo++;
+                       if (rs.rs_status & AR5K_RXERR_PHY) {
+                               sc->stats.rxerr_phy++;
+                               if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32)
+                                       sc->stats.rxerr_phy_code[rs.rs_phyerr]++;
                                goto next;
+                       }
                        if (rs.rs_status & AR5K_RXERR_DECRYPT) {
                                /*
                                 * Decrypt error.  If the error occurred
@@ -1868,12 +1954,14 @@ ath5k_tasklet_rx(unsigned long data)
                                 *
                                 * XXX do key cache faulting
                                 */
+                               sc->stats.rxerr_decrypt++;
                                if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&
                                    !(rs.rs_status & AR5K_RXERR_CRC))
                                        goto accept;
                        }
                        if (rs.rs_status & AR5K_RXERR_MIC) {
                                rx_flag |= RX_FLAG_MMIC_ERROR;
+                               sc->stats.rxerr_mic++;
                                goto accept;
                        }
 
@@ -1883,6 +1971,12 @@ ath5k_tasklet_rx(unsigned long data)
                                        sc->opmode != NL80211_IFTYPE_MONITOR)
                                goto next;
                }
+
+               if (unlikely(rs.rs_more)) {
+                       sc->stats.rxerr_jumbo++;
+                       goto next;
+
+               }
 accept:
                next_skb = ath5k_rx_skb_alloc(sc, &next_skb_addr);
 
@@ -1905,12 +1999,8 @@ accept:
                 * bytes and we can optimize this a bit. In addition, we must
                 * not try to remove padding from short control frames that do
                 * not have payload. */
-               hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-               padsize = ath5k_pad_size(hdrlen);
-               if (padsize) {
-                       memmove(skb->data + padsize, skb->data, hdrlen);
-                       skb_pull(skb, padsize);
-               }
+               ath5k_remove_padding(skb);
+
                rxs = IEEE80211_SKB_RXCB(skb);
 
                /*
@@ -1939,10 +2029,15 @@ accept:
                rxs->freq = sc->curchan->center_freq;
                rxs->band = sc->curband->band;
 
-               rxs->noise = sc->ah->ah_noise_floor;
-               rxs->signal = rxs->noise + rs.rs_rssi;
+               rxs->signal = sc->ah->ah_noise_floor + rs.rs_rssi;
 
                rxs->antenna = rs.rs_antenna;
+
+               if (rs.rs_antenna > 0 && rs.rs_antenna < 5)
+                       sc->stats.antenna_rx[rs.rs_antenna]++;
+               else
+                       sc->stats.antenna_rx[0]++; /* invalid */
+
                rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);
                rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs);
 
@@ -1952,6 +2047,8 @@ accept:
 
                ath5k_debug_dump_skb(sc, skb, "RX  ", 0);
 
+               ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi);
+
                /* check beacons in IBSS mode */
                if (sc->opmode == NL80211_IFTYPE_ADHOC)
                        ath5k_check_ibss_tsf(sc, skb, rxs);
@@ -1988,6 +2085,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
        list_for_each_entry_safe(bf, bf0, &txq->q, list) {
                ds = bf->desc;
 
+               /*
+                * It's possible that the hardware can say the buffer is
+                * completed when it hasn't yet loaded the ds_link from
+                * host memory and moved on.  If there are more TX
+                * descriptors in the queue, wait for TXDP to change
+                * before processing this one.
+                */
+               if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr &&
+                   !list_is_last(&bf->list, &txq->q))
+                       break;
+
                ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);
                if (unlikely(ret == -EINPROGRESS))
                        break;
@@ -1997,6 +2105,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                        break;
                }
 
+               sc->stats.tx_all_count++;
                skb = bf->skb;
                info = IEEE80211_SKB_CB(skb);
                bf->skb = NULL;
@@ -2022,14 +2131,31 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
                info->status.rates[ts.ts_final_idx].count++;
 
                if (unlikely(ts.ts_status)) {
-                       sc->ll_stats.dot11ACKFailureCount++;
-                       if (ts.ts_status & AR5K_TXERR_FILT)
+                       sc->stats.ack_fail++;
+                       if (ts.ts_status & AR5K_TXERR_FILT) {
                                info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+                               sc->stats.txerr_filt++;
+                       }
+                       if (ts.ts_status & AR5K_TXERR_XRETRY)
+                               sc->stats.txerr_retry++;
+                       if (ts.ts_status & AR5K_TXERR_FIFO)
+                               sc->stats.txerr_fifo++;
                } else {
                        info->flags |= IEEE80211_TX_STAT_ACK;
                        info->status.ack_signal = ts.ts_rssi;
                }
 
+               /*
+                * Remove MAC header padding before giving the frame
+                * back to mac80211.
+                */
+               ath5k_remove_padding(skb);
+
+               if (ts.ts_antenna > 0 && ts.ts_antenna < 5)
+                       sc->stats.antenna_tx[ts.ts_antenna]++;
+               else
+                       sc->stats.antenna_tx[0]++; /* invalid */
+
                ieee80211_tx_status(sc->hw, skb);
 
                spin_lock(&sc->txbuflock);
@@ -2073,6 +2199,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
        int ret = 0;
        u8 antenna;
        u32 flags;
+       const int padsize = 0;
 
        bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
                        PCI_DMA_TODEVICE);
@@ -2120,7 +2247,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
         * from tx power (value is in dB units already) */
        ds->ds_data = bf->skbaddr;
        ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
-                       ieee80211_get_hdrlen_from_skb(skb),
+                       ieee80211_get_hdrlen_from_skb(skb), padsize,
                        AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),
                        ieee80211_get_tx_rate(sc->hw, info)->hw_value,
                        1, AR5K_TXKEYIX_INVALID,
@@ -2407,9 +2534,6 @@ ath5k_init(struct ath5k_softc *sc)
         */
        ath5k_stop_locked(sc);
 
-       /* Set PHY calibration interval */
-       ah->ah_cal_intval = ath5k_calinterval;
-
        /*
         * The basic interface to setting the hardware in a good
         * state is ``reset''.  On return the hardware is known to
@@ -2421,7 +2545,8 @@ ath5k_init(struct ath5k_softc *sc)
        sc->curband = &sc->sbands[sc->curchan->band];
        sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
                AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
-               AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI;
+               AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
+
        ret = ath5k_reset(sc, NULL);
        if (ret)
                goto done;
@@ -2435,8 +2560,7 @@ ath5k_init(struct ath5k_softc *sc)
        for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)
                ath5k_hw_reset_key(ah, i);
 
-       /* Set ack to be sent at low bit-rates */
-       ath5k_hw_set_ack_bitrate_high(ah, false);
+       ath5k_hw_set_ack_bitrate_high(ah, true);
        ret = 0;
 done:
        mmiowb();
@@ -2533,12 +2657,33 @@ ath5k_stop_hw(struct ath5k_softc *sc)
        tasklet_kill(&sc->restq);
        tasklet_kill(&sc->calib);
        tasklet_kill(&sc->beacontq);
+       tasklet_kill(&sc->ani_tasklet);
 
        ath5k_rfkill_hw_stop(sc->ah);
 
        return ret;
 }
 
+static void
+ath5k_intr_calibration_poll(struct ath5k_hw *ah)
+{
+       if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) &&
+           !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) {
+               /* run ANI only when full calibration is not active */
+               ah->ah_cal_next_ani = jiffies +
+                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
+               tasklet_schedule(&ah->ah_sc->ani_tasklet);
+
+       } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) {
+               ah->ah_cal_next_full = jiffies +
+                       msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
+               tasklet_schedule(&ah->ah_sc->calib);
+       }
+       /* we could use SWI to generate enough interrupts to meet our
+        * calibration interval requirements, if necessary:
+        * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
+}
+
 static irqreturn_t
 ath5k_intr(int irq, void *dev_id)
 {
@@ -2562,7 +2707,20 @@ ath5k_intr(int irq, void *dev_id)
                         */
                        tasklet_schedule(&sc->restq);
                } else if (unlikely(status & AR5K_INT_RXORN)) {
-                       tasklet_schedule(&sc->restq);
+                       /*
+                        * Receive buffers are full. Either the bus is busy or
+                        * the CPU is not fast enough to process all received
+                        * frames.
+                        * Older chipsets need a reset to come out of this
+                        * condition, but we treat it as RX for newer chips.
+                        * We don't know exactly which versions need a reset -
+                        * this guess is copied from the HAL.
+                        */
+                       sc->stats.rxorn_intr++;
+                       if (ah->ah_mac_srev < AR5K_SREV_AR5212)
+                               tasklet_schedule(&sc->restq);
+                       else
+                               tasklet_schedule(&sc->rxtq);
                } else {
                        if (status & AR5K_INT_SWBA) {
                                tasklet_hi_schedule(&sc->beacontq);
@@ -2587,15 +2745,10 @@ ath5k_intr(int irq, void *dev_id)
                        if (status & AR5K_INT_BMISS) {
                                /* TODO */
                        }
-                       if (status & AR5K_INT_SWI) {
-                               tasklet_schedule(&sc->calib);
-                       }
                        if (status & AR5K_INT_MIB) {
-                               /*
-                                * These stats are also used for ANI i think
-                                * so how about updating them more often ?
-                                */
-                               ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
+                               sc->stats.mib_intr++;
+                               ath5k_hw_update_mib_counters(ah);
+                               ath5k_ani_mib_intr(ah);
                        }
                        if (status & AR5K_INT_GPIO)
                                tasklet_schedule(&sc->rf_kill.toggleq);
@@ -2606,7 +2759,7 @@ ath5k_intr(int irq, void *dev_id)
        if (unlikely(!counter))
                ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
 
-       ath5k_hw_calibration_poll(ah);
+       ath5k_intr_calibration_poll(ah);
 
        return IRQ_HANDLED;
 }
@@ -2630,8 +2783,7 @@ ath5k_tasklet_calibrate(unsigned long data)
        struct ath5k_hw *ah = sc->ah;
 
        /* Only full calibration for now */
-       if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION)
-               return;
+       ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
 
        /* Stop queues so that calibration
         * doesn't interfere with tx */
@@ -2647,18 +2799,29 @@ ath5k_tasklet_calibrate(unsigned long data)
                 * to load new gain values.
                 */
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n");
-               ath5k_reset_wake(sc);
+               ath5k_reset(sc, sc->curchan);
        }
        if (ath5k_hw_phy_calibrate(ah, sc->curchan))
                ATH5K_ERR(sc, "calibration of channel %u failed\n",
                        ieee80211_frequency_to_channel(
                                sc->curchan->center_freq));
 
-       ah->ah_swi_mask = 0;
-
        /* Wake queues */
        ieee80211_wake_queues(sc->hw);
 
+       ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
+}
+
+
+static void
+ath5k_tasklet_ani(unsigned long data)
+{
+       struct ath5k_softc *sc = (void *)data;
+       struct ath5k_hw *ah = sc->ah;
+
+       ah->ah_cal_mask |= AR5K_CALIBRATION_ANI;
+       ath5k_ani_calibration(ah);
+       ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI;
 }
 
 
@@ -2680,7 +2843,6 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_buf *bf;
        unsigned long flags;
-       int hdrlen;
        int padsize;
 
        ath5k_debug_dump_skb(sc, skb, "TX  ", 1);
@@ -2692,17 +2854,11 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
         * the hardware expects the header padded to 4 byte boundaries
         * if this is not the case we add the padding after the header
         */
-       hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-       padsize = ath5k_pad_size(hdrlen);
-       if (padsize) {
-
-               if (skb_headroom(skb) < padsize) {
-                       ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
-                                 " headroom to pad %d\n", hdrlen, padsize);
-                       goto drop_packet;
-               }
-               skb_push(skb, padsize);
-               memmove(skb->data, skb->data+padsize, hdrlen);
+       padsize = ath5k_add_padding(skb);
+       if (padsize < 0) {
+               ATH5K_ERR(sc, "tx hdrlen not %%4: not enough"
+                         " headroom to pad");
+               goto drop_packet;
        }
 
        spin_lock_irqsave(&sc->txbuflock, flags);
@@ -2721,7 +2877,7 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        bf->skb = skb;
 
-       if (ath5k_txbuf_setup(sc, bf, txq)) {
+       if (ath5k_txbuf_setup(sc, bf, txq, padsize)) {
                bf->skb = NULL;
                spin_lock_irqsave(&sc->txbuflock, flags);
                list_add_tail(&bf->list, &sc->txbuf);
@@ -2768,6 +2924,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
                goto err;
        }
 
+       ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
+
        /*
         * Change channels and update the h/w rate map if we're switching;
         * e.g. 11a to 11b/g.
@@ -2836,6 +2994,8 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,
                goto end;
        }
 
+       ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode);
+
        ath5k_hw_set_lladdr(sc->ah, vif->addr);
        ath5k_mode_setup(sc);
 
@@ -2906,7 +3066,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
         * then we must allow the user to set how many tx antennas we
         * have available
         */
-       ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
+       ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
 
 unlock:
        mutex_unlock(&sc->lock);
@@ -2914,22 +3074,20 @@ unlock:
 }
 
 static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
-                                  int mc_count, struct dev_addr_list *mclist)
+                                  struct netdev_hw_addr_list *mc_list)
 {
        u32 mfilt[2], val;
-       int i;
        u8 pos;
+       struct netdev_hw_addr *ha;
 
        mfilt[0] = 0;
        mfilt[1] = 1;
 
-       for (i = 0; i < mc_count; i++) {
-               if (!mclist)
-                       break;
+       netdev_hw_addr_list_for_each(ha, mc_list) {
                /* calculate XOR of eight 6-bit values */
-               val = get_unaligned_le32(mclist->dmi_addr + 0);
+               val = get_unaligned_le32(ha->addr + 0);
                pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
-               val = get_unaligned_le32(mclist->dmi_addr + 3);
+               val = get_unaligned_le32(ha->addr + 3);
                pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
                pos &= 0x3f;
                mfilt[pos / 32] |= (1 << (pos % 32));
@@ -2937,8 +3095,7 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,
                * but not sure, needs testing, if we do use this we'd
                * neet to inform below to not reset the mcast */
                /* ath5k_hw_set_mcast_filterindex(ah,
-                *      mclist->dmi_addr[5]); */
-               mclist = mclist->next;
+                *      ha->addr[5]); */
        }
 
        return ((u64)(mfilt[1]) << 32) | mfilt[0];
@@ -3124,12 +3281,30 @@ ath5k_get_stats(struct ieee80211_hw *hw,
                struct ieee80211_low_level_stats *stats)
 {
        struct ath5k_softc *sc = hw->priv;
-       struct ath5k_hw *ah = sc->ah;
 
        /* Force update */
-       ath5k_hw_update_mib_counters(ah, &sc->ll_stats);
+       ath5k_hw_update_mib_counters(sc->ah);
+
+       stats->dot11ACKFailureCount = sc->stats.ack_fail;
+       stats->dot11RTSFailureCount = sc->stats.rts_fail;
+       stats->dot11RTSSuccessCount = sc->stats.rts_ok;
+       stats->dot11FCSErrorCount = sc->stats.fcs_error;
+
+       return 0;
+}
+
+static int ath5k_get_survey(struct ieee80211_hw *hw, int idx,
+               struct survey_info *survey)
+{
+       struct ath5k_softc *sc = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
+
+        if (idx != 0)
+               return -ENOENT;
 
-       memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats));
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = sc->ah->ah_noise_floor;
 
        return 0;
 }
index 7e1a88a5abdb3e930259a7451078b26a5c6a7ee9..56221bc7c8cd095208af6f8a591678df5f327e84 100644 (file)
@@ -50,6 +50,7 @@
 
 #include "ath5k.h"
 #include "debug.h"
+#include "ani.h"
 
 #include "../regd.h"
 #include "../ath.h"
@@ -105,6 +106,38 @@ struct ath5k_rfkill {
        struct tasklet_struct toggleq;
 };
 
+/* statistics */
+struct ath5k_statistics {
+       /* antenna use */
+       unsigned int antenna_rx[5];     /* frames count per antenna RX */
+       unsigned int antenna_tx[5];     /* frames count per antenna TX */
+
+       /* frame errors */
+       unsigned int rx_all_count;      /* all RX frames, including errors */
+       unsigned int tx_all_count;      /* all TX frames, including errors */
+       unsigned int rxerr_crc;
+       unsigned int rxerr_phy;
+       unsigned int rxerr_phy_code[32];
+       unsigned int rxerr_fifo;
+       unsigned int rxerr_decrypt;
+       unsigned int rxerr_mic;
+       unsigned int rxerr_proc;
+       unsigned int rxerr_jumbo;
+       unsigned int txerr_retry;
+       unsigned int txerr_fifo;
+       unsigned int txerr_filt;
+
+       /* MIB counters */
+       unsigned int ack_fail;
+       unsigned int rts_fail;
+       unsigned int rts_ok;
+       unsigned int fcs_error;
+       unsigned int beacons;
+
+       unsigned int mib_intr;
+       unsigned int rxorn_intr;
+};
+
 #if CHAN_DEBUG
 #define ATH_CHAN_MAX   (26+26+26+200+200)
 #else
@@ -117,7 +150,6 @@ struct ath5k_softc {
        struct pci_dev          *pdev;          /* for dma mapping */
        void __iomem            *iobase;        /* address of the device */
        struct mutex            lock;           /* dev-level lock */
-       struct ieee80211_low_level_stats ll_stats;
        struct ieee80211_hw     *hw;            /* IEEE 802.11 common */
        struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
        struct ieee80211_channel channels[ATH_CHAN_MAX];
@@ -191,6 +223,11 @@ struct ath5k_softc {
        int                     power_level;    /* Requested tx power in dbm */
        bool                    assoc;          /* associate state */
        bool                    enable_beacon;  /* true if beacons are on */
+
+       struct ath5k_statistics stats;
+
+       struct ath5k_ani_state  ani_state;
+       struct tasklet_struct   ani_tasklet;    /* ANI calibration */
 };
 
 #define ath5k_hw_hasbssidmask(_ah) \
index 367a6c7d3cc7dd493f93103ed980749011a158ad..74f007126f4100ce549e28b1569a43b5463eb42a 100644 (file)
@@ -102,9 +102,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
                }
        }
 
-       /* GPIO */
-       ah->ah_gpio_npins = AR5K_NUM_GPIO;
-
        /* Set number of supported TX queues */
        if (ah->ah_version == AR5K_AR5210)
                ah->ah_capabilities.cap_queues.q_tx_num =
@@ -112,6 +109,12 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
        else
                ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES;
 
+       /* newer hardware has PHY error counters */
+       if (ah->ah_mac_srev >= AR5K_SREV_AR5213A)
+               ah->ah_capabilities.cap_has_phyerr_counters = true;
+       else
+               ah->ah_capabilities.cap_has_phyerr_counters = false;
+
        return 0;
 }
 
index 747508c15d34c33140d017f90796d0d0236b0967..6fb5c5ffa5b1c08060de32dfb51f05c251e1a87a 100644 (file)
@@ -69,6 +69,7 @@ module_param_named(debug, ath5k_debug, uint, 0);
 
 #include <linux/seq_file.h>
 #include "reg.h"
+#include "ani.h"
 
 static struct dentry *ath5k_global_debugfs;
 
@@ -307,6 +308,7 @@ static const struct {
        { ATH5K_DEBUG_DUMP_TX,  "dumptx",       "print transmit skb content" },
        { ATH5K_DEBUG_DUMPBANDS, "dumpbands",   "dump bands" },
        { ATH5K_DEBUG_TRACE,    "trace",        "trace function calls" },
+       { ATH5K_DEBUG_ANI,      "ani",          "adaptive noise immunity" },
        { ATH5K_DEBUG_ANY,      "all",          "show all debug levels" },
 };
 
@@ -364,6 +366,369 @@ static const struct file_operations fops_debug = {
 };
 
 
+/* debugfs: antenna */
+
+static ssize_t read_file_antenna(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       char buf[700];
+       unsigned int len = 0;
+       unsigned int i;
+       unsigned int v;
+
+       len += snprintf(buf+len, sizeof(buf)-len, "antenna mode\t%d\n",
+               sc->ah->ah_ant_mode);
+       len += snprintf(buf+len, sizeof(buf)-len, "default antenna\t%d\n",
+               sc->ah->ah_def_ant);
+       len += snprintf(buf+len, sizeof(buf)-len, "tx antenna\t%d\n",
+               sc->ah->ah_tx_ant);
+
+       len += snprintf(buf+len, sizeof(buf)-len, "\nANTENNA\t\tRX\tTX\n");
+       for (i = 1; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) {
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "[antenna %d]\t%d\t%d\n",
+                       i, sc->stats.antenna_rx[i], sc->stats.antenna_tx[i]);
+       }
+       len += snprintf(buf+len, sizeof(buf)-len, "[invalid]\t%d\t%d\n",
+                       sc->stats.antenna_rx[0], sc->stats.antenna_tx[0]);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_DEFAULT_ANTENNA);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "\nAR5K_DEFAULT_ANTENNA\t0x%08x\n", v);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_STA_ID1);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "AR5K_STA_ID1_DEFAULT_ANTENNA\t%d\n",
+               (v & AR5K_STA_ID1_DEFAULT_ANTENNA) != 0);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "AR5K_STA_ID1_DESC_ANTENNA\t%d\n",
+               (v & AR5K_STA_ID1_DESC_ANTENNA) != 0);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "AR5K_STA_ID1_RTS_DEF_ANTENNA\t%d\n",
+               (v & AR5K_STA_ID1_RTS_DEF_ANTENNA) != 0);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "AR5K_STA_ID1_SELFGEN_DEF_ANT\t%d\n",
+               (v & AR5K_STA_ID1_SELFGEN_DEF_ANT) != 0);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_AGCCTL);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "\nAR5K_PHY_AGCCTL_OFDM_DIV_DIS\t%d\n",
+               (v & AR5K_PHY_AGCCTL_OFDM_DIV_DIS) != 0);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_RESTART);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "AR5K_PHY_RESTART_DIV_GC\t\t%x\n",
+               (v & AR5K_PHY_RESTART_DIV_GC) >> AR5K_PHY_RESTART_DIV_GC_S);
+
+       v = ath5k_hw_reg_read(sc->ah, AR5K_PHY_FAST_ANT_DIV);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "AR5K_PHY_FAST_ANT_DIV_EN\t%d\n",
+               (v & AR5K_PHY_FAST_ANT_DIV_EN) != 0);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_antenna(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       unsigned int i;
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       if (strncmp(buf, "diversity", 9) == 0) {
+               ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_DEFAULT);
+               printk(KERN_INFO "ath5k debug: enable diversity\n");
+       } else if (strncmp(buf, "fixed-a", 7) == 0) {
+               ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_A);
+               printk(KERN_INFO "ath5k debugfs: fixed antenna A\n");
+       } else if (strncmp(buf, "fixed-b", 7) == 0) {
+               ath5k_hw_set_antenna_mode(sc->ah, AR5K_ANTMODE_FIXED_B);
+               printk(KERN_INFO "ath5k debug: fixed antenna B\n");
+       } else if (strncmp(buf, "clear", 5) == 0) {
+               for (i = 0; i < ARRAY_SIZE(sc->stats.antenna_rx); i++) {
+                       sc->stats.antenna_rx[i] = 0;
+                       sc->stats.antenna_tx[i] = 0;
+               }
+               printk(KERN_INFO "ath5k debug: cleared antenna stats\n");
+       }
+       return count;
+}
+
+static const struct file_operations fops_antenna = {
+       .read = read_file_antenna,
+       .write = write_file_antenna,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
+/* debugfs: frameerrors */
+
+static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       struct ath5k_statistics *st = &sc->stats;
+       char buf[700];
+       unsigned int len = 0;
+       int i;
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "RX\n---------------------\n");
+       len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%d\t(%d%%)\n",
+                       st->rxerr_crc,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_crc*100/st->rx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%d\t(%d%%)\n",
+                       st->rxerr_phy,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_phy*100/st->rx_all_count : 0);
+       for (i = 0; i < 32; i++) {
+               if (st->rxerr_phy_code[i])
+                       len += snprintf(buf+len, sizeof(buf)-len,
+                               " phy_err[%d]\t%d\n",
+                               i, st->rxerr_phy_code[i]);
+       }
+
+       len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
+                       st->rxerr_fifo,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_fifo*100/st->rx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%d\t(%d%%)\n",
+                       st->rxerr_decrypt,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_decrypt*100/st->rx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%d\t(%d%%)\n",
+                       st->rxerr_mic,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_mic*100/st->rx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "process\t%d\t(%d%%)\n",
+                       st->rxerr_proc,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_proc*100/st->rx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%d\t(%d%%)\n",
+                       st->rxerr_jumbo,
+                       st->rx_all_count > 0 ?
+                               st->rxerr_jumbo*100/st->rx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n",
+                       st->rx_all_count);
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "\nTX\n---------------------\n");
+       len += snprintf(buf+len, sizeof(buf)-len, "retry\t%d\t(%d%%)\n",
+                       st->txerr_retry,
+                       st->tx_all_count > 0 ?
+                               st->txerr_retry*100/st->tx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n",
+                       st->txerr_fifo,
+                       st->tx_all_count > 0 ?
+                               st->txerr_fifo*100/st->tx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "filter\t%d\t(%d%%)\n",
+                       st->txerr_filt,
+                       st->tx_all_count > 0 ?
+                               st->txerr_filt*100/st->tx_all_count : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n",
+                       st->tx_all_count);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_frameerrors(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       struct ath5k_statistics *st = &sc->stats;
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       if (strncmp(buf, "clear", 5) == 0) {
+               st->rxerr_crc = 0;
+               st->rxerr_phy = 0;
+               st->rxerr_fifo = 0;
+               st->rxerr_decrypt = 0;
+               st->rxerr_mic = 0;
+               st->rxerr_proc = 0;
+               st->rxerr_jumbo = 0;
+               st->rx_all_count = 0;
+               st->txerr_retry = 0;
+               st->txerr_fifo = 0;
+               st->txerr_filt = 0;
+               st->tx_all_count = 0;
+               printk(KERN_INFO "ath5k debug: cleared frameerrors stats\n");
+       }
+       return count;
+}
+
+static const struct file_operations fops_frameerrors = {
+       .read = read_file_frameerrors,
+       .write = write_file_frameerrors,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
+/* debugfs: ani */
+
+static ssize_t read_file_ani(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       struct ath5k_statistics *st = &sc->stats;
+       struct ath5k_ani_state *as = &sc->ani_state;
+
+       char buf[700];
+       unsigned int len = 0;
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "HW has PHY error counters:\t%s\n",
+                       sc->ah->ah_capabilities.cap_has_phyerr_counters ?
+                       "yes" : "no");
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "HW max spur immunity level:\t%d\n",
+                       as->max_spur_level);
+       len += snprintf(buf+len, sizeof(buf)-len,
+               "\nANI state\n--------------------------------------------\n");
+       len += snprintf(buf+len, sizeof(buf)-len, "operating mode:\t\t\t");
+       switch (as->ani_mode) {
+       case ATH5K_ANI_MODE_OFF:
+               len += snprintf(buf+len, sizeof(buf)-len, "OFF\n");
+               break;
+       case ATH5K_ANI_MODE_MANUAL_LOW:
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "MANUAL LOW\n");
+               break;
+       case ATH5K_ANI_MODE_MANUAL_HIGH:
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "MANUAL HIGH\n");
+               break;
+       case ATH5K_ANI_MODE_AUTO:
+               len += snprintf(buf+len, sizeof(buf)-len, "AUTO\n");
+               break;
+       default:
+               len += snprintf(buf+len, sizeof(buf)-len,
+                       "??? (not good)\n");
+               break;
+       }
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "noise immunity level:\t\t%d\n",
+                       as->noise_imm_level);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "spur immunity level:\t\t%d\n",
+                       as->spur_level);
+       len += snprintf(buf+len, sizeof(buf)-len, "firstep level:\t\t\t%d\n",
+                       as->firstep_level);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "OFDM weak signal detection:\t%s\n",
+                       as->ofdm_weak_sig ? "on" : "off");
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "CCK weak signal detection:\t%s\n",
+                       as->cck_weak_sig ? "on" : "off");
+
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "\nMIB INTERRUPTS:\t\t%u\n",
+                       st->mib_intr);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "beacon RSSI average:\t%d\n",
+                       sc->ah->ah_beacon_rssi_avg.avg);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt tx\t\t%u\t(%d%%)\n",
+                       as->pfc_tx,
+                       as->pfc_cycles > 0 ?
+                       as->pfc_tx*100/as->pfc_cycles : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt rx\t\t%u\t(%d%%)\n",
+                       as->pfc_rx,
+                       as->pfc_cycles > 0 ?
+                       as->pfc_rx*100/as->pfc_cycles : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt busy\t\t%u\t(%d%%)\n",
+                       as->pfc_busy,
+                       as->pfc_cycles > 0 ?
+                       as->pfc_busy*100/as->pfc_cycles : 0);
+       len += snprintf(buf+len, sizeof(buf)-len, "profcnt cycles\t\t%u\n",
+                       as->pfc_cycles);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "listen time\t\t%d\tlast: %d\n",
+                       as->listen_time, as->last_listen);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "OFDM errors\t\t%u\tlast: %u\tsum: %u\n",
+                       as->ofdm_errors, as->last_ofdm_errors,
+                       as->sum_ofdm_errors);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "CCK errors\t\t%u\tlast: %u\tsum: %u\n",
+                       as->cck_errors, as->last_cck_errors,
+                       as->sum_cck_errors);
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "AR5K_PHYERR_CNT1\t%x\t(=%d)\n",
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1),
+                       ATH5K_ANI_OFDM_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT1)));
+       len += snprintf(buf+len, sizeof(buf)-len,
+                       "AR5K_PHYERR_CNT2\t%x\t(=%d)\n",
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2),
+                       ATH5K_ANI_CCK_TRIG_HIGH - (ATH5K_PHYERR_CNT_MAX -
+                       ath5k_hw_reg_read(sc->ah, AR5K_PHYERR_CNT2)));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_ani(struct file *file,
+                                const char __user *userbuf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath5k_softc *sc = file->private_data;
+       char buf[20];
+
+       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
+               return -EFAULT;
+
+       if (strncmp(buf, "sens-low", 8) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_HIGH);
+       } else if (strncmp(buf, "sens-high", 9) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_MANUAL_LOW);
+       } else if (strncmp(buf, "ani-off", 7) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_OFF);
+       } else if (strncmp(buf, "ani-on", 6) == 0) {
+               ath5k_ani_init(sc->ah, ATH5K_ANI_MODE_AUTO);
+       } else if (strncmp(buf, "noise-low", 9) == 0) {
+               ath5k_ani_set_noise_immunity_level(sc->ah, 0);
+       } else if (strncmp(buf, "noise-high", 10) == 0) {
+               ath5k_ani_set_noise_immunity_level(sc->ah,
+                                                  ATH5K_ANI_MAX_NOISE_IMM_LVL);
+       } else if (strncmp(buf, "spur-low", 8) == 0) {
+               ath5k_ani_set_spur_immunity_level(sc->ah, 0);
+       } else if (strncmp(buf, "spur-high", 9) == 0) {
+               ath5k_ani_set_spur_immunity_level(sc->ah,
+                                                 sc->ani_state.max_spur_level);
+       } else if (strncmp(buf, "fir-low", 7) == 0) {
+               ath5k_ani_set_firstep_level(sc->ah, 0);
+       } else if (strncmp(buf, "fir-high", 8) == 0) {
+               ath5k_ani_set_firstep_level(sc->ah, ATH5K_ANI_MAX_FIRSTEP_LVL);
+       } else if (strncmp(buf, "ofdm-off", 8) == 0) {
+               ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, false);
+       } else if (strncmp(buf, "ofdm-on", 7) == 0) {
+               ath5k_ani_set_ofdm_weak_signal_detection(sc->ah, true);
+       } else if (strncmp(buf, "cck-off", 7) == 0) {
+               ath5k_ani_set_cck_weak_signal_detection(sc->ah, false);
+       } else if (strncmp(buf, "cck-on", 6) == 0) {
+               ath5k_ani_set_cck_weak_signal_detection(sc->ah, true);
+       }
+       return count;
+}
+
+static const struct file_operations fops_ani = {
+       .read = read_file_ani,
+       .write = write_file_ani,
+       .open = ath5k_debugfs_open,
+       .owner = THIS_MODULE,
+};
+
+
 /* init */
 
 void
@@ -393,6 +758,20 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
 
        sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
                                sc->debug.debugfs_phydir, sc, &fops_reset);
+
+       sc->debug.debugfs_antenna = debugfs_create_file("antenna",
+                               S_IWUSR | S_IRUSR,
+                               sc->debug.debugfs_phydir, sc, &fops_antenna);
+
+       sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
+                               S_IWUSR | S_IRUSR,
+                               sc->debug.debugfs_phydir, sc,
+                               &fops_frameerrors);
+
+       sc->debug.debugfs_ani = debugfs_create_file("ani",
+                               S_IWUSR | S_IRUSR,
+                               sc->debug.debugfs_phydir, sc,
+                               &fops_ani);
 }
 
 void
@@ -408,6 +787,9 @@ ath5k_debug_finish_device(struct ath5k_softc *sc)
        debugfs_remove(sc->debug.debugfs_registers);
        debugfs_remove(sc->debug.debugfs_beacon);
        debugfs_remove(sc->debug.debugfs_reset);
+       debugfs_remove(sc->debug.debugfs_antenna);
+       debugfs_remove(sc->debug.debugfs_frameerrors);
+       debugfs_remove(sc->debug.debugfs_ani);
        debugfs_remove(sc->debug.debugfs_phydir);
 }
 
index 66f69f04e55efbed331099d7b7fd5e26f0b61db1..ddd5b3a99e8d8fb33d665d086d0c06b1199454dd 100644 (file)
@@ -74,6 +74,9 @@ struct ath5k_dbg_info {
        struct dentry           *debugfs_registers;
        struct dentry           *debugfs_beacon;
        struct dentry           *debugfs_reset;
+       struct dentry           *debugfs_antenna;
+       struct dentry           *debugfs_frameerrors;
+       struct dentry           *debugfs_ani;
 };
 
 /**
@@ -113,6 +116,7 @@ enum ath5k_debug_level {
        ATH5K_DEBUG_DUMP_TX     = 0x00000200,
        ATH5K_DEBUG_DUMPBANDS   = 0x00000400,
        ATH5K_DEBUG_TRACE       = 0x00001000,
+       ATH5K_DEBUG_ANI         = 0x00002000,
        ATH5K_DEBUG_ANY         = 0xffffffff
 };
 
index dc30a2b70a6b41861e9471df551dd1ba4fb62b4e..7d7b646ab65a1a3f4d1f4b632500a3a3484502da 100644 (file)
@@ -35,7 +35,8 @@
  */
 static int
 ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
-       unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type,
+       unsigned int pkt_len, unsigned int hdr_len, int padsize,
+       enum ath5k_pkt_type type,
        unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0,
        unsigned int key_index, unsigned int antenna_mode, unsigned int flags,
        unsigned int rtscts_rate, unsigned int rtscts_duration)
@@ -71,7 +72,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
        /* Verify and set frame length */
 
        /* remove padding we might have added before */
-       frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
+       frame_len = pkt_len - padsize + FCS_LEN;
 
        if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN)
                return -EINVAL;
@@ -100,7 +101,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
                        AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN);
        }
 
-       /*Diferences between 5210-5211*/
+       /*Differences between 5210-5211*/
        if (ah->ah_version == AR5K_AR5210) {
                switch (type) {
                case AR5K_PKT_TYPE_BEACON:
@@ -165,6 +166,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
  */
 static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
        struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len,
+       int padsize,
        enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0,
        unsigned int tx_tries0, unsigned int key_index,
        unsigned int antenna_mode, unsigned int flags,
@@ -206,7 +208,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
        /* Verify and set frame length */
 
        /* remove padding we might have added before */
-       frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN;
+       frame_len = pkt_len - padsize + FCS_LEN;
 
        if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
                return -EINVAL;
@@ -229,7 +231,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
                AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
        tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
                                        AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
-       tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES,
+       tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0,
                                        AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
        tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
 
@@ -643,6 +645,7 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
                        rs->rs_status |= AR5K_RXERR_PHY;
                        rs->rs_phyerr |= AR5K_REG_MS(rx_err->rx_error_1,
                                           AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE);
+                       ath5k_ani_phy_error_report(ah, rs->rs_phyerr);
                }
 
                if (rx_status->rx_status_1 &
@@ -668,12 +671,6 @@ int ath5k_hw_init_desc_functions(struct ath5k_hw *ah)
                ah->ah_version != AR5K_AR5212)
                        return -ENOTSUPP;
 
-       /* XXX: What is this magic value and where is it used ? */
-       if (ah->ah_version == AR5K_AR5212)
-               ah->ah_magic = AR5K_EEPROM_MAGIC_5212;
-       else if (ah->ah_version == AR5K_AR5211)
-               ah->ah_magic = AR5K_EEPROM_MAGIC_5211;
-
        if (ah->ah_version == AR5K_AR5212) {
                ah->ah_setup_rx_desc = ath5k_hw_setup_rx_desc;
                ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc;
index 56158c804e3eeeadc6c3d616695742520b04d548..64538fbe416732f5353433d32baad77e13039c48 100644 (file)
@@ -112,15 +112,32 @@ struct ath5k_hw_rx_error {
 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE     0x0000ff00
 #define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S   8
 
-/* PHY Error codes */
-#define AR5K_DESC_RX_PHY_ERROR_NONE            0x00
-#define AR5K_DESC_RX_PHY_ERROR_TIMING          0x20
-#define AR5K_DESC_RX_PHY_ERROR_PARITY          0x40
-#define AR5K_DESC_RX_PHY_ERROR_RATE            0x60
-#define AR5K_DESC_RX_PHY_ERROR_LENGTH          0x80
-#define AR5K_DESC_RX_PHY_ERROR_64QAM           0xa0
-#define AR5K_DESC_RX_PHY_ERROR_SERVICE         0xc0
-#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR     0xe0
+/**
+ * enum ath5k_phy_error_code - PHY Error codes
+ */
+enum ath5k_phy_error_code {
+       AR5K_RX_PHY_ERROR_UNDERRUN              = 0,    /* Transmit underrun */
+       AR5K_RX_PHY_ERROR_TIMING                = 1,    /* Timing error */
+       AR5K_RX_PHY_ERROR_PARITY                = 2,    /* Illegal parity */
+       AR5K_RX_PHY_ERROR_RATE                  = 3,    /* Illegal rate */
+       AR5K_RX_PHY_ERROR_LENGTH                = 4,    /* Illegal length */
+       AR5K_RX_PHY_ERROR_RADAR                 = 5,    /* Radar detect */
+       AR5K_RX_PHY_ERROR_SERVICE               = 6,    /* Illegal service */
+       AR5K_RX_PHY_ERROR_TOR                   = 7,    /* Transmit override receive */
+       /* these are specific to the 5212 */
+       AR5K_RX_PHY_ERROR_OFDM_TIMING           = 17,
+       AR5K_RX_PHY_ERROR_OFDM_SIGNAL_PARITY    = 18,
+       AR5K_RX_PHY_ERROR_OFDM_RATE_ILLEGAL     = 19,
+       AR5K_RX_PHY_ERROR_OFDM_LENGTH_ILLEGAL   = 20,
+       AR5K_RX_PHY_ERROR_OFDM_POWER_DROP       = 21,
+       AR5K_RX_PHY_ERROR_OFDM_SERVICE          = 22,
+       AR5K_RX_PHY_ERROR_OFDM_RESTART          = 23,
+       AR5K_RX_PHY_ERROR_CCK_TIMING            = 25,
+       AR5K_RX_PHY_ERROR_CCK_HEADER_CRC        = 26,
+       AR5K_RX_PHY_ERROR_CCK_RATE_ILLEGAL      = 27,
+       AR5K_RX_PHY_ERROR_CCK_SERVICE           = 30,
+       AR5K_RX_PHY_ERROR_CCK_RESTART           = 31,
+};
 
 /*
  * 5210/5211 hardware 2-word TX control descriptor
index 67665cdc7afe256822f610968c292dc8031d1549..ed0263672d6d0cd9bf17d36d7d3c5126d8da248a 100644 (file)
@@ -331,7 +331,8 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
        ee->ee_x_gain[mode]             = (val >> 1) & 0xf;
        ee->ee_xpd[mode]                = val & 0x1;
 
-       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
+       if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
+           mode != AR5K_EEPROM_MODE_11B)
                ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
 
        if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
@@ -341,6 +342,7 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
                if (mode == AR5K_EEPROM_MODE_11A)
                        ee->ee_xr_power[mode] = val & 0x3f;
                else {
+                       /* b_DB_11[bg] and b_OB_11[bg] */
                        ee->ee_ob[mode][0] = val & 0x7;
                        ee->ee_db[mode][0] = (val >> 3) & 0x7;
                }
index 473a483bb9c3d6daa08052b1972d1d2aa1867f2b..c4a6d5f26af4f08ac9b379a22045aaed1a6c5c84 100644 (file)
@@ -24,9 +24,6 @@
                                                 * SERDES infos are present */
 #define AR5K_EEPROM_MAGIC              0x003d  /* EEPROM Magic number */
 #define AR5K_EEPROM_MAGIC_VALUE                0x5aa5  /* Default - found on EEPROM */
-#define AR5K_EEPROM_MAGIC_5212         0x0000145c /* 5212 */
-#define AR5K_EEPROM_MAGIC_5211         0x0000145b /* 5211 */
-#define AR5K_EEPROM_MAGIC_5210         0x0000145a /* 5210 */
 
 #define        AR5K_EEPROM_IS_HB63             0x000b  /* Talon detect */
 
@@ -78,9 +75,9 @@
 #define AR5K_EEPROM_HDR_11A(_v)                (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1)
 #define AR5K_EEPROM_HDR_11B(_v)                (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1)
 #define AR5K_EEPROM_HDR_11G(_v)                (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1)
-#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1)     /* Disable turbo for 2Ghz (?) */
-#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f)    /* Max turbo power for a/XR mode (eeprom_init) */
-#define AR5K_EEPROM_HDR_DEVICE(_v)     (((_v) >> 11) & 0x7)
+#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1)     /* Disable turbo for 2Ghz */
+#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f)    /* Max turbo power for < 2W power consumption */
+#define AR5K_EEPROM_HDR_DEVICE(_v)     (((_v) >> 11) & 0x7)    /* Device type (1 Cardbus, 2 PCI, 3 MiniPCI, 4 AP) */
 #define AR5K_EEPROM_HDR_RFKILL(_v)     (((_v) >> 14) & 0x1)    /* Device has RFKill support */
 #define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1)    /* Disable turbo for 5Ghz */
 
 
 #define AR5K_EEPROM_MISC1                      AR5K_EEPROM_INFO(5)
 #define AR5K_EEPROM_TARGET_PWRSTART(_v)                ((_v) & 0xfff)
-#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)                (((_v) >> 14) & 0x1)
+#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v)                (((_v) >> 14) & 0x1)    /* has 32KHz crystal for sleep mode */
 #define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v)    (((_v) >> 15) & 0x1)
 
 #define AR5K_EEPROM_MISC2                      AR5K_EEPROM_INFO(6)
 
 #define AR5K_EEPROM_MISC4              AR5K_EEPROM_INFO(8)
 #define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff)
-#define AR5K_EEPROM_MASK_R0(_v)                (((_v) >> 2) & 0x3)
-#define AR5K_EEPROM_MASK_R1(_v)                ((_v) & 0x3)
+#define AR5K_EEPROM_MASK_R0(_v)                (((_v) >> 2) & 0x3)     /* modes supported by radio 0 (bit 1: G, bit 2: A) */
+#define AR5K_EEPROM_MASK_R1(_v)                ((_v) & 0x3)            /* modes supported by radio 1 (bit 1: G, bit 2: A) */
 
 #define AR5K_EEPROM_MISC5              AR5K_EEPROM_INFO(9)
-#define AR5K_EEPROM_COMP_DIS(_v)       ((_v) & 0x1)
-#define AR5K_EEPROM_AES_DIS(_v)                (((_v) >> 1) & 0x1)
-#define AR5K_EEPROM_FF_DIS(_v)         (((_v) >> 2) & 0x1)
-#define AR5K_EEPROM_BURST_DIS(_v)      (((_v) >> 3) & 0x1)
-#define AR5K_EEPROM_MAX_QCU(_v)                (((_v) >> 4) & 0xf)
-#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)  (((_v) >> 8) & 0x1)
-#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf)
+#define AR5K_EEPROM_COMP_DIS(_v)       ((_v) & 0x1)            /* disable compression */
+#define AR5K_EEPROM_AES_DIS(_v)                (((_v) >> 1) & 0x1)     /* disable AES */
+#define AR5K_EEPROM_FF_DIS(_v)         (((_v) >> 2) & 0x1)     /* disable fast frames */
+#define AR5K_EEPROM_BURST_DIS(_v)      (((_v) >> 3) & 0x1)     /* disable bursting */
+#define AR5K_EEPROM_MAX_QCU(_v)                (((_v) >> 4) & 0xf)     /* max number of QCUs. defaults to 10 */
+#define AR5K_EEPROM_HEAVY_CLIP_EN(_v)  (((_v) >> 8) & 0x1)     /* enable heayy clipping */
+#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf)    /* key cache size. defaults to 128 */
 
 #define AR5K_EEPROM_MISC6              AR5K_EEPROM_INFO(10)
-#define AR5K_EEPROM_TX_CHAIN_DIS       ((_v) & 0x8)
-#define AR5K_EEPROM_RX_CHAIN_DIS       (((_v) >> 3) & 0x8)
-#define AR5K_EEPROM_FCC_MID_EN         (((_v) >> 6) & 0x1)
-#define AR5K_EEPROM_JAP_U1EVEN_EN      (((_v) >> 7) & 0x1)
-#define AR5K_EEPROM_JAP_U2_EN          (((_v) >> 8) & 0x1)
-#define AR5K_EEPROM_JAP_U1ODD_EN       (((_v) >> 9) & 0x1)
-#define AR5K_EEPROM_JAP_11A_NEW_EN     (((_v) >> 10) & 0x1)
+#define AR5K_EEPROM_TX_CHAIN_DIS       ((_v) & 0x7)            /* MIMO chains disabled for TX bitmask */
+#define AR5K_EEPROM_RX_CHAIN_DIS       (((_v) >> 3) & 0x7)     /* MIMO chains disabled for RX bitmask */
+#define AR5K_EEPROM_FCC_MID_EN         (((_v) >> 6) & 0x1)     /* 5.47-5.7GHz supported */
+#define AR5K_EEPROM_JAP_U1EVEN_EN      (((_v) >> 7) & 0x1)     /* Japan UNII1 band (5.15-5.25GHz) on even channels (5180, 5200, 5220, 5240) supported */
+#define AR5K_EEPROM_JAP_U2_EN          (((_v) >> 8) & 0x1)     /* Japan UNII2 band (5.25-5.35GHz) supported */
+#define AR5K_EEPROM_JAP_MID_EN         (((_v) >> 9) & 0x1)     /* Japan band from 5.47-5.7GHz supported */
+#define AR5K_EEPROM_JAP_U1ODD_EN       (((_v) >> 10) & 0x1)    /* Japan UNII2 band (5.15-5.25GHz) on odd channels (5170, 5190, 5210, 5230) supported */
+#define AR5K_EEPROM_JAP_11A_NEW_EN     (((_v) >> 11) & 0x1)    /* Japan A mode enabled (using even channels) */
 
 /* calibration settings */
 #define AR5K_EEPROM_MODES_11A(_v)      AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4)
@@ -389,7 +387,49 @@ struct ath5k_edge_power {
        bool flag;
 };
 
-/* EEPROM calibration data */
+/**
+ * struct ath5k_eeprom_info - EEPROM calibration data
+ *
+ * @ee_regdomain: ath/regd.c takes care of COUNTRY_ERD and WORLDWIDE_ROAMING
+ *     flags
+ * @ee_ant_gain: Antenna gain in 0.5dB steps signed [5211 only?]
+ * @ee_cck_ofdm_gain_delta: difference in gainF to output the same power for
+ *     OFDM and CCK packets
+ * @ee_cck_ofdm_power_delta: power difference between OFDM (6Mbps) and CCK
+ *     (11Mbps) rate in G mode. 0.1dB steps
+ * @ee_scaled_cck_delta: for Japan Channel 14: 0.1dB resolution
+ *
+ * @ee_i_cal: Initial I coefficient to correct I/Q mismatch in the receive path
+ * @ee_q_cal: Initial Q coefficient to correct I/Q mismatch in the receive path
+ * @ee_fixed_bias: use ee_ob and ee_db settings or use automatic control
+ * @ee_switch_settling: RX/TX Switch settling time
+ * @ee_atn_tx_rx: Difference in attenuation between TX and RX in 1dB steps
+ * @ee_ant_control: Antenna Control Settings
+ * @ee_ob: Bias current for Output stage of PA
+ *     B/G mode: Index [0] is used for AR2112/5112, otherwise [1]
+ *     A mode: [0] 5.15-5.25 [1] 5.25-5.50 [2] 5.50-5.70 [3] 5.70-5.85 GHz
+ * @ee_db: Bias current for Output stage of PA. see @ee_ob
+ * @ee_tx_end2xlna_enable: Time difference from when BB finishes sending a frame
+ *     to when the external LNA is activated
+ * @ee_tx_end2xpa_disable: Time difference from when BB finishes sending a frame
+ *     to when the external PA switch is deactivated
+ * @ee_tx_frm2xpa_enable: Time difference from when MAC sends frame to when
+ *     external PA switch is activated
+ * @ee_thr_62: Clear Channel Assessment (CCA) sensitivity
+ *     (IEEE802.11a section 17.3.10.5 )
+ * @ee_xlna_gain: Total gain of the LNA (information only)
+ * @ee_xpd: Use external (1) or internal power detector
+ * @ee_x_gain: Gain for external power detector output (differences in EEMAP
+ *     versions!)
+ * @ee_i_gain: Initial gain value after reset
+ * @ee_margin_tx_rx: Margin in dB when final attenuation stage should be used
+ *
+ * @ee_false_detect: Backoff in Sensitivity (dB) on channels with spur signals
+ * @ee_noise_floor_thr: Noise floor threshold in 1dB steps
+ * @ee_adc_desired_size: Desired amplitude for ADC, used by AGC; in 0.5 dB steps
+ * @ee_pga_desired_size: Desired output of PGA (for BB gain) in 0.5 dB steps
+ * @ee_pd_gain_overlap: PD ADC curves need to overlap in 0.5dB steps (ee_map>=2)
+ */
 struct ath5k_eeprom_info {
 
        /* Header information */
index aefe84f9c04bf8136abea73bd24e6bd49d0b4dc5..5212e275f1c7795531eb6a606d8cb1cbf8853359 100644 (file)
  * ath5k_hw_set_opmode - Set PCU operating mode
  *
  * @ah: The &struct ath5k_hw
+ * @op_mode: &enum nl80211_iftype operating mode
  *
  * Initialize PCU for the various operating modes (AP/STA etc)
- *
- * NOTE: ah->ah_op_mode must be set before calling this.
  */
-int ath5k_hw_set_opmode(struct ath5k_hw *ah)
+int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
 {
        struct ath_common *common = ath5k_hw_common(ah);
        u32 pcu_reg, beacon_reg, low_id, high_id;
 
+       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
 
        /* Preserve rest settings */
        pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000;
@@ -61,7 +61,7 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
 
        ATH5K_TRACE(ah->ah_sc);
 
-       switch (ah->ah_op_mode) {
+       switch (op_mode) {
        case NL80211_IFTYPE_ADHOC:
                pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
                beacon_reg |= AR5K_BCR_ADHOC;
@@ -113,39 +113,26 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_update - Update mib counters (mac layer statistics)
+ * ath5k_hw_update - Update MIB counters (mac layer statistics)
  *
  * @ah: The &struct ath5k_hw
- * @stats: The &struct ieee80211_low_level_stats we use to track
- * statistics on the driver
  *
- * Reads MIB counters from PCU and updates sw statistics. Must be
- * called after a MIB interrupt.
+ * Reads MIB counters from PCU and updates sw statistics. Is called after a
+ * MIB interrupt, because one of these counters might have reached their maximum
+ * and triggered the MIB interrupt, to let us read and clear the counter.
+ *
+ * Is called in interrupt context!
  */
-void ath5k_hw_update_mib_counters(struct ath5k_hw *ah,
-               struct ieee80211_low_level_stats  *stats)
+void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
 {
-       ATH5K_TRACE(ah->ah_sc);
+       struct ath5k_statistics *stats = &ah->ah_sc->stats;
 
        /* Read-And-Clear */
-       stats->dot11ACKFailureCount += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
-       stats->dot11RTSFailureCount += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
-       stats->dot11RTSSuccessCount += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
-       stats->dot11FCSErrorCount += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
-
-       /* XXX: Should we use this to track beacon count ?
-        * -we read it anyway to clear the register */
-       ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
-
-       /* Reset profile count registers on 5212*/
-       if (ah->ah_version == AR5K_AR5212) {
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX);
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX);
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR);
-               ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE);
-       }
-
-       /* TODO: Handle ANI stats */
+       stats->ack_fail += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL);
+       stats->rts_fail += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL);
+       stats->rts_ok += ath5k_hw_reg_read(ah, AR5K_RTS_OK);
+       stats->fcs_error += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL);
+       stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
 }
 
 /**
@@ -167,9 +154,9 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
        else {
                u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
                if (high)
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
-               else
                        AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+               else
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
        }
 }
 
@@ -178,26 +165,13 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
 * ACK/CTS Timeouts *
 \******************/
 
-/**
- * ath5k_hw_het_ack_timeout - Get ACK timeout from PCU in usec
- *
- * @ah: The &struct ath5k_hw
- */
-unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah)
-{
-       ATH5K_TRACE(ah->ah_sc);
-
-       return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
-                       AR5K_TIME_OUT), AR5K_TIME_OUT_ACK));
-}
-
 /**
  * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
  *
  * @ah: The &struct ath5k_hw
  * @timeout: Timeout in usec
  */
-int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
+static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
        ATH5K_TRACE(ah->ah_sc);
        if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
@@ -210,25 +184,13 @@ int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
        return 0;
 }
 
-/**
- * ath5k_hw_get_cts_timeout - Get CTS timeout from PCU in usec
- *
- * @ah: The &struct ath5k_hw
- */
-unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah)
-{
-       ATH5K_TRACE(ah->ah_sc);
-       return ath5k_hw_clocktoh(ah, AR5K_REG_MS(ath5k_hw_reg_read(ah,
-                       AR5K_TIME_OUT), AR5K_TIME_OUT_CTS));
-}
-
 /**
  * ath5k_hw_set_cts_timeout - Set CTS timeout on PCU
  *
  * @ah: The &struct ath5k_hw
  * @timeout: Timeout in usec
  */
-int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
+static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
 {
        ATH5K_TRACE(ah->ah_sc);
        if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
@@ -290,7 +252,7 @@ unsigned int ath5k_hw_get_clockrate(struct ath5k_hw *ah)
  *
  * @ah: The &struct ath5k_hw
  */
-unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
+static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
 {
        struct ieee80211_channel *channel = ah->ah_current_channel;
 
@@ -308,7 +270,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
  *
  * @ah: The &struct ath5k_hw
  */
-unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
+static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
 {
        struct ieee80211_channel *channel = ah->ah_current_channel;
 
@@ -417,7 +379,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
  * (ACK etc).
  *
  * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
- * TODO: Init ANI here
  */
 void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
 {
@@ -451,42 +412,6 @@ void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
        ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
 }
 
-/*
- * Set multicast filter by index
- */
-int ath5k_hw_set_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
-{
-
-       ATH5K_TRACE(ah->ah_sc);
-       if (index >= 64)
-               return -EINVAL;
-       else if (index >= 32)
-               AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1,
-                               (1 << (index - 32)));
-       else
-               AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
-
-       return 0;
-}
-
-/*
- * Clear Multicast filter by index
- */
-int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index)
-{
-
-       ATH5K_TRACE(ah->ah_sc);
-       if (index >= 64)
-               return -EINVAL;
-       else if (index >= 32)
-               AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1,
-                               (1 << (index - 32)));
-       else
-               AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index));
-
-       return 0;
-}
-
 /**
  * ath5k_hw_get_rx_filter - Get current rx filter
  *
@@ -571,18 +496,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
 * Beacon control *
 \****************/
 
-/**
- * ath5k_hw_get_tsf32 - Get a 32bit TSF
- *
- * @ah: The &struct ath5k_hw
- *
- * Returns lower 32 bits of current TSF
- */
-u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
-{
-       ATH5K_TRACE(ah->ah_sc);
-       return ath5k_hw_reg_read(ah, AR5K_TSF_L32);
-}
+#define ATH5K_MAX_TSF_READ 10
 
 /**
  * ath5k_hw_get_tsf64 - Get the full 64bit TSF
@@ -593,10 +507,35 @@ u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah)
  */
 u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
 {
-       u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+       u32 tsf_lower, tsf_upper1, tsf_upper2;
+       int i;
+
+       /*
+        * While reading TSF upper and then lower part, the clock is still
+        * counting (or jumping in case of IBSS merge) so we might get
+        * inconsistent values. To avoid this, we read the upper part again
+        * and check it has not been changed. We make the hypothesis that a
+        * maximum of 3 changes can happens in a row (we use 10 as a safe
+        * value).
+        *
+        * Impact on performance is pretty small, since in most cases, only
+        * 3 register reads are needed.
+        */
+
+       tsf_upper1 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+       for (i = 0; i < ATH5K_MAX_TSF_READ; i++) {
+               tsf_lower = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
+               tsf_upper2 = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+               if (tsf_upper2 == tsf_upper1)
+                       break;
+               tsf_upper1 = tsf_upper2;
+       }
+
+       WARN_ON( i == ATH5K_MAX_TSF_READ );
+
        ATH5K_TRACE(ah->ah_sc);
 
-       return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32);
+       return (((u64)tsf_upper1 << 32) | tsf_lower);
 }
 
 /**
@@ -651,7 +590,7 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
        /*
         * Set the additional timers by mode
         */
-       switch (ah->ah_op_mode) {
+       switch (ah->ah_sc->opmode) {
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_STATION:
                /* In STA mode timer1 is used as next wakeup
@@ -688,8 +627,8 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
         * Set the beacon register and enable all timers.
         */
        /* When in AP or Mesh Point mode zero timer0 to start TSF */
-       if (ah->ah_op_mode == NL80211_IFTYPE_AP ||
-           ah->ah_op_mode == NL80211_IFTYPE_MESH_POINT)
+       if (ah->ah_sc->opmode == NL80211_IFTYPE_AP ||
+           ah->ah_sc->opmode == NL80211_IFTYPE_MESH_POINT)
                ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
 
        ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0);
@@ -722,203 +661,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
 
 }
 
-#if 0
-/*
- * Set beacon timers
- */
-int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah,
-               const struct ath5k_beacon_state *state)
-{
-       u32 cfp_period, next_cfp, dtim, interval, next_beacon;
-
-       /*
-        * TODO: should be changed through *state
-        * review struct ath5k_beacon_state struct
-        *
-        * XXX: These are used for cfp period bellow, are they
-        * ok ? Is it O.K. for tsf here to be 0 or should we use
-        * get_tsf ?
-        */
-       u32 dtim_count = 0; /* XXX */
-       u32 cfp_count = 0; /* XXX */
-       u32 tsf = 0; /* XXX */
-
-       ATH5K_TRACE(ah->ah_sc);
-       /* Return on an invalid beacon state */
-       if (state->bs_interval < 1)
-               return -EINVAL;
-
-       interval = state->bs_interval;
-       dtim = state->bs_dtim_period;
-
-       /*
-        * PCF support?
-        */
-       if (state->bs_cfp_period > 0) {
-               /*
-                * Enable PCF mode and set the CFP
-                * (Contention Free Period) and timer registers
-                */
-               cfp_period = state->bs_cfp_period * state->bs_dtim_period *
-                       state->bs_interval;
-               next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) *
-                       state->bs_interval;
-
-               AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
-                               AR5K_STA_ID1_DEFAULT_ANTENNA |
-                               AR5K_STA_ID1_PCF);
-               ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD);
-               ath5k_hw_reg_write(ah, state->bs_cfp_max_duration,
-                               AR5K_CFP_DUR);
-               ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period :
-                                               next_cfp)) << 3, AR5K_TIMER2);
-       } else {
-               /* Disable PCF mode */
-               AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
-                               AR5K_STA_ID1_DEFAULT_ANTENNA |
-                               AR5K_STA_ID1_PCF);
-       }
-
-       /*
-        * Enable the beacon timer register
-        */
-       ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0);
-
-       /*
-        * Start the beacon timers
-        */
-       ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &
-               ~(AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) |
-               AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0,
-               AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval,
-               AR5K_BEACON_PERIOD), AR5K_BEACON);
-
-       /*
-        * Write new beacon miss threshold, if it appears to be valid
-        * XXX: Figure out right values for min <= bs_bmiss_threshold <= max
-        * and return if its not in range. We can test this by reading value and
-        * setting value to a largest value and seeing which values register.
-        */
-
-       AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS,
-                       state->bs_bmiss_threshold);
-
-       /*
-        * Set sleep control register
-        * XXX: Didn't find this in 5210 code but since this register
-        * exists also in ar5k's 5210 headers i leave it as common code.
-        */
-       AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR,
-                       (state->bs_sleep_duration - 3) << 3);
-
-       /*
-        * Set enhanced sleep registers on 5212
-        */
-       if (ah->ah_version == AR5K_AR5212) {
-               if (state->bs_sleep_duration > state->bs_interval &&
-                               roundup(state->bs_sleep_duration, interval) ==
-                               state->bs_sleep_duration)
-                       interval = state->bs_sleep_duration;
-
-               if (state->bs_sleep_duration > dtim && (dtim == 0 ||
-                               roundup(state->bs_sleep_duration, dtim) ==
-                               state->bs_sleep_duration))
-                       dtim = state->bs_sleep_duration;
-
-               if (interval > dtim)
-                       return -EINVAL;
-
-               next_beacon = interval == dtim ? state->bs_next_dtim :
-                       state->bs_next_beacon;
-
-               ath5k_hw_reg_write(ah,
-                       AR5K_REG_SM((state->bs_next_dtim - 3) << 3,
-                       AR5K_SLEEP0_NEXT_DTIM) |
-                       AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) |
-                       AR5K_SLEEP0_ENH_SLEEP_EN |
-                       AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0);
-
-               ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3,
-                       AR5K_SLEEP1_NEXT_TIM) |
-                       AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1);
-
-               ath5k_hw_reg_write(ah,
-                       AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) |
-                       AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2);
-       }
-
-       return 0;
-}
-
-/*
- * Reset beacon timers
- */
-void ath5k_hw_reset_beacon(struct ath5k_hw *ah)
-{
-       ATH5K_TRACE(ah->ah_sc);
-       /*
-        * Disable beacon timer
-        */
-       ath5k_hw_reg_write(ah, 0, AR5K_TIMER0);
-
-       /*
-        * Disable some beacon register values
-        */
-       AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
-                       AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF);
-       ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON);
-}
-
-/*
- * Wait for beacon queue to finish
- */
-int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr)
-{
-       unsigned int i;
-       int ret;
-
-       ATH5K_TRACE(ah->ah_sc);
-
-       /* 5210 doesn't have QCU*/
-       if (ah->ah_version == AR5K_AR5210) {
-               /*
-                * Wait for beaconn queue to finish by checking
-                * Control Register and Beacon Status Register.
-                */
-               for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) {
-                       if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F)
-                                       ||
-                           !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F))
-                               break;
-                       udelay(10);
-               }
-
-               /* Timeout... */
-               if (i <= 0) {
-                       /*
-                        * Re-schedule the beacon queue
-                        */
-                       ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1);
-                       ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE,
-                                       AR5K_BCR);
-
-                       return -EIO;
-               }
-               ret = 0;
-       } else {
-       /*5211/5212*/
-               ret = ath5k_hw_register_timeout(ah,
-                       AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON),
-                       AR5K_QCU_STS_FRMPENDCNT, 0, false);
-
-               if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON))
-                       return -EIO;
-       }
-
-       return ret;
-}
-#endif
-
 
 /*********************\
 * Key table functions *
@@ -971,19 +713,6 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
        return 0;
 }
 
-/*
- * Check if a table entry is valid
- */
-int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry)
-{
-       ATH5K_TRACE(ah->ah_sc);
-       AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
-
-       /* Check the validation flag at the end of the entry */
-       return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) &
-               AR5K_KEYTABLE_VALID;
-}
-
 static
 int ath5k_keycache_type(const struct ieee80211_key_conf *key)
 {
index 68e2bccd90d34418d3b85070b0f7b09ee468a93f..1b81c4778800f62222eec48bc88c61ff993e9a69 100644 (file)
@@ -20,8 +20,6 @@
  *
  */
 
-#define _ATH5K_PHY
-
 #include <linux/delay.h>
 #include <linux/slab.h>
 
@@ -982,7 +980,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
                        return -EINVAL;
 
                data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
-       } else if ((c - (c % 5)) != 2 || c > 5435) {
+       } else if ((c % 5) != 2 || c > 5435) {
                if (!(c % 20) && c >= 5120) {
                        data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
                        data2 = ath5k_hw_bitswap(3, 2);
@@ -995,7 +993,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
                } else
                        return -EINVAL;
        } else {
-               data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+               data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8);
                data2 = ath5k_hw_bitswap(0, 2);
        }
 
@@ -1023,7 +1021,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
                data0 = ath5k_hw_bitswap((c - 2272), 8);
                data2 = 0;
        /* ? 5GHz ? */
-       } else if ((c - (c % 5)) != 2 || c > 5435) {
+       } else if ((c % 5) != 2 || c > 5435) {
                if (!(c % 20) && c < 5120)
                        data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
                else if (!(c % 10))
@@ -1034,7 +1032,7 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
                        return -EINVAL;
                data2 = ath5k_hw_bitswap(1, 2);
        } else {
-               data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+               data0 = ath5k_hw_bitswap((10 * (c - 2 - 4800)) / 25 + 1, 8);
                data2 = ath5k_hw_bitswap(0, 2);
        }
 
@@ -1105,28 +1103,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
   PHY calibration
 \*****************/
 
-void
-ath5k_hw_calibration_poll(struct ath5k_hw *ah)
-{
-       /* Calibration interval in jiffies */
-       unsigned long cal_intval;
-
-       cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000);
-
-       /* Initialize timestamp if needed */
-       if (!ah->ah_cal_tstamp)
-               ah->ah_cal_tstamp = jiffies;
-
-       /* For now we always do full calibration
-        * Mark software interrupt mask and fire software
-        * interrupt (bit gets auto-cleared) */
-       if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) {
-               ah->ah_cal_tstamp = jiffies;
-               ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
-               AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
-       }
-}
-
 static int sign_extend(int val, const int nbits)
 {
        int order = BIT(nbits-1);
@@ -1191,7 +1167,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
  * The median of the values in the history is then loaded into the
  * hardware for its own use for RSSI and CCA measurements.
  */
-void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
+static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 {
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
        u32 val;
@@ -1400,7 +1376,11 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
        }
 
        i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
-       q_coffd = q_pwr >> 7;
+
+       if (ah->ah_version == AR5K_AR5211)
+               q_coffd = q_pwr >> 6;
+       else
+               q_coffd = q_pwr >> 7;
 
        /* protect against divide by 0 and loss of sign bits */
        if (i_coffd == 0 || q_coffd < 2)
@@ -1409,7 +1389,10 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
        i_coff = (-iq_corr) / i_coffd;
        i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
 
-       q_coff = (i_pwr / q_coffd) - 128;
+       if (ah->ah_version == AR5K_AR5211)
+               q_coff = (i_pwr / q_coffd) - 64;
+       else
+               q_coff = (i_pwr / q_coffd) - 128;
        q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */
 
        ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
@@ -1769,7 +1752,7 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
 * Antenna control *
 \*****************/
 
-void /*TODO:Boundary check*/
+static void /*TODO:Boundary check*/
 ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant)
 {
        ATH5K_TRACE(ah->ah_sc);
@@ -1778,16 +1761,6 @@ ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant)
                ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA);
 }
 
-unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah)
-{
-       ATH5K_TRACE(ah->ah_sc);
-
-       if (ah->ah_version != AR5K_AR5210)
-               return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA) & 0x7;
-
-       return false; /*XXX: What do we return for 5210 ?*/
-}
-
 /*
  * Enable/disable fast rx antenna diversity
  */
@@ -1931,6 +1904,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
 
        ah->ah_tx_ant = tx_ant;
        ah->ah_ant_mode = ant_mode;
+       ah->ah_def_ant = def_ant;
 
        sta_id1 |= use_def_for_tx ? AR5K_STA_ID1_DEFAULT_ANTENNA : 0;
        sta_id1 |= update_def_on_tx ? AR5K_STA_ID1_DESC_ANTENNA : 0;
@@ -2171,8 +2145,6 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah,
 done:
        *pcinfo_l = &pcinfo[idx_l];
        *pcinfo_r = &pcinfo[idx_r];
-
-       return;
 }
 
 /*
@@ -2441,19 +2413,6 @@ ath5k_combine_linear_pcdac_curves(struct ath5k_hw *ah, s16* table_min,
                pcdac_tmp = pcdac_high_pwr;
 
                edge_flag = 0x40;
-#if 0
-               /* If both min and max power limits are in lower
-                * power curve's range, only use the low power curve.
-                * TODO: min/max levels are related to target
-                * power values requested from driver/user
-                * XXX: Is this really needed ? */
-               if (min_pwr < table_max[1] &&
-               max_pwr < table_max[1]) {
-                       edge_flag = 0;
-                       pcdac_tmp = pcdac_low_pwr;
-                       max_pwr_idx = (table_max[1] - table_min[1])/2;
-               }
-#endif
        } else {
                pcdac_low_pwr = ah->ah_txpower.tmpL[1]; /* Zeroed */
                pcdac_high_pwr = ah->ah_txpower.tmpL[0];
@@ -2600,7 +2559,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah,
                max_idx = (pdadc_n < table_size) ? pdadc_n : table_size;
 
                /* Fill pdadc_out table */
-               while (pdadc_0 < max_idx)
+               while (pdadc_0 < max_idx && pdadc_i < 128)
                        pdadc_out[pdadc_i++] = pdadc_tmp[pdadc_0++];
 
                /* Need to extrapolate above this pdgain? */
@@ -3144,5 +3103,3 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
 
        return ath5k_hw_txpower(ah, channel, ee_mode, txpower);
 }
-
-#undef _ATH5K_PHY
index 9122a8556f45c3e02a6e2e215f16702458f14147..f5831da33f7bccde87da720019259385a222b639 100644 (file)
@@ -516,23 +516,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
        return 0;
 }
 
-/*
- * Get slot time from DCU
- */
-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)
-               slot_time_clock = ath5k_hw_reg_read(ah, AR5K_SLOT_TIME);
-       else
-               slot_time_clock = ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT);
-
-       return ath5k_hw_clocktoh(ah, slot_time_clock & 0xffff);
-}
-
 /*
  * Set slot time on DCU
  */
index 1464f89b249c6b70e7187350cd8b08755db6bc0c..55b4ac6d236f1d93192ae72ae6323acbdc9f670c 100644 (file)
  * MIB control register
  */
 #define AR5K_MIBC              0x0040                  /* Register Address */
-#define AR5K_MIBC_COW          0x00000001      /* Warn test indicator */
+#define AR5K_MIBC_COW          0x00000001      /* Counter Overflow Warning */
 #define AR5K_MIBC_FMC          0x00000002      /* Freeze MIB Counters  */
-#define AR5K_MIBC_CMC          0x00000004      /* Clean MIB Counters  */
-#define AR5K_MIBC_MCS          0x00000008      /* MIB counter strobe */
+#define AR5K_MIBC_CMC          0x00000004      /* Clear MIB Counters  */
+#define AR5K_MIBC_MCS          0x00000008      /* MIB counter strobe, increment all */
 
 /*
  * Timeout prescale register
 #define AR5K_STA_ID1_DEFAULT_ANTENNA   0x00200000      /* Use default antenna */
 #define AR5K_STA_ID1_DESC_ANTENNA      0x00400000      /* Update antenna from descriptor */
 #define AR5K_STA_ID1_RTS_DEF_ANTENNA   0x00800000      /* Use default antenna for RTS */
-#define AR5K_STA_ID1_ACKCTS_6MB                0x01000000      /* Use 6Mbit/s for ACK/CTS */
-#define AR5K_STA_ID1_BASE_RATE_11B     0x02000000      /* Use 11b base rate for ACK/CTS [5211+] */
+#define AR5K_STA_ID1_ACKCTS_6MB                0x01000000      /* Rate to use for ACK/CTS. 0: highest mandatory rate <= RX rate; 1: 1Mbps in B mode */
+#define AR5K_STA_ID1_BASE_RATE_11B     0x02000000      /* 802.11b base rate. 0: 1, 2, 5.5 and 11Mbps; 1: 1 and 2Mbps. [5211+] */
 #define AR5K_STA_ID1_SELFGEN_DEF_ANT   0x04000000      /* Use def. antenna for self generated frames */
 #define AR5K_STA_ID1_CRYPT_MIC_EN      0x08000000      /* Enable MIC */
 #define AR5K_STA_ID1_KEYSRCH_MODE      0x10000000      /* Look up key when key id != 0 */
                                AR5K_NAV_5210 : AR5K_NAV_5211)
 
 /*
- * RTS success register
+ * MIB counters:
+ *
+ * max value is 0xc000, if this is reached we get a MIB interrupt.
+ * they can be controlled via AR5K_MIBC and are cleared on read.
+ */
+
+/*
+ * RTS success (MIB counter)
  */
 #define AR5K_RTS_OK_5210       0x8090
 #define AR5K_RTS_OK_5211       0x8088
                                AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211)
 
 /*
- * RTS failure register
+ * RTS failure (MIB counter)
  */
 #define AR5K_RTS_FAIL_5210     0x8094
 #define AR5K_RTS_FAIL_5211     0x808c
                                AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211)
 
 /*
- * ACK failure register
+ * ACK failure (MIB counter)
  */
 #define AR5K_ACK_FAIL_5210     0x8098
 #define AR5K_ACK_FAIL_5211     0x8090
                                AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211)
 
 /*
- * FCS failure register
+ * FCS failure (MIB counter)
  */
 #define AR5K_FCS_FAIL_5210     0x809c
 #define AR5K_FCS_FAIL_5211     0x8094
 
 /*
  * Profile count registers
+ *
+ * These registers can be cleared and freezed with ATH5K_MIBC, but they do not
+ * generate a MIB interrupt.
+ * Instead of overflowing, they shift by one bit to the right. All registers
+ * shift together, i.e. when one reaches the max, all shift at the same time by
+ * one bit to the right. This way we should always get consistent values.
  */
 #define AR5K_PROFCNT_TX                        0x80ec  /* Tx count */
 #define AR5K_PROFCNT_RX                        0x80f0  /* Rx count */
-#define AR5K_PROFCNT_RXCLR             0x80f4  /* Clear Rx count */
-#define AR5K_PROFCNT_CYCLE             0x80f8  /* Cycle count (?) */
+#define AR5K_PROFCNT_RXCLR             0x80f4  /* Busy count */
+#define AR5K_PROFCNT_CYCLE             0x80f8  /* Cycle counter */
 
 /*
  * Quiet period control registers
 #define        AR5K_CCK_FIL_CNT                0x8128
 
 /*
- * PHY Error Counters (?)
+ * PHY Error Counters (same masks as AR5K_PHY_ERR_FIL)
  */
 #define        AR5K_PHYERR_CNT1                0x812c
 #define        AR5K_PHYERR_CNT1_MASK           0x8130
 #define        AR5K_PHYERR_CNT2                0x8134
 #define        AR5K_PHYERR_CNT2_MASK           0x8138
 
+/* if the PHY Error Counters reach this maximum, we get MIB interrupts */
+#define ATH5K_PHYERR_CNT_MAX           0x00c00000
+
 /*
  * TSF Threshold register (?)
  */
 #define AR5K_PHY_SETTLING              0x9844                  /* Register Address */
 #define        AR5K_PHY_SETTLING_AGC           0x0000007f      /* AGC settling time */
 #define        AR5K_PHY_SETTLING_AGC_S         0
-#define        AR5K_PHY_SETTLING_SWITCH        0x00003f80      /* Switch settlig time */
+#define        AR5K_PHY_SETTLING_SWITCH        0x00003f80      /* Switch settling time */
 #define        AR5K_PHY_SETTLING_SWITCH_S      7
 
 /*
index cbf28e379843838a16d410b438636d6252cf901e..307f80e83f941d8996fb84f5684e94db15155694 100644 (file)
@@ -19,8 +19,6 @@
  *
  */
 
-#define _ATH5K_RESET
-
 /*****************************\
   Reset functions and helpers
 \*****************************/
 #include "base.h"
 #include "debug.h"
 
+/*
+ * Check if a register write has been completed
+ */
+int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
+                             bool is_set)
+{
+       int i;
+       u32 data;
+
+       for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) {
+               data = ath5k_hw_reg_read(ah, reg);
+               if (is_set && (data & flag))
+                       break;
+               else if ((data & flag) == val)
+                       break;
+               udelay(15);
+       }
+
+       return (i <= 0) ? -EAGAIN : 0;
+}
+
 /**
  * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
  *
@@ -221,8 +240,8 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
 /*
  * Sleep control
  */
-int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
-               bool set_chip, u16 sleep_duration)
+static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
+                             bool set_chip, u16 sleep_duration)
 {
        unsigned int i;
        u32 staid, data;
@@ -608,7 +627,6 @@ static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
 
                AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
        }
-       return;
 }
 
 /* TODO: Half/Quarter rate */
@@ -864,8 +882,6 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
        /* Heavy clipping -disable for now */
        if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_1)
                ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
-
-       return;
 }
 
 /*
@@ -1017,11 +1033,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        if (ret)
                return ret;
 
-       /*
-        * Initialize operating mode
-        */
-       ah->ah_op_mode = op_mode;
-
        /* PHY access enable */
        if (ah->ah_mac_srev >= AR5K_SREV_AR5211)
                ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
@@ -1192,7 +1203,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        ath5k_hw_set_associd(ah);
 
        /* Set PCU config */
-       ath5k_hw_set_opmode(ah);
+       ath5k_hw_set_opmode(ah, op_mode);
 
        /* Clear any pending interrupts
         * PISR/SISR Not available on 5210 */
@@ -1378,7 +1389,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
         * external 32KHz crystal when sleeping if one
         * exists */
        if (ah->ah_version == AR5K_AR5212 &&
-           ah->ah_op_mode != NL80211_IFTYPE_AP)
+           op_mode != NL80211_IFTYPE_AP)
                ath5k_hw_set_sleep_clock(ah, true);
 
        /*
@@ -1388,5 +1399,3 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        ath5k_hw_reset_tsf(ah);
        return 0;
 }
-
-#undef _ATH5K_RESET
index 5774cea23a3b12c2faf0784b956ae075692f6c6a..35f23bdc442f243e485da8acb70d9f4fecd28977 100644 (file)
@@ -32,3 +32,24 @@ config ATH9K_DEBUGFS
 
          Also required for changing debug message flags at run time.
 
+config ATH9K_HTC
+       tristate "Atheros HTC based wireless cards support"
+       depends on USB && MAC80211
+       select ATH9K_HW
+       select MAC80211_LEDS
+       select LEDS_CLASS
+       select NEW_LEDS
+       select ATH9K_COMMON
+       ---help---
+        Support for Atheros HTC based cards.
+        Chipsets supported: AR9271
+
+        For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc
+
+        The built module will be ath9k_htc.
+
+config ATH9K_HTC_DEBUGFS
+       bool "Atheros ath9k_htc debugging"
+       depends on ATH9K_HTC && DEBUG_FS
+       ---help---
+         Say Y, if you need access to ath9k_htc's statistics.
index 6b50d5eb9ec3e8821ea0bb44475669742b77c739..dd112be218abf951bc5875c107a43d1f9fe87ddf 100644 (file)
@@ -13,18 +13,38 @@ ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o
 
-ath9k_hw-y:=   hw.o \
+ath9k_hw-y:=   \
+               ar9002_hw.o \
+               ar9003_hw.o \
+               hw.o \
+               ar9003_phy.o \
+               ar9002_phy.o \
+               ar5008_phy.o \
+               ar9002_calib.o \
+               ar9003_calib.o \
+               calib.o \
                eeprom.o \
                eeprom_def.o \
                eeprom_4k.o \
                eeprom_9287.o \
-               calib.o \
                ani.o \
-               phy.o \
                btcoex.o \
                mac.o \
+               ar9002_mac.o \
+               ar9003_mac.o \
+               ar9003_eeprom.o
 
 obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o
 
 obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o
 ath9k_common-y:=       common.o
+
+ath9k_htc-y += htc_hst.o \
+               hif_usb.o \
+               wmi.o \
+               htc_drv_txrx.o \
+               htc_drv_main.o \
+               htc_drv_beacon.o \
+               htc_drv_init.o
+
+obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
index ca4994f1315153b4ef2a9aae256846bbb4f6cf91..85fdd26039c8e70fd8f77888c083559006418caa 100644 (file)
@@ -47,6 +47,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 }
 
 static struct ath_bus_ops ath_ahb_bus_ops  = {
+       .ath_bus_type = ATH_AHB,
        .read_cachesize = ath_ahb_read_cachesize,
        .eeprom_read = ath_ahb_eeprom_read,
 };
index 2a0cd64c2bfbc64830a8a71bf714972302ebc2dc..ba8b20f01594a8908f135620dd10b392d1498227 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "hw.h"
+#include "hw-ops.h"
 
 static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
                                        struct ath9k_channel *chan)
@@ -37,190 +38,6 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
        return 0;
 }
 
-static bool ath9k_hw_ani_control(struct ath_hw *ah,
-                                enum ath9k_ani_cmd cmd, int param)
-{
-       struct ar5416AniState *aniState = ah->curani;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       switch (cmd & ah->ani_function) {
-       case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "level out of range (%u > %u)\n",
-                                 level,
-                                 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
-                       return false;
-               }
-
-               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-                             AR_PHY_DESIRED_SZ_TOT_DES,
-                             ah->totalSizeDesired[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_LOW,
-                             ah->coarse_low[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_HIGH,
-                             ah->coarse_high[level]);
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRPWR,
-                             ah->firpwr[level]);
-
-               if (level > aniState->noiseImmunityLevel)
-                       ah->stats.ast_ani_niup++;
-               else if (level < aniState->noiseImmunityLevel)
-                       ah->stats.ast_ani_nidown++;
-               aniState->noiseImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
-               const int m1ThreshLow[] = { 127, 50 };
-               const int m2ThreshLow[] = { 127, 40 };
-               const int m1Thresh[] = { 127, 0x4d };
-               const int m2Thresh[] = { 127, 0x40 };
-               const int m2CountThr[] = { 31, 16 };
-               const int m2CountThrLow[] = { 63, 48 };
-               u32 on = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
-                             m1ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
-                             m2ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M1_THRESH,
-                             m1Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M2_THRESH,
-                             m2Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M2COUNT_THR,
-                             m2CountThr[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
-                             m2CountThrLow[on]);
-
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
-                             m1ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
-                             m2ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M1_THRESH,
-                             m1Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M2_THRESH,
-                             m2Thresh[on]);
-
-               if (on)
-                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-               else
-                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
-               if (!on != aniState->ofdmWeakSigDetectOff) {
-                       if (on)
-                               ah->stats.ast_ani_ofdmon++;
-                       else
-                               ah->stats.ast_ani_ofdmoff++;
-                       aniState->ofdmWeakSigDetectOff = !on;
-               }
-               break;
-       }
-       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
-               const int weakSigThrCck[] = { 8, 6 };
-               u32 high = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
-                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
-                             weakSigThrCck[high]);
-               if (high != aniState->cckWeakSigThreshold) {
-                       if (high)
-                               ah->stats.ast_ani_cckhigh++;
-                       else
-                               ah->stats.ast_ani_ccklow++;
-                       aniState->cckWeakSigThreshold = high;
-               }
-               break;
-       }
-       case ATH9K_ANI_FIRSTEP_LEVEL:{
-               const int firstep[] = { 0, 4, 8 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(firstep)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "level out of range (%u > %u)\n",
-                                 level,
-                                 (unsigned) ARRAY_SIZE(firstep));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRSTEP,
-                             firstep[level]);
-               if (level > aniState->firstepLevel)
-                       ah->stats.ast_ani_stepup++;
-               else if (level < aniState->firstepLevel)
-                       ah->stats.ast_ani_stepdown++;
-               aniState->firstepLevel = level;
-               break;
-       }
-       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
-               const int cycpwrThr1[] =
-                       { 2, 4, 6, 8, 10, 12, 14, 16 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(cycpwrThr1)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "level out of range (%u > %u)\n",
-                                 level,
-                                 (unsigned) ARRAY_SIZE(cycpwrThr1));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
-                             AR_PHY_TIMING5_CYCPWR_THR1,
-                             cycpwrThr1[level]);
-               if (level > aniState->spurImmunityLevel)
-                       ah->stats.ast_ani_spurup++;
-               else if (level < aniState->spurImmunityLevel)
-                       ah->stats.ast_ani_spurdown++;
-               aniState->spurImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_PRESENT:
-               break;
-       default:
-               ath_print(common, ATH_DBG_ANI,
-                         "invalid cmd %u\n", cmd);
-               return false;
-       }
-
-       ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
-       ath_print(common, ATH_DBG_ANI,
-                 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
-                 "ofdmWeakSigDetectOff=%d\n",
-                 aniState->noiseImmunityLevel,
-                 aniState->spurImmunityLevel,
-                 !aniState->ofdmWeakSigDetectOff);
-       ath_print(common, ATH_DBG_ANI,
-                 "cckWeakSigThreshold=%d, "
-                 "firstepLevel=%d, listenTime=%d\n",
-                 aniState->cckWeakSigThreshold,
-                 aniState->firstepLevel,
-                 aniState->listenTime);
-       ath_print(common, ATH_DBG_ANI,
-               "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-               aniState->cycleCount,
-               aniState->ofdmPhyErrCount,
-               aniState->cckPhyErrCount);
-
-       return true;
-}
-
 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
                                     struct ath9k_mib_stats *stats)
 {
@@ -262,11 +79,17 @@ static void ath9k_ani_restart(struct ath_hw *ah)
                  "Writing ofdmbase=%u   cckbase=%u\n",
                  aniState->ofdmPhyErrBase,
                  aniState->cckPhyErrBase);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
        REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
        aniState->ofdmPhyErrCount = 0;
@@ -540,8 +363,14 @@ void ath9k_ani_reset(struct ath_hw *ah)
        ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
                             ~ATH9K_RX_FILTER_PHYERR);
        ath9k_ani_restart(ah);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 void ath9k_hw_ani_monitor(struct ath_hw *ah,
@@ -639,6 +468,8 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
 
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_FILT_OFDM, 0);
        REG_WRITE(ah, AR_FILT_CCK, 0);
        REG_WRITE(ah, AR_MIBC,
@@ -646,6 +477,9 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
                  & 0x0f);
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* Freeze the MIB counters, get the stats and then clear them */
@@ -809,20 +643,17 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
        ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
                  ah->ani[0].cckPhyErrBase);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
        REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        ath9k_enable_mib_counters(ah);
 
        ah->aniperiod = ATH9K_ANI_PERIOD;
        if (ah->config.enable_ani)
                ah->proc_phyerr |= HAL_PROCESS_ANI;
 }
-
-void ath9k_hw_ani_disable(struct ath_hw *ah)
-{
-       ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
-
-       ath9k_hw_disable_mib_counters(ah);
-       REG_WRITE(ah, AR_PHY_ERR_1, 0);
-       REG_WRITE(ah, AR_PHY_ERR_2, 0);
-}
index 4e1ab94a51536705b49979babf3d0296789ef66b..3356762ea384af7fc4f3dfd049d8f27cca576ff5 100644 (file)
@@ -118,6 +118,5 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah, u32 *rxc_pcnt,
 void ath9k_hw_procmibevent(struct ath_hw *ah);
 void ath9k_hw_ani_setup(struct ath_hw *ah);
 void ath9k_hw_ani_init(struct ath_hw *ah);
-void ath9k_hw_ani_disable(struct ath_hw *ah);
 
 #endif /* ANI_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
new file mode 100644 (file)
index 0000000..025c31a
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * 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.
+ */
+
+#ifndef INITVALS_AR5008_H
+#define INITVALS_AR5008_H
+
+static const u32 ar5416Modes[][6] = {
+    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+    { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
+    { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
+    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+    { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
+    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de },
+    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
+    { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
+    { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
+    { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
+    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+    { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
+    { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
+    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
+    { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
+    { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
+    { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
+    { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
+    { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
+    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
+    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+    { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c },
+    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
+    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
+    { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
+    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
+    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
+    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
+    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
+    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
+    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
+    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
+    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
+    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
+    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
+    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u32 ar5416Common[][2] = {
+    { 0x0000000c, 0x00000000 },
+    { 0x00000030, 0x00020015 },
+    { 0x00000034, 0x00000005 },
+    { 0x00000040, 0x00000000 },
+    { 0x00000044, 0x00000008 },
+    { 0x00000048, 0x00000008 },
+    { 0x0000004c, 0x00000010 },
+    { 0x00000050, 0x00000000 },
+    { 0x00000054, 0x0000001f },
+    { 0x00000800, 0x00000000 },
+    { 0x00000804, 0x00000000 },
+    { 0x00000808, 0x00000000 },
+    { 0x0000080c, 0x00000000 },
+    { 0x00000810, 0x00000000 },
+    { 0x00000814, 0x00000000 },
+    { 0x00000818, 0x00000000 },
+    { 0x0000081c, 0x00000000 },
+    { 0x00000820, 0x00000000 },
+    { 0x00000824, 0x00000000 },
+    { 0x00001040, 0x002ffc0f },
+    { 0x00001044, 0x002ffc0f },
+    { 0x00001048, 0x002ffc0f },
+    { 0x0000104c, 0x002ffc0f },
+    { 0x00001050, 0x002ffc0f },
+    { 0x00001054, 0x002ffc0f },
+    { 0x00001058, 0x002ffc0f },
+    { 0x0000105c, 0x002ffc0f },
+    { 0x00001060, 0x002ffc0f },
+    { 0x00001064, 0x002ffc0f },
+    { 0x00001230, 0x00000000 },
+    { 0x00001270, 0x00000000 },
+    { 0x00001038, 0x00000000 },
+    { 0x00001078, 0x00000000 },
+    { 0x000010b8, 0x00000000 },
+    { 0x000010f8, 0x00000000 },
+    { 0x00001138, 0x00000000 },
+    { 0x00001178, 0x00000000 },
+    { 0x000011b8, 0x00000000 },
+    { 0x000011f8, 0x00000000 },
+    { 0x00001238, 0x00000000 },
+    { 0x00001278, 0x00000000 },
+    { 0x000012b8, 0x00000000 },
+    { 0x000012f8, 0x00000000 },
+    { 0x00001338, 0x00000000 },
+    { 0x00001378, 0x00000000 },
+    { 0x000013b8, 0x00000000 },
+    { 0x000013f8, 0x00000000 },
+    { 0x00001438, 0x00000000 },
+    { 0x00001478, 0x00000000 },
+    { 0x000014b8, 0x00000000 },
+    { 0x000014f8, 0x00000000 },
+    { 0x00001538, 0x00000000 },
+    { 0x00001578, 0x00000000 },
+    { 0x000015b8, 0x00000000 },
+    { 0x000015f8, 0x00000000 },
+    { 0x00001638, 0x00000000 },
+    { 0x00001678, 0x00000000 },
+    { 0x000016b8, 0x00000000 },
+    { 0x000016f8, 0x00000000 },
+    { 0x00001738, 0x00000000 },
+    { 0x00001778, 0x00000000 },
+    { 0x000017b8, 0x00000000 },
+    { 0x000017f8, 0x00000000 },
+    { 0x0000103c, 0x00000000 },
+    { 0x0000107c, 0x00000000 },
+    { 0x000010bc, 0x00000000 },
+    { 0x000010fc, 0x00000000 },
+    { 0x0000113c, 0x00000000 },
+    { 0x0000117c, 0x00000000 },
+    { 0x000011bc, 0x00000000 },
+    { 0x000011fc, 0x00000000 },
+    { 0x0000123c, 0x00000000 },
+    { 0x0000127c, 0x00000000 },
+    { 0x000012bc, 0x00000000 },
+    { 0x000012fc, 0x00000000 },
+    { 0x0000133c, 0x00000000 },
+    { 0x0000137c, 0x00000000 },
+    { 0x000013bc, 0x00000000 },
+    { 0x000013fc, 0x00000000 },
+    { 0x0000143c, 0x00000000 },
+    { 0x0000147c, 0x00000000 },
+    { 0x00004030, 0x00000002 },
+    { 0x0000403c, 0x00000002 },
+    { 0x00007010, 0x00000000 },
+    { 0x00007038, 0x000004c2 },
+    { 0x00008004, 0x00000000 },
+    { 0x00008008, 0x00000000 },
+    { 0x0000800c, 0x00000000 },
+    { 0x00008018, 0x00000700 },
+    { 0x00008020, 0x00000000 },
+    { 0x00008038, 0x00000000 },
+    { 0x0000803c, 0x00000000 },
+    { 0x00008048, 0x40000000 },
+    { 0x00008054, 0x00000000 },
+    { 0x00008058, 0x00000000 },
+    { 0x0000805c, 0x000fc78f },
+    { 0x00008060, 0x0000000f },
+    { 0x00008064, 0x00000000 },
+    { 0x000080c0, 0x2a82301a },
+    { 0x000080c4, 0x05dc01e0 },
+    { 0x000080c8, 0x1f402710 },
+    { 0x000080cc, 0x01f40000 },
+    { 0x000080d0, 0x00001e00 },
+    { 0x000080d4, 0x00000000 },
+    { 0x000080d8, 0x00400000 },
+    { 0x000080e0, 0xffffffff },
+    { 0x000080e4, 0x0000ffff },
+    { 0x000080e8, 0x003f3f3f },
+    { 0x000080ec, 0x00000000 },
+    { 0x000080f0, 0x00000000 },
+    { 0x000080f4, 0x00000000 },
+    { 0x000080f8, 0x00000000 },
+    { 0x000080fc, 0x00020000 },
+    { 0x00008100, 0x00020000 },
+    { 0x00008104, 0x00000001 },
+    { 0x00008108, 0x00000052 },
+    { 0x0000810c, 0x00000000 },
+    { 0x00008110, 0x00000168 },
+    { 0x00008118, 0x000100aa },
+    { 0x0000811c, 0x00003210 },
+    { 0x00008124, 0x00000000 },
+    { 0x00008128, 0x00000000 },
+    { 0x0000812c, 0x00000000 },
+    { 0x00008130, 0x00000000 },
+    { 0x00008134, 0x00000000 },
+    { 0x00008138, 0x00000000 },
+    { 0x0000813c, 0x00000000 },
+    { 0x00008144, 0xffffffff },
+    { 0x00008168, 0x00000000 },
+    { 0x0000816c, 0x00000000 },
+    { 0x00008170, 0x32143320 },
+    { 0x00008174, 0xfaa4fa50 },
+    { 0x00008178, 0x00000100 },
+    { 0x0000817c, 0x00000000 },
+    { 0x000081c4, 0x00000000 },
+    { 0x000081ec, 0x00000000 },
+    { 0x000081f0, 0x00000000 },
+    { 0x000081f4, 0x00000000 },
+    { 0x000081f8, 0x00000000 },
+    { 0x000081fc, 0x00000000 },
+    { 0x00008200, 0x00000000 },
+    { 0x00008204, 0x00000000 },
+    { 0x00008208, 0x00000000 },
+    { 0x0000820c, 0x00000000 },
+    { 0x00008210, 0x00000000 },
+    { 0x00008214, 0x00000000 },
+    { 0x00008218, 0x00000000 },
+    { 0x0000821c, 0x00000000 },
+    { 0x00008220, 0x00000000 },
+    { 0x00008224, 0x00000000 },
+    { 0x00008228, 0x00000000 },
+    { 0x0000822c, 0x00000000 },
+    { 0x00008230, 0x00000000 },
+    { 0x00008234, 0x00000000 },
+    { 0x00008238, 0x00000000 },
+    { 0x0000823c, 0x00000000 },
+    { 0x00008240, 0x00100000 },
+    { 0x00008244, 0x0010f400 },
+    { 0x00008248, 0x00000100 },
+    { 0x0000824c, 0x0001e800 },
+    { 0x00008250, 0x00000000 },
+    { 0x00008254, 0x00000000 },
+    { 0x00008258, 0x00000000 },
+    { 0x0000825c, 0x400000ff },
+    { 0x00008260, 0x00080922 },
+    { 0x00008264, 0x88000010 },
+    { 0x00008270, 0x00000000 },
+    { 0x00008274, 0x40000000 },
+    { 0x00008278, 0x003e4180 },
+    { 0x0000827c, 0x00000000 },
+    { 0x00008284, 0x0000002c },
+    { 0x00008288, 0x0000002c },
+    { 0x0000828c, 0x00000000 },
+    { 0x00008294, 0x00000000 },
+    { 0x00008298, 0x00000000 },
+    { 0x00008300, 0x00000000 },
+    { 0x00008304, 0x00000000 },
+    { 0x00008308, 0x00000000 },
+    { 0x0000830c, 0x00000000 },
+    { 0x00008310, 0x00000000 },
+    { 0x00008314, 0x00000000 },
+    { 0x00008318, 0x00000000 },
+    { 0x00008328, 0x00000000 },
+    { 0x0000832c, 0x00000007 },
+    { 0x00008330, 0x00000302 },
+    { 0x00008334, 0x00000e00 },
+    { 0x00008338, 0x00070000 },
+    { 0x0000833c, 0x00000000 },
+    { 0x00008340, 0x000107ff },
+    { 0x00009808, 0x00000000 },
+    { 0x0000980c, 0xad848e19 },
+    { 0x00009810, 0x7d14e000 },
+    { 0x00009814, 0x9c0a9f6b },
+    { 0x0000981c, 0x00000000 },
+    { 0x0000982c, 0x0000a000 },
+    { 0x00009830, 0x00000000 },
+    { 0x0000983c, 0x00200400 },
+    { 0x00009840, 0x206a002e },
+    { 0x0000984c, 0x1284233c },
+    { 0x00009854, 0x00000859 },
+    { 0x00009900, 0x00000000 },
+    { 0x00009904, 0x00000000 },
+    { 0x00009908, 0x00000000 },
+    { 0x0000990c, 0x00000000 },
+    { 0x0000991c, 0x10000fff },
+    { 0x00009920, 0x05100000 },
+    { 0x0000a920, 0x05100000 },
+    { 0x0000b920, 0x05100000 },
+    { 0x00009928, 0x00000001 },
+    { 0x0000992c, 0x00000004 },
+    { 0x00009934, 0x1e1f2022 },
+    { 0x00009938, 0x0a0b0c0d },
+    { 0x0000993c, 0x00000000 },
+    { 0x00009948, 0x9280b212 },
+    { 0x0000994c, 0x00020028 },
+    { 0x00009954, 0x5d50e188 },
+    { 0x00009958, 0x00081fff },
+    { 0x0000c95c, 0x004b6a8e },
+    { 0x0000c968, 0x000003ce },
+    { 0x00009970, 0x190fb515 },
+    { 0x00009974, 0x00000000 },
+    { 0x00009978, 0x00000001 },
+    { 0x0000997c, 0x00000000 },
+    { 0x00009980, 0x00000000 },
+    { 0x00009984, 0x00000000 },
+    { 0x00009988, 0x00000000 },
+    { 0x0000998c, 0x00000000 },
+    { 0x00009990, 0x00000000 },
+    { 0x00009994, 0x00000000 },
+    { 0x00009998, 0x00000000 },
+    { 0x0000999c, 0x00000000 },
+    { 0x000099a0, 0x00000000 },
+    { 0x000099a4, 0x00000001 },
+    { 0x000099a8, 0x001fff00 },
+    { 0x000099ac, 0x00000000 },
+    { 0x000099b0, 0x03051000 },
+    { 0x000099dc, 0x00000000 },
+    { 0x000099e0, 0x00000200 },
+    { 0x000099e4, 0xaaaaaaaa },
+    { 0x000099e8, 0x3c466478 },
+    { 0x000099ec, 0x000000aa },
+    { 0x000099fc, 0x00001042 },
+    { 0x00009b00, 0x00000000 },
+    { 0x00009b04, 0x00000001 },
+    { 0x00009b08, 0x00000002 },
+    { 0x00009b0c, 0x00000003 },
+    { 0x00009b10, 0x00000004 },
+    { 0x00009b14, 0x00000005 },
+    { 0x00009b18, 0x00000008 },
+    { 0x00009b1c, 0x00000009 },
+    { 0x00009b20, 0x0000000a },
+    { 0x00009b24, 0x0000000b },
+    { 0x00009b28, 0x0000000c },
+    { 0x00009b2c, 0x0000000d },
+    { 0x00009b30, 0x00000010 },
+    { 0x00009b34, 0x00000011 },
+    { 0x00009b38, 0x00000012 },
+    { 0x00009b3c, 0x00000013 },
+    { 0x00009b40, 0x00000014 },
+    { 0x00009b44, 0x00000015 },
+    { 0x00009b48, 0x00000018 },
+    { 0x00009b4c, 0x00000019 },
+    { 0x00009b50, 0x0000001a },
+    { 0x00009b54, 0x0000001b },
+    { 0x00009b58, 0x0000001c },
+    { 0x00009b5c, 0x0000001d },
+    { 0x00009b60, 0x00000020 },
+    { 0x00009b64, 0x00000021 },
+    { 0x00009b68, 0x00000022 },
+    { 0x00009b6c, 0x00000023 },
+    { 0x00009b70, 0x00000024 },
+    { 0x00009b74, 0x00000025 },
+    { 0x00009b78, 0x00000028 },
+    { 0x00009b7c, 0x00000029 },
+    { 0x00009b80, 0x0000002a },
+    { 0x00009b84, 0x0000002b },
+    { 0x00009b88, 0x0000002c },
+    { 0x00009b8c, 0x0000002d },
+    { 0x00009b90, 0x00000030 },
+    { 0x00009b94, 0x00000031 },
+    { 0x00009b98, 0x00000032 },
+    { 0x00009b9c, 0x00000033 },
+    { 0x00009ba0, 0x00000034 },
+    { 0x00009ba4, 0x00000035 },
+    { 0x00009ba8, 0x00000035 },
+    { 0x00009bac, 0x00000035 },
+    { 0x00009bb0, 0x00000035 },
+    { 0x00009bb4, 0x00000035 },
+    { 0x00009bb8, 0x00000035 },
+    { 0x00009bbc, 0x00000035 },
+    { 0x00009bc0, 0x00000035 },
+    { 0x00009bc4, 0x00000035 },
+    { 0x00009bc8, 0x00000035 },
+    { 0x00009bcc, 0x00000035 },
+    { 0x00009bd0, 0x00000035 },
+    { 0x00009bd4, 0x00000035 },
+    { 0x00009bd8, 0x00000035 },
+    { 0x00009bdc, 0x00000035 },
+    { 0x00009be0, 0x00000035 },
+    { 0x00009be4, 0x00000035 },
+    { 0x00009be8, 0x00000035 },
+    { 0x00009bec, 0x00000035 },
+    { 0x00009bf0, 0x00000035 },
+    { 0x00009bf4, 0x00000035 },
+    { 0x00009bf8, 0x00000010 },
+    { 0x00009bfc, 0x0000001a },
+    { 0x0000a210, 0x40806333 },
+    { 0x0000a214, 0x00106c10 },
+    { 0x0000a218, 0x009c4060 },
+    { 0x0000a220, 0x018830c6 },
+    { 0x0000a224, 0x00000400 },
+    { 0x0000a228, 0x00000bb5 },
+    { 0x0000a22c, 0x00000011 },
+    { 0x0000a234, 0x20202020 },
+    { 0x0000a238, 0x20202020 },
+    { 0x0000a23c, 0x13c889af },
+    { 0x0000a240, 0x38490a20 },
+    { 0x0000a244, 0x00007bb6 },
+    { 0x0000a248, 0x0fff3ffc },
+    { 0x0000a24c, 0x00000001 },
+    { 0x0000a250, 0x0000a000 },
+    { 0x0000a254, 0x00000000 },
+    { 0x0000a258, 0x0cc75380 },
+    { 0x0000a25c, 0x0f0f0f01 },
+    { 0x0000a260, 0xdfa91f01 },
+    { 0x0000a268, 0x00000000 },
+    { 0x0000a26c, 0x0e79e5c6 },
+    { 0x0000b26c, 0x0e79e5c6 },
+    { 0x0000c26c, 0x0e79e5c6 },
+    { 0x0000d270, 0x00820820 },
+    { 0x0000a278, 0x1ce739ce },
+    { 0x0000a27c, 0x051701ce },
+    { 0x0000a338, 0x00000000 },
+    { 0x0000a33c, 0x00000000 },
+    { 0x0000a340, 0x00000000 },
+    { 0x0000a344, 0x00000000 },
+    { 0x0000a348, 0x3fffffff },
+    { 0x0000a34c, 0x3fffffff },
+    { 0x0000a350, 0x3fffffff },
+    { 0x0000a354, 0x0003ffff },
+    { 0x0000a358, 0x79a8aa1f },
+    { 0x0000d35c, 0x07ffffef },
+    { 0x0000d360, 0x0fffffe7 },
+    { 0x0000d364, 0x17ffffe5 },
+    { 0x0000d368, 0x1fffffe4 },
+    { 0x0000d36c, 0x37ffffe3 },
+    { 0x0000d370, 0x3fffffe3 },
+    { 0x0000d374, 0x57ffffe3 },
+    { 0x0000d378, 0x5fffffe2 },
+    { 0x0000d37c, 0x7fffffe2 },
+    { 0x0000d380, 0x7f3c7bba },
+    { 0x0000d384, 0xf3307ff0 },
+    { 0x0000a388, 0x08000000 },
+    { 0x0000a38c, 0x20202020 },
+    { 0x0000a390, 0x20202020 },
+    { 0x0000a394, 0x1ce739ce },
+    { 0x0000a398, 0x000001ce },
+    { 0x0000a39c, 0x00000001 },
+    { 0x0000a3a0, 0x00000000 },
+    { 0x0000a3a4, 0x00000000 },
+    { 0x0000a3a8, 0x00000000 },
+    { 0x0000a3ac, 0x00000000 },
+    { 0x0000a3b0, 0x00000000 },
+    { 0x0000a3b4, 0x00000000 },
+    { 0x0000a3b8, 0x00000000 },
+    { 0x0000a3bc, 0x00000000 },
+    { 0x0000a3c0, 0x00000000 },
+    { 0x0000a3c4, 0x00000000 },
+    { 0x0000a3c8, 0x00000246 },
+    { 0x0000a3cc, 0x20202020 },
+    { 0x0000a3d0, 0x20202020 },
+    { 0x0000a3d4, 0x20202020 },
+    { 0x0000a3dc, 0x1ce739ce },
+    { 0x0000a3e0, 0x000001ce },
+};
+
+static const u32 ar5416Bank0[][2] = {
+    { 0x000098b0, 0x1e5795e5 },
+    { 0x000098e0, 0x02008020 },
+};
+
+static const u32 ar5416BB_RfGain[][3] = {
+    { 0x00009a00, 0x00000000, 0x00000000 },
+    { 0x00009a04, 0x00000040, 0x00000040 },
+    { 0x00009a08, 0x00000080, 0x00000080 },
+    { 0x00009a0c, 0x000001a1, 0x00000141 },
+    { 0x00009a10, 0x000001e1, 0x00000181 },
+    { 0x00009a14, 0x00000021, 0x000001c1 },
+    { 0x00009a18, 0x00000061, 0x00000001 },
+    { 0x00009a1c, 0x00000168, 0x00000041 },
+    { 0x00009a20, 0x000001a8, 0x000001a8 },
+    { 0x00009a24, 0x000001e8, 0x000001e8 },
+    { 0x00009a28, 0x00000028, 0x00000028 },
+    { 0x00009a2c, 0x00000068, 0x00000068 },
+    { 0x00009a30, 0x00000189, 0x000000a8 },
+    { 0x00009a34, 0x000001c9, 0x00000169 },
+    { 0x00009a38, 0x00000009, 0x000001a9 },
+    { 0x00009a3c, 0x00000049, 0x000001e9 },
+    { 0x00009a40, 0x00000089, 0x00000029 },
+    { 0x00009a44, 0x00000170, 0x00000069 },
+    { 0x00009a48, 0x000001b0, 0x00000190 },
+    { 0x00009a4c, 0x000001f0, 0x000001d0 },
+    { 0x00009a50, 0x00000030, 0x00000010 },
+    { 0x00009a54, 0x00000070, 0x00000050 },
+    { 0x00009a58, 0x00000191, 0x00000090 },
+    { 0x00009a5c, 0x000001d1, 0x00000151 },
+    { 0x00009a60, 0x00000011, 0x00000191 },
+    { 0x00009a64, 0x00000051, 0x000001d1 },
+    { 0x00009a68, 0x00000091, 0x00000011 },
+    { 0x00009a6c, 0x000001b8, 0x00000051 },
+    { 0x00009a70, 0x000001f8, 0x00000198 },
+    { 0x00009a74, 0x00000038, 0x000001d8 },
+    { 0x00009a78, 0x00000078, 0x00000018 },
+    { 0x00009a7c, 0x00000199, 0x00000058 },
+    { 0x00009a80, 0x000001d9, 0x00000098 },
+    { 0x00009a84, 0x00000019, 0x00000159 },
+    { 0x00009a88, 0x00000059, 0x00000199 },
+    { 0x00009a8c, 0x00000099, 0x000001d9 },
+    { 0x00009a90, 0x000000d9, 0x00000019 },
+    { 0x00009a94, 0x000000f9, 0x00000059 },
+    { 0x00009a98, 0x000000f9, 0x00000099 },
+    { 0x00009a9c, 0x000000f9, 0x000000d9 },
+    { 0x00009aa0, 0x000000f9, 0x000000f9 },
+    { 0x00009aa4, 0x000000f9, 0x000000f9 },
+    { 0x00009aa8, 0x000000f9, 0x000000f9 },
+    { 0x00009aac, 0x000000f9, 0x000000f9 },
+    { 0x00009ab0, 0x000000f9, 0x000000f9 },
+    { 0x00009ab4, 0x000000f9, 0x000000f9 },
+    { 0x00009ab8, 0x000000f9, 0x000000f9 },
+    { 0x00009abc, 0x000000f9, 0x000000f9 },
+    { 0x00009ac0, 0x000000f9, 0x000000f9 },
+    { 0x00009ac4, 0x000000f9, 0x000000f9 },
+    { 0x00009ac8, 0x000000f9, 0x000000f9 },
+    { 0x00009acc, 0x000000f9, 0x000000f9 },
+    { 0x00009ad0, 0x000000f9, 0x000000f9 },
+    { 0x00009ad4, 0x000000f9, 0x000000f9 },
+    { 0x00009ad8, 0x000000f9, 0x000000f9 },
+    { 0x00009adc, 0x000000f9, 0x000000f9 },
+    { 0x00009ae0, 0x000000f9, 0x000000f9 },
+    { 0x00009ae4, 0x000000f9, 0x000000f9 },
+    { 0x00009ae8, 0x000000f9, 0x000000f9 },
+    { 0x00009aec, 0x000000f9, 0x000000f9 },
+    { 0x00009af0, 0x000000f9, 0x000000f9 },
+    { 0x00009af4, 0x000000f9, 0x000000f9 },
+    { 0x00009af8, 0x000000f9, 0x000000f9 },
+    { 0x00009afc, 0x000000f9, 0x000000f9 },
+};
+
+static const u32 ar5416Bank1[][2] = {
+    { 0x000098b0, 0x02108421 },
+    { 0x000098ec, 0x00000008 },
+};
+
+static const u32 ar5416Bank2[][2] = {
+    { 0x000098b0, 0x0e73ff17 },
+    { 0x000098e0, 0x00000420 },
+};
+
+static const u32 ar5416Bank3[][3] = {
+    { 0x000098f0, 0x01400018, 0x01c00018 },
+};
+
+static const u32 ar5416Bank6[][3] = {
+
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00e00000, 0x00e00000 },
+    { 0x0000989c, 0x005e0000, 0x005e0000 },
+    { 0x0000989c, 0x00120000, 0x00120000 },
+    { 0x0000989c, 0x00620000, 0x00620000 },
+    { 0x0000989c, 0x00020000, 0x00020000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+    { 0x0000989c, 0x005f0000, 0x005f0000 },
+    { 0x0000989c, 0x00870000, 0x00870000 },
+    { 0x0000989c, 0x00f90000, 0x00f90000 },
+    { 0x0000989c, 0x007b0000, 0x007b0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00f50000, 0x00f50000 },
+    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+    { 0x0000989c, 0x00110000, 0x00110000 },
+    { 0x0000989c, 0x006100a8, 0x006100a8 },
+    { 0x0000989c, 0x004210a2, 0x004210a2 },
+    { 0x0000989c, 0x0014008f, 0x0014008f },
+    { 0x0000989c, 0x00c40003, 0x00c40003 },
+    { 0x0000989c, 0x003000f2, 0x003000f2 },
+    { 0x0000989c, 0x00440016, 0x00440016 },
+    { 0x0000989c, 0x00410040, 0x00410040 },
+    { 0x0000989c, 0x0001805e, 0x0001805e },
+    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+    { 0x0000989c, 0x000000f1, 0x000000f1 },
+    { 0x0000989c, 0x00002081, 0x00002081 },
+    { 0x0000989c, 0x000000d4, 0x000000d4 },
+    { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank6TPC[][3] = {
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00e00000, 0x00e00000 },
+    { 0x0000989c, 0x005e0000, 0x005e0000 },
+    { 0x0000989c, 0x00120000, 0x00120000 },
+    { 0x0000989c, 0x00620000, 0x00620000 },
+    { 0x0000989c, 0x00020000, 0x00020000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+    { 0x0000989c, 0x005f0000, 0x005f0000 },
+    { 0x0000989c, 0x00870000, 0x00870000 },
+    { 0x0000989c, 0x00f90000, 0x00f90000 },
+    { 0x0000989c, 0x007b0000, 0x007b0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00f50000, 0x00f50000 },
+    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+    { 0x0000989c, 0x00110000, 0x00110000 },
+    { 0x0000989c, 0x006100a8, 0x006100a8 },
+    { 0x0000989c, 0x00423022, 0x00423022 },
+    { 0x0000989c, 0x201400df, 0x201400df },
+    { 0x0000989c, 0x00c40002, 0x00c40002 },
+    { 0x0000989c, 0x003000f2, 0x003000f2 },
+    { 0x0000989c, 0x00440016, 0x00440016 },
+    { 0x0000989c, 0x00410040, 0x00410040 },
+    { 0x0000989c, 0x0001805e, 0x0001805e },
+    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+    { 0x0000989c, 0x000000e1, 0x000000e1 },
+    { 0x0000989c, 0x00007081, 0x00007081 },
+    { 0x0000989c, 0x000000d4, 0x000000d4 },
+    { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank7[][2] = {
+    { 0x0000989c, 0x00000500 },
+    { 0x0000989c, 0x00000800 },
+    { 0x000098cc, 0x0000000e },
+};
+
+static const u32 ar5416Addac[][2] = {
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000003 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x0000000c },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000030 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000060 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000058 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x000098cc,  0x00000000 },
+};
+
+static const u32 ar5416Modes_9100[][6] = {
+    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
+    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
+    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e },
+    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
+    { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
+    { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
+    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
+    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
+    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d },
+    { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 },
+    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
+    { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e },
+    { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff },
+#ifdef TB243
+    { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
+    { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
+    { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
+    { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 },
+#else
+    { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
+    { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
+    { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
+    { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+#endif
+    { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 },
+    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
+    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
+    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
+    { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
+    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
+    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
+    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
+    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
+    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
+    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
+    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
+    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
+    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
+    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
+    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+#endif /* INITVALS_AR5008_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
new file mode 100644 (file)
index 0000000..b2c17c9
--- /dev/null
@@ -0,0 +1,1374 @@
+/*
+ * Copyright (c) 2008-2010 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 "hw.h"
+#include "hw-ops.h"
+#include "../regd.h"
+#include "ar9002_phy.h"
+
+/* All code below is for non single-chip solutions */
+
+/**
+ * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
+ * @rfbuf:
+ * @reg32:
+ * @numBits:
+ * @firstBit:
+ * @column:
+ *
+ * Performs analog "swizzling" of parameters into their location.
+ * Used on external AR2133/AR5133 radios.
+ */
+static void ar5008_hw_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
+                                          u32 numBits, u32 firstBit,
+                                          u32 column)
+{
+       u32 tmp32, mask, arrayEntry, lastBit;
+       int32_t bitPosition, bitsLeft;
+
+       tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
+       arrayEntry = (firstBit - 1) / 8;
+       bitPosition = (firstBit - 1) % 8;
+       bitsLeft = numBits;
+       while (bitsLeft > 0) {
+               lastBit = (bitPosition + bitsLeft > 8) ?
+                   8 : bitPosition + bitsLeft;
+               mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
+                   (column * 8);
+               rfBuf[arrayEntry] &= ~mask;
+               rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
+                                     (column * 8)) & mask;
+               bitsLeft -= 8 - bitPosition;
+               tmp32 = tmp32 >> (8 - bitPosition);
+               bitPosition = 0;
+               arrayEntry++;
+       }
+}
+
+/*
+ * Fix on 2.4 GHz band for orientation sensitivity issue by increasing
+ * rf_pwd_icsyndiv.
+ *
+ * Theoretical Rules:
+ *   if 2 GHz band
+ *      if forceBiasAuto
+ *         if synth_freq < 2412
+ *            bias = 0
+ *         else if 2412 <= synth_freq <= 2422
+ *            bias = 1
+ *         else // synth_freq > 2422
+ *            bias = 2
+ *      else if forceBias > 0
+ *         bias = forceBias & 7
+ *      else
+ *         no change, use value from ini file
+ *   else
+ *      no change, invalid band
+ *
+ *  1st Mod:
+ *    2422 also uses value of 2
+ *    <approved>
+ *
+ *  2nd Mod:
+ *    Less than 2412 uses value of 0, 2412 and above uses value of 2
+ */
+static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 tmp_reg;
+       int reg_writes = 0;
+       u32 new_bias = 0;
+
+       if (!AR_SREV_5416(ah) || synth_freq >= 3000)
+               return;
+
+       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
+
+       if (synth_freq < 2412)
+               new_bias = 0;
+       else if (synth_freq < 2422)
+               new_bias = 1;
+       else
+               new_bias = 2;
+
+       /* pre-reverse this field */
+       tmp_reg = ath9k_hw_reverse_bits(new_bias, 3);
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "Force rf_pwd_icsyndiv to %1d on %4d\n",
+                 new_bias, synth_freq);
+
+       /* swizzle rf_pwd_icsyndiv */
+       ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
+
+       /* write Bank 6 with new params */
+       REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
+}
+
+/**
+ * ar5008_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
+ * @ah: atheros hardware stucture
+ * @chan:
+ *
+ * For the external AR2133/AR5133 radios, takes the MHz channel value and set
+ * the channel value. Assumes writes enabled to analog bus and bank6 register
+ * cache in ah->analogBank6Data.
+ */
+static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 channelSel = 0;
+       u32 bModeSynth = 0;
+       u32 aModeRefSel = 0;
+       u32 reg32 = 0;
+       u16 freq;
+       struct chan_centers centers;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = centers.synth_center;
+
+       if (freq < 4800) {
+               u32 txctl;
+
+               if (((freq - 2192) % 5) == 0) {
+                       channelSel = ((freq - 672) * 2 - 3040) / 10;
+                       bModeSynth = 0;
+               } else if (((freq - 2224) % 5) == 0) {
+                       channelSel = ((freq - 704) * 2 - 3040) / 10;
+                       bModeSynth = 1;
+               } else {
+                       ath_print(common, ATH_DBG_FATAL,
+                                 "Invalid channel %u MHz\n", freq);
+                       return -EINVAL;
+               }
+
+               channelSel = (channelSel << 2) & 0xff;
+               channelSel = ath9k_hw_reverse_bits(channelSel, 8);
+
+               txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+               if (freq == 2484) {
+
+                       REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+                                 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+               } else {
+                       REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+                                 txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+               }
+
+       } else if ((freq % 20) == 0 && freq >= 5120) {
+               channelSel =
+                   ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
+               aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+       } else if ((freq % 10) == 0) {
+               channelSel =
+                   ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
+               if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
+                       aModeRefSel = ath9k_hw_reverse_bits(2, 2);
+               else
+                       aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+       } else if ((freq % 5) == 0) {
+               channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
+               aModeRefSel = ath9k_hw_reverse_bits(1, 2);
+       } else {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Invalid channel %u MHz\n", freq);
+               return -EINVAL;
+       }
+
+       ar5008_hw_force_bias(ah, freq);
+
+       reg32 =
+           (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
+           (1 << 5) | 0x1;
+
+       REG_WRITE(ah, AR_PHY(0x37), reg32);
+
+       ah->curchan = chan;
+       ah->curchan_rad_index = -1;
+
+       return 0;
+}
+
+/**
+ * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For non single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ */
+static void ar5008_hw_spur_mitigate(struct ath_hw *ah,
+                                   struct ath9k_channel *chan)
+{
+       int bb_spur = AR_NO_SPUR;
+       int bin, cur_bin;
+       int spur_freq_sd;
+       int spur_delta_phase;
+       int denominator;
+       int upper, lower, cur_vit_mask;
+       int tmp, new;
+       int i;
+       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
+                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+       };
+       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
+                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+       };
+       int inc[4] = { 0, 100, 0, 0 };
+
+       int8_t mask_m[123];
+       int8_t mask_p[123];
+       int8_t mask_amt;
+       int tmp_mask;
+       int cur_bb_spur;
+       bool is2GHz = IS_CHAN_2GHZ(chan);
+
+       memset(&mask_m, 0, sizeof(int8_t) * 123);
+       memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+               cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+               if (AR_NO_SPUR == cur_bb_spur)
+                       break;
+               cur_bb_spur = cur_bb_spur - (chan->channel * 10);
+               if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
+                       bb_spur = cur_bb_spur;
+                       break;
+               }
+       }
+
+       if (AR_NO_SPUR == bb_spur)
+               return;
+
+       bin = bb_spur * 32;
+
+       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+       new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+                    AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+                    AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+                    AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+
+       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
+
+       new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+              AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+              AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+              AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+              SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+       REG_WRITE(ah, AR_PHY_SPUR_REG, new);
+
+       spur_delta_phase = ((bb_spur * 524288) / 100) &
+               AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+       denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
+       spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
+
+       new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+              SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+              SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+       REG_WRITE(ah, AR_PHY_TIMING11, new);
+
+       cur_bin = -6000;
+       upper = bin + 100;
+       lower = bin - 100;
+
+       for (i = 0; i < 4; i++) {
+               int pilot_mask = 0;
+               int chan_mask = 0;
+               int bp = 0;
+               for (bp = 0; bp < 30; bp++) {
+                       if ((cur_bin > lower) && (cur_bin < upper)) {
+                               pilot_mask = pilot_mask | 0x1 << bp;
+                               chan_mask = chan_mask | 0x1 << bp;
+                       }
+                       cur_bin += 100;
+               }
+               cur_bin += inc[i];
+               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+       }
+
+       cur_vit_mask = 6100;
+       upper = bin + 120;
+       lower = bin - 120;
+
+       for (i = 0; i < 123; i++) {
+               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+                       /* workaround for gcc bug #37014 */
+                       volatile int tmp_v = abs(cur_vit_mask - bin);
+
+                       if (tmp_v < 75)
+                               mask_amt = 1;
+                       else
+                               mask_amt = 0;
+                       if (cur_vit_mask < 0)
+                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+                       else
+                               mask_p[cur_vit_mask / 100] = mask_amt;
+               }
+               cur_vit_mask -= 100;
+       }
+
+       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+               | (mask_m[48] << 26) | (mask_m[49] << 24)
+               | (mask_m[50] << 22) | (mask_m[51] << 20)
+               | (mask_m[52] << 18) | (mask_m[53] << 16)
+               | (mask_m[54] << 14) | (mask_m[55] << 12)
+               | (mask_m[56] << 10) | (mask_m[57] << 8)
+               | (mask_m[58] << 6) | (mask_m[59] << 4)
+               | (mask_m[60] << 2) | (mask_m[61] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+       tmp_mask = (mask_m[31] << 28)
+               | (mask_m[32] << 26) | (mask_m[33] << 24)
+               | (mask_m[34] << 22) | (mask_m[35] << 20)
+               | (mask_m[36] << 18) | (mask_m[37] << 16)
+               | (mask_m[48] << 14) | (mask_m[39] << 12)
+               | (mask_m[40] << 10) | (mask_m[41] << 8)
+               | (mask_m[42] << 6) | (mask_m[43] << 4)
+               | (mask_m[44] << 2) | (mask_m[45] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+               | (mask_m[18] << 26) | (mask_m[18] << 24)
+               | (mask_m[20] << 22) | (mask_m[20] << 20)
+               | (mask_m[22] << 18) | (mask_m[22] << 16)
+               | (mask_m[24] << 14) | (mask_m[24] << 12)
+               | (mask_m[25] << 10) | (mask_m[26] << 8)
+               | (mask_m[27] << 6) | (mask_m[28] << 4)
+               | (mask_m[29] << 2) | (mask_m[30] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+               | (mask_m[2] << 26) | (mask_m[3] << 24)
+               | (mask_m[4] << 22) | (mask_m[5] << 20)
+               | (mask_m[6] << 18) | (mask_m[7] << 16)
+               | (mask_m[8] << 14) | (mask_m[9] << 12)
+               | (mask_m[10] << 10) | (mask_m[11] << 8)
+               | (mask_m[12] << 6) | (mask_m[13] << 4)
+               | (mask_m[14] << 2) | (mask_m[15] << 0);
+       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+       tmp_mask = (mask_p[15] << 28)
+               | (mask_p[14] << 26) | (mask_p[13] << 24)
+               | (mask_p[12] << 22) | (mask_p[11] << 20)
+               | (mask_p[10] << 18) | (mask_p[9] << 16)
+               | (mask_p[8] << 14) | (mask_p[7] << 12)
+               | (mask_p[6] << 10) | (mask_p[5] << 8)
+               | (mask_p[4] << 6) | (mask_p[3] << 4)
+               | (mask_p[2] << 2) | (mask_p[1] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+
+       tmp_mask = (mask_p[30] << 28)
+               | (mask_p[29] << 26) | (mask_p[28] << 24)
+               | (mask_p[27] << 22) | (mask_p[26] << 20)
+               | (mask_p[25] << 18) | (mask_p[24] << 16)
+               | (mask_p[23] << 14) | (mask_p[22] << 12)
+               | (mask_p[21] << 10) | (mask_p[20] << 8)
+               | (mask_p[19] << 6) | (mask_p[18] << 4)
+               | (mask_p[17] << 2) | (mask_p[16] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+
+       tmp_mask = (mask_p[45] << 28)
+               | (mask_p[44] << 26) | (mask_p[43] << 24)
+               | (mask_p[42] << 22) | (mask_p[41] << 20)
+               | (mask_p[40] << 18) | (mask_p[39] << 16)
+               | (mask_p[38] << 14) | (mask_p[37] << 12)
+               | (mask_p[36] << 10) | (mask_p[35] << 8)
+               | (mask_p[34] << 6) | (mask_p[33] << 4)
+               | (mask_p[32] << 2) | (mask_p[31] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+
+       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+               | (mask_p[59] << 26) | (mask_p[58] << 24)
+               | (mask_p[57] << 22) | (mask_p[56] << 20)
+               | (mask_p[55] << 18) | (mask_p[54] << 16)
+               | (mask_p[53] << 14) | (mask_p[52] << 12)
+               | (mask_p[51] << 10) | (mask_p[50] << 8)
+               | (mask_p[49] << 6) | (mask_p[48] << 4)
+               | (mask_p[47] << 2) | (mask_p[46] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+}
+
+/**
+ * ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming
+ * @ah: atheros hardware structure
+ *
+ * Only required for older devices with external AR2133/AR5133 radios.
+ */
+static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah)
+{
+#define ATH_ALLOC_BANK(bank, size) do { \
+               bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
+               if (!bank) { \
+                       ath_print(common, ATH_DBG_FATAL, \
+                                 "Cannot allocate RF banks\n"); \
+                       return -ENOMEM; \
+               } \
+       } while (0);
+
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
+
+       ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
+       ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
+       ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
+       ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
+       ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
+       ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
+       ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
+       ATH_ALLOC_BANK(ah->addac5416_21,
+                      ah->iniAddac.ia_rows * ah->iniAddac.ia_columns);
+       ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
+
+       return 0;
+#undef ATH_ALLOC_BANK
+}
+
+
+/**
+ * ar5008_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
+ * @ah: atheros hardware struture
+ * For the external AR2133/AR5133 radios banks.
+ */
+static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah)
+{
+#define ATH_FREE_BANK(bank) do { \
+               kfree(bank); \
+               bank = NULL; \
+       } while (0);
+
+       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
+
+       ATH_FREE_BANK(ah->analogBank0Data);
+       ATH_FREE_BANK(ah->analogBank1Data);
+       ATH_FREE_BANK(ah->analogBank2Data);
+       ATH_FREE_BANK(ah->analogBank3Data);
+       ATH_FREE_BANK(ah->analogBank6Data);
+       ATH_FREE_BANK(ah->analogBank6TPCData);
+       ATH_FREE_BANK(ah->analogBank7Data);
+       ATH_FREE_BANK(ah->addac5416_21);
+       ATH_FREE_BANK(ah->bank6Temp);
+
+#undef ATH_FREE_BANK
+}
+
+/* *
+ * ar5008_hw_set_rf_regs - programs rf registers based on EEPROM
+ * @ah: atheros hardware structure
+ * @chan:
+ * @modesIndex:
+ *
+ * Used for the external AR2133/AR5133 radios.
+ *
+ * Reads the EEPROM header info from the device structure and programs
+ * all rf registers. This routine requires access to the analog
+ * rf device. This is not required for single-chip devices.
+ */
+static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
+                                 struct ath9k_channel *chan,
+                                 u16 modesIndex)
+{
+       u32 eepMinorRev;
+       u32 ob5GHz = 0, db5GHz = 0;
+       u32 ob2GHz = 0, db2GHz = 0;
+       int regWrites = 0;
+
+       /*
+        * Software does not need to program bank data
+        * for single chip devices, that is AR9280 or anything
+        * after that.
+        */
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               return true;
+
+       /* Setup rf parameters */
+       eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
+
+       /* Setup Bank 0 Write */
+       RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
+
+       /* Setup Bank 1 Write */
+       RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
+
+       /* Setup Bank 2 Write */
+       RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
+
+       /* Setup Bank 6 Write */
+       RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3,
+                     modesIndex);
+       {
+               int i;
+               for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
+                       ah->analogBank6Data[i] =
+                           INI_RA(&ah->iniBank6TPC, i, modesIndex);
+               }
+       }
+
+       /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
+       if (eepMinorRev >= 2) {
+               if (IS_CHAN_2GHZ(chan)) {
+                       ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2);
+                       db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2);
+                       ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+                                                      ob2GHz, 3, 197, 0);
+                       ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+                                                      db2GHz, 3, 194, 0);
+               } else {
+                       ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5);
+                       db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5);
+                       ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+                                                      ob5GHz, 3, 203, 0);
+                       ar5008_hw_phy_modify_rx_buffer(ah->analogBank6Data,
+                                                      db5GHz, 3, 200, 0);
+               }
+       }
+
+       /* Setup Bank 7 Setup */
+       RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
+
+       /* Write Analog registers */
+       REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
+                          regWrites);
+       REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
+                          regWrites);
+       REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
+                          regWrites);
+       REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
+                          regWrites);
+       REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
+                          regWrites);
+       REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
+                          regWrites);
+
+       return true;
+}
+
+static void ar5008_hw_init_bb(struct ath_hw *ah,
+                             struct ath9k_channel *chan)
+{
+       u32 synthDelay;
+
+       synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+       if (IS_CHAN_B(chan))
+               synthDelay = (4 * synthDelay) / 22;
+       else
+               synthDelay /= 10;
+
+       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+       udelay(synthDelay + BASE_ACTIVATE_DELAY);
+}
+
+static void ar5008_hw_init_chain_masks(struct ath_hw *ah)
+{
+       int rx_chainmask, tx_chainmask;
+
+       rx_chainmask = ah->rxchainmask;
+       tx_chainmask = ah->txchainmask;
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       switch (rx_chainmask) {
+       case 0x5:
+               DISABLE_REGWRITE_BUFFER(ah);
+               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+                           AR_PHY_SWAP_ALT_CHAIN);
+               ENABLE_REGWRITE_BUFFER(ah);
+       case 0x3:
+               if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
+                       REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
+                       REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
+                       break;
+               }
+       case 0x1:
+       case 0x2:
+       case 0x7:
+               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+               break;
+       default:
+               break;
+       }
+
+       REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (tx_chainmask == 0x5) {
+               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+                           AR_PHY_SWAP_ALT_CHAIN);
+       }
+       if (AR_SREV_9100(ah))
+               REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
+                         REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
+}
+
+static void ar5008_hw_override_ini(struct ath_hw *ah,
+                                  struct ath9k_channel *chan)
+{
+       u32 val;
+
+       /*
+        * Set the RX_ABORT and RX_DIS and clear if off only after
+        * RXE is set for MAC. This prevents frames with corrupted
+        * descriptor status.
+        */
+       REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               val = REG_READ(ah, AR_PCU_MISC_MODE2);
+
+               if (!AR_SREV_9271(ah))
+                       val &= ~AR_PCU_MISC_MODE2_HWWAR1;
+
+               if (AR_SREV_9287_10_OR_LATER(ah))
+                       val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
+
+               REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
+       }
+
+       if (!AR_SREV_5416_20_OR_LATER(ah) ||
+           AR_SREV_9280_10_OR_LATER(ah))
+               return;
+       /*
+        * Disable BB clock gating
+        * Necessary to avoid issues on AR5416 2.0
+        */
+       REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
+
+       /*
+        * Disable RIFS search on some chips to avoid baseband
+        * hang issues.
+        */
+       if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
+               val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
+               val &= ~AR_PHY_RIFS_INIT_DELAY;
+               REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
+       }
+}
+
+static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
+                                      struct ath9k_channel *chan)
+{
+       u32 phymode;
+       u32 enableDacFifo = 0;
+
+       if (AR_SREV_9285_10_OR_LATER(ah))
+               enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
+                                        AR_PHY_FC_ENABLE_DAC_FIFO);
+
+       phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
+               | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
+
+       if (IS_CHAN_HT40(chan)) {
+               phymode |= AR_PHY_FC_DYN2040_EN;
+
+               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+                   (chan->chanmode == CHANNEL_G_HT40PLUS))
+                       phymode |= AR_PHY_FC_DYN2040_PRI_CH;
+
+       }
+       REG_WRITE(ah, AR_PHY_TURBO, phymode);
+
+       ath9k_hw_set11nmac2040(ah);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+       REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+}
+
+
+static int ar5008_hw_process_ini(struct ath_hw *ah,
+                                struct ath9k_channel *chan)
+{
+       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+       int i, regWrites = 0;
+       struct ieee80211_channel *channel = chan->chan;
+       u32 modesIndex, freqIndex;
+
+       switch (chan->chanmode) {
+       case CHANNEL_A:
+       case CHANNEL_A_HT20:
+               modesIndex = 1;
+               freqIndex = 1;
+               break;
+       case CHANNEL_A_HT40PLUS:
+       case CHANNEL_A_HT40MINUS:
+               modesIndex = 2;
+               freqIndex = 1;
+               break;
+       case CHANNEL_G:
+       case CHANNEL_G_HT20:
+       case CHANNEL_B:
+               modesIndex = 4;
+               freqIndex = 2;
+               break;
+       case CHANNEL_G_HT40PLUS:
+       case CHANNEL_G_HT40MINUS:
+               modesIndex = 3;
+               freqIndex = 2;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (AR_SREV_9287_12_OR_LATER(ah)) {
+               /* Enable ASYNC FIFO */
+               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+               REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+               REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+       }
+
+       /*
+        * Set correct baseband to analog shift setting to
+        * access analog chips.
+        */
+       REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+       /* Write ADDAC shifts */
+       REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
+       ah->eep_ops->set_addac(ah, chan);
+
+       if (AR_SREV_5416_22_OR_LATER(ah)) {
+               REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
+       } else {
+               struct ar5416IniArray temp;
+               u32 addacSize =
+                       sizeof(u32) * ah->iniAddac.ia_rows *
+                       ah->iniAddac.ia_columns;
+
+               /* For AR5416 2.0/2.1 */
+               memcpy(ah->addac5416_21,
+                      ah->iniAddac.ia_array, addacSize);
+
+               /* override CLKDRV value at [row, column] = [31, 1] */
+               (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0;
+
+               temp.ia_array = ah->addac5416_21;
+               temp.ia_columns = ah->iniAddac.ia_columns;
+               temp.ia_rows = ah->iniAddac.ia_rows;
+               REG_WRITE_ARRAY(&temp, 1, regWrites);
+       }
+
+       REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       for (i = 0; i < ah->iniModes.ia_rows; i++) {
+               u32 reg = INI_RA(&ah->iniModes, i, 0);
+               u32 val = INI_RA(&ah->iniModes, i, modesIndex);
+
+               if (reg == AR_AN_TOP2 && ah->need_an_top2_fixup)
+                       val &= ~AR_AN_TOP2_PWDCLKIND;
+
+               REG_WRITE(ah, reg, val);
+
+               if (reg >= 0x7800 && reg < 0x78a0
+                   && ah->config.analog_shiftreg) {
+                       udelay(100);
+               }
+
+               DO_DELAY(regWrites);
+       }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
+               REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
+
+       if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
+           AR_SREV_9287_10_OR_LATER(ah))
+               REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+
+       if (AR_SREV_9271_10(ah))
+               REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only,
+                               modesIndex, regWrites);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       /* Write common array parameters */
+       for (i = 0; i < ah->iniCommon.ia_rows; i++) {
+               u32 reg = INI_RA(&ah->iniCommon, i, 0);
+               u32 val = INI_RA(&ah->iniCommon, i, 1);
+
+               REG_WRITE(ah, reg, val);
+
+               if (reg >= 0x7800 && reg < 0x78a0
+                   && ah->config.analog_shiftreg) {
+                       udelay(100);
+               }
+
+               DO_DELAY(regWrites);
+       }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (AR_SREV_9271(ah)) {
+               if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) == 1)
+                       REG_WRITE_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
+                                       modesIndex, regWrites);
+               else
+                       REG_WRITE_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
+                                       modesIndex, regWrites);
+       }
+
+       REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
+
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan)) {
+               REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex,
+                               regWrites);
+       }
+
+       ar5008_hw_override_ini(ah, chan);
+       ar5008_hw_set_channel_regs(ah, chan);
+       ar5008_hw_init_chain_masks(ah);
+       ath9k_olc_init(ah);
+
+       /* Set TX power */
+       ah->eep_ops->set_txpower(ah, chan,
+                                ath9k_regd_get_ctl(regulatory, chan),
+                                channel->max_antenna_gain * 2,
+                                channel->max_power * 2,
+                                min((u32) MAX_RATE_POWER,
+                                (u32) regulatory->power_limit));
+
+       /* Write analog registers */
+       if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
+               ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+                         "ar5416SetRfRegs failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       u32 rfMode = 0;
+
+       if (chan == NULL)
+               return;
+
+       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+       if (!AR_SREV_9280_10_OR_LATER(ah))
+               rfMode |= (IS_CHAN_5GHZ(chan)) ?
+                       AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
+
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+               rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+       REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static void ar5008_hw_mark_phy_inactive(struct ath_hw *ah)
+{
+       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+static void ar5008_hw_set_delta_slope(struct ath_hw *ah,
+                                     struct ath9k_channel *chan)
+{
+       u32 coef_scaled, ds_coef_exp, ds_coef_man;
+       u32 clockMhzScaled = 0x64000000;
+       struct chan_centers centers;
+
+       if (IS_CHAN_HALF_RATE(chan))
+               clockMhzScaled = clockMhzScaled >> 1;
+       else if (IS_CHAN_QUARTER_RATE(chan))
+               clockMhzScaled = clockMhzScaled >> 2;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       coef_scaled = clockMhzScaled / centers.synth_center;
+
+       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+                                     &ds_coef_exp);
+
+       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+                     AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+                     AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
+
+       coef_scaled = (9 * coef_scaled) / 10;
+
+       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+                                     &ds_coef_exp);
+
+       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+                     AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
+       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
+                     AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
+}
+
+static bool ar5008_hw_rfbus_req(struct ath_hw *ah)
+{
+       REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+       return ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+                          AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT);
+}
+
+static void ar5008_hw_rfbus_done(struct ath_hw *ah)
+{
+       u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+       if (IS_CHAN_B(ah->curchan))
+               synthDelay = (4 * synthDelay) / 22;
+       else
+               synthDelay /= 10;
+
+       udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+       REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+}
+
+static void ar5008_hw_enable_rfkill(struct ath_hw *ah)
+{
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+                   AR_GPIO_INPUT_MUX2_RFSILENT);
+
+       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
+       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+
+static void ar5008_restore_chainmask(struct ath_hw *ah)
+{
+       int rx_chainmask = ah->rxchainmask;
+
+       if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
+               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
+               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
+       }
+}
+
+static void ar5008_set_diversity(struct ath_hw *ah, bool value)
+{
+       u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
+       if (value)
+               v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+       else
+               v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+       REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+}
+
+static u32 ar9100_hw_compute_pll_control(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       if (chan && IS_CHAN_5GHZ(chan))
+               return 0x1450;
+       return 0x1458;
+}
+
+static u32 ar9160_hw_compute_pll_control(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       u32 pll;
+
+       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+       if (chan && IS_CHAN_HALF_RATE(chan))
+               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+       if (chan && IS_CHAN_5GHZ(chan))
+               pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
+       else
+               pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
+
+       return pll;
+}
+
+static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       u32 pll;
+
+       pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
+
+       if (chan && IS_CHAN_HALF_RATE(chan))
+               pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
+       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+               pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
+
+       if (chan && IS_CHAN_5GHZ(chan))
+               pll |= SM(0xa, AR_RTC_PLL_DIV);
+       else
+               pll |= SM(0xb, AR_RTC_PLL_DIV);
+
+       return pll;
+}
+
+static bool ar5008_hw_ani_control(struct ath_hw *ah,
+                                 enum ath9k_ani_cmd cmd, int param)
+{
+       struct ar5416AniState *aniState = ah->curani;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       switch (cmd & ah->ani_function) {
+       case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
+                       ath_print(common, ATH_DBG_ANI,
+                                 "level out of range (%u > %u)\n",
+                                 level,
+                                 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
+                       return false;
+               }
+
+               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+                             AR_PHY_DESIRED_SZ_TOT_DES,
+                             ah->totalSizeDesired[level]);
+               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+                             AR_PHY_AGC_CTL1_COARSE_LOW,
+                             ah->coarse_low[level]);
+               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
+                             AR_PHY_AGC_CTL1_COARSE_HIGH,
+                             ah->coarse_high[level]);
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRPWR,
+                             ah->firpwr[level]);
+
+               if (level > aniState->noiseImmunityLevel)
+                       ah->stats.ast_ani_niup++;
+               else if (level < aniState->noiseImmunityLevel)
+                       ah->stats.ast_ani_nidown++;
+               aniState->noiseImmunityLevel = level;
+               break;
+       }
+       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+               const int m1ThreshLow[] = { 127, 50 };
+               const int m2ThreshLow[] = { 127, 40 };
+               const int m1Thresh[] = { 127, 0x4d };
+               const int m2Thresh[] = { 127, 0x40 };
+               const int m2CountThr[] = { 31, 16 };
+               const int m2CountThrLow[] = { 63, 48 };
+               u32 on = param ? 1 : 0;
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+                             m1ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+                             m2ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M1_THRESH,
+                             m1Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2_THRESH,
+                             m2Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2COUNT_THR,
+                             m2CountThr[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+                             m2CountThrLow[on]);
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
+                             m1ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
+                             m2ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH,
+                             m1Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH,
+                             m2Thresh[on]);
+
+               if (on)
+                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+               else
+                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+               if (!on != aniState->ofdmWeakSigDetectOff) {
+                       if (on)
+                               ah->stats.ast_ani_ofdmon++;
+                       else
+                               ah->stats.ast_ani_ofdmoff++;
+                       aniState->ofdmWeakSigDetectOff = !on;
+               }
+               break;
+       }
+       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+               const int weakSigThrCck[] = { 8, 6 };
+               u32 high = param ? 1 : 0;
+
+               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+                             weakSigThrCck[high]);
+               if (high != aniState->cckWeakSigThreshold) {
+                       if (high)
+                               ah->stats.ast_ani_cckhigh++;
+                       else
+                               ah->stats.ast_ani_ccklow++;
+                       aniState->cckWeakSigThreshold = high;
+               }
+               break;
+       }
+       case ATH9K_ANI_FIRSTEP_LEVEL:{
+               const int firstep[] = { 0, 4, 8 };
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(firstep)) {
+                       ath_print(common, ATH_DBG_ANI,
+                                 "level out of range (%u > %u)\n",
+                                 level,
+                                 (unsigned) ARRAY_SIZE(firstep));
+                       return false;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRSTEP,
+                             firstep[level]);
+               if (level > aniState->firstepLevel)
+                       ah->stats.ast_ani_stepup++;
+               else if (level < aniState->firstepLevel)
+                       ah->stats.ast_ani_stepdown++;
+               aniState->firstepLevel = level;
+               break;
+       }
+       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+               const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(cycpwrThr1)) {
+                       ath_print(common, ATH_DBG_ANI,
+                                 "level out of range (%u > %u)\n",
+                                 level,
+                                 (unsigned) ARRAY_SIZE(cycpwrThr1));
+                       return false;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+                             AR_PHY_TIMING5_CYCPWR_THR1,
+                             cycpwrThr1[level]);
+               if (level > aniState->spurImmunityLevel)
+                       ah->stats.ast_ani_spurup++;
+               else if (level < aniState->spurImmunityLevel)
+                       ah->stats.ast_ani_spurdown++;
+               aniState->spurImmunityLevel = level;
+               break;
+       }
+       case ATH9K_ANI_PRESENT:
+               break;
+       default:
+               ath_print(common, ATH_DBG_ANI,
+                         "invalid cmd %u\n", cmd);
+               return false;
+       }
+
+       ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
+       ath_print(common, ATH_DBG_ANI,
+                 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+                 "ofdmWeakSigDetectOff=%d\n",
+                 aniState->noiseImmunityLevel,
+                 aniState->spurImmunityLevel,
+                 !aniState->ofdmWeakSigDetectOff);
+       ath_print(common, ATH_DBG_ANI,
+                 "cckWeakSigThreshold=%d, "
+                 "firstepLevel=%d, listenTime=%d\n",
+                 aniState->cckWeakSigThreshold,
+                 aniState->firstepLevel,
+                 aniState->listenTime);
+       ath_print(common, ATH_DBG_ANI,
+               "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+               aniState->cycleCount,
+               aniState->ofdmPhyErrCount,
+               aniState->cckPhyErrCount);
+
+       return true;
+}
+
+static void ar5008_hw_do_getnf(struct ath_hw *ah,
+                             int16_t nfarray[NUM_NF_READINGS])
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       int16_t nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 0] is %d\n", nf);
+       nfarray[0] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 1] is %d\n", nf);
+       nfarray[1] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 2] is %d\n", nf);
+       nfarray[2] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 0] is %d\n", nf);
+       nfarray[3] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 1] is %d\n", nf);
+       nfarray[4] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 2] is %d\n", nf);
+       nfarray[5] = nf;
+}
+
+static void ar5008_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath9k_nfcal_hist *h;
+       int i, j;
+       int32_t val;
+       const u32 ar5416_cca_regs[6] = {
+               AR_PHY_CCA,
+               AR_PHY_CH1_CCA,
+               AR_PHY_CH2_CCA,
+               AR_PHY_EXT_CCA,
+               AR_PHY_CH1_EXT_CCA,
+               AR_PHY_CH2_EXT_CCA
+       };
+       u8 chainmask, rx_chain_status;
+
+       rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               chainmask = 0x9;
+       else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
+               if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
+                       chainmask = 0x1B;
+               else
+                       chainmask = 0x09;
+       } else {
+               if (rx_chain_status & 0x4)
+                       chainmask = 0x3F;
+               else if (rx_chain_status & 0x2)
+                       chainmask = 0x1B;
+               else
+                       chainmask = 0x09;
+       }
+
+       h = ah->nfCalHist;
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
+                       val = REG_READ(ah, ar5416_cca_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+                       REG_WRITE(ah, ar5416_cca_regs[i], val);
+               }
+       }
+
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_ENABLE_NF);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+       for (j = 0; j < 5; j++) {
+               if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+                    AR_PHY_AGC_CONTROL_NF) == 0)
+                       break;
+               udelay(50);
+       }
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
+                       val = REG_READ(ah, ar5416_cca_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (-50) << 1) & 0x1ff);
+                       REG_WRITE(ah, ar5416_cca_regs[i], val);
+               }
+       }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+}
+
+void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+
+       priv_ops->rf_set_freq = ar5008_hw_set_channel;
+       priv_ops->spur_mitigate_freq = ar5008_hw_spur_mitigate;
+
+       priv_ops->rf_alloc_ext_banks = ar5008_hw_rf_alloc_ext_banks;
+       priv_ops->rf_free_ext_banks = ar5008_hw_rf_free_ext_banks;
+       priv_ops->set_rf_regs = ar5008_hw_set_rf_regs;
+       priv_ops->set_channel_regs = ar5008_hw_set_channel_regs;
+       priv_ops->init_bb = ar5008_hw_init_bb;
+       priv_ops->process_ini = ar5008_hw_process_ini;
+       priv_ops->set_rfmode = ar5008_hw_set_rfmode;
+       priv_ops->mark_phy_inactive = ar5008_hw_mark_phy_inactive;
+       priv_ops->set_delta_slope = ar5008_hw_set_delta_slope;
+       priv_ops->rfbus_req = ar5008_hw_rfbus_req;
+       priv_ops->rfbus_done = ar5008_hw_rfbus_done;
+       priv_ops->enable_rfkill = ar5008_hw_enable_rfkill;
+       priv_ops->restore_chainmask = ar5008_restore_chainmask;
+       priv_ops->set_diversity = ar5008_set_diversity;
+       priv_ops->ani_control = ar5008_hw_ani_control;
+       priv_ops->do_getnf = ar5008_hw_do_getnf;
+       priv_ops->loadnf = ar5008_hw_loadnf;
+
+       if (AR_SREV_9100(ah))
+               priv_ops->compute_pll_control = ar9100_hw_compute_pll_control;
+       else if (AR_SREV_9160_10_OR_LATER(ah))
+               priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
+       else
+               priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
new file mode 100644 (file)
index 0000000..0b94bd3
--- /dev/null
@@ -0,0 +1,1254 @@
+
+static const u32 ar5416Common_9100[][2] = {
+    { 0x0000000c, 0x00000000 },
+    { 0x00000030, 0x00020015 },
+    { 0x00000034, 0x00000005 },
+    { 0x00000040, 0x00000000 },
+    { 0x00000044, 0x00000008 },
+    { 0x00000048, 0x00000008 },
+    { 0x0000004c, 0x00000010 },
+    { 0x00000050, 0x00000000 },
+    { 0x00000054, 0x0000001f },
+    { 0x00000800, 0x00000000 },
+    { 0x00000804, 0x00000000 },
+    { 0x00000808, 0x00000000 },
+    { 0x0000080c, 0x00000000 },
+    { 0x00000810, 0x00000000 },
+    { 0x00000814, 0x00000000 },
+    { 0x00000818, 0x00000000 },
+    { 0x0000081c, 0x00000000 },
+    { 0x00000820, 0x00000000 },
+    { 0x00000824, 0x00000000 },
+    { 0x00001040, 0x002ffc0f },
+    { 0x00001044, 0x002ffc0f },
+    { 0x00001048, 0x002ffc0f },
+    { 0x0000104c, 0x002ffc0f },
+    { 0x00001050, 0x002ffc0f },
+    { 0x00001054, 0x002ffc0f },
+    { 0x00001058, 0x002ffc0f },
+    { 0x0000105c, 0x002ffc0f },
+    { 0x00001060, 0x002ffc0f },
+    { 0x00001064, 0x002ffc0f },
+    { 0x00001230, 0x00000000 },
+    { 0x00001270, 0x00000000 },
+    { 0x00001038, 0x00000000 },
+    { 0x00001078, 0x00000000 },
+    { 0x000010b8, 0x00000000 },
+    { 0x000010f8, 0x00000000 },
+    { 0x00001138, 0x00000000 },
+    { 0x00001178, 0x00000000 },
+    { 0x000011b8, 0x00000000 },
+    { 0x000011f8, 0x00000000 },
+    { 0x00001238, 0x00000000 },
+    { 0x00001278, 0x00000000 },
+    { 0x000012b8, 0x00000000 },
+    { 0x000012f8, 0x00000000 },
+    { 0x00001338, 0x00000000 },
+    { 0x00001378, 0x00000000 },
+    { 0x000013b8, 0x00000000 },
+    { 0x000013f8, 0x00000000 },
+    { 0x00001438, 0x00000000 },
+    { 0x00001478, 0x00000000 },
+    { 0x000014b8, 0x00000000 },
+    { 0x000014f8, 0x00000000 },
+    { 0x00001538, 0x00000000 },
+    { 0x00001578, 0x00000000 },
+    { 0x000015b8, 0x00000000 },
+    { 0x000015f8, 0x00000000 },
+    { 0x00001638, 0x00000000 },
+    { 0x00001678, 0x00000000 },
+    { 0x000016b8, 0x00000000 },
+    { 0x000016f8, 0x00000000 },
+    { 0x00001738, 0x00000000 },
+    { 0x00001778, 0x00000000 },
+    { 0x000017b8, 0x00000000 },
+    { 0x000017f8, 0x00000000 },
+    { 0x0000103c, 0x00000000 },
+    { 0x0000107c, 0x00000000 },
+    { 0x000010bc, 0x00000000 },
+    { 0x000010fc, 0x00000000 },
+    { 0x0000113c, 0x00000000 },
+    { 0x0000117c, 0x00000000 },
+    { 0x000011bc, 0x00000000 },
+    { 0x000011fc, 0x00000000 },
+    { 0x0000123c, 0x00000000 },
+    { 0x0000127c, 0x00000000 },
+    { 0x000012bc, 0x00000000 },
+    { 0x000012fc, 0x00000000 },
+    { 0x0000133c, 0x00000000 },
+    { 0x0000137c, 0x00000000 },
+    { 0x000013bc, 0x00000000 },
+    { 0x000013fc, 0x00000000 },
+    { 0x0000143c, 0x00000000 },
+    { 0x0000147c, 0x00000000 },
+    { 0x00020010, 0x00000003 },
+    { 0x00020038, 0x000004c2 },
+    { 0x00008004, 0x00000000 },
+    { 0x00008008, 0x00000000 },
+    { 0x0000800c, 0x00000000 },
+    { 0x00008018, 0x00000700 },
+    { 0x00008020, 0x00000000 },
+    { 0x00008038, 0x00000000 },
+    { 0x0000803c, 0x00000000 },
+    { 0x00008048, 0x40000000 },
+    { 0x00008054, 0x00004000 },
+    { 0x00008058, 0x00000000 },
+    { 0x0000805c, 0x000fc78f },
+    { 0x00008060, 0x0000000f },
+    { 0x00008064, 0x00000000 },
+    { 0x000080c0, 0x2a82301a },
+    { 0x000080c4, 0x05dc01e0 },
+    { 0x000080c8, 0x1f402710 },
+    { 0x000080cc, 0x01f40000 },
+    { 0x000080d0, 0x00001e00 },
+    { 0x000080d4, 0x00000000 },
+    { 0x000080d8, 0x00400000 },
+    { 0x000080e0, 0xffffffff },
+    { 0x000080e4, 0x0000ffff },
+    { 0x000080e8, 0x003f3f3f },
+    { 0x000080ec, 0x00000000 },
+    { 0x000080f0, 0x00000000 },
+    { 0x000080f4, 0x00000000 },
+    { 0x000080f8, 0x00000000 },
+    { 0x000080fc, 0x00020000 },
+    { 0x00008100, 0x00020000 },
+    { 0x00008104, 0x00000001 },
+    { 0x00008108, 0x00000052 },
+    { 0x0000810c, 0x00000000 },
+    { 0x00008110, 0x00000168 },
+    { 0x00008118, 0x000100aa },
+    { 0x0000811c, 0x00003210 },
+    { 0x00008120, 0x08f04800 },
+    { 0x00008124, 0x00000000 },
+    { 0x00008128, 0x00000000 },
+    { 0x0000812c, 0x00000000 },
+    { 0x00008130, 0x00000000 },
+    { 0x00008134, 0x00000000 },
+    { 0x00008138, 0x00000000 },
+    { 0x0000813c, 0x00000000 },
+    { 0x00008144, 0x00000000 },
+    { 0x00008168, 0x00000000 },
+    { 0x0000816c, 0x00000000 },
+    { 0x00008170, 0x32143320 },
+    { 0x00008174, 0xfaa4fa50 },
+    { 0x00008178, 0x00000100 },
+    { 0x0000817c, 0x00000000 },
+    { 0x000081c4, 0x00000000 },
+    { 0x000081d0, 0x00003210 },
+    { 0x000081ec, 0x00000000 },
+    { 0x000081f0, 0x00000000 },
+    { 0x000081f4, 0x00000000 },
+    { 0x000081f8, 0x00000000 },
+    { 0x000081fc, 0x00000000 },
+    { 0x00008200, 0x00000000 },
+    { 0x00008204, 0x00000000 },
+    { 0x00008208, 0x00000000 },
+    { 0x0000820c, 0x00000000 },
+    { 0x00008210, 0x00000000 },
+    { 0x00008214, 0x00000000 },
+    { 0x00008218, 0x00000000 },
+    { 0x0000821c, 0x00000000 },
+    { 0x00008220, 0x00000000 },
+    { 0x00008224, 0x00000000 },
+    { 0x00008228, 0x00000000 },
+    { 0x0000822c, 0x00000000 },
+    { 0x00008230, 0x00000000 },
+    { 0x00008234, 0x00000000 },
+    { 0x00008238, 0x00000000 },
+    { 0x0000823c, 0x00000000 },
+    { 0x00008240, 0x00100000 },
+    { 0x00008244, 0x0010f400 },
+    { 0x00008248, 0x00000100 },
+    { 0x0000824c, 0x0001e800 },
+    { 0x00008250, 0x00000000 },
+    { 0x00008254, 0x00000000 },
+    { 0x00008258, 0x00000000 },
+    { 0x0000825c, 0x400000ff },
+    { 0x00008260, 0x00080922 },
+    { 0x00008270, 0x00000000 },
+    { 0x00008274, 0x40000000 },
+    { 0x00008278, 0x003e4180 },
+    { 0x0000827c, 0x00000000 },
+    { 0x00008284, 0x0000002c },
+    { 0x00008288, 0x0000002c },
+    { 0x0000828c, 0x00000000 },
+    { 0x00008294, 0x00000000 },
+    { 0x00008298, 0x00000000 },
+    { 0x00008300, 0x00000000 },
+    { 0x00008304, 0x00000000 },
+    { 0x00008308, 0x00000000 },
+    { 0x0000830c, 0x00000000 },
+    { 0x00008310, 0x00000000 },
+    { 0x00008314, 0x00000000 },
+    { 0x00008318, 0x00000000 },
+    { 0x00008328, 0x00000000 },
+    { 0x0000832c, 0x00000007 },
+    { 0x00008330, 0x00000302 },
+    { 0x00008334, 0x00000e00 },
+    { 0x00008338, 0x00000000 },
+    { 0x0000833c, 0x00000000 },
+    { 0x00008340, 0x000107ff },
+    { 0x00009808, 0x00000000 },
+    { 0x0000980c, 0xad848e19 },
+    { 0x00009810, 0x7d14e000 },
+    { 0x00009814, 0x9c0a9f6b },
+    { 0x0000981c, 0x00000000 },
+    { 0x0000982c, 0x0000a000 },
+    { 0x00009830, 0x00000000 },
+    { 0x0000983c, 0x00200400 },
+    { 0x00009840, 0x206a01ae },
+    { 0x0000984c, 0x1284233c },
+    { 0x00009854, 0x00000859 },
+    { 0x00009900, 0x00000000 },
+    { 0x00009904, 0x00000000 },
+    { 0x00009908, 0x00000000 },
+    { 0x0000990c, 0x00000000 },
+    { 0x0000991c, 0x10000fff },
+    { 0x00009920, 0x05100000 },
+    { 0x0000a920, 0x05100000 },
+    { 0x0000b920, 0x05100000 },
+    { 0x00009928, 0x00000001 },
+    { 0x0000992c, 0x00000004 },
+    { 0x00009934, 0x1e1f2022 },
+    { 0x00009938, 0x0a0b0c0d },
+    { 0x0000993c, 0x00000000 },
+    { 0x00009948, 0x9280b212 },
+    { 0x0000994c, 0x00020028 },
+    { 0x0000c95c, 0x004b6a8e },
+    { 0x0000c968, 0x000003ce },
+    { 0x00009970, 0x190fb515 },
+    { 0x00009974, 0x00000000 },
+    { 0x00009978, 0x00000001 },
+    { 0x0000997c, 0x00000000 },
+    { 0x00009980, 0x00000000 },
+    { 0x00009984, 0x00000000 },
+    { 0x00009988, 0x00000000 },
+    { 0x0000998c, 0x00000000 },
+    { 0x00009990, 0x00000000 },
+    { 0x00009994, 0x00000000 },
+    { 0x00009998, 0x00000000 },
+    { 0x0000999c, 0x00000000 },
+    { 0x000099a0, 0x00000000 },
+    { 0x000099a4, 0x00000001 },
+    { 0x000099a8, 0x201fff00 },
+    { 0x000099ac, 0x006f0000 },
+    { 0x000099b0, 0x03051000 },
+    { 0x000099dc, 0x00000000 },
+    { 0x000099e0, 0x00000200 },
+    { 0x000099e4, 0xaaaaaaaa },
+    { 0x000099e8, 0x3c466478 },
+    { 0x000099ec, 0x0cc80caa },
+    { 0x000099fc, 0x00001042 },
+    { 0x00009b00, 0x00000000 },
+    { 0x00009b04, 0x00000001 },
+    { 0x00009b08, 0x00000002 },
+    { 0x00009b0c, 0x00000003 },
+    { 0x00009b10, 0x00000004 },
+    { 0x00009b14, 0x00000005 },
+    { 0x00009b18, 0x00000008 },
+    { 0x00009b1c, 0x00000009 },
+    { 0x00009b20, 0x0000000a },
+    { 0x00009b24, 0x0000000b },
+    { 0x00009b28, 0x0000000c },
+    { 0x00009b2c, 0x0000000d },
+    { 0x00009b30, 0x00000010 },
+    { 0x00009b34, 0x00000011 },
+    { 0x00009b38, 0x00000012 },
+    { 0x00009b3c, 0x00000013 },
+    { 0x00009b40, 0x00000014 },
+    { 0x00009b44, 0x00000015 },
+    { 0x00009b48, 0x00000018 },
+    { 0x00009b4c, 0x00000019 },
+    { 0x00009b50, 0x0000001a },
+    { 0x00009b54, 0x0000001b },
+    { 0x00009b58, 0x0000001c },
+    { 0x00009b5c, 0x0000001d },
+    { 0x00009b60, 0x00000020 },
+    { 0x00009b64, 0x00000021 },
+    { 0x00009b68, 0x00000022 },
+    { 0x00009b6c, 0x00000023 },
+    { 0x00009b70, 0x00000024 },
+    { 0x00009b74, 0x00000025 },
+    { 0x00009b78, 0x00000028 },
+    { 0x00009b7c, 0x00000029 },
+    { 0x00009b80, 0x0000002a },
+    { 0x00009b84, 0x0000002b },
+    { 0x00009b88, 0x0000002c },
+    { 0x00009b8c, 0x0000002d },
+    { 0x00009b90, 0x00000030 },
+    { 0x00009b94, 0x00000031 },
+    { 0x00009b98, 0x00000032 },
+    { 0x00009b9c, 0x00000033 },
+    { 0x00009ba0, 0x00000034 },
+    { 0x00009ba4, 0x00000035 },
+    { 0x00009ba8, 0x00000035 },
+    { 0x00009bac, 0x00000035 },
+    { 0x00009bb0, 0x00000035 },
+    { 0x00009bb4, 0x00000035 },
+    { 0x00009bb8, 0x00000035 },
+    { 0x00009bbc, 0x00000035 },
+    { 0x00009bc0, 0x00000035 },
+    { 0x00009bc4, 0x00000035 },
+    { 0x00009bc8, 0x00000035 },
+    { 0x00009bcc, 0x00000035 },
+    { 0x00009bd0, 0x00000035 },
+    { 0x00009bd4, 0x00000035 },
+    { 0x00009bd8, 0x00000035 },
+    { 0x00009bdc, 0x00000035 },
+    { 0x00009be0, 0x00000035 },
+    { 0x00009be4, 0x00000035 },
+    { 0x00009be8, 0x00000035 },
+    { 0x00009bec, 0x00000035 },
+    { 0x00009bf0, 0x00000035 },
+    { 0x00009bf4, 0x00000035 },
+    { 0x00009bf8, 0x00000010 },
+    { 0x00009bfc, 0x0000001a },
+    { 0x0000a210, 0x40806333 },
+    { 0x0000a214, 0x00106c10 },
+    { 0x0000a218, 0x009c4060 },
+    { 0x0000a220, 0x018830c6 },
+    { 0x0000a224, 0x00000400 },
+    { 0x0000a228, 0x001a0bb5 },
+    { 0x0000a22c, 0x00000000 },
+    { 0x0000a234, 0x20202020 },
+    { 0x0000a238, 0x20202020 },
+    { 0x0000a23c, 0x13c889ae },
+    { 0x0000a240, 0x38490a20 },
+    { 0x0000a244, 0x00007bb6 },
+    { 0x0000a248, 0x0fff3ffc },
+    { 0x0000a24c, 0x00000001 },
+    { 0x0000a250, 0x0000a000 },
+    { 0x0000a254, 0x00000000 },
+    { 0x0000a258, 0x0cc75380 },
+    { 0x0000a25c, 0x0f0f0f01 },
+    { 0x0000a260, 0xdfa91f01 },
+    { 0x0000a268, 0x00000001 },
+    { 0x0000a26c, 0x0ebae9c6 },
+    { 0x0000b26c, 0x0ebae9c6 },
+    { 0x0000c26c, 0x0ebae9c6 },
+    { 0x0000d270, 0x00820820 },
+    { 0x0000a278, 0x1ce739ce },
+    { 0x0000a27c, 0x050701ce },
+    { 0x0000a338, 0x00000000 },
+    { 0x0000a33c, 0x00000000 },
+    { 0x0000a340, 0x00000000 },
+    { 0x0000a344, 0x00000000 },
+    { 0x0000a348, 0x3fffffff },
+    { 0x0000a34c, 0x3fffffff },
+    { 0x0000a350, 0x3fffffff },
+    { 0x0000a354, 0x0003ffff },
+    { 0x0000a358, 0x79a8aa33 },
+    { 0x0000d35c, 0x07ffffef },
+    { 0x0000d360, 0x0fffffe7 },
+    { 0x0000d364, 0x17ffffe5 },
+    { 0x0000d368, 0x1fffffe4 },
+    { 0x0000d36c, 0x37ffffe3 },
+    { 0x0000d370, 0x3fffffe3 },
+    { 0x0000d374, 0x57ffffe3 },
+    { 0x0000d378, 0x5fffffe2 },
+    { 0x0000d37c, 0x7fffffe2 },
+    { 0x0000d380, 0x7f3c7bba },
+    { 0x0000d384, 0xf3307ff0 },
+    { 0x0000a388, 0x0c000000 },
+    { 0x0000a38c, 0x20202020 },
+    { 0x0000a390, 0x20202020 },
+    { 0x0000a394, 0x1ce739ce },
+    { 0x0000a398, 0x000001ce },
+    { 0x0000a39c, 0x00000001 },
+    { 0x0000a3a0, 0x00000000 },
+    { 0x0000a3a4, 0x00000000 },
+    { 0x0000a3a8, 0x00000000 },
+    { 0x0000a3ac, 0x00000000 },
+    { 0x0000a3b0, 0x00000000 },
+    { 0x0000a3b4, 0x00000000 },
+    { 0x0000a3b8, 0x00000000 },
+    { 0x0000a3bc, 0x00000000 },
+    { 0x0000a3c0, 0x00000000 },
+    { 0x0000a3c4, 0x00000000 },
+    { 0x0000a3c8, 0x00000246 },
+    { 0x0000a3cc, 0x20202020 },
+    { 0x0000a3d0, 0x20202020 },
+    { 0x0000a3d4, 0x20202020 },
+    { 0x0000a3dc, 0x1ce739ce },
+    { 0x0000a3e0, 0x000001ce },
+};
+
+static const u32 ar5416Bank0_9100[][2] = {
+    { 0x000098b0, 0x1e5795e5 },
+    { 0x000098e0, 0x02008020 },
+};
+
+static const u32 ar5416BB_RfGain_9100[][3] = {
+    { 0x00009a00, 0x00000000, 0x00000000 },
+    { 0x00009a04, 0x00000040, 0x00000040 },
+    { 0x00009a08, 0x00000080, 0x00000080 },
+    { 0x00009a0c, 0x000001a1, 0x00000141 },
+    { 0x00009a10, 0x000001e1, 0x00000181 },
+    { 0x00009a14, 0x00000021, 0x000001c1 },
+    { 0x00009a18, 0x00000061, 0x00000001 },
+    { 0x00009a1c, 0x00000168, 0x00000041 },
+    { 0x00009a20, 0x000001a8, 0x000001a8 },
+    { 0x00009a24, 0x000001e8, 0x000001e8 },
+    { 0x00009a28, 0x00000028, 0x00000028 },
+    { 0x00009a2c, 0x00000068, 0x00000068 },
+    { 0x00009a30, 0x00000189, 0x000000a8 },
+    { 0x00009a34, 0x000001c9, 0x00000169 },
+    { 0x00009a38, 0x00000009, 0x000001a9 },
+    { 0x00009a3c, 0x00000049, 0x000001e9 },
+    { 0x00009a40, 0x00000089, 0x00000029 },
+    { 0x00009a44, 0x00000170, 0x00000069 },
+    { 0x00009a48, 0x000001b0, 0x00000190 },
+    { 0x00009a4c, 0x000001f0, 0x000001d0 },
+    { 0x00009a50, 0x00000030, 0x00000010 },
+    { 0x00009a54, 0x00000070, 0x00000050 },
+    { 0x00009a58, 0x00000191, 0x00000090 },
+    { 0x00009a5c, 0x000001d1, 0x00000151 },
+    { 0x00009a60, 0x00000011, 0x00000191 },
+    { 0x00009a64, 0x00000051, 0x000001d1 },
+    { 0x00009a68, 0x00000091, 0x00000011 },
+    { 0x00009a6c, 0x000001b8, 0x00000051 },
+    { 0x00009a70, 0x000001f8, 0x00000198 },
+    { 0x00009a74, 0x00000038, 0x000001d8 },
+    { 0x00009a78, 0x00000078, 0x00000018 },
+    { 0x00009a7c, 0x00000199, 0x00000058 },
+    { 0x00009a80, 0x000001d9, 0x00000098 },
+    { 0x00009a84, 0x00000019, 0x00000159 },
+    { 0x00009a88, 0x00000059, 0x00000199 },
+    { 0x00009a8c, 0x00000099, 0x000001d9 },
+    { 0x00009a90, 0x000000d9, 0x00000019 },
+    { 0x00009a94, 0x000000f9, 0x00000059 },
+    { 0x00009a98, 0x000000f9, 0x00000099 },
+    { 0x00009a9c, 0x000000f9, 0x000000d9 },
+    { 0x00009aa0, 0x000000f9, 0x000000f9 },
+    { 0x00009aa4, 0x000000f9, 0x000000f9 },
+    { 0x00009aa8, 0x000000f9, 0x000000f9 },
+    { 0x00009aac, 0x000000f9, 0x000000f9 },
+    { 0x00009ab0, 0x000000f9, 0x000000f9 },
+    { 0x00009ab4, 0x000000f9, 0x000000f9 },
+    { 0x00009ab8, 0x000000f9, 0x000000f9 },
+    { 0x00009abc, 0x000000f9, 0x000000f9 },
+    { 0x00009ac0, 0x000000f9, 0x000000f9 },
+    { 0x00009ac4, 0x000000f9, 0x000000f9 },
+    { 0x00009ac8, 0x000000f9, 0x000000f9 },
+    { 0x00009acc, 0x000000f9, 0x000000f9 },
+    { 0x00009ad0, 0x000000f9, 0x000000f9 },
+    { 0x00009ad4, 0x000000f9, 0x000000f9 },
+    { 0x00009ad8, 0x000000f9, 0x000000f9 },
+    { 0x00009adc, 0x000000f9, 0x000000f9 },
+    { 0x00009ae0, 0x000000f9, 0x000000f9 },
+    { 0x00009ae4, 0x000000f9, 0x000000f9 },
+    { 0x00009ae8, 0x000000f9, 0x000000f9 },
+    { 0x00009aec, 0x000000f9, 0x000000f9 },
+    { 0x00009af0, 0x000000f9, 0x000000f9 },
+    { 0x00009af4, 0x000000f9, 0x000000f9 },
+    { 0x00009af8, 0x000000f9, 0x000000f9 },
+    { 0x00009afc, 0x000000f9, 0x000000f9 },
+};
+
+static const u32 ar5416Bank1_9100[][2] = {
+    { 0x000098b0, 0x02108421},
+    { 0x000098ec, 0x00000008},
+};
+
+static const u32 ar5416Bank2_9100[][2] = {
+    { 0x000098b0, 0x0e73ff17},
+    { 0x000098e0, 0x00000420},
+};
+
+static const u32 ar5416Bank3_9100[][3] = {
+    { 0x000098f0, 0x01400018, 0x01c00018 },
+};
+
+static const u32 ar5416Bank6_9100[][3] = {
+
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00e00000, 0x00e00000 },
+    { 0x0000989c, 0x005e0000, 0x005e0000 },
+    { 0x0000989c, 0x00120000, 0x00120000 },
+    { 0x0000989c, 0x00620000, 0x00620000 },
+    { 0x0000989c, 0x00020000, 0x00020000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x005f0000, 0x005f0000 },
+    { 0x0000989c, 0x00870000, 0x00870000 },
+    { 0x0000989c, 0x00f90000, 0x00f90000 },
+    { 0x0000989c, 0x007b0000, 0x007b0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00f50000, 0x00f50000 },
+    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+    { 0x0000989c, 0x00110000, 0x00110000 },
+    { 0x0000989c, 0x006100a8, 0x006100a8 },
+    { 0x0000989c, 0x004210a2, 0x004210a2 },
+    { 0x0000989c, 0x0014000f, 0x0014000f },
+    { 0x0000989c, 0x00c40002, 0x00c40002 },
+    { 0x0000989c, 0x003000f2, 0x003000f2 },
+    { 0x0000989c, 0x00440016, 0x00440016 },
+    { 0x0000989c, 0x00410040, 0x00410040 },
+    { 0x0000989c, 0x000180d6, 0x000180d6 },
+    { 0x0000989c, 0x0000c0aa, 0x0000c0aa },
+    { 0x0000989c, 0x000000b1, 0x000000b1 },
+    { 0x0000989c, 0x00002000, 0x00002000 },
+    { 0x0000989c, 0x000000d4, 0x000000d4 },
+    { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+
+static const u32 ar5416Bank6TPC_9100[][3] = {
+
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00e00000, 0x00e00000 },
+    { 0x0000989c, 0x005e0000, 0x005e0000 },
+    { 0x0000989c, 0x00120000, 0x00120000 },
+    { 0x0000989c, 0x00620000, 0x00620000 },
+    { 0x0000989c, 0x00020000, 0x00020000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+    { 0x0000989c, 0x005f0000, 0x005f0000 },
+    { 0x0000989c, 0x00870000, 0x00870000 },
+    { 0x0000989c, 0x00f90000, 0x00f90000 },
+    { 0x0000989c, 0x007b0000, 0x007b0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00f50000, 0x00f50000 },
+    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+    { 0x0000989c, 0x00110000, 0x00110000 },
+    { 0x0000989c, 0x006100a8, 0x006100a8 },
+    { 0x0000989c, 0x00423022, 0x00423022 },
+    { 0x0000989c, 0x2014008f, 0x2014008f },
+    { 0x0000989c, 0x00c40002, 0x00c40002 },
+    { 0x0000989c, 0x003000f2, 0x003000f2 },
+    { 0x0000989c, 0x00440016, 0x00440016 },
+    { 0x0000989c, 0x00410040, 0x00410040 },
+    { 0x0000989c, 0x0001805e, 0x0001805e },
+    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+    { 0x0000989c, 0x000000e1, 0x000000e1 },
+    { 0x0000989c, 0x00007080, 0x00007080 },
+    { 0x0000989c, 0x000000d4, 0x000000d4 },
+    { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank7_9100[][2] = {
+    { 0x0000989c, 0x00000500 },
+    { 0x0000989c, 0x00000800 },
+    { 0x000098cc, 0x0000000e },
+};
+
+static const u32 ar5416Addac_9100[][2] = {
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000010 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x000000c0 },
+    {0x0000989c, 0x00000015 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x0000989c, 0x00000000 },
+    {0x000098cc, 0x00000000 },
+};
+
+static const u32 ar5416Modes_9160[][6] = {
+    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
+    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
+    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
+    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
+    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
+    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
+    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
+    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
+    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
+    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
+    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
+    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
+    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
+    { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
+    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
+    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
+    { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
+    { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
+    { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
+    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
+    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
+    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
+    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
+    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
+    { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
+    { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
+    { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
+    { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
+    { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
+    { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
+    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
+    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
+    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
+    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
+    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
+    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
+    { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
+    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
+    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
+    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
+    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
+    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
+    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
+    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
+    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
+    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
+    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
+    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
+    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
+    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
+    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+};
+
+static const u32 ar5416Common_9160[][2] = {
+    { 0x0000000c, 0x00000000 },
+    { 0x00000030, 0x00020015 },
+    { 0x00000034, 0x00000005 },
+    { 0x00000040, 0x00000000 },
+    { 0x00000044, 0x00000008 },
+    { 0x00000048, 0x00000008 },
+    { 0x0000004c, 0x00000010 },
+    { 0x00000050, 0x00000000 },
+    { 0x00000054, 0x0000001f },
+    { 0x00000800, 0x00000000 },
+    { 0x00000804, 0x00000000 },
+    { 0x00000808, 0x00000000 },
+    { 0x0000080c, 0x00000000 },
+    { 0x00000810, 0x00000000 },
+    { 0x00000814, 0x00000000 },
+    { 0x00000818, 0x00000000 },
+    { 0x0000081c, 0x00000000 },
+    { 0x00000820, 0x00000000 },
+    { 0x00000824, 0x00000000 },
+    { 0x00001040, 0x002ffc0f },
+    { 0x00001044, 0x002ffc0f },
+    { 0x00001048, 0x002ffc0f },
+    { 0x0000104c, 0x002ffc0f },
+    { 0x00001050, 0x002ffc0f },
+    { 0x00001054, 0x002ffc0f },
+    { 0x00001058, 0x002ffc0f },
+    { 0x0000105c, 0x002ffc0f },
+    { 0x00001060, 0x002ffc0f },
+    { 0x00001064, 0x002ffc0f },
+    { 0x00001230, 0x00000000 },
+    { 0x00001270, 0x00000000 },
+    { 0x00001038, 0x00000000 },
+    { 0x00001078, 0x00000000 },
+    { 0x000010b8, 0x00000000 },
+    { 0x000010f8, 0x00000000 },
+    { 0x00001138, 0x00000000 },
+    { 0x00001178, 0x00000000 },
+    { 0x000011b8, 0x00000000 },
+    { 0x000011f8, 0x00000000 },
+    { 0x00001238, 0x00000000 },
+    { 0x00001278, 0x00000000 },
+    { 0x000012b8, 0x00000000 },
+    { 0x000012f8, 0x00000000 },
+    { 0x00001338, 0x00000000 },
+    { 0x00001378, 0x00000000 },
+    { 0x000013b8, 0x00000000 },
+    { 0x000013f8, 0x00000000 },
+    { 0x00001438, 0x00000000 },
+    { 0x00001478, 0x00000000 },
+    { 0x000014b8, 0x00000000 },
+    { 0x000014f8, 0x00000000 },
+    { 0x00001538, 0x00000000 },
+    { 0x00001578, 0x00000000 },
+    { 0x000015b8, 0x00000000 },
+    { 0x000015f8, 0x00000000 },
+    { 0x00001638, 0x00000000 },
+    { 0x00001678, 0x00000000 },
+    { 0x000016b8, 0x00000000 },
+    { 0x000016f8, 0x00000000 },
+    { 0x00001738, 0x00000000 },
+    { 0x00001778, 0x00000000 },
+    { 0x000017b8, 0x00000000 },
+    { 0x000017f8, 0x00000000 },
+    { 0x0000103c, 0x00000000 },
+    { 0x0000107c, 0x00000000 },
+    { 0x000010bc, 0x00000000 },
+    { 0x000010fc, 0x00000000 },
+    { 0x0000113c, 0x00000000 },
+    { 0x0000117c, 0x00000000 },
+    { 0x000011bc, 0x00000000 },
+    { 0x000011fc, 0x00000000 },
+    { 0x0000123c, 0x00000000 },
+    { 0x0000127c, 0x00000000 },
+    { 0x000012bc, 0x00000000 },
+    { 0x000012fc, 0x00000000 },
+    { 0x0000133c, 0x00000000 },
+    { 0x0000137c, 0x00000000 },
+    { 0x000013bc, 0x00000000 },
+    { 0x000013fc, 0x00000000 },
+    { 0x0000143c, 0x00000000 },
+    { 0x0000147c, 0x00000000 },
+    { 0x00004030, 0x00000002 },
+    { 0x0000403c, 0x00000002 },
+    { 0x00007010, 0x00000020 },
+    { 0x00007038, 0x000004c2 },
+    { 0x00008004, 0x00000000 },
+    { 0x00008008, 0x00000000 },
+    { 0x0000800c, 0x00000000 },
+    { 0x00008018, 0x00000700 },
+    { 0x00008020, 0x00000000 },
+    { 0x00008038, 0x00000000 },
+    { 0x0000803c, 0x00000000 },
+    { 0x00008048, 0x40000000 },
+    { 0x00008054, 0x00000000 },
+    { 0x00008058, 0x00000000 },
+    { 0x0000805c, 0x000fc78f },
+    { 0x00008060, 0x0000000f },
+    { 0x00008064, 0x00000000 },
+    { 0x000080c0, 0x2a82301a },
+    { 0x000080c4, 0x05dc01e0 },
+    { 0x000080c8, 0x1f402710 },
+    { 0x000080cc, 0x01f40000 },
+    { 0x000080d0, 0x00001e00 },
+    { 0x000080d4, 0x00000000 },
+    { 0x000080d8, 0x00400000 },
+    { 0x000080e0, 0xffffffff },
+    { 0x000080e4, 0x0000ffff },
+    { 0x000080e8, 0x003f3f3f },
+    { 0x000080ec, 0x00000000 },
+    { 0x000080f0, 0x00000000 },
+    { 0x000080f4, 0x00000000 },
+    { 0x000080f8, 0x00000000 },
+    { 0x000080fc, 0x00020000 },
+    { 0x00008100, 0x00020000 },
+    { 0x00008104, 0x00000001 },
+    { 0x00008108, 0x00000052 },
+    { 0x0000810c, 0x00000000 },
+    { 0x00008110, 0x00000168 },
+    { 0x00008118, 0x000100aa },
+    { 0x0000811c, 0x00003210 },
+    { 0x00008120, 0x08f04800 },
+    { 0x00008124, 0x00000000 },
+    { 0x00008128, 0x00000000 },
+    { 0x0000812c, 0x00000000 },
+    { 0x00008130, 0x00000000 },
+    { 0x00008134, 0x00000000 },
+    { 0x00008138, 0x00000000 },
+    { 0x0000813c, 0x00000000 },
+    { 0x00008144, 0xffffffff },
+    { 0x00008168, 0x00000000 },
+    { 0x0000816c, 0x00000000 },
+    { 0x00008170, 0x32143320 },
+    { 0x00008174, 0xfaa4fa50 },
+    { 0x00008178, 0x00000100 },
+    { 0x0000817c, 0x00000000 },
+    { 0x000081c4, 0x00000000 },
+    { 0x000081d0, 0x00003210 },
+    { 0x000081ec, 0x00000000 },
+    { 0x000081f0, 0x00000000 },
+    { 0x000081f4, 0x00000000 },
+    { 0x000081f8, 0x00000000 },
+    { 0x000081fc, 0x00000000 },
+    { 0x00008200, 0x00000000 },
+    { 0x00008204, 0x00000000 },
+    { 0x00008208, 0x00000000 },
+    { 0x0000820c, 0x00000000 },
+    { 0x00008210, 0x00000000 },
+    { 0x00008214, 0x00000000 },
+    { 0x00008218, 0x00000000 },
+    { 0x0000821c, 0x00000000 },
+    { 0x00008220, 0x00000000 },
+    { 0x00008224, 0x00000000 },
+    { 0x00008228, 0x00000000 },
+    { 0x0000822c, 0x00000000 },
+    { 0x00008230, 0x00000000 },
+    { 0x00008234, 0x00000000 },
+    { 0x00008238, 0x00000000 },
+    { 0x0000823c, 0x00000000 },
+    { 0x00008240, 0x00100000 },
+    { 0x00008244, 0x0010f400 },
+    { 0x00008248, 0x00000100 },
+    { 0x0000824c, 0x0001e800 },
+    { 0x00008250, 0x00000000 },
+    { 0x00008254, 0x00000000 },
+    { 0x00008258, 0x00000000 },
+    { 0x0000825c, 0x400000ff },
+    { 0x00008260, 0x00080922 },
+    { 0x00008270, 0x00000000 },
+    { 0x00008274, 0x40000000 },
+    { 0x00008278, 0x003e4180 },
+    { 0x0000827c, 0x00000000 },
+    { 0x00008284, 0x0000002c },
+    { 0x00008288, 0x0000002c },
+    { 0x0000828c, 0x00000000 },
+    { 0x00008294, 0x00000000 },
+    { 0x00008298, 0x00000000 },
+    { 0x00008300, 0x00000000 },
+    { 0x00008304, 0x00000000 },
+    { 0x00008308, 0x00000000 },
+    { 0x0000830c, 0x00000000 },
+    { 0x00008310, 0x00000000 },
+    { 0x00008314, 0x00000000 },
+    { 0x00008318, 0x00000000 },
+    { 0x00008328, 0x00000000 },
+    { 0x0000832c, 0x00000007 },
+    { 0x00008330, 0x00000302 },
+    { 0x00008334, 0x00000e00 },
+    { 0x00008338, 0x00ff0000 },
+    { 0x0000833c, 0x00000000 },
+    { 0x00008340, 0x000107ff },
+    { 0x00009808, 0x00000000 },
+    { 0x0000980c, 0xad848e19 },
+    { 0x00009810, 0x7d14e000 },
+    { 0x00009814, 0x9c0a9f6b },
+    { 0x0000981c, 0x00000000 },
+    { 0x0000982c, 0x0000a000 },
+    { 0x00009830, 0x00000000 },
+    { 0x0000983c, 0x00200400 },
+    { 0x00009840, 0x206a01ae },
+    { 0x0000984c, 0x1284233c },
+    { 0x00009854, 0x00000859 },
+    { 0x00009900, 0x00000000 },
+    { 0x00009904, 0x00000000 },
+    { 0x00009908, 0x00000000 },
+    { 0x0000990c, 0x00000000 },
+    { 0x0000991c, 0x10000fff },
+    { 0x00009920, 0x05100000 },
+    { 0x0000a920, 0x05100000 },
+    { 0x0000b920, 0x05100000 },
+    { 0x00009928, 0x00000001 },
+    { 0x0000992c, 0x00000004 },
+    { 0x00009934, 0x1e1f2022 },
+    { 0x00009938, 0x0a0b0c0d },
+    { 0x0000993c, 0x00000000 },
+    { 0x00009948, 0x9280b212 },
+    { 0x0000994c, 0x00020028 },
+    { 0x00009954, 0x5f3ca3de },
+    { 0x00009958, 0x2108ecff },
+    { 0x00009940, 0x00750604 },
+    { 0x0000c95c, 0x004b6a8e },
+    { 0x00009970, 0x190fb515 },
+    { 0x00009974, 0x00000000 },
+    { 0x00009978, 0x00000001 },
+    { 0x0000997c, 0x00000000 },
+    { 0x00009980, 0x00000000 },
+    { 0x00009984, 0x00000000 },
+    { 0x00009988, 0x00000000 },
+    { 0x0000998c, 0x00000000 },
+    { 0x00009990, 0x00000000 },
+    { 0x00009994, 0x00000000 },
+    { 0x00009998, 0x00000000 },
+    { 0x0000999c, 0x00000000 },
+    { 0x000099a0, 0x00000000 },
+    { 0x000099a4, 0x00000001 },
+    { 0x000099a8, 0x201fff00 },
+    { 0x000099ac, 0x006f0000 },
+    { 0x000099b0, 0x03051000 },
+    { 0x000099dc, 0x00000000 },
+    { 0x000099e0, 0x00000200 },
+    { 0x000099e4, 0xaaaaaaaa },
+    { 0x000099e8, 0x3c466478 },
+    { 0x000099ec, 0x0cc80caa },
+    { 0x000099fc, 0x00001042 },
+    { 0x00009b00, 0x00000000 },
+    { 0x00009b04, 0x00000001 },
+    { 0x00009b08, 0x00000002 },
+    { 0x00009b0c, 0x00000003 },
+    { 0x00009b10, 0x00000004 },
+    { 0x00009b14, 0x00000005 },
+    { 0x00009b18, 0x00000008 },
+    { 0x00009b1c, 0x00000009 },
+    { 0x00009b20, 0x0000000a },
+    { 0x00009b24, 0x0000000b },
+    { 0x00009b28, 0x0000000c },
+    { 0x00009b2c, 0x0000000d },
+    { 0x00009b30, 0x00000010 },
+    { 0x00009b34, 0x00000011 },
+    { 0x00009b38, 0x00000012 },
+    { 0x00009b3c, 0x00000013 },
+    { 0x00009b40, 0x00000014 },
+    { 0x00009b44, 0x00000015 },
+    { 0x00009b48, 0x00000018 },
+    { 0x00009b4c, 0x00000019 },
+    { 0x00009b50, 0x0000001a },
+    { 0x00009b54, 0x0000001b },
+    { 0x00009b58, 0x0000001c },
+    { 0x00009b5c, 0x0000001d },
+    { 0x00009b60, 0x00000020 },
+    { 0x00009b64, 0x00000021 },
+    { 0x00009b68, 0x00000022 },
+    { 0x00009b6c, 0x00000023 },
+    { 0x00009b70, 0x00000024 },
+    { 0x00009b74, 0x00000025 },
+    { 0x00009b78, 0x00000028 },
+    { 0x00009b7c, 0x00000029 },
+    { 0x00009b80, 0x0000002a },
+    { 0x00009b84, 0x0000002b },
+    { 0x00009b88, 0x0000002c },
+    { 0x00009b8c, 0x0000002d },
+    { 0x00009b90, 0x00000030 },
+    { 0x00009b94, 0x00000031 },
+    { 0x00009b98, 0x00000032 },
+    { 0x00009b9c, 0x00000033 },
+    { 0x00009ba0, 0x00000034 },
+    { 0x00009ba4, 0x00000035 },
+    { 0x00009ba8, 0x00000035 },
+    { 0x00009bac, 0x00000035 },
+    { 0x00009bb0, 0x00000035 },
+    { 0x00009bb4, 0x00000035 },
+    { 0x00009bb8, 0x00000035 },
+    { 0x00009bbc, 0x00000035 },
+    { 0x00009bc0, 0x00000035 },
+    { 0x00009bc4, 0x00000035 },
+    { 0x00009bc8, 0x00000035 },
+    { 0x00009bcc, 0x00000035 },
+    { 0x00009bd0, 0x00000035 },
+    { 0x00009bd4, 0x00000035 },
+    { 0x00009bd8, 0x00000035 },
+    { 0x00009bdc, 0x00000035 },
+    { 0x00009be0, 0x00000035 },
+    { 0x00009be4, 0x00000035 },
+    { 0x00009be8, 0x00000035 },
+    { 0x00009bec, 0x00000035 },
+    { 0x00009bf0, 0x00000035 },
+    { 0x00009bf4, 0x00000035 },
+    { 0x00009bf8, 0x00000010 },
+    { 0x00009bfc, 0x0000001a },
+    { 0x0000a210, 0x40806333 },
+    { 0x0000a214, 0x00106c10 },
+    { 0x0000a218, 0x009c4060 },
+    { 0x0000a220, 0x018830c6 },
+    { 0x0000a224, 0x00000400 },
+    { 0x0000a228, 0x001a0bb5 },
+    { 0x0000a22c, 0x00000000 },
+    { 0x0000a234, 0x20202020 },
+    { 0x0000a238, 0x20202020 },
+    { 0x0000a23c, 0x13c889af },
+    { 0x0000a240, 0x38490a20 },
+    { 0x0000a244, 0x00007bb6 },
+    { 0x0000a248, 0x0fff3ffc },
+    { 0x0000a24c, 0x00000001 },
+    { 0x0000a250, 0x0000e000 },
+    { 0x0000a254, 0x00000000 },
+    { 0x0000a258, 0x0cc75380 },
+    { 0x0000a25c, 0x0f0f0f01 },
+    { 0x0000a260, 0xdfa91f01 },
+    { 0x0000a268, 0x00000001 },
+    { 0x0000a26c, 0x0ebae9c6 },
+    { 0x0000b26c, 0x0ebae9c6 },
+    { 0x0000c26c, 0x0ebae9c6 },
+    { 0x0000d270, 0x00820820 },
+    { 0x0000a278, 0x1ce739ce },
+    { 0x0000a27c, 0x050701ce },
+    { 0x0000a338, 0x00000000 },
+    { 0x0000a33c, 0x00000000 },
+    { 0x0000a340, 0x00000000 },
+    { 0x0000a344, 0x00000000 },
+    { 0x0000a348, 0x3fffffff },
+    { 0x0000a34c, 0x3fffffff },
+    { 0x0000a350, 0x3fffffff },
+    { 0x0000a354, 0x0003ffff },
+    { 0x0000a358, 0x79bfaa03 },
+    { 0x0000d35c, 0x07ffffef },
+    { 0x0000d360, 0x0fffffe7 },
+    { 0x0000d364, 0x17ffffe5 },
+    { 0x0000d368, 0x1fffffe4 },
+    { 0x0000d36c, 0x37ffffe3 },
+    { 0x0000d370, 0x3fffffe3 },
+    { 0x0000d374, 0x57ffffe3 },
+    { 0x0000d378, 0x5fffffe2 },
+    { 0x0000d37c, 0x7fffffe2 },
+    { 0x0000d380, 0x7f3c7bba },
+    { 0x0000d384, 0xf3307ff0 },
+    { 0x0000a388, 0x0c000000 },
+    { 0x0000a38c, 0x20202020 },
+    { 0x0000a390, 0x20202020 },
+    { 0x0000a394, 0x1ce739ce },
+    { 0x0000a398, 0x000001ce },
+    { 0x0000a39c, 0x00000001 },
+    { 0x0000a3a0, 0x00000000 },
+    { 0x0000a3a4, 0x00000000 },
+    { 0x0000a3a8, 0x00000000 },
+    { 0x0000a3ac, 0x00000000 },
+    { 0x0000a3b0, 0x00000000 },
+    { 0x0000a3b4, 0x00000000 },
+    { 0x0000a3b8, 0x00000000 },
+    { 0x0000a3bc, 0x00000000 },
+    { 0x0000a3c0, 0x00000000 },
+    { 0x0000a3c4, 0x00000000 },
+    { 0x0000a3c8, 0x00000246 },
+    { 0x0000a3cc, 0x20202020 },
+    { 0x0000a3d0, 0x20202020 },
+    { 0x0000a3d4, 0x20202020 },
+    { 0x0000a3dc, 0x1ce739ce },
+    { 0x0000a3e0, 0x000001ce },
+};
+
+static const u32 ar5416Bank0_9160[][2] = {
+    { 0x000098b0, 0x1e5795e5 },
+    { 0x000098e0, 0x02008020 },
+};
+
+static const u32 ar5416BB_RfGain_9160[][3] = {
+    { 0x00009a00, 0x00000000, 0x00000000 },
+    { 0x00009a04, 0x00000040, 0x00000040 },
+    { 0x00009a08, 0x00000080, 0x00000080 },
+    { 0x00009a0c, 0x000001a1, 0x00000141 },
+    { 0x00009a10, 0x000001e1, 0x00000181 },
+    { 0x00009a14, 0x00000021, 0x000001c1 },
+    { 0x00009a18, 0x00000061, 0x00000001 },
+    { 0x00009a1c, 0x00000168, 0x00000041 },
+    { 0x00009a20, 0x000001a8, 0x000001a8 },
+    { 0x00009a24, 0x000001e8, 0x000001e8 },
+    { 0x00009a28, 0x00000028, 0x00000028 },
+    { 0x00009a2c, 0x00000068, 0x00000068 },
+    { 0x00009a30, 0x00000189, 0x000000a8 },
+    { 0x00009a34, 0x000001c9, 0x00000169 },
+    { 0x00009a38, 0x00000009, 0x000001a9 },
+    { 0x00009a3c, 0x00000049, 0x000001e9 },
+    { 0x00009a40, 0x00000089, 0x00000029 },
+    { 0x00009a44, 0x00000170, 0x00000069 },
+    { 0x00009a48, 0x000001b0, 0x00000190 },
+    { 0x00009a4c, 0x000001f0, 0x000001d0 },
+    { 0x00009a50, 0x00000030, 0x00000010 },
+    { 0x00009a54, 0x00000070, 0x00000050 },
+    { 0x00009a58, 0x00000191, 0x00000090 },
+    { 0x00009a5c, 0x000001d1, 0x00000151 },
+    { 0x00009a60, 0x00000011, 0x00000191 },
+    { 0x00009a64, 0x00000051, 0x000001d1 },
+    { 0x00009a68, 0x00000091, 0x00000011 },
+    { 0x00009a6c, 0x000001b8, 0x00000051 },
+    { 0x00009a70, 0x000001f8, 0x00000198 },
+    { 0x00009a74, 0x00000038, 0x000001d8 },
+    { 0x00009a78, 0x00000078, 0x00000018 },
+    { 0x00009a7c, 0x00000199, 0x00000058 },
+    { 0x00009a80, 0x000001d9, 0x00000098 },
+    { 0x00009a84, 0x00000019, 0x00000159 },
+    { 0x00009a88, 0x00000059, 0x00000199 },
+    { 0x00009a8c, 0x00000099, 0x000001d9 },
+    { 0x00009a90, 0x000000d9, 0x00000019 },
+    { 0x00009a94, 0x000000f9, 0x00000059 },
+    { 0x00009a98, 0x000000f9, 0x00000099 },
+    { 0x00009a9c, 0x000000f9, 0x000000d9 },
+    { 0x00009aa0, 0x000000f9, 0x000000f9 },
+    { 0x00009aa4, 0x000000f9, 0x000000f9 },
+    { 0x00009aa8, 0x000000f9, 0x000000f9 },
+    { 0x00009aac, 0x000000f9, 0x000000f9 },
+    { 0x00009ab0, 0x000000f9, 0x000000f9 },
+    { 0x00009ab4, 0x000000f9, 0x000000f9 },
+    { 0x00009ab8, 0x000000f9, 0x000000f9 },
+    { 0x00009abc, 0x000000f9, 0x000000f9 },
+    { 0x00009ac0, 0x000000f9, 0x000000f9 },
+    { 0x00009ac4, 0x000000f9, 0x000000f9 },
+    { 0x00009ac8, 0x000000f9, 0x000000f9 },
+    { 0x00009acc, 0x000000f9, 0x000000f9 },
+    { 0x00009ad0, 0x000000f9, 0x000000f9 },
+    { 0x00009ad4, 0x000000f9, 0x000000f9 },
+    { 0x00009ad8, 0x000000f9, 0x000000f9 },
+    { 0x00009adc, 0x000000f9, 0x000000f9 },
+    { 0x00009ae0, 0x000000f9, 0x000000f9 },
+    { 0x00009ae4, 0x000000f9, 0x000000f9 },
+    { 0x00009ae8, 0x000000f9, 0x000000f9 },
+    { 0x00009aec, 0x000000f9, 0x000000f9 },
+    { 0x00009af0, 0x000000f9, 0x000000f9 },
+    { 0x00009af4, 0x000000f9, 0x000000f9 },
+    { 0x00009af8, 0x000000f9, 0x000000f9 },
+    { 0x00009afc, 0x000000f9, 0x000000f9 },
+};
+
+static const u32 ar5416Bank1_9160[][2] = {
+    { 0x000098b0, 0x02108421 },
+    { 0x000098ec, 0x00000008 },
+};
+
+static const u32 ar5416Bank2_9160[][2] = {
+    { 0x000098b0, 0x0e73ff17 },
+    { 0x000098e0, 0x00000420 },
+};
+
+static const u32 ar5416Bank3_9160[][3] = {
+    { 0x000098f0, 0x01400018, 0x01c00018 },
+};
+
+static const u32 ar5416Bank6_9160[][3] = {
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00e00000, 0x00e00000 },
+    { 0x0000989c, 0x005e0000, 0x005e0000 },
+    { 0x0000989c, 0x00120000, 0x00120000 },
+    { 0x0000989c, 0x00620000, 0x00620000 },
+    { 0x0000989c, 0x00020000, 0x00020000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+    { 0x0000989c, 0x005f0000, 0x005f0000 },
+    { 0x0000989c, 0x00870000, 0x00870000 },
+    { 0x0000989c, 0x00f90000, 0x00f90000 },
+    { 0x0000989c, 0x007b0000, 0x007b0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00f50000, 0x00f50000 },
+    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+    { 0x0000989c, 0x00110000, 0x00110000 },
+    { 0x0000989c, 0x006100a8, 0x006100a8 },
+    { 0x0000989c, 0x004210a2, 0x004210a2 },
+    { 0x0000989c, 0x0014008f, 0x0014008f },
+    { 0x0000989c, 0x00c40003, 0x00c40003 },
+    { 0x0000989c, 0x003000f2, 0x003000f2 },
+    { 0x0000989c, 0x00440016, 0x00440016 },
+    { 0x0000989c, 0x00410040, 0x00410040 },
+    { 0x0000989c, 0x0001805e, 0x0001805e },
+    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+    { 0x0000989c, 0x000000f1, 0x000000f1 },
+    { 0x0000989c, 0x00002081, 0x00002081 },
+    { 0x0000989c, 0x000000d4, 0x000000d4 },
+    { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank6TPC_9160[][3] = {
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00000000, 0x00000000 },
+    { 0x0000989c, 0x00e00000, 0x00e00000 },
+    { 0x0000989c, 0x005e0000, 0x005e0000 },
+    { 0x0000989c, 0x00120000, 0x00120000 },
+    { 0x0000989c, 0x00620000, 0x00620000 },
+    { 0x0000989c, 0x00020000, 0x00020000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
+    { 0x0000989c, 0x005f0000, 0x005f0000 },
+    { 0x0000989c, 0x00870000, 0x00870000 },
+    { 0x0000989c, 0x00f90000, 0x00f90000 },
+    { 0x0000989c, 0x007b0000, 0x007b0000 },
+    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
+    { 0x0000989c, 0x00f50000, 0x00f50000 },
+    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
+    { 0x0000989c, 0x00110000, 0x00110000 },
+    { 0x0000989c, 0x006100a8, 0x006100a8 },
+    { 0x0000989c, 0x00423022, 0x00423022 },
+    { 0x0000989c, 0x2014008f, 0x2014008f },
+    { 0x0000989c, 0x00c40002, 0x00c40002 },
+    { 0x0000989c, 0x003000f2, 0x003000f2 },
+    { 0x0000989c, 0x00440016, 0x00440016 },
+    { 0x0000989c, 0x00410040, 0x00410040 },
+    { 0x0000989c, 0x0001805e, 0x0001805e },
+    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
+    { 0x0000989c, 0x000000e1, 0x000000e1 },
+    { 0x0000989c, 0x00007080, 0x00007080 },
+    { 0x0000989c, 0x000000d4, 0x000000d4 },
+    { 0x000098d0, 0x0000000f, 0x0010000f },
+};
+
+static const u32 ar5416Bank7_9160[][2] = {
+    { 0x0000989c, 0x00000500 },
+    { 0x0000989c, 0x00000800 },
+    { 0x000098cc, 0x0000000e },
+};
+
+static const u32 ar5416Addac_9160[][2] = {
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x000000c0 },
+    {0x0000989c,  0x00000018 },
+    {0x0000989c,  0x00000004 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x000000c0 },
+    {0x0000989c,  0x00000019 },
+    {0x0000989c,  0x00000004 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000004 },
+    {0x0000989c,  0x00000003 },
+    {0x0000989c,  0x00000008 },
+    {0x0000989c,  0x00000000 },
+    {0x000098cc,  0x00000000 },
+};
+
+static const u32 ar5416Addac_91601_1[][2] = {
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x000000c0 },
+    {0x0000989c,  0x00000018 },
+    {0x0000989c,  0x00000004 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x000000c0 },
+    {0x0000989c,  0x00000019 },
+    {0x0000989c,  0x00000004 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x0000989c,  0x00000000 },
+    {0x000098cc,  0x00000000 },
+};
+
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
new file mode 100644 (file)
index 0000000..5fdbb53
--- /dev/null
@@ -0,0 +1,1000 @@
+/*
+ * Copyright (c) 2008-2010 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 "hw.h"
+#include "hw-ops.h"
+#include "ar9002_phy.h"
+
+#define AR9285_CLCAL_REDO_THRESH    1
+
+static void ar9002_hw_setup_calibration(struct ath_hw *ah,
+                                       struct ath9k_cal_list *currCal)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
+                     AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
+                     currCal->calData->calCountMax);
+
+       switch (currCal->calData->calType) {
+       case IQ_MISMATCH_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "starting IQ Mismatch Calibration\n");
+               break;
+       case ADC_GAIN_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "starting ADC Gain Calibration\n");
+               break;
+       case ADC_DC_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "starting ADC DC Calibration\n");
+               break;
+       case ADC_DC_INIT_CAL:
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "starting Init ADC DC Calibration\n");
+               break;
+       case TEMP_COMP_CAL:
+               break; /* Not supported */
+       }
+
+       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+                   AR_PHY_TIMING_CTRL4_DO_CAL);
+}
+
+static bool ar9002_hw_per_calibration(struct ath_hw *ah,
+                                     struct ath9k_channel *ichan,
+                                     u8 rxchainmask,
+                                     struct ath9k_cal_list *currCal)
+{
+       bool iscaldone = false;
+
+       if (currCal->calState == CAL_RUNNING) {
+               if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
+                     AR_PHY_TIMING_CTRL4_DO_CAL)) {
+
+                       currCal->calData->calCollect(ah);
+                       ah->cal_samples++;
+
+                       if (ah->cal_samples >=
+                           currCal->calData->calNumSamples) {
+                               int i, numChains = 0;
+                               for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+                                       if (rxchainmask & (1 << i))
+                                               numChains++;
+                               }
+
+                               currCal->calData->calPostProc(ah, numChains);
+                               ichan->CalValid |= currCal->calData->calType;
+                               currCal->calState = CAL_DONE;
+                               iscaldone = true;
+                       } else {
+                               ar9002_hw_setup_calibration(ah, currCal);
+                       }
+               }
+       } else if (!(ichan->CalValid & currCal->calData->calType)) {
+               ath9k_hw_reset_calibration(ah, currCal);
+       }
+
+       return iscaldone;
+}
+
+/* Assumes you are talking about the currently configured channel */
+static bool ar9002_hw_iscal_supported(struct ath_hw *ah,
+                                     enum ath9k_cal_types calType)
+{
+       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+
+       switch (calType & ah->supp_cals) {
+       case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
+               return true;
+       case ADC_GAIN_CAL:
+       case ADC_DC_CAL:
+               if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
+                     conf_is_ht20(conf)))
+                       return true;
+               break;
+       }
+       return false;
+}
+
+static void ar9002_hw_iqcal_collect(struct ath_hw *ah)
+{
+       int i;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ah->totalPowerMeasI[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ah->totalPowerMeasQ[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ah->totalIqCorrMeas[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+                         "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+                         ah->cal_samples, i, ah->totalPowerMeasI[i],
+                         ah->totalPowerMeasQ[i],
+                         ah->totalIqCorrMeas[i]);
+       }
+}
+
+static void ar9002_hw_adc_gaincal_collect(struct ath_hw *ah)
+{
+       int i;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ah->totalAdcIOddPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ah->totalAdcIEvenPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ah->totalAdcQOddPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               ah->totalAdcQEvenPhase[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+                         "oddq=0x%08x; evenq=0x%08x;\n",
+                         ah->cal_samples, i,
+                         ah->totalAdcIOddPhase[i],
+                         ah->totalAdcIEvenPhase[i],
+                         ah->totalAdcQOddPhase[i],
+                         ah->totalAdcQEvenPhase[i]);
+       }
+}
+
+static void ar9002_hw_adc_dccal_collect(struct ath_hw *ah)
+{
+       int i;
+
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ah->totalAdcDcOffsetIOddPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ah->totalAdcDcOffsetIEvenPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ah->totalAdcDcOffsetQOddPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               ah->totalAdcDcOffsetQEvenPhase[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
+
+               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
+                         "oddq=0x%08x; evenq=0x%08x;\n",
+                         ah->cal_samples, i,
+                         ah->totalAdcDcOffsetIOddPhase[i],
+                         ah->totalAdcDcOffsetIEvenPhase[i],
+                         ah->totalAdcDcOffsetQOddPhase[i],
+                         ah->totalAdcDcOffsetQEvenPhase[i]);
+       }
+}
+
+static void ar9002_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 powerMeasQ, powerMeasI, iqCorrMeas;
+       u32 qCoffDenom, iCoffDenom;
+       int32_t qCoff, iCoff;
+       int iqCorrNeg, i;
+
+       for (i = 0; i < numChains; i++) {
+               powerMeasI = ah->totalPowerMeasI[i];
+               powerMeasQ = ah->totalPowerMeasQ[i];
+               iqCorrMeas = ah->totalIqCorrMeas[i];
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Starting IQ Cal and Correction for Chain %d\n",
+                         i);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+                         i, ah->totalIqCorrMeas[i]);
+
+               iqCorrNeg = 0;
+
+               if (iqCorrMeas > 0x80000000) {
+                       iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+                       iqCorrNeg = 1;
+               }
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+               ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+                         iqCorrNeg);
+
+               iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
+               qCoffDenom = powerMeasQ / 64;
+
+               if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
+                   (qCoffDenom != 0)) {
+                       iCoff = iqCorrMeas / iCoffDenom;
+                       qCoff = powerMeasI / qCoffDenom - 64;
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d iCoff = 0x%08x\n", i, iCoff);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+                       iCoff = iCoff & 0x3f;
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
+                       if (iqCorrNeg == 0x0)
+                               iCoff = 0x40 - iCoff;
+
+                       if (qCoff > 15)
+                               qCoff = 15;
+                       else if (qCoff <= -16)
+                               qCoff = 16;
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+                                 i, iCoff, qCoff);
+
+                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
+                                     iCoff);
+                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
+                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
+                                     qCoff);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "IQ Cal and Correction done for Chain %d\n",
+                                 i);
+               }
+       }
+
+       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+                   AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
+}
+
+static void ar9002_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
+       u32 qGainMismatch, iGainMismatch, val, i;
+
+       for (i = 0; i < numChains; i++) {
+               iOddMeasOffset = ah->totalAdcIOddPhase[i];
+               iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
+               qOddMeasOffset = ah->totalAdcQOddPhase[i];
+               qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Starting ADC Gain Cal for Chain %d\n", i);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
+                         iOddMeasOffset);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_even_i = 0x%08x\n", i,
+                         iEvenMeasOffset);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
+                         qOddMeasOffset);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_even_q = 0x%08x\n", i,
+                         qEvenMeasOffset);
+
+               if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
+                       iGainMismatch =
+                               ((iEvenMeasOffset * 32) /
+                                iOddMeasOffset) & 0x3f;
+                       qGainMismatch =
+                               ((qOddMeasOffset * 32) /
+                                qEvenMeasOffset) & 0x3f;
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d gain_mismatch_i = 0x%08x\n", i,
+                                 iGainMismatch);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d gain_mismatch_q = 0x%08x\n", i,
+                                 qGainMismatch);
+
+                       val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+                       val &= 0xfffff000;
+                       val |= (qGainMismatch) | (iGainMismatch << 6);
+                       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "ADC Gain Cal done for Chain %d\n", i);
+               }
+       }
+
+       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+                 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
+}
+
+static void ar9002_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 iOddMeasOffset, iEvenMeasOffset, val, i;
+       int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
+       const struct ath9k_percal_data *calData =
+               ah->cal_list_curr->calData;
+       u32 numSamples =
+               (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
+
+       for (i = 0; i < numChains; i++) {
+               iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
+               iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
+               qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
+               qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                          "Starting ADC DC Offset Cal for Chain %d\n", i);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_odd_i = %d\n", i,
+                         iOddMeasOffset);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_even_i = %d\n", i,
+                         iEvenMeasOffset);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_odd_q = %d\n", i,
+                         qOddMeasOffset);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_even_q = %d\n", i,
+                         qEvenMeasOffset);
+
+               iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
+                              numSamples) & 0x1ff;
+               qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
+                              numSamples) & 0x1ff;
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
+                         iDcMismatch);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
+                         qDcMismatch);
+
+               val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
+               val &= 0xc0000fff;
+               val |= (qDcMismatch << 12) | (iDcMismatch << 21);
+               REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "ADC DC Offset Cal done for Chain %d\n", i);
+       }
+
+       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
+                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
+                 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
+}
+
+static void ar9287_hw_olc_temp_compensation(struct ath_hw *ah)
+{
+       u32 rddata;
+       int32_t delta, currPDADC, slope;
+
+       rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
+       currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+
+       if (ah->initPDADC == 0 || currPDADC == 0) {
+               /*
+                * Zero value indicates that no frames have been transmitted
+                * yet, can't do temperature compensation until frames are
+                * transmitted.
+                */
+               return;
+       } else {
+               slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
+
+               if (slope == 0) { /* to avoid divide by zero case */
+                       delta = 0;
+               } else {
+                       delta = ((currPDADC - ah->initPDADC)*4) / slope;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
+                             AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+               REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
+                             AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
+       }
+}
+
+static void ar9280_hw_olc_temp_compensation(struct ath_hw *ah)
+{
+       u32 rddata, i;
+       int delta, currPDADC, regval;
+
+       rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
+       currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
+
+       if (ah->initPDADC == 0 || currPDADC == 0)
+               return;
+
+       if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+               delta = (currPDADC - ah->initPDADC + 4) / 8;
+       else
+               delta = (currPDADC - ah->initPDADC + 5) / 10;
+
+       if (delta != ah->PDADCdelta) {
+               ah->PDADCdelta = delta;
+               for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+                       regval = ah->originalGain[i] - delta;
+                       if (regval < 0)
+                               regval = 0;
+
+                       REG_RMW_FIELD(ah,
+                                     AR_PHY_TX_GAIN_TBL1 + i * 4,
+                                     AR_PHY_TX_GAIN, regval);
+               }
+       }
+}
+
+static void ar9271_hw_pa_cal(struct ath_hw *ah, bool is_reset)
+{
+       u32 regVal;
+       unsigned int i;
+       u32 regList[][2] = {
+               { 0x786c, 0 },
+               { 0x7854, 0 },
+               { 0x7820, 0 },
+               { 0x7824, 0 },
+               { 0x7868, 0 },
+               { 0x783c, 0 },
+               { 0x7838, 0 } ,
+               { 0x7828, 0 } ,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(regList); i++)
+               regList[i][1] = REG_READ(ah, regList[i][0]);
+
+       regVal = REG_READ(ah, 0x7834);
+       regVal &= (~(0x1));
+       REG_WRITE(ah, 0x7834, regVal);
+       regVal = REG_READ(ah, 0x9808);
+       regVal |= (0x1 << 27);
+       REG_WRITE(ah, 0x9808, regVal);
+
+       /* 786c,b23,1, pwddac=1 */
+       REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+       /* 7854, b5,1, pdrxtxbb=1 */
+       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+       /* 7854, b7,1, pdv2i=1 */
+       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+       /* 7854, b8,1, pddacinterface=1 */
+       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+       /* 7824,b12,0, offcal=0 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+       /* 7838, b1,0, pwddb=0 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+       /* 7820,b11,0, enpacal=0 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+       /* 7820,b25,1, pdpadrv1=0 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
+       /* 7820,b24,0, pdpadrv2=0 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
+       /* 7820,b23,0, pdpaout=0 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+       /* 783c,b14-16,7, padrvgn2tab_0=7 */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+       /*
+        * 7838,b29-31,0, padrvgn1tab_0=0
+        * does not matter since we turn it off
+        */
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
+
+       /* Set:
+        * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
+        * txon=1,paon=1,oscon=1,synthon_force=1
+        */
+       REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+       udelay(30);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
+
+       /* find off_6_1; */
+       for (i = 6; i > 0; i--) {
+               regVal = REG_READ(ah, 0x7834);
+               regVal |= (1 << (20 + i));
+               REG_WRITE(ah, 0x7834, regVal);
+               udelay(1);
+               /* regVal = REG_READ(ah, 0x7834); */
+               regVal &= (~(0x1 << (20 + i)));
+               regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
+                           << (20 + i));
+               REG_WRITE(ah, 0x7834, regVal);
+       }
+
+       regVal = (regVal >> 20) & 0x7f;
+
+       /* Update PA cal info */
+       if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
+               if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+                       ah->pacal_info.max_skipcount =
+                               2 * ah->pacal_info.max_skipcount;
+               ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+       } else {
+               ah->pacal_info.max_skipcount = 1;
+               ah->pacal_info.skipcount = 0;
+               ah->pacal_info.prev_offset = regVal;
+       }
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       regVal = REG_READ(ah, 0x7834);
+       regVal |= 0x1;
+       REG_WRITE(ah, 0x7834, regVal);
+       regVal = REG_READ(ah, 0x9808);
+       regVal &= (~(0x1 << 27));
+       REG_WRITE(ah, 0x9808, regVal);
+
+       for (i = 0; i < ARRAY_SIZE(regList); i++)
+               REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+}
+
+static inline void ar9285_hw_pa_cal(struct ath_hw *ah, bool is_reset)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 regVal;
+       int i, offset, offs_6_1, offs_0;
+       u32 ccomp_org, reg_field;
+       u32 regList[][2] = {
+               { 0x786c, 0 },
+               { 0x7854, 0 },
+               { 0x7820, 0 },
+               { 0x7824, 0 },
+               { 0x7868, 0 },
+               { 0x783c, 0 },
+               { 0x7838, 0 },
+       };
+
+       ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
+
+       /* PA CAL is not needed for high power solution */
+       if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
+           AR5416_EEP_TXGAIN_HIGH_POWER)
+               return;
+
+       if (AR_SREV_9285_11(ah)) {
+               REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
+               udelay(10);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(regList); i++)
+               regList[i][1] = REG_READ(ah, regList[i][0]);
+
+       regVal = REG_READ(ah, 0x7834);
+       regVal &= (~(0x1));
+       REG_WRITE(ah, 0x7834, regVal);
+       regVal = REG_READ(ah, 0x9808);
+       regVal |= (0x1 << 27);
+       REG_WRITE(ah, 0x9808, regVal);
+
+       REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
+       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
+       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
+       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
+       ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
+
+       REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
+       udelay(30);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
+
+       for (i = 6; i > 0; i--) {
+               regVal = REG_READ(ah, 0x7834);
+               regVal |= (1 << (19 + i));
+               REG_WRITE(ah, 0x7834, regVal);
+               udelay(1);
+               regVal = REG_READ(ah, 0x7834);
+               regVal &= (~(0x1 << (19 + i)));
+               reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
+               regVal |= (reg_field << (19 + i));
+               REG_WRITE(ah, 0x7834, regVal);
+       }
+
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
+       udelay(1);
+       reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
+       offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
+       offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
+
+       offset = (offs_6_1<<1) | offs_0;
+       offset = offset - 0;
+       offs_6_1 = offset>>1;
+       offs_0 = offset & 1;
+
+       if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
+               if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
+                       ah->pacal_info.max_skipcount =
+                               2 * ah->pacal_info.max_skipcount;
+               ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
+       } else {
+               ah->pacal_info.max_skipcount = 1;
+               ah->pacal_info.skipcount = 0;
+               ah->pacal_info.prev_offset = offset;
+       }
+
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
+
+       regVal = REG_READ(ah, 0x7834);
+       regVal |= 0x1;
+       REG_WRITE(ah, 0x7834, regVal);
+       regVal = REG_READ(ah, 0x9808);
+       regVal &= (~(0x1 << 27));
+       REG_WRITE(ah, 0x9808, regVal);
+
+       for (i = 0; i < ARRAY_SIZE(regList); i++)
+               REG_WRITE(ah, regList[i][0], regList[i][1]);
+
+       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
+
+       if (AR_SREV_9285_11(ah))
+               REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
+
+}
+
+static void ar9002_hw_pa_cal(struct ath_hw *ah, bool is_reset)
+{
+       if (AR_SREV_9271(ah)) {
+               if (is_reset || !ah->pacal_info.skipcount)
+                       ar9271_hw_pa_cal(ah, is_reset);
+               else
+                       ah->pacal_info.skipcount--;
+       } else if (AR_SREV_9285_11_OR_LATER(ah)) {
+               if (is_reset || !ah->pacal_info.skipcount)
+                       ar9285_hw_pa_cal(ah, is_reset);
+               else
+                       ah->pacal_info.skipcount--;
+       }
+}
+
+static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
+{
+       if (OLC_FOR_AR9287_10_LATER)
+               ar9287_hw_olc_temp_compensation(ah);
+       else if (OLC_FOR_AR9280_20_LATER)
+               ar9280_hw_olc_temp_compensation(ah);
+}
+
+static bool ar9002_hw_calibrate(struct ath_hw *ah,
+                               struct ath9k_channel *chan,
+                               u8 rxchainmask,
+                               bool longcal)
+{
+       bool iscaldone = true;
+       struct ath9k_cal_list *currCal = ah->cal_list_curr;
+
+       if (currCal &&
+           (currCal->calState == CAL_RUNNING ||
+            currCal->calState == CAL_WAITING)) {
+               iscaldone = ar9002_hw_per_calibration(ah, chan,
+                                                     rxchainmask, currCal);
+               if (iscaldone) {
+                       ah->cal_list_curr = currCal = currCal->calNext;
+
+                       if (currCal->calState == CAL_WAITING) {
+                               iscaldone = false;
+                               ath9k_hw_reset_calibration(ah, currCal);
+                       }
+               }
+       }
+
+       /* Do NF cal only at longer intervals */
+       if (longcal) {
+               /* Do periodic PAOffset Cal */
+               ar9002_hw_pa_cal(ah, false);
+               ar9002_hw_olc_temp_compensation(ah);
+
+               /*
+                * Get the value from the previous NF cal and update
+                * history buffer.
+                */
+               ath9k_hw_getnf(ah, chan);
+
+               /*
+                * Load the NF from history buffer of the current channel.
+                * NF is slow time-variant, so it is OK to use a historical
+                * value.
+                */
+               ath9k_hw_loadnf(ah, ah->curchan);
+
+               ath9k_hw_start_nfcal(ah);
+       }
+
+       return iscaldone;
+}
+
+/* Carrier leakage Calibration fix */
+static bool ar9285_hw_cl_cal(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       if (IS_CHAN_HT20(chan)) {
+               REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
+               REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
+               REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                           AR_PHY_AGC_CONTROL_FLTR_CAL);
+               REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
+               REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
+               if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                 AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
+                       ath_print(common, ATH_DBG_CALIBRATE, "offset "
+                                 "calibration failed to complete in "
+                                 "1ms; noisy ??\n");
+                       return false;
+               }
+               REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
+               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
+               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       }
+       REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+       REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
+       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+                         0, AH_WAIT_TIMEOUT)) {
+               ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
+                         "failed to complete in 1ms; noisy ??\n");
+               return false;
+       }
+
+       REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+       REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+
+       return true;
+}
+
+static bool ar9285_hw_clc(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       int i;
+       u_int32_t txgain_max;
+       u_int32_t clc_gain, gain_mask = 0, clc_num = 0;
+       u_int32_t reg_clc_I0, reg_clc_Q0;
+       u_int32_t i0_num = 0;
+       u_int32_t q0_num = 0;
+       u_int32_t total_num = 0;
+       u_int32_t reg_rf2g5_org;
+       bool retv = true;
+
+       if (!(ar9285_hw_cl_cal(ah, chan)))
+               return false;
+
+       txgain_max = MS(REG_READ(ah, AR_PHY_TX_PWRCTRL7),
+                       AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX);
+
+       for (i = 0; i < (txgain_max+1); i++) {
+               clc_gain = (REG_READ(ah, (AR_PHY_TX_GAIN_TBL1+(i<<2))) &
+                          AR_PHY_TX_GAIN_CLC) >> AR_PHY_TX_GAIN_CLC_S;
+               if (!(gain_mask & (1 << clc_gain))) {
+                       gain_mask |= (1 << clc_gain);
+                       clc_num++;
+               }
+       }
+
+       for (i = 0; i < clc_num; i++) {
+               reg_clc_I0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
+                             & AR_PHY_CLC_I0) >> AR_PHY_CLC_I0_S;
+               reg_clc_Q0 = (REG_READ(ah, (AR_PHY_CLC_TBL1 + (i << 2)))
+                             & AR_PHY_CLC_Q0) >> AR_PHY_CLC_Q0_S;
+               if (reg_clc_I0 == 0)
+                       i0_num++;
+
+               if (reg_clc_Q0 == 0)
+                       q0_num++;
+       }
+       total_num = i0_num + q0_num;
+       if (total_num > AR9285_CLCAL_REDO_THRESH) {
+               reg_rf2g5_org = REG_READ(ah, AR9285_RF2G5);
+               if (AR_SREV_9285E_20(ah)) {
+                       REG_WRITE(ah, AR9285_RF2G5,
+                                 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
+                                 AR9285_RF2G5_IC50TX_XE_SET);
+               } else {
+                       REG_WRITE(ah, AR9285_RF2G5,
+                                 (reg_rf2g5_org & AR9285_RF2G5_IC50TX) |
+                                 AR9285_RF2G5_IC50TX_SET);
+               }
+               retv = ar9285_hw_cl_cal(ah, chan);
+               REG_WRITE(ah, AR9285_RF2G5, reg_rf2g5_org);
+       }
+       return retv;
+}
+
+static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
+               if (!ar9285_hw_clc(ah, chan))
+                       return false;
+       } else {
+               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                       if (!AR_SREV_9287_10_OR_LATER(ah))
+                               REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
+                                           AR_PHY_ADC_CTL_OFF_PWDADC);
+                       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                                   AR_PHY_AGC_CONTROL_FLTR_CAL);
+               }
+
+               /* Calibrate the AGC */
+               REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                         REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                         AR_PHY_AGC_CONTROL_CAL);
+
+               /* Poll for offset calibration complete */
+               if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                  AR_PHY_AGC_CONTROL_CAL,
+                                  0, AH_WAIT_TIMEOUT)) {
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "offset calibration failed to "
+                                 "complete in 1ms; noisy environment?\n");
+                       return false;
+               }
+
+               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                       if (!AR_SREV_9287_10_OR_LATER(ah))
+                               REG_SET_BIT(ah, AR_PHY_ADC_CTL,
+                                           AR_PHY_ADC_CTL_OFF_PWDADC);
+                       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                                   AR_PHY_AGC_CONTROL_FLTR_CAL);
+               }
+       }
+
+       /* Do PA Calibration */
+       ar9002_hw_pa_cal(ah, true);
+
+       /* Do NF Calibration after DC offset and other calibrations */
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                 REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
+
+       ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+
+       /* Enable IQ, ADC Gain and ADC DC offset CALs */
+       if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
+               if (ar9002_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
+                       INIT_CAL(&ah->adcgain_caldata);
+                       INSERT_CAL(ah, &ah->adcgain_caldata);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "enabling ADC Gain Calibration.\n");
+               }
+               if (ar9002_hw_iscal_supported(ah, ADC_DC_CAL)) {
+                       INIT_CAL(&ah->adcdc_caldata);
+                       INSERT_CAL(ah, &ah->adcdc_caldata);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "enabling ADC DC Calibration.\n");
+               }
+               if (ar9002_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
+                       INIT_CAL(&ah->iq_caldata);
+                       INSERT_CAL(ah, &ah->iq_caldata);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "enabling IQ Calibration.\n");
+               }
+
+               ah->cal_list_curr = ah->cal_list;
+
+               if (ah->cal_list_curr)
+                       ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
+       }
+
+       chan->CalValid = 0;
+
+       return true;
+}
+
+static const struct ath9k_percal_data iq_cal_multi_sample = {
+       IQ_MISMATCH_CAL,
+       MAX_CAL_SAMPLES,
+       PER_MIN_LOG_COUNT,
+       ar9002_hw_iqcal_collect,
+       ar9002_hw_iqcalibrate
+};
+static const struct ath9k_percal_data iq_cal_single_sample = {
+       IQ_MISMATCH_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ar9002_hw_iqcal_collect,
+       ar9002_hw_iqcalibrate
+};
+static const struct ath9k_percal_data adc_gain_cal_multi_sample = {
+       ADC_GAIN_CAL,
+       MAX_CAL_SAMPLES,
+       PER_MIN_LOG_COUNT,
+       ar9002_hw_adc_gaincal_collect,
+       ar9002_hw_adc_gaincal_calibrate
+};
+static const struct ath9k_percal_data adc_gain_cal_single_sample = {
+       ADC_GAIN_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ar9002_hw_adc_gaincal_collect,
+       ar9002_hw_adc_gaincal_calibrate
+};
+static const struct ath9k_percal_data adc_dc_cal_multi_sample = {
+       ADC_DC_CAL,
+       MAX_CAL_SAMPLES,
+       PER_MIN_LOG_COUNT,
+       ar9002_hw_adc_dccal_collect,
+       ar9002_hw_adc_dccal_calibrate
+};
+static const struct ath9k_percal_data adc_dc_cal_single_sample = {
+       ADC_DC_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ar9002_hw_adc_dccal_collect,
+       ar9002_hw_adc_dccal_calibrate
+};
+static const struct ath9k_percal_data adc_init_dc_cal = {
+       ADC_DC_INIT_CAL,
+       MIN_CAL_SAMPLES,
+       INIT_LOG_COUNT,
+       ar9002_hw_adc_dccal_collect,
+       ar9002_hw_adc_dccal_calibrate
+};
+
+static void ar9002_hw_init_cal_settings(struct ath_hw *ah)
+{
+       if (AR_SREV_9100(ah)) {
+               ah->iq_caldata.calData = &iq_cal_multi_sample;
+               ah->supp_cals = IQ_MISMATCH_CAL;
+               return;
+       }
+
+       if (AR_SREV_9160_10_OR_LATER(ah)) {
+               if (AR_SREV_9280_10_OR_LATER(ah)) {
+                       ah->iq_caldata.calData = &iq_cal_single_sample;
+                       ah->adcgain_caldata.calData =
+                               &adc_gain_cal_single_sample;
+                       ah->adcdc_caldata.calData =
+                               &adc_dc_cal_single_sample;
+                       ah->adcdc_calinitdata.calData =
+                               &adc_init_dc_cal;
+               } else {
+                       ah->iq_caldata.calData = &iq_cal_multi_sample;
+                       ah->adcgain_caldata.calData =
+                               &adc_gain_cal_multi_sample;
+                       ah->adcdc_caldata.calData =
+                               &adc_dc_cal_multi_sample;
+                       ah->adcdc_calinitdata.calData =
+                               &adc_init_dc_cal;
+               }
+               ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
+       }
+}
+
+void ar9002_hw_attach_calib_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+       priv_ops->init_cal_settings = ar9002_hw_init_cal_settings;
+       priv_ops->init_cal = ar9002_hw_init_cal;
+       priv_ops->setup_calibration = ar9002_hw_setup_calibration;
+       priv_ops->iscal_supported = ar9002_hw_iscal_supported;
+
+       ops->calibrate = ar9002_hw_calibrate;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
new file mode 100644 (file)
index 0000000..a8a8cdc
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2008-2010 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 "hw.h"
+#include "ar5008_initvals.h"
+#include "ar9001_initvals.h"
+#include "ar9002_initvals.h"
+
+/* General hardware code for the A5008/AR9001/AR9002 hadware families */
+
+static bool ar9002_hw_macversion_supported(u32 macversion)
+{
+       switch (macversion) {
+       case AR_SREV_VERSION_5416_PCI:
+       case AR_SREV_VERSION_5416_PCIE:
+       case AR_SREV_VERSION_9160:
+       case AR_SREV_VERSION_9100:
+       case AR_SREV_VERSION_9280:
+       case AR_SREV_VERSION_9285:
+       case AR_SREV_VERSION_9287:
+       case AR_SREV_VERSION_9271:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+static void ar9002_hw_init_mode_regs(struct ath_hw *ah)
+{
+       if (AR_SREV_9271(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271,
+                              ARRAY_SIZE(ar9271Modes_9271), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
+                              ARRAY_SIZE(ar9271Common_9271), 2);
+               INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271,
+                              ar9271Common_normal_cck_fir_coeff_9271,
+                              ARRAY_SIZE(ar9271Common_normal_cck_fir_coeff_9271), 2);
+               INIT_INI_ARRAY(&ah->iniCommon_japan_2484_cck_fir_coeff_9271,
+                              ar9271Common_japan_2484_cck_fir_coeff_9271,
+                              ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2);
+               INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
+                              ar9271Modes_9271_1_0_only,
+                              ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6);
+               INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg,
+                              ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 6);
+               INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271,
+                              ar9271Modes_high_power_tx_gain_9271,
+                              ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 6);
+               INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271,
+                              ar9271Modes_normal_power_tx_gain_9271,
+                              ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 6);
+               return;
+       }
+
+       if (AR_SREV_9287_11_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
+                               ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
+                               ARRAY_SIZE(ar9287Common_9287_1_1), 2);
+               if (ah->config.pcie_clock_req)
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_off_L1_9287_1_1,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
+               else
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
+                                       2);
+       } else if (AR_SREV_9287_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
+                               ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
+                               ARRAY_SIZE(ar9287Common_9287_1_0), 2);
+
+               if (ah->config.pcie_clock_req)
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_off_L1_9287_1_0,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
+               else
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
+                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
+                                 2);
+       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
+
+
+               INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
+                              ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
+                              ARRAY_SIZE(ar9285Common_9285_1_2), 2);
+
+               if (ah->config.pcie_clock_req) {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9285PciePhy_clkreq_off_L1_9285_1_2,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
+               } else {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
+                                 2);
+               }
+       } else if (AR_SREV_9285_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
+                              ARRAY_SIZE(ar9285Modes_9285), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285,
+                              ARRAY_SIZE(ar9285Common_9285), 2);
+
+               if (ah->config.pcie_clock_req) {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9285PciePhy_clkreq_off_L1_9285,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
+               } else {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                       ar9285PciePhy_clkreq_always_on_L1_9285,
+                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
+               }
+       } else if (AR_SREV_9280_20_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
+                              ARRAY_SIZE(ar9280Modes_9280_2), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
+                              ARRAY_SIZE(ar9280Common_9280_2), 2);
+
+               if (ah->config.pcie_clock_req) {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                              ar9280PciePhy_clkreq_off_L1_9280,
+                              ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2);
+               } else {
+                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                              ar9280PciePhy_clkreq_always_on_L1_9280,
+                              ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
+               }
+               INIT_INI_ARRAY(&ah->iniModesAdditional,
+                              ar9280Modes_fast_clock_9280_2,
+                              ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
+       } else if (AR_SREV_9280_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280,
+                              ARRAY_SIZE(ar9280Modes_9280), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280,
+                              ARRAY_SIZE(ar9280Common_9280), 2);
+       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
+                              ARRAY_SIZE(ar5416Modes_9160), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
+                              ARRAY_SIZE(ar5416Common_9160), 2);
+               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
+                              ARRAY_SIZE(ar5416Bank0_9160), 2);
+               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
+                              ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
+               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
+                              ARRAY_SIZE(ar5416Bank1_9160), 2);
+               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
+                              ARRAY_SIZE(ar5416Bank2_9160), 2);
+               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
+                              ARRAY_SIZE(ar5416Bank3_9160), 3);
+               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
+                              ARRAY_SIZE(ar5416Bank6_9160), 3);
+               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
+                              ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
+               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
+                              ARRAY_SIZE(ar5416Bank7_9160), 2);
+               if (AR_SREV_9160_11(ah)) {
+                       INIT_INI_ARRAY(&ah->iniAddac,
+                                      ar5416Addac_91601_1,
+                                      ARRAY_SIZE(ar5416Addac_91601_1), 2);
+               } else {
+                       INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
+                                      ARRAY_SIZE(ar5416Addac_9160), 2);
+               }
+       } else if (AR_SREV_9100_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100,
+                              ARRAY_SIZE(ar5416Modes_9100), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
+                              ARRAY_SIZE(ar5416Common_9100), 2);
+               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
+                              ARRAY_SIZE(ar5416Bank0_9100), 2);
+               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
+                              ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
+               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
+                              ARRAY_SIZE(ar5416Bank1_9100), 2);
+               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
+                              ARRAY_SIZE(ar5416Bank2_9100), 2);
+               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
+                              ARRAY_SIZE(ar5416Bank3_9100), 3);
+               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
+                              ARRAY_SIZE(ar5416Bank6_9100), 3);
+               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
+                              ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
+               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
+                              ARRAY_SIZE(ar5416Bank7_9100), 2);
+               INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
+                              ARRAY_SIZE(ar5416Addac_9100), 2);
+       } else {
+               INIT_INI_ARRAY(&ah->iniModes, ar5416Modes,
+                              ARRAY_SIZE(ar5416Modes), 6);
+               INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
+                              ARRAY_SIZE(ar5416Common), 2);
+               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
+                              ARRAY_SIZE(ar5416Bank0), 2);
+               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
+                              ARRAY_SIZE(ar5416BB_RfGain), 3);
+               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
+                              ARRAY_SIZE(ar5416Bank1), 2);
+               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
+                              ARRAY_SIZE(ar5416Bank2), 2);
+               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
+                              ARRAY_SIZE(ar5416Bank3), 3);
+               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
+                              ARRAY_SIZE(ar5416Bank6), 3);
+               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
+                              ARRAY_SIZE(ar5416Bank6TPC), 3);
+               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
+                              ARRAY_SIZE(ar5416Bank7), 2);
+               INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
+                              ARRAY_SIZE(ar5416Addac), 2);
+       }
+}
+
+/* Support for Japan ch.14 (2484) spread */
+void ar9002_hw_cck_chan14_spread(struct ath_hw *ah)
+{
+       if (AR_SREV_9287_11_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniCckfirNormal,
+                      ar9287Common_normal_cck_fir_coeff_92871_1,
+                      ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1),
+                      2);
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                      ar9287Common_japan_2484_cck_fir_coeff_92871_1,
+                      ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1),
+                      2);
+       }
+}
+
+static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah)
+{
+       u32 rxgain_type;
+
+       if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
+           AR5416_EEP_MINOR_VER_17) {
+               rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
+
+               if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
+                       INIT_INI_ARRAY(&ah->iniModesRxGain,
+                       ar9280Modes_backoff_13db_rxgain_9280_2,
+                       ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
+               else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
+                       INIT_INI_ARRAY(&ah->iniModesRxGain,
+                       ar9280Modes_backoff_23db_rxgain_9280_2,
+                       ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
+               else
+                       INIT_INI_ARRAY(&ah->iniModesRxGain,
+                       ar9280Modes_original_rxgain_9280_2,
+                       ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+       } else {
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                       ar9280Modes_original_rxgain_9280_2,
+                       ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
+       }
+}
+
+static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah)
+{
+       u32 txgain_type;
+
+       if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >=
+           AR5416_EEP_MINOR_VER_19) {
+               txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
+
+               if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9280Modes_high_power_tx_gain_9280_2,
+                       ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
+               else
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9280Modes_original_tx_gain_9280_2,
+                       ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+       } else {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9280Modes_original_tx_gain_9280_2,
+               ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
+       }
+}
+
+static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+       if (AR_SREV_9287_11_OR_LATER(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+               ar9287Modes_rx_gain_9287_1_1,
+               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
+       else if (AR_SREV_9287_10(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+               ar9287Modes_rx_gain_9287_1_0,
+               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
+       else if (AR_SREV_9280_20(ah))
+               ar9280_20_hw_init_rxgain_ini(ah);
+
+       if (AR_SREV_9287_11_OR_LATER(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9287Modes_tx_gain_9287_1_1,
+               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
+       } else if (AR_SREV_9287_10(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+               ar9287Modes_tx_gain_9287_1_0,
+               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
+       } else if (AR_SREV_9280_20(ah)) {
+               ar9280_20_hw_init_txgain_ini(ah);
+       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
+               u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
+
+               /* txgain table */
+               if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
+                       if (AR_SREV_9285E_20(ah)) {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_XE2_0_high_power,
+                               ARRAY_SIZE(
+                                 ar9285Modes_XE2_0_high_power), 6);
+                       } else {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_high_power_tx_gain_9285_1_2,
+                               ARRAY_SIZE(
+                                 ar9285Modes_high_power_tx_gain_9285_1_2), 6);
+                       }
+               } else {
+                       if (AR_SREV_9285E_20(ah)) {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_XE2_0_normal_power,
+                               ARRAY_SIZE(
+                                 ar9285Modes_XE2_0_normal_power), 6);
+                       } else {
+                               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                               ar9285Modes_original_tx_gain_9285_1_2,
+                               ARRAY_SIZE(
+                                 ar9285Modes_original_tx_gain_9285_1_2), 6);
+                       }
+               }
+       }
+}
+
+/*
+ * Helper for ASPM support.
+ *
+ * Disable PLL when in L0s as well as receiver clock when in L1.
+ * This power saving option must be enabled through the SerDes.
+ *
+ * Programming the SerDes must go through the same 288 bit serial shift
+ * register as the other analog registers.  Hence the 9 writes.
+ */
+static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
+                                        int restore,
+                                        int power_off)
+{
+       u8 i;
+       u32 val;
+
+       if (ah->is_pciexpress != true)
+               return;
+
+       /* Do not touch SerDes registers */
+       if (ah->config.pcie_powersave_enable == 2)
+               return;
+
+       /* Nothing to do on restore for 11N */
+       if (!restore) {
+               if (AR_SREV_9280_20_OR_LATER(ah)) {
+                       /*
+                        * AR9280 2.0 or later chips use SerDes values from the
+                        * initvals.h initialized depending on chipset during
+                        * __ath9k_hw_init()
+                        */
+                       for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
+                               REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
+                                         INI_RA(&ah->iniPcieSerdes, i, 1));
+                       }
+               } else if (AR_SREV_9280(ah) &&
+                          (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+                       /* RX shut off when elecidle is asserted */
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
+
+                       /* Shut off CLKREQ active in L1 */
+                       if (ah->config.pcie_clock_req)
+                               REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
+                       else
+                               REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
+
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
+
+                       /* Load the new settings */
+                       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+               } else {
+                       ENABLE_REGWRITE_BUFFER(ah);
+
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
+
+                       /* RX shut off when elecidle is asserted */
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
+
+                       /*
+                        * Ignore ah->ah_config.pcie_clock_req setting for
+                        * pre-AR9280 11n
+                        */
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
+
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
+                       REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
+
+                       /* Load the new settings */
+                       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+                       REGWRITE_BUFFER_FLUSH(ah);
+                       DISABLE_REGWRITE_BUFFER(ah);
+               }
+
+               udelay(1000);
+
+               /* set bit 19 to allow forcing of pcie core into L1 state */
+               REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+               /* Several PCIe massages to ensure proper behaviour */
+               if (ah->config.pcie_waen) {
+                       val = ah->config.pcie_waen;
+                       if (!power_off)
+                               val &= (~AR_WA_D3_L1_DISABLE);
+               } else {
+                       if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+                           AR_SREV_9287(ah)) {
+                               val = AR9285_WA_DEFAULT;
+                               if (!power_off)
+                                       val &= (~AR_WA_D3_L1_DISABLE);
+                       } else if (AR_SREV_9280(ah)) {
+                               /*
+                                * On AR9280 chips bit 22 of 0x4004 needs to be
+                                * set otherwise card may disappear.
+                                */
+                               val = AR9280_WA_DEFAULT;
+                               if (!power_off)
+                                       val &= (~AR_WA_D3_L1_DISABLE);
+                       } else
+                               val = AR_WA_DEFAULT;
+               }
+
+               REG_WRITE(ah, AR_WA, val);
+       }
+
+       if (power_off) {
+               /*
+                * Set PCIe workaround bits
+                * bit 14 in WA register (disable L1) should only
+                * be set when device enters D3 and be cleared
+                * when device comes back to D0.
+                */
+               if (ah->config.pcie_waen) {
+                       if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+                               REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
+               } else {
+                       if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+                             AR_SREV_9287(ah)) &&
+                            (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+                           (AR_SREV_9280(ah) &&
+                            (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+                               REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
+                       }
+               }
+       }
+}
+
+static int ar9002_hw_get_radiorev(struct ath_hw *ah)
+{
+       u32 val;
+       int i;
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
+       for (i = 0; i < 8; i++)
+               REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
+       val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
+
+       return ath9k_hw_reverse_bits(val, 8);
+}
+
+int ar9002_hw_rf_claim(struct ath_hw *ah)
+{
+       u32 val;
+
+       REG_WRITE(ah, AR_PHY(0), 0x00000007);
+
+       val = ar9002_hw_get_radiorev(ah);
+       switch (val & AR_RADIO_SREV_MAJOR) {
+       case 0:
+               val = AR_RAD5133_SREV_MAJOR;
+               break;
+       case AR_RAD5133_SREV_MAJOR:
+       case AR_RAD5122_SREV_MAJOR:
+       case AR_RAD2133_SREV_MAJOR:
+       case AR_RAD2122_SREV_MAJOR:
+               break;
+       default:
+               ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+                         "Radio Chip Rev 0x%02X not supported\n",
+                         val & AR_RADIO_SREV_MAJOR);
+               return -EOPNOTSUPP;
+       }
+
+       ah->hw_version.analog5GhzRev = val;
+
+       return 0;
+}
+
+/*
+ * Enable ASYNC FIFO
+ *
+ * If Async FIFO is enabled, the following counters change as MAC now runs
+ * at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
+ *
+ * The values below tested for ht40 2 chain.
+ * Overwrite the delay/timeouts initialized in process ini.
+ */
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+{
+       if (AR_SREV_9287_12_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+                         AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+                         AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+                         AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+
+               REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+               REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+
+               REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+                           AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+               REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+                             AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+       }
+}
+
+/*
+ * We don't enable WEP aggregation on mac80211 but we keep this
+ * around for HAL unification purposes.
+ */
+void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
+{
+       if (AR_SREV_9287_12_OR_LATER(ah)) {
+               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+                               AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+       }
+}
+
+/* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
+void ar9002_hw_attach_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+       priv_ops->init_mode_regs = ar9002_hw_init_mode_regs;
+       priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
+       priv_ops->macversion_supported = ar9002_hw_macversion_supported;
+
+       ops->config_pci_powersave = ar9002_hw_configpcipowersave;
+
+       ar5008_hw_attach_phy_ops(ah);
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               ar9002_hw_attach_phy_ops(ah);
+
+       ar9002_hw_attach_calib_ops(ah);
+       ar9002_hw_attach_mac_ops(ah);
+}
similarity index 77%
rename from drivers/net/wireless/ath/ath9k/initvals.h
rename to drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index 8a3bf3ab998d065f7ced6c20569f57b21888505e..dae7f3304eb877610e2dca763aa904e491771756 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2010 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
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-static const u32 ar5416Modes[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
-    { 0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810 },
-    { 0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a },
-    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
-    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
-    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0 },
-    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e },
-    { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 },
-    { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 },
-    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 },
-    { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b },
-    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
-    { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
-    { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
-    { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 },
-    { 0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120 },
-    { 0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00 },
-    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
-    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
-    { 0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c },
-    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
-    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
-    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
-    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
-    { 0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
-    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
-    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
-    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
-    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
-    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
-    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
-    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
-    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
-    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
-    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
-    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-};
-
-static const u32 ar5416Common[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 0x00000034, 0x00000005 },
-    { 0x00000040, 0x00000000 },
-    { 0x00000044, 0x00000008 },
-    { 0x00000048, 0x00000008 },
-    { 0x0000004c, 0x00000010 },
-    { 0x00000050, 0x00000000 },
-    { 0x00000054, 0x0000001f },
-    { 0x00000800, 0x00000000 },
-    { 0x00000804, 0x00000000 },
-    { 0x00000808, 0x00000000 },
-    { 0x0000080c, 0x00000000 },
-    { 0x00000810, 0x00000000 },
-    { 0x00000814, 0x00000000 },
-    { 0x00000818, 0x00000000 },
-    { 0x0000081c, 0x00000000 },
-    { 0x00000820, 0x00000000 },
-    { 0x00000824, 0x00000000 },
-    { 0x00001040, 0x002ffc0f },
-    { 0x00001044, 0x002ffc0f },
-    { 0x00001048, 0x002ffc0f },
-    { 0x0000104c, 0x002ffc0f },
-    { 0x00001050, 0x002ffc0f },
-    { 0x00001054, 0x002ffc0f },
-    { 0x00001058, 0x002ffc0f },
-    { 0x0000105c, 0x002ffc0f },
-    { 0x00001060, 0x002ffc0f },
-    { 0x00001064, 0x002ffc0f },
-    { 0x00001230, 0x00000000 },
-    { 0x00001270, 0x00000000 },
-    { 0x00001038, 0x00000000 },
-    { 0x00001078, 0x00000000 },
-    { 0x000010b8, 0x00000000 },
-    { 0x000010f8, 0x00000000 },
-    { 0x00001138, 0x00000000 },
-    { 0x00001178, 0x00000000 },
-    { 0x000011b8, 0x00000000 },
-    { 0x000011f8, 0x00000000 },
-    { 0x00001238, 0x00000000 },
-    { 0x00001278, 0x00000000 },
-    { 0x000012b8, 0x00000000 },
-    { 0x000012f8, 0x00000000 },
-    { 0x00001338, 0x00000000 },
-    { 0x00001378, 0x00000000 },
-    { 0x000013b8, 0x00000000 },
-    { 0x000013f8, 0x00000000 },
-    { 0x00001438, 0x00000000 },
-    { 0x00001478, 0x00000000 },
-    { 0x000014b8, 0x00000000 },
-    { 0x000014f8, 0x00000000 },
-    { 0x00001538, 0x00000000 },
-    { 0x00001578, 0x00000000 },
-    { 0x000015b8, 0x00000000 },
-    { 0x000015f8, 0x00000000 },
-    { 0x00001638, 0x00000000 },
-    { 0x00001678, 0x00000000 },
-    { 0x000016b8, 0x00000000 },
-    { 0x000016f8, 0x00000000 },
-    { 0x00001738, 0x00000000 },
-    { 0x00001778, 0x00000000 },
-    { 0x000017b8, 0x00000000 },
-    { 0x000017f8, 0x00000000 },
-    { 0x0000103c, 0x00000000 },
-    { 0x0000107c, 0x00000000 },
-    { 0x000010bc, 0x00000000 },
-    { 0x000010fc, 0x00000000 },
-    { 0x0000113c, 0x00000000 },
-    { 0x0000117c, 0x00000000 },
-    { 0x000011bc, 0x00000000 },
-    { 0x000011fc, 0x00000000 },
-    { 0x0000123c, 0x00000000 },
-    { 0x0000127c, 0x00000000 },
-    { 0x000012bc, 0x00000000 },
-    { 0x000012fc, 0x00000000 },
-    { 0x0000133c, 0x00000000 },
-    { 0x0000137c, 0x00000000 },
-    { 0x000013bc, 0x00000000 },
-    { 0x000013fc, 0x00000000 },
-    { 0x0000143c, 0x00000000 },
-    { 0x0000147c, 0x00000000 },
-    { 0x00004030, 0x00000002 },
-    { 0x0000403c, 0x00000002 },
-    { 0x00007010, 0x00000000 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00000000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 0x000080c4, 0x05dc01e0 },
-    { 0x000080c8, 0x1f402710 },
-    { 0x000080cc, 0x01f40000 },
-    { 0x000080d0, 0x00001e00 },
-    { 0x000080d4, 0x00000000 },
-    { 0x000080d8, 0x00400000 },
-    { 0x000080e0, 0xffffffff },
-    { 0x000080e4, 0x0000ffff },
-    { 0x000080e8, 0x003f3f3f },
-    { 0x000080ec, 0x00000000 },
-    { 0x000080f0, 0x00000000 },
-    { 0x000080f4, 0x00000000 },
-    { 0x000080f8, 0x00000000 },
-    { 0x000080fc, 0x00020000 },
-    { 0x00008100, 0x00020000 },
-    { 0x00008104, 0x00000001 },
-    { 0x00008108, 0x00000052 },
-    { 0x0000810c, 0x00000000 },
-    { 0x00008110, 0x00000168 },
-    { 0x00008118, 0x000100aa },
-    { 0x0000811c, 0x00003210 },
-    { 0x00008124, 0x00000000 },
-    { 0x00008128, 0x00000000 },
-    { 0x0000812c, 0x00000000 },
-    { 0x00008130, 0x00000000 },
-    { 0x00008134, 0x00000000 },
-    { 0x00008138, 0x00000000 },
-    { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0xffffffff },
-    { 0x00008168, 0x00000000 },
-    { 0x0000816c, 0x00000000 },
-    { 0x00008170, 0x32143320 },
-    { 0x00008174, 0xfaa4fa50 },
-    { 0x00008178, 0x00000100 },
-    { 0x0000817c, 0x00000000 },
-    { 0x000081c4, 0x00000000 },
-    { 0x000081ec, 0x00000000 },
-    { 0x000081f0, 0x00000000 },
-    { 0x000081f4, 0x00000000 },
-    { 0x000081f8, 0x00000000 },
-    { 0x000081fc, 0x00000000 },
-    { 0x00008200, 0x00000000 },
-    { 0x00008204, 0x00000000 },
-    { 0x00008208, 0x00000000 },
-    { 0x0000820c, 0x00000000 },
-    { 0x00008210, 0x00000000 },
-    { 0x00008214, 0x00000000 },
-    { 0x00008218, 0x00000000 },
-    { 0x0000821c, 0x00000000 },
-    { 0x00008220, 0x00000000 },
-    { 0x00008224, 0x00000000 },
-    { 0x00008228, 0x00000000 },
-    { 0x0000822c, 0x00000000 },
-    { 0x00008230, 0x00000000 },
-    { 0x00008234, 0x00000000 },
-    { 0x00008238, 0x00000000 },
-    { 0x0000823c, 0x00000000 },
-    { 0x00008240, 0x00100000 },
-    { 0x00008244, 0x0010f400 },
-    { 0x00008248, 0x00000100 },
-    { 0x0000824c, 0x0001e800 },
-    { 0x00008250, 0x00000000 },
-    { 0x00008254, 0x00000000 },
-    { 0x00008258, 0x00000000 },
-    { 0x0000825c, 0x400000ff },
-    { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8000010 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00070000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xad848e19 },
-    { 0x00009810, 0x7d14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a002e },
-    { 0x0000984c, 0x1284233c },
-    { 0x00009854, 0x00000859 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x05100000 },
-    { 0x0000a920, 0x05100000 },
-    { 0x0000b920, 0x05100000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280b212 },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5d50e188 },
-    { 0x00009958, 0x00081fff },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb515 },
-    { 0x00009974, 0x00000000 },
-    { 0x00009978, 0x00000001 },
-    { 0x0000997c, 0x00000000 },
-    { 0x00009980, 0x00000000 },
-    { 0x00009984, 0x00000000 },
-    { 0x00009988, 0x00000000 },
-    { 0x0000998c, 0x00000000 },
-    { 0x00009990, 0x00000000 },
-    { 0x00009994, 0x00000000 },
-    { 0x00009998, 0x00000000 },
-    { 0x0000999c, 0x00000000 },
-    { 0x000099a0, 0x00000000 },
-    { 0x000099a4, 0x00000001 },
-    { 0x000099a8, 0x001fff00 },
-    { 0x000099ac, 0x00000000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000200 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x000000aa },
-    { 0x000099fc, 0x00001042 },
-    { 0x00009b00, 0x00000000 },
-    { 0x00009b04, 0x00000001 },
-    { 0x00009b08, 0x00000002 },
-    { 0x00009b0c, 0x00000003 },
-    { 0x00009b10, 0x00000004 },
-    { 0x00009b14, 0x00000005 },
-    { 0x00009b18, 0x00000008 },
-    { 0x00009b1c, 0x00000009 },
-    { 0x00009b20, 0x0000000a },
-    { 0x00009b24, 0x0000000b },
-    { 0x00009b28, 0x0000000c },
-    { 0x00009b2c, 0x0000000d },
-    { 0x00009b30, 0x00000010 },
-    { 0x00009b34, 0x00000011 },
-    { 0x00009b38, 0x00000012 },
-    { 0x00009b3c, 0x00000013 },
-    { 0x00009b40, 0x00000014 },
-    { 0x00009b44, 0x00000015 },
-    { 0x00009b48, 0x00000018 },
-    { 0x00009b4c, 0x00000019 },
-    { 0x00009b50, 0x0000001a },
-    { 0x00009b54, 0x0000001b },
-    { 0x00009b58, 0x0000001c },
-    { 0x00009b5c, 0x0000001d },
-    { 0x00009b60, 0x00000020 },
-    { 0x00009b64, 0x00000021 },
-    { 0x00009b68, 0x00000022 },
-    { 0x00009b6c, 0x00000023 },
-    { 0x00009b70, 0x00000024 },
-    { 0x00009b74, 0x00000025 },
-    { 0x00009b78, 0x00000028 },
-    { 0x00009b7c, 0x00000029 },
-    { 0x00009b80, 0x0000002a },
-    { 0x00009b84, 0x0000002b },
-    { 0x00009b88, 0x0000002c },
-    { 0x00009b8c, 0x0000002d },
-    { 0x00009b90, 0x00000030 },
-    { 0x00009b94, 0x00000031 },
-    { 0x00009b98, 0x00000032 },
-    { 0x00009b9c, 0x00000033 },
-    { 0x00009ba0, 0x00000034 },
-    { 0x00009ba4, 0x00000035 },
-    { 0x00009ba8, 0x00000035 },
-    { 0x00009bac, 0x00000035 },
-    { 0x00009bb0, 0x00000035 },
-    { 0x00009bb4, 0x00000035 },
-    { 0x00009bb8, 0x00000035 },
-    { 0x00009bbc, 0x00000035 },
-    { 0x00009bc0, 0x00000035 },
-    { 0x00009bc4, 0x00000035 },
-    { 0x00009bc8, 0x00000035 },
-    { 0x00009bcc, 0x00000035 },
-    { 0x00009bd0, 0x00000035 },
-    { 0x00009bd4, 0x00000035 },
-    { 0x00009bd8, 0x00000035 },
-    { 0x00009bdc, 0x00000035 },
-    { 0x00009be0, 0x00000035 },
-    { 0x00009be4, 0x00000035 },
-    { 0x00009be8, 0x00000035 },
-    { 0x00009bec, 0x00000035 },
-    { 0x00009bf0, 0x00000035 },
-    { 0x00009bf4, 0x00000035 },
-    { 0x00009bf8, 0x00000010 },
-    { 0x00009bfc, 0x0000001a },
-    { 0x0000a210, 0x40806333 },
-    { 0x0000a214, 0x00106c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x018830c6 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x00000bb5 },
-    { 0x0000a22c, 0x00000011 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000a000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cc75380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000000 },
-    { 0x0000a26c, 0x0e79e5c6 },
-    { 0x0000b26c, 0x0e79e5c6 },
-    { 0x0000c26c, 0x0e79e5c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x051701ce },
-    { 0x0000a338, 0x00000000 },
-    { 0x0000a33c, 0x00000000 },
-    { 0x0000a340, 0x00000000 },
-    { 0x0000a344, 0x00000000 },
-    { 0x0000a348, 0x3fffffff },
-    { 0x0000a34c, 0x3fffffff },
-    { 0x0000a350, 0x3fffffff },
-    { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79a8aa1f },
-    { 0x0000d35c, 0x07ffffef },
-    { 0x0000d360, 0x0fffffe7 },
-    { 0x0000d364, 0x17ffffe5 },
-    { 0x0000d368, 0x1fffffe4 },
-    { 0x0000d36c, 0x37ffffe3 },
-    { 0x0000d370, 0x3fffffe3 },
-    { 0x0000d374, 0x57ffffe3 },
-    { 0x0000d378, 0x5fffffe2 },
-    { 0x0000d37c, 0x7fffffe2 },
-    { 0x0000d380, 0x7f3c7bba },
-    { 0x0000d384, 0xf3307ff0 },
-    { 0x0000a388, 0x08000000 },
-    { 0x0000a38c, 0x20202020 },
-    { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-};
-
-static const u32 ar5416Bank0[][2] = {
-    { 0x000098b0, 0x1e5795e5 },
-    { 0x000098e0, 0x02008020 },
-};
-
-static const u32 ar5416BB_RfGain[][3] = {
-    { 0x00009a00, 0x00000000, 0x00000000 },
-    { 0x00009a04, 0x00000040, 0x00000040 },
-    { 0x00009a08, 0x00000080, 0x00000080 },
-    { 0x00009a0c, 0x000001a1, 0x00000141 },
-    { 0x00009a10, 0x000001e1, 0x00000181 },
-    { 0x00009a14, 0x00000021, 0x000001c1 },
-    { 0x00009a18, 0x00000061, 0x00000001 },
-    { 0x00009a1c, 0x00000168, 0x00000041 },
-    { 0x00009a20, 0x000001a8, 0x000001a8 },
-    { 0x00009a24, 0x000001e8, 0x000001e8 },
-    { 0x00009a28, 0x00000028, 0x00000028 },
-    { 0x00009a2c, 0x00000068, 0x00000068 },
-    { 0x00009a30, 0x00000189, 0x000000a8 },
-    { 0x00009a34, 0x000001c9, 0x00000169 },
-    { 0x00009a38, 0x00000009, 0x000001a9 },
-    { 0x00009a3c, 0x00000049, 0x000001e9 },
-    { 0x00009a40, 0x00000089, 0x00000029 },
-    { 0x00009a44, 0x00000170, 0x00000069 },
-    { 0x00009a48, 0x000001b0, 0x00000190 },
-    { 0x00009a4c, 0x000001f0, 0x000001d0 },
-    { 0x00009a50, 0x00000030, 0x00000010 },
-    { 0x00009a54, 0x00000070, 0x00000050 },
-    { 0x00009a58, 0x00000191, 0x00000090 },
-    { 0x00009a5c, 0x000001d1, 0x00000151 },
-    { 0x00009a60, 0x00000011, 0x00000191 },
-    { 0x00009a64, 0x00000051, 0x000001d1 },
-    { 0x00009a68, 0x00000091, 0x00000011 },
-    { 0x00009a6c, 0x000001b8, 0x00000051 },
-    { 0x00009a70, 0x000001f8, 0x00000198 },
-    { 0x00009a74, 0x00000038, 0x000001d8 },
-    { 0x00009a78, 0x00000078, 0x00000018 },
-    { 0x00009a7c, 0x00000199, 0x00000058 },
-    { 0x00009a80, 0x000001d9, 0x00000098 },
-    { 0x00009a84, 0x00000019, 0x00000159 },
-    { 0x00009a88, 0x00000059, 0x00000199 },
-    { 0x00009a8c, 0x00000099, 0x000001d9 },
-    { 0x00009a90, 0x000000d9, 0x00000019 },
-    { 0x00009a94, 0x000000f9, 0x00000059 },
-    { 0x00009a98, 0x000000f9, 0x00000099 },
-    { 0x00009a9c, 0x000000f9, 0x000000d9 },
-    { 0x00009aa0, 0x000000f9, 0x000000f9 },
-    { 0x00009aa4, 0x000000f9, 0x000000f9 },
-    { 0x00009aa8, 0x000000f9, 0x000000f9 },
-    { 0x00009aac, 0x000000f9, 0x000000f9 },
-    { 0x00009ab0, 0x000000f9, 0x000000f9 },
-    { 0x00009ab4, 0x000000f9, 0x000000f9 },
-    { 0x00009ab8, 0x000000f9, 0x000000f9 },
-    { 0x00009abc, 0x000000f9, 0x000000f9 },
-    { 0x00009ac0, 0x000000f9, 0x000000f9 },
-    { 0x00009ac4, 0x000000f9, 0x000000f9 },
-    { 0x00009ac8, 0x000000f9, 0x000000f9 },
-    { 0x00009acc, 0x000000f9, 0x000000f9 },
-    { 0x00009ad0, 0x000000f9, 0x000000f9 },
-    { 0x00009ad4, 0x000000f9, 0x000000f9 },
-    { 0x00009ad8, 0x000000f9, 0x000000f9 },
-    { 0x00009adc, 0x000000f9, 0x000000f9 },
-    { 0x00009ae0, 0x000000f9, 0x000000f9 },
-    { 0x00009ae4, 0x000000f9, 0x000000f9 },
-    { 0x00009ae8, 0x000000f9, 0x000000f9 },
-    { 0x00009aec, 0x000000f9, 0x000000f9 },
-    { 0x00009af0, 0x000000f9, 0x000000f9 },
-    { 0x00009af4, 0x000000f9, 0x000000f9 },
-    { 0x00009af8, 0x000000f9, 0x000000f9 },
-    { 0x00009afc, 0x000000f9, 0x000000f9 },
-};
-
-static const u32 ar5416Bank1[][2] = {
-    { 0x000098b0, 0x02108421 },
-    { 0x000098ec, 0x00000008 },
-};
-
-static const u32 ar5416Bank2[][2] = {
-    { 0x000098b0, 0x0e73ff17 },
-    { 0x000098e0, 0x00000420 },
-};
-
-static const u32 ar5416Bank3[][3] = {
-    { 0x000098f0, 0x01400018, 0x01c00018 },
-};
-
-static const u32 ar5416Bank6[][3] = {
-
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x004210a2, 0x004210a2 },
-    { 0x0000989c, 0x0014008f, 0x0014008f },
-    { 0x0000989c, 0x00c40003, 0x00c40003 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000f1, 0x000000f1 },
-    { 0x0000989c, 0x00002081, 0x00002081 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
-};
-
-static const u32 ar5416Bank6TPC[][3] = {
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x00423022, 0x00423022 },
-    { 0x0000989c, 0x201400df, 0x201400df },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000e1, 0x000000e1 },
-    { 0x0000989c, 0x00007081, 0x00007081 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
-};
-
-static const u32 ar5416Bank7[][2] = {
-    { 0x0000989c, 0x00000500 },
-    { 0x0000989c, 0x00000800 },
-    { 0x000098cc, 0x0000000e },
-};
-
-static const u32 ar5416Addac[][2] = {
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000003 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x0000000c },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000030 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000060 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000058 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x000098cc,  0x00000000 },
-};
-
-static const u32 ar5416Modes_9100[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
-    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
-    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
-    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec86d2e, 0x7ec84d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e },
-    { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
-    { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
-    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a11, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009940, 0x00754604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204 },
-    { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 },
-    { 0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e },
-    { 0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff },
-#ifdef TB243
-    { 0x00009960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
-    { 0x0000a960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
-    { 0x0000b960, 0x00000900, 0x00000900, 0x00009b40, 0x00009b40, 0x00012d80 },
-    { 0x00009964, 0x00000000, 0x00000000, 0x00002210, 0x00002210, 0x00001120 },
-#else
-    { 0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
-    { 0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
-    { 0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0 },
-    { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
-#endif
-    { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00 },
-    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
-    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
-    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
-    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
-    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
-    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
-    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
-    { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
-    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
-    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
-    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
-    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
-    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
-    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
-    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
-    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
-    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
-    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
-    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-};
-
-static const u32 ar5416Common_9100[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 0x00000034, 0x00000005 },
-    { 0x00000040, 0x00000000 },
-    { 0x00000044, 0x00000008 },
-    { 0x00000048, 0x00000008 },
-    { 0x0000004c, 0x00000010 },
-    { 0x00000050, 0x00000000 },
-    { 0x00000054, 0x0000001f },
-    { 0x00000800, 0x00000000 },
-    { 0x00000804, 0x00000000 },
-    { 0x00000808, 0x00000000 },
-    { 0x0000080c, 0x00000000 },
-    { 0x00000810, 0x00000000 },
-    { 0x00000814, 0x00000000 },
-    { 0x00000818, 0x00000000 },
-    { 0x0000081c, 0x00000000 },
-    { 0x00000820, 0x00000000 },
-    { 0x00000824, 0x00000000 },
-    { 0x00001040, 0x002ffc0f },
-    { 0x00001044, 0x002ffc0f },
-    { 0x00001048, 0x002ffc0f },
-    { 0x0000104c, 0x002ffc0f },
-    { 0x00001050, 0x002ffc0f },
-    { 0x00001054, 0x002ffc0f },
-    { 0x00001058, 0x002ffc0f },
-    { 0x0000105c, 0x002ffc0f },
-    { 0x00001060, 0x002ffc0f },
-    { 0x00001064, 0x002ffc0f },
-    { 0x00001230, 0x00000000 },
-    { 0x00001270, 0x00000000 },
-    { 0x00001038, 0x00000000 },
-    { 0x00001078, 0x00000000 },
-    { 0x000010b8, 0x00000000 },
-    { 0x000010f8, 0x00000000 },
-    { 0x00001138, 0x00000000 },
-    { 0x00001178, 0x00000000 },
-    { 0x000011b8, 0x00000000 },
-    { 0x000011f8, 0x00000000 },
-    { 0x00001238, 0x00000000 },
-    { 0x00001278, 0x00000000 },
-    { 0x000012b8, 0x00000000 },
-    { 0x000012f8, 0x00000000 },
-    { 0x00001338, 0x00000000 },
-    { 0x00001378, 0x00000000 },
-    { 0x000013b8, 0x00000000 },
-    { 0x000013f8, 0x00000000 },
-    { 0x00001438, 0x00000000 },
-    { 0x00001478, 0x00000000 },
-    { 0x000014b8, 0x00000000 },
-    { 0x000014f8, 0x00000000 },
-    { 0x00001538, 0x00000000 },
-    { 0x00001578, 0x00000000 },
-    { 0x000015b8, 0x00000000 },
-    { 0x000015f8, 0x00000000 },
-    { 0x00001638, 0x00000000 },
-    { 0x00001678, 0x00000000 },
-    { 0x000016b8, 0x00000000 },
-    { 0x000016f8, 0x00000000 },
-    { 0x00001738, 0x00000000 },
-    { 0x00001778, 0x00000000 },
-    { 0x000017b8, 0x00000000 },
-    { 0x000017f8, 0x00000000 },
-    { 0x0000103c, 0x00000000 },
-    { 0x0000107c, 0x00000000 },
-    { 0x000010bc, 0x00000000 },
-    { 0x000010fc, 0x00000000 },
-    { 0x0000113c, 0x00000000 },
-    { 0x0000117c, 0x00000000 },
-    { 0x000011bc, 0x00000000 },
-    { 0x000011fc, 0x00000000 },
-    { 0x0000123c, 0x00000000 },
-    { 0x0000127c, 0x00000000 },
-    { 0x000012bc, 0x00000000 },
-    { 0x000012fc, 0x00000000 },
-    { 0x0000133c, 0x00000000 },
-    { 0x0000137c, 0x00000000 },
-    { 0x000013bc, 0x00000000 },
-    { 0x000013fc, 0x00000000 },
-    { 0x0000143c, 0x00000000 },
-    { 0x0000147c, 0x00000000 },
-    { 0x00020010, 0x00000003 },
-    { 0x00020038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00004000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 0x000080c4, 0x05dc01e0 },
-    { 0x000080c8, 0x1f402710 },
-    { 0x000080cc, 0x01f40000 },
-    { 0x000080d0, 0x00001e00 },
-    { 0x000080d4, 0x00000000 },
-    { 0x000080d8, 0x00400000 },
-    { 0x000080e0, 0xffffffff },
-    { 0x000080e4, 0x0000ffff },
-    { 0x000080e8, 0x003f3f3f },
-    { 0x000080ec, 0x00000000 },
-    { 0x000080f0, 0x00000000 },
-    { 0x000080f4, 0x00000000 },
-    { 0x000080f8, 0x00000000 },
-    { 0x000080fc, 0x00020000 },
-    { 0x00008100, 0x00020000 },
-    { 0x00008104, 0x00000001 },
-    { 0x00008108, 0x00000052 },
-    { 0x0000810c, 0x00000000 },
-    { 0x00008110, 0x00000168 },
-    { 0x00008118, 0x000100aa },
-    { 0x0000811c, 0x00003210 },
-    { 0x00008120, 0x08f04800 },
-    { 0x00008124, 0x00000000 },
-    { 0x00008128, 0x00000000 },
-    { 0x0000812c, 0x00000000 },
-    { 0x00008130, 0x00000000 },
-    { 0x00008134, 0x00000000 },
-    { 0x00008138, 0x00000000 },
-    { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0x00000000 },
-    { 0x00008168, 0x00000000 },
-    { 0x0000816c, 0x00000000 },
-    { 0x00008170, 0x32143320 },
-    { 0x00008174, 0xfaa4fa50 },
-    { 0x00008178, 0x00000100 },
-    { 0x0000817c, 0x00000000 },
-    { 0x000081c4, 0x00000000 },
-    { 0x000081d0, 0x00003210 },
-    { 0x000081ec, 0x00000000 },
-    { 0x000081f0, 0x00000000 },
-    { 0x000081f4, 0x00000000 },
-    { 0x000081f8, 0x00000000 },
-    { 0x000081fc, 0x00000000 },
-    { 0x00008200, 0x00000000 },
-    { 0x00008204, 0x00000000 },
-    { 0x00008208, 0x00000000 },
-    { 0x0000820c, 0x00000000 },
-    { 0x00008210, 0x00000000 },
-    { 0x00008214, 0x00000000 },
-    { 0x00008218, 0x00000000 },
-    { 0x0000821c, 0x00000000 },
-    { 0x00008220, 0x00000000 },
-    { 0x00008224, 0x00000000 },
-    { 0x00008228, 0x00000000 },
-    { 0x0000822c, 0x00000000 },
-    { 0x00008230, 0x00000000 },
-    { 0x00008234, 0x00000000 },
-    { 0x00008238, 0x00000000 },
-    { 0x0000823c, 0x00000000 },
-    { 0x00008240, 0x00100000 },
-    { 0x00008244, 0x0010f400 },
-    { 0x00008248, 0x00000100 },
-    { 0x0000824c, 0x0001e800 },
-    { 0x00008250, 0x00000000 },
-    { 0x00008254, 0x00000000 },
-    { 0x00008258, 0x00000000 },
-    { 0x0000825c, 0x400000ff },
-    { 0x00008260, 0x00080922 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00000000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xad848e19 },
-    { 0x00009810, 0x7d14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a01ae },
-    { 0x0000984c, 0x1284233c },
-    { 0x00009854, 0x00000859 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x05100000 },
-    { 0x0000a920, 0x05100000 },
-    { 0x0000b920, 0x05100000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280b212 },
-    { 0x0000994c, 0x00020028 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x0000c968, 0x000003ce },
-    { 0x00009970, 0x190fb515 },
-    { 0x00009974, 0x00000000 },
-    { 0x00009978, 0x00000001 },
-    { 0x0000997c, 0x00000000 },
-    { 0x00009980, 0x00000000 },
-    { 0x00009984, 0x00000000 },
-    { 0x00009988, 0x00000000 },
-    { 0x0000998c, 0x00000000 },
-    { 0x00009990, 0x00000000 },
-    { 0x00009994, 0x00000000 },
-    { 0x00009998, 0x00000000 },
-    { 0x0000999c, 0x00000000 },
-    { 0x000099a0, 0x00000000 },
-    { 0x000099a4, 0x00000001 },
-    { 0x000099a8, 0x201fff00 },
-    { 0x000099ac, 0x006f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000200 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099fc, 0x00001042 },
-    { 0x00009b00, 0x00000000 },
-    { 0x00009b04, 0x00000001 },
-    { 0x00009b08, 0x00000002 },
-    { 0x00009b0c, 0x00000003 },
-    { 0x00009b10, 0x00000004 },
-    { 0x00009b14, 0x00000005 },
-    { 0x00009b18, 0x00000008 },
-    { 0x00009b1c, 0x00000009 },
-    { 0x00009b20, 0x0000000a },
-    { 0x00009b24, 0x0000000b },
-    { 0x00009b28, 0x0000000c },
-    { 0x00009b2c, 0x0000000d },
-    { 0x00009b30, 0x00000010 },
-    { 0x00009b34, 0x00000011 },
-    { 0x00009b38, 0x00000012 },
-    { 0x00009b3c, 0x00000013 },
-    { 0x00009b40, 0x00000014 },
-    { 0x00009b44, 0x00000015 },
-    { 0x00009b48, 0x00000018 },
-    { 0x00009b4c, 0x00000019 },
-    { 0x00009b50, 0x0000001a },
-    { 0x00009b54, 0x0000001b },
-    { 0x00009b58, 0x0000001c },
-    { 0x00009b5c, 0x0000001d },
-    { 0x00009b60, 0x00000020 },
-    { 0x00009b64, 0x00000021 },
-    { 0x00009b68, 0x00000022 },
-    { 0x00009b6c, 0x00000023 },
-    { 0x00009b70, 0x00000024 },
-    { 0x00009b74, 0x00000025 },
-    { 0x00009b78, 0x00000028 },
-    { 0x00009b7c, 0x00000029 },
-    { 0x00009b80, 0x0000002a },
-    { 0x00009b84, 0x0000002b },
-    { 0x00009b88, 0x0000002c },
-    { 0x00009b8c, 0x0000002d },
-    { 0x00009b90, 0x00000030 },
-    { 0x00009b94, 0x00000031 },
-    { 0x00009b98, 0x00000032 },
-    { 0x00009b9c, 0x00000033 },
-    { 0x00009ba0, 0x00000034 },
-    { 0x00009ba4, 0x00000035 },
-    { 0x00009ba8, 0x00000035 },
-    { 0x00009bac, 0x00000035 },
-    { 0x00009bb0, 0x00000035 },
-    { 0x00009bb4, 0x00000035 },
-    { 0x00009bb8, 0x00000035 },
-    { 0x00009bbc, 0x00000035 },
-    { 0x00009bc0, 0x00000035 },
-    { 0x00009bc4, 0x00000035 },
-    { 0x00009bc8, 0x00000035 },
-    { 0x00009bcc, 0x00000035 },
-    { 0x00009bd0, 0x00000035 },
-    { 0x00009bd4, 0x00000035 },
-    { 0x00009bd8, 0x00000035 },
-    { 0x00009bdc, 0x00000035 },
-    { 0x00009be0, 0x00000035 },
-    { 0x00009be4, 0x00000035 },
-    { 0x00009be8, 0x00000035 },
-    { 0x00009bec, 0x00000035 },
-    { 0x00009bf0, 0x00000035 },
-    { 0x00009bf4, 0x00000035 },
-    { 0x00009bf8, 0x00000010 },
-    { 0x00009bfc, 0x0000001a },
-    { 0x0000a210, 0x40806333 },
-    { 0x0000a214, 0x00106c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x018830c6 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x001a0bb5 },
-    { 0x0000a22c, 0x00000000 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889ae },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000a000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cc75380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000001 },
-    { 0x0000a26c, 0x0ebae9c6 },
-    { 0x0000b26c, 0x0ebae9c6 },
-    { 0x0000c26c, 0x0ebae9c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 0x0000a338, 0x00000000 },
-    { 0x0000a33c, 0x00000000 },
-    { 0x0000a340, 0x00000000 },
-    { 0x0000a344, 0x00000000 },
-    { 0x0000a348, 0x3fffffff },
-    { 0x0000a34c, 0x3fffffff },
-    { 0x0000a350, 0x3fffffff },
-    { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79a8aa33 },
-    { 0x0000d35c, 0x07ffffef },
-    { 0x0000d360, 0x0fffffe7 },
-    { 0x0000d364, 0x17ffffe5 },
-    { 0x0000d368, 0x1fffffe4 },
-    { 0x0000d36c, 0x37ffffe3 },
-    { 0x0000d370, 0x3fffffe3 },
-    { 0x0000d374, 0x57ffffe3 },
-    { 0x0000d378, 0x5fffffe2 },
-    { 0x0000d37c, 0x7fffffe2 },
-    { 0x0000d380, 0x7f3c7bba },
-    { 0x0000d384, 0xf3307ff0 },
-    { 0x0000a388, 0x0c000000 },
-    { 0x0000a38c, 0x20202020 },
-    { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-};
-
-static const u32 ar5416Bank0_9100[][2] = {
-    { 0x000098b0, 0x1e5795e5 },
-    { 0x000098e0, 0x02008020 },
-};
-
-static const u32 ar5416BB_RfGain_9100[][3] = {
-    { 0x00009a00, 0x00000000, 0x00000000 },
-    { 0x00009a04, 0x00000040, 0x00000040 },
-    { 0x00009a08, 0x00000080, 0x00000080 },
-    { 0x00009a0c, 0x000001a1, 0x00000141 },
-    { 0x00009a10, 0x000001e1, 0x00000181 },
-    { 0x00009a14, 0x00000021, 0x000001c1 },
-    { 0x00009a18, 0x00000061, 0x00000001 },
-    { 0x00009a1c, 0x00000168, 0x00000041 },
-    { 0x00009a20, 0x000001a8, 0x000001a8 },
-    { 0x00009a24, 0x000001e8, 0x000001e8 },
-    { 0x00009a28, 0x00000028, 0x00000028 },
-    { 0x00009a2c, 0x00000068, 0x00000068 },
-    { 0x00009a30, 0x00000189, 0x000000a8 },
-    { 0x00009a34, 0x000001c9, 0x00000169 },
-    { 0x00009a38, 0x00000009, 0x000001a9 },
-    { 0x00009a3c, 0x00000049, 0x000001e9 },
-    { 0x00009a40, 0x00000089, 0x00000029 },
-    { 0x00009a44, 0x00000170, 0x00000069 },
-    { 0x00009a48, 0x000001b0, 0x00000190 },
-    { 0x00009a4c, 0x000001f0, 0x000001d0 },
-    { 0x00009a50, 0x00000030, 0x00000010 },
-    { 0x00009a54, 0x00000070, 0x00000050 },
-    { 0x00009a58, 0x00000191, 0x00000090 },
-    { 0x00009a5c, 0x000001d1, 0x00000151 },
-    { 0x00009a60, 0x00000011, 0x00000191 },
-    { 0x00009a64, 0x00000051, 0x000001d1 },
-    { 0x00009a68, 0x00000091, 0x00000011 },
-    { 0x00009a6c, 0x000001b8, 0x00000051 },
-    { 0x00009a70, 0x000001f8, 0x00000198 },
-    { 0x00009a74, 0x00000038, 0x000001d8 },
-    { 0x00009a78, 0x00000078, 0x00000018 },
-    { 0x00009a7c, 0x00000199, 0x00000058 },
-    { 0x00009a80, 0x000001d9, 0x00000098 },
-    { 0x00009a84, 0x00000019, 0x00000159 },
-    { 0x00009a88, 0x00000059, 0x00000199 },
-    { 0x00009a8c, 0x00000099, 0x000001d9 },
-    { 0x00009a90, 0x000000d9, 0x00000019 },
-    { 0x00009a94, 0x000000f9, 0x00000059 },
-    { 0x00009a98, 0x000000f9, 0x00000099 },
-    { 0x00009a9c, 0x000000f9, 0x000000d9 },
-    { 0x00009aa0, 0x000000f9, 0x000000f9 },
-    { 0x00009aa4, 0x000000f9, 0x000000f9 },
-    { 0x00009aa8, 0x000000f9, 0x000000f9 },
-    { 0x00009aac, 0x000000f9, 0x000000f9 },
-    { 0x00009ab0, 0x000000f9, 0x000000f9 },
-    { 0x00009ab4, 0x000000f9, 0x000000f9 },
-    { 0x00009ab8, 0x000000f9, 0x000000f9 },
-    { 0x00009abc, 0x000000f9, 0x000000f9 },
-    { 0x00009ac0, 0x000000f9, 0x000000f9 },
-    { 0x00009ac4, 0x000000f9, 0x000000f9 },
-    { 0x00009ac8, 0x000000f9, 0x000000f9 },
-    { 0x00009acc, 0x000000f9, 0x000000f9 },
-    { 0x00009ad0, 0x000000f9, 0x000000f9 },
-    { 0x00009ad4, 0x000000f9, 0x000000f9 },
-    { 0x00009ad8, 0x000000f9, 0x000000f9 },
-    { 0x00009adc, 0x000000f9, 0x000000f9 },
-    { 0x00009ae0, 0x000000f9, 0x000000f9 },
-    { 0x00009ae4, 0x000000f9, 0x000000f9 },
-    { 0x00009ae8, 0x000000f9, 0x000000f9 },
-    { 0x00009aec, 0x000000f9, 0x000000f9 },
-    { 0x00009af0, 0x000000f9, 0x000000f9 },
-    { 0x00009af4, 0x000000f9, 0x000000f9 },
-    { 0x00009af8, 0x000000f9, 0x000000f9 },
-    { 0x00009afc, 0x000000f9, 0x000000f9 },
-};
-
-static const u32 ar5416Bank1_9100[][2] = {
-    { 0x000098b0, 0x02108421},
-    { 0x000098ec, 0x00000008},
-};
-
-static const u32 ar5416Bank2_9100[][2] = {
-    { 0x000098b0, 0x0e73ff17},
-    { 0x000098e0, 0x00000420},
-};
-
-static const u32 ar5416Bank3_9100[][3] = {
-    { 0x000098f0, 0x01400018, 0x01c00018 },
-};
-
-static const u32 ar5416Bank6_9100[][3] = {
-
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x004210a2, 0x004210a2 },
-    { 0x0000989c, 0x0014000f, 0x0014000f },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x000180d6, 0x000180d6 },
-    { 0x0000989c, 0x0000c0aa, 0x0000c0aa },
-    { 0x0000989c, 0x000000b1, 0x000000b1 },
-    { 0x0000989c, 0x00002000, 0x00002000 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
-};
-
-
-static const u32 ar5416Bank6TPC_9100[][3] = {
-
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x00423022, 0x00423022 },
-    { 0x0000989c, 0x2014008f, 0x2014008f },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000e1, 0x000000e1 },
-    { 0x0000989c, 0x00007080, 0x00007080 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
-};
-
-static const u32 ar5416Bank7_9100[][2] = {
-    { 0x0000989c, 0x00000500 },
-    { 0x0000989c, 0x00000800 },
-    { 0x000098cc, 0x0000000e },
-};
-
-static const u32 ar5416Addac_9100[][2] = {
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000010 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x000000c0 },
-    {0x0000989c, 0x00000015 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x0000989c, 0x00000000 },
-    {0x000098cc, 0x00000000 },
-};
-
-static const u32 ar5416Modes_9160[][6] = {
-    { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
-    { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
-    { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
-    { 0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008 },
-    { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 },
-    { 0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf },
-    { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 },
-    { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 },
-    { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
-    { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e },
-    { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 },
-    { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 },
-    { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 },
-    { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 },
-    { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e },
-    { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e },
-    { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 },
-    { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 },
-    { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 },
-    { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 },
-    { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 },
-    { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 },
-    { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d },
-    { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 },
-    { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
-    { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
-    { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 },
-    { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 },
-    { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce },
-    { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 },
-    { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be },
-    { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
-    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
-    { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
-    { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
-    { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880 },
-    { 0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788 },
-    { 0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120 },
-    { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
-    { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
-    { 0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa },
-    { 0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 },
-    { 0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402 },
-    { 0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06 },
-    { 0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b },
-    { 0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b },
-    { 0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a },
-    { 0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf },
-    { 0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f },
-    { 0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f },
-    { 0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f },
-    { 0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-};
-
-static const u32 ar5416Common_9160[][2] = {
-    { 0x0000000c, 0x00000000 },
-    { 0x00000030, 0x00020015 },
-    { 0x00000034, 0x00000005 },
-    { 0x00000040, 0x00000000 },
-    { 0x00000044, 0x00000008 },
-    { 0x00000048, 0x00000008 },
-    { 0x0000004c, 0x00000010 },
-    { 0x00000050, 0x00000000 },
-    { 0x00000054, 0x0000001f },
-    { 0x00000800, 0x00000000 },
-    { 0x00000804, 0x00000000 },
-    { 0x00000808, 0x00000000 },
-    { 0x0000080c, 0x00000000 },
-    { 0x00000810, 0x00000000 },
-    { 0x00000814, 0x00000000 },
-    { 0x00000818, 0x00000000 },
-    { 0x0000081c, 0x00000000 },
-    { 0x00000820, 0x00000000 },
-    { 0x00000824, 0x00000000 },
-    { 0x00001040, 0x002ffc0f },
-    { 0x00001044, 0x002ffc0f },
-    { 0x00001048, 0x002ffc0f },
-    { 0x0000104c, 0x002ffc0f },
-    { 0x00001050, 0x002ffc0f },
-    { 0x00001054, 0x002ffc0f },
-    { 0x00001058, 0x002ffc0f },
-    { 0x0000105c, 0x002ffc0f },
-    { 0x00001060, 0x002ffc0f },
-    { 0x00001064, 0x002ffc0f },
-    { 0x00001230, 0x00000000 },
-    { 0x00001270, 0x00000000 },
-    { 0x00001038, 0x00000000 },
-    { 0x00001078, 0x00000000 },
-    { 0x000010b8, 0x00000000 },
-    { 0x000010f8, 0x00000000 },
-    { 0x00001138, 0x00000000 },
-    { 0x00001178, 0x00000000 },
-    { 0x000011b8, 0x00000000 },
-    { 0x000011f8, 0x00000000 },
-    { 0x00001238, 0x00000000 },
-    { 0x00001278, 0x00000000 },
-    { 0x000012b8, 0x00000000 },
-    { 0x000012f8, 0x00000000 },
-    { 0x00001338, 0x00000000 },
-    { 0x00001378, 0x00000000 },
-    { 0x000013b8, 0x00000000 },
-    { 0x000013f8, 0x00000000 },
-    { 0x00001438, 0x00000000 },
-    { 0x00001478, 0x00000000 },
-    { 0x000014b8, 0x00000000 },
-    { 0x000014f8, 0x00000000 },
-    { 0x00001538, 0x00000000 },
-    { 0x00001578, 0x00000000 },
-    { 0x000015b8, 0x00000000 },
-    { 0x000015f8, 0x00000000 },
-    { 0x00001638, 0x00000000 },
-    { 0x00001678, 0x00000000 },
-    { 0x000016b8, 0x00000000 },
-    { 0x000016f8, 0x00000000 },
-    { 0x00001738, 0x00000000 },
-    { 0x00001778, 0x00000000 },
-    { 0x000017b8, 0x00000000 },
-    { 0x000017f8, 0x00000000 },
-    { 0x0000103c, 0x00000000 },
-    { 0x0000107c, 0x00000000 },
-    { 0x000010bc, 0x00000000 },
-    { 0x000010fc, 0x00000000 },
-    { 0x0000113c, 0x00000000 },
-    { 0x0000117c, 0x00000000 },
-    { 0x000011bc, 0x00000000 },
-    { 0x000011fc, 0x00000000 },
-    { 0x0000123c, 0x00000000 },
-    { 0x0000127c, 0x00000000 },
-    { 0x000012bc, 0x00000000 },
-    { 0x000012fc, 0x00000000 },
-    { 0x0000133c, 0x00000000 },
-    { 0x0000137c, 0x00000000 },
-    { 0x000013bc, 0x00000000 },
-    { 0x000013fc, 0x00000000 },
-    { 0x0000143c, 0x00000000 },
-    { 0x0000147c, 0x00000000 },
-    { 0x00004030, 0x00000002 },
-    { 0x0000403c, 0x00000002 },
-    { 0x00007010, 0x00000020 },
-    { 0x00007038, 0x000004c2 },
-    { 0x00008004, 0x00000000 },
-    { 0x00008008, 0x00000000 },
-    { 0x0000800c, 0x00000000 },
-    { 0x00008018, 0x00000700 },
-    { 0x00008020, 0x00000000 },
-    { 0x00008038, 0x00000000 },
-    { 0x0000803c, 0x00000000 },
-    { 0x00008048, 0x40000000 },
-    { 0x00008054, 0x00000000 },
-    { 0x00008058, 0x00000000 },
-    { 0x0000805c, 0x000fc78f },
-    { 0x00008060, 0x0000000f },
-    { 0x00008064, 0x00000000 },
-    { 0x000080c0, 0x2a82301a },
-    { 0x000080c4, 0x05dc01e0 },
-    { 0x000080c8, 0x1f402710 },
-    { 0x000080cc, 0x01f40000 },
-    { 0x000080d0, 0x00001e00 },
-    { 0x000080d4, 0x00000000 },
-    { 0x000080d8, 0x00400000 },
-    { 0x000080e0, 0xffffffff },
-    { 0x000080e4, 0x0000ffff },
-    { 0x000080e8, 0x003f3f3f },
-    { 0x000080ec, 0x00000000 },
-    { 0x000080f0, 0x00000000 },
-    { 0x000080f4, 0x00000000 },
-    { 0x000080f8, 0x00000000 },
-    { 0x000080fc, 0x00020000 },
-    { 0x00008100, 0x00020000 },
-    { 0x00008104, 0x00000001 },
-    { 0x00008108, 0x00000052 },
-    { 0x0000810c, 0x00000000 },
-    { 0x00008110, 0x00000168 },
-    { 0x00008118, 0x000100aa },
-    { 0x0000811c, 0x00003210 },
-    { 0x00008120, 0x08f04800 },
-    { 0x00008124, 0x00000000 },
-    { 0x00008128, 0x00000000 },
-    { 0x0000812c, 0x00000000 },
-    { 0x00008130, 0x00000000 },
-    { 0x00008134, 0x00000000 },
-    { 0x00008138, 0x00000000 },
-    { 0x0000813c, 0x00000000 },
-    { 0x00008144, 0xffffffff },
-    { 0x00008168, 0x00000000 },
-    { 0x0000816c, 0x00000000 },
-    { 0x00008170, 0x32143320 },
-    { 0x00008174, 0xfaa4fa50 },
-    { 0x00008178, 0x00000100 },
-    { 0x0000817c, 0x00000000 },
-    { 0x000081c4, 0x00000000 },
-    { 0x000081d0, 0x00003210 },
-    { 0x000081ec, 0x00000000 },
-    { 0x000081f0, 0x00000000 },
-    { 0x000081f4, 0x00000000 },
-    { 0x000081f8, 0x00000000 },
-    { 0x000081fc, 0x00000000 },
-    { 0x00008200, 0x00000000 },
-    { 0x00008204, 0x00000000 },
-    { 0x00008208, 0x00000000 },
-    { 0x0000820c, 0x00000000 },
-    { 0x00008210, 0x00000000 },
-    { 0x00008214, 0x00000000 },
-    { 0x00008218, 0x00000000 },
-    { 0x0000821c, 0x00000000 },
-    { 0x00008220, 0x00000000 },
-    { 0x00008224, 0x00000000 },
-    { 0x00008228, 0x00000000 },
-    { 0x0000822c, 0x00000000 },
-    { 0x00008230, 0x00000000 },
-    { 0x00008234, 0x00000000 },
-    { 0x00008238, 0x00000000 },
-    { 0x0000823c, 0x00000000 },
-    { 0x00008240, 0x00100000 },
-    { 0x00008244, 0x0010f400 },
-    { 0x00008248, 0x00000100 },
-    { 0x0000824c, 0x0001e800 },
-    { 0x00008250, 0x00000000 },
-    { 0x00008254, 0x00000000 },
-    { 0x00008258, 0x00000000 },
-    { 0x0000825c, 0x400000ff },
-    { 0x00008260, 0x00080922 },
-    { 0x00008270, 0x00000000 },
-    { 0x00008274, 0x40000000 },
-    { 0x00008278, 0x003e4180 },
-    { 0x0000827c, 0x00000000 },
-    { 0x00008284, 0x0000002c },
-    { 0x00008288, 0x0000002c },
-    { 0x0000828c, 0x00000000 },
-    { 0x00008294, 0x00000000 },
-    { 0x00008298, 0x00000000 },
-    { 0x00008300, 0x00000000 },
-    { 0x00008304, 0x00000000 },
-    { 0x00008308, 0x00000000 },
-    { 0x0000830c, 0x00000000 },
-    { 0x00008310, 0x00000000 },
-    { 0x00008314, 0x00000000 },
-    { 0x00008318, 0x00000000 },
-    { 0x00008328, 0x00000000 },
-    { 0x0000832c, 0x00000007 },
-    { 0x00008330, 0x00000302 },
-    { 0x00008334, 0x00000e00 },
-    { 0x00008338, 0x00ff0000 },
-    { 0x0000833c, 0x00000000 },
-    { 0x00008340, 0x000107ff },
-    { 0x00009808, 0x00000000 },
-    { 0x0000980c, 0xad848e19 },
-    { 0x00009810, 0x7d14e000 },
-    { 0x00009814, 0x9c0a9f6b },
-    { 0x0000981c, 0x00000000 },
-    { 0x0000982c, 0x0000a000 },
-    { 0x00009830, 0x00000000 },
-    { 0x0000983c, 0x00200400 },
-    { 0x00009840, 0x206a01ae },
-    { 0x0000984c, 0x1284233c },
-    { 0x00009854, 0x00000859 },
-    { 0x00009900, 0x00000000 },
-    { 0x00009904, 0x00000000 },
-    { 0x00009908, 0x00000000 },
-    { 0x0000990c, 0x00000000 },
-    { 0x0000991c, 0x10000fff },
-    { 0x00009920, 0x05100000 },
-    { 0x0000a920, 0x05100000 },
-    { 0x0000b920, 0x05100000 },
-    { 0x00009928, 0x00000001 },
-    { 0x0000992c, 0x00000004 },
-    { 0x00009934, 0x1e1f2022 },
-    { 0x00009938, 0x0a0b0c0d },
-    { 0x0000993c, 0x00000000 },
-    { 0x00009948, 0x9280b212 },
-    { 0x0000994c, 0x00020028 },
-    { 0x00009954, 0x5f3ca3de },
-    { 0x00009958, 0x2108ecff },
-    { 0x00009940, 0x00750604 },
-    { 0x0000c95c, 0x004b6a8e },
-    { 0x00009970, 0x190fb515 },
-    { 0x00009974, 0x00000000 },
-    { 0x00009978, 0x00000001 },
-    { 0x0000997c, 0x00000000 },
-    { 0x00009980, 0x00000000 },
-    { 0x00009984, 0x00000000 },
-    { 0x00009988, 0x00000000 },
-    { 0x0000998c, 0x00000000 },
-    { 0x00009990, 0x00000000 },
-    { 0x00009994, 0x00000000 },
-    { 0x00009998, 0x00000000 },
-    { 0x0000999c, 0x00000000 },
-    { 0x000099a0, 0x00000000 },
-    { 0x000099a4, 0x00000001 },
-    { 0x000099a8, 0x201fff00 },
-    { 0x000099ac, 0x006f0000 },
-    { 0x000099b0, 0x03051000 },
-    { 0x000099dc, 0x00000000 },
-    { 0x000099e0, 0x00000200 },
-    { 0x000099e4, 0xaaaaaaaa },
-    { 0x000099e8, 0x3c466478 },
-    { 0x000099ec, 0x0cc80caa },
-    { 0x000099fc, 0x00001042 },
-    { 0x00009b00, 0x00000000 },
-    { 0x00009b04, 0x00000001 },
-    { 0x00009b08, 0x00000002 },
-    { 0x00009b0c, 0x00000003 },
-    { 0x00009b10, 0x00000004 },
-    { 0x00009b14, 0x00000005 },
-    { 0x00009b18, 0x00000008 },
-    { 0x00009b1c, 0x00000009 },
-    { 0x00009b20, 0x0000000a },
-    { 0x00009b24, 0x0000000b },
-    { 0x00009b28, 0x0000000c },
-    { 0x00009b2c, 0x0000000d },
-    { 0x00009b30, 0x00000010 },
-    { 0x00009b34, 0x00000011 },
-    { 0x00009b38, 0x00000012 },
-    { 0x00009b3c, 0x00000013 },
-    { 0x00009b40, 0x00000014 },
-    { 0x00009b44, 0x00000015 },
-    { 0x00009b48, 0x00000018 },
-    { 0x00009b4c, 0x00000019 },
-    { 0x00009b50, 0x0000001a },
-    { 0x00009b54, 0x0000001b },
-    { 0x00009b58, 0x0000001c },
-    { 0x00009b5c, 0x0000001d },
-    { 0x00009b60, 0x00000020 },
-    { 0x00009b64, 0x00000021 },
-    { 0x00009b68, 0x00000022 },
-    { 0x00009b6c, 0x00000023 },
-    { 0x00009b70, 0x00000024 },
-    { 0x00009b74, 0x00000025 },
-    { 0x00009b78, 0x00000028 },
-    { 0x00009b7c, 0x00000029 },
-    { 0x00009b80, 0x0000002a },
-    { 0x00009b84, 0x0000002b },
-    { 0x00009b88, 0x0000002c },
-    { 0x00009b8c, 0x0000002d },
-    { 0x00009b90, 0x00000030 },
-    { 0x00009b94, 0x00000031 },
-    { 0x00009b98, 0x00000032 },
-    { 0x00009b9c, 0x00000033 },
-    { 0x00009ba0, 0x00000034 },
-    { 0x00009ba4, 0x00000035 },
-    { 0x00009ba8, 0x00000035 },
-    { 0x00009bac, 0x00000035 },
-    { 0x00009bb0, 0x00000035 },
-    { 0x00009bb4, 0x00000035 },
-    { 0x00009bb8, 0x00000035 },
-    { 0x00009bbc, 0x00000035 },
-    { 0x00009bc0, 0x00000035 },
-    { 0x00009bc4, 0x00000035 },
-    { 0x00009bc8, 0x00000035 },
-    { 0x00009bcc, 0x00000035 },
-    { 0x00009bd0, 0x00000035 },
-    { 0x00009bd4, 0x00000035 },
-    { 0x00009bd8, 0x00000035 },
-    { 0x00009bdc, 0x00000035 },
-    { 0x00009be0, 0x00000035 },
-    { 0x00009be4, 0x00000035 },
-    { 0x00009be8, 0x00000035 },
-    { 0x00009bec, 0x00000035 },
-    { 0x00009bf0, 0x00000035 },
-    { 0x00009bf4, 0x00000035 },
-    { 0x00009bf8, 0x00000010 },
-    { 0x00009bfc, 0x0000001a },
-    { 0x0000a210, 0x40806333 },
-    { 0x0000a214, 0x00106c10 },
-    { 0x0000a218, 0x009c4060 },
-    { 0x0000a220, 0x018830c6 },
-    { 0x0000a224, 0x00000400 },
-    { 0x0000a228, 0x001a0bb5 },
-    { 0x0000a22c, 0x00000000 },
-    { 0x0000a234, 0x20202020 },
-    { 0x0000a238, 0x20202020 },
-    { 0x0000a23c, 0x13c889af },
-    { 0x0000a240, 0x38490a20 },
-    { 0x0000a244, 0x00007bb6 },
-    { 0x0000a248, 0x0fff3ffc },
-    { 0x0000a24c, 0x00000001 },
-    { 0x0000a250, 0x0000e000 },
-    { 0x0000a254, 0x00000000 },
-    { 0x0000a258, 0x0cc75380 },
-    { 0x0000a25c, 0x0f0f0f01 },
-    { 0x0000a260, 0xdfa91f01 },
-    { 0x0000a268, 0x00000001 },
-    { 0x0000a26c, 0x0ebae9c6 },
-    { 0x0000b26c, 0x0ebae9c6 },
-    { 0x0000c26c, 0x0ebae9c6 },
-    { 0x0000d270, 0x00820820 },
-    { 0x0000a278, 0x1ce739ce },
-    { 0x0000a27c, 0x050701ce },
-    { 0x0000a338, 0x00000000 },
-    { 0x0000a33c, 0x00000000 },
-    { 0x0000a340, 0x00000000 },
-    { 0x0000a344, 0x00000000 },
-    { 0x0000a348, 0x3fffffff },
-    { 0x0000a34c, 0x3fffffff },
-    { 0x0000a350, 0x3fffffff },
-    { 0x0000a354, 0x0003ffff },
-    { 0x0000a358, 0x79bfaa03 },
-    { 0x0000d35c, 0x07ffffef },
-    { 0x0000d360, 0x0fffffe7 },
-    { 0x0000d364, 0x17ffffe5 },
-    { 0x0000d368, 0x1fffffe4 },
-    { 0x0000d36c, 0x37ffffe3 },
-    { 0x0000d370, 0x3fffffe3 },
-    { 0x0000d374, 0x57ffffe3 },
-    { 0x0000d378, 0x5fffffe2 },
-    { 0x0000d37c, 0x7fffffe2 },
-    { 0x0000d380, 0x7f3c7bba },
-    { 0x0000d384, 0xf3307ff0 },
-    { 0x0000a388, 0x0c000000 },
-    { 0x0000a38c, 0x20202020 },
-    { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x1ce739ce },
-    { 0x0000a398, 0x000001ce },
-    { 0x0000a39c, 0x00000001 },
-    { 0x0000a3a0, 0x00000000 },
-    { 0x0000a3a4, 0x00000000 },
-    { 0x0000a3a8, 0x00000000 },
-    { 0x0000a3ac, 0x00000000 },
-    { 0x0000a3b0, 0x00000000 },
-    { 0x0000a3b4, 0x00000000 },
-    { 0x0000a3b8, 0x00000000 },
-    { 0x0000a3bc, 0x00000000 },
-    { 0x0000a3c0, 0x00000000 },
-    { 0x0000a3c4, 0x00000000 },
-    { 0x0000a3c8, 0x00000246 },
-    { 0x0000a3cc, 0x20202020 },
-    { 0x0000a3d0, 0x20202020 },
-    { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x1ce739ce },
-    { 0x0000a3e0, 0x000001ce },
-};
-
-static const u32 ar5416Bank0_9160[][2] = {
-    { 0x000098b0, 0x1e5795e5 },
-    { 0x000098e0, 0x02008020 },
-};
-
-static const u32 ar5416BB_RfGain_9160[][3] = {
-    { 0x00009a00, 0x00000000, 0x00000000 },
-    { 0x00009a04, 0x00000040, 0x00000040 },
-    { 0x00009a08, 0x00000080, 0x00000080 },
-    { 0x00009a0c, 0x000001a1, 0x00000141 },
-    { 0x00009a10, 0x000001e1, 0x00000181 },
-    { 0x00009a14, 0x00000021, 0x000001c1 },
-    { 0x00009a18, 0x00000061, 0x00000001 },
-    { 0x00009a1c, 0x00000168, 0x00000041 },
-    { 0x00009a20, 0x000001a8, 0x000001a8 },
-    { 0x00009a24, 0x000001e8, 0x000001e8 },
-    { 0x00009a28, 0x00000028, 0x00000028 },
-    { 0x00009a2c, 0x00000068, 0x00000068 },
-    { 0x00009a30, 0x00000189, 0x000000a8 },
-    { 0x00009a34, 0x000001c9, 0x00000169 },
-    { 0x00009a38, 0x00000009, 0x000001a9 },
-    { 0x00009a3c, 0x00000049, 0x000001e9 },
-    { 0x00009a40, 0x00000089, 0x00000029 },
-    { 0x00009a44, 0x00000170, 0x00000069 },
-    { 0x00009a48, 0x000001b0, 0x00000190 },
-    { 0x00009a4c, 0x000001f0, 0x000001d0 },
-    { 0x00009a50, 0x00000030, 0x00000010 },
-    { 0x00009a54, 0x00000070, 0x00000050 },
-    { 0x00009a58, 0x00000191, 0x00000090 },
-    { 0x00009a5c, 0x000001d1, 0x00000151 },
-    { 0x00009a60, 0x00000011, 0x00000191 },
-    { 0x00009a64, 0x00000051, 0x000001d1 },
-    { 0x00009a68, 0x00000091, 0x00000011 },
-    { 0x00009a6c, 0x000001b8, 0x00000051 },
-    { 0x00009a70, 0x000001f8, 0x00000198 },
-    { 0x00009a74, 0x00000038, 0x000001d8 },
-    { 0x00009a78, 0x00000078, 0x00000018 },
-    { 0x00009a7c, 0x00000199, 0x00000058 },
-    { 0x00009a80, 0x000001d9, 0x00000098 },
-    { 0x00009a84, 0x00000019, 0x00000159 },
-    { 0x00009a88, 0x00000059, 0x00000199 },
-    { 0x00009a8c, 0x00000099, 0x000001d9 },
-    { 0x00009a90, 0x000000d9, 0x00000019 },
-    { 0x00009a94, 0x000000f9, 0x00000059 },
-    { 0x00009a98, 0x000000f9, 0x00000099 },
-    { 0x00009a9c, 0x000000f9, 0x000000d9 },
-    { 0x00009aa0, 0x000000f9, 0x000000f9 },
-    { 0x00009aa4, 0x000000f9, 0x000000f9 },
-    { 0x00009aa8, 0x000000f9, 0x000000f9 },
-    { 0x00009aac, 0x000000f9, 0x000000f9 },
-    { 0x00009ab0, 0x000000f9, 0x000000f9 },
-    { 0x00009ab4, 0x000000f9, 0x000000f9 },
-    { 0x00009ab8, 0x000000f9, 0x000000f9 },
-    { 0x00009abc, 0x000000f9, 0x000000f9 },
-    { 0x00009ac0, 0x000000f9, 0x000000f9 },
-    { 0x00009ac4, 0x000000f9, 0x000000f9 },
-    { 0x00009ac8, 0x000000f9, 0x000000f9 },
-    { 0x00009acc, 0x000000f9, 0x000000f9 },
-    { 0x00009ad0, 0x000000f9, 0x000000f9 },
-    { 0x00009ad4, 0x000000f9, 0x000000f9 },
-    { 0x00009ad8, 0x000000f9, 0x000000f9 },
-    { 0x00009adc, 0x000000f9, 0x000000f9 },
-    { 0x00009ae0, 0x000000f9, 0x000000f9 },
-    { 0x00009ae4, 0x000000f9, 0x000000f9 },
-    { 0x00009ae8, 0x000000f9, 0x000000f9 },
-    { 0x00009aec, 0x000000f9, 0x000000f9 },
-    { 0x00009af0, 0x000000f9, 0x000000f9 },
-    { 0x00009af4, 0x000000f9, 0x000000f9 },
-    { 0x00009af8, 0x000000f9, 0x000000f9 },
-    { 0x00009afc, 0x000000f9, 0x000000f9 },
-};
-
-static const u32 ar5416Bank1_9160[][2] = {
-    { 0x000098b0, 0x02108421 },
-    { 0x000098ec, 0x00000008 },
-};
-
-static const u32 ar5416Bank2_9160[][2] = {
-    { 0x000098b0, 0x0e73ff17 },
-    { 0x000098e0, 0x00000420 },
-};
-
-static const u32 ar5416Bank3_9160[][3] = {
-    { 0x000098f0, 0x01400018, 0x01c00018 },
-};
-
-static const u32 ar5416Bank6_9160[][3] = {
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x004210a2, 0x004210a2 },
-    { 0x0000989c, 0x0014008f, 0x0014008f },
-    { 0x0000989c, 0x00c40003, 0x00c40003 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000f1, 0x000000f1 },
-    { 0x0000989c, 0x00002081, 0x00002081 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
-};
-
-static const u32 ar5416Bank6TPC_9160[][3] = {
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00000000, 0x00000000 },
-    { 0x0000989c, 0x00e00000, 0x00e00000 },
-    { 0x0000989c, 0x005e0000, 0x005e0000 },
-    { 0x0000989c, 0x00120000, 0x00120000 },
-    { 0x0000989c, 0x00620000, 0x00620000 },
-    { 0x0000989c, 0x00020000, 0x00020000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x40ff0000, 0x40ff0000 },
-    { 0x0000989c, 0x005f0000, 0x005f0000 },
-    { 0x0000989c, 0x00870000, 0x00870000 },
-    { 0x0000989c, 0x00f90000, 0x00f90000 },
-    { 0x0000989c, 0x007b0000, 0x007b0000 },
-    { 0x0000989c, 0x00ff0000, 0x00ff0000 },
-    { 0x0000989c, 0x00f50000, 0x00f50000 },
-    { 0x0000989c, 0x00dc0000, 0x00dc0000 },
-    { 0x0000989c, 0x00110000, 0x00110000 },
-    { 0x0000989c, 0x006100a8, 0x006100a8 },
-    { 0x0000989c, 0x00423022, 0x00423022 },
-    { 0x0000989c, 0x2014008f, 0x2014008f },
-    { 0x0000989c, 0x00c40002, 0x00c40002 },
-    { 0x0000989c, 0x003000f2, 0x003000f2 },
-    { 0x0000989c, 0x00440016, 0x00440016 },
-    { 0x0000989c, 0x00410040, 0x00410040 },
-    { 0x0000989c, 0x0001805e, 0x0001805e },
-    { 0x0000989c, 0x0000c0ab, 0x0000c0ab },
-    { 0x0000989c, 0x000000e1, 0x000000e1 },
-    { 0x0000989c, 0x00007080, 0x00007080 },
-    { 0x0000989c, 0x000000d4, 0x000000d4 },
-    { 0x000098d0, 0x0000000f, 0x0010000f },
-};
-
-static const u32 ar5416Bank7_9160[][2] = {
-    { 0x0000989c, 0x00000500 },
-    { 0x0000989c, 0x00000800 },
-    { 0x000098cc, 0x0000000e },
-};
-
-static u32 ar5416Addac_9160[][2] = {
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000018 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000019 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000003 },
-    {0x0000989c,  0x00000008 },
-    {0x0000989c,  0x00000000 },
-    {0x000098cc,  0x00000000 },
-};
-
-static u32 ar5416Addac_91601_1[][2] = {
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000018 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x000000c0 },
-    {0x0000989c,  0x00000019 },
-    {0x0000989c,  0x00000004 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x0000989c,  0x00000000 },
-    {0x000098cc,  0x00000000 },
-};
+#ifndef INITVALS_9002_10_H
+#define INITVALS_9002_10_H
 
-/* XXX 9280 1 */
 static const u32 ar9280Modes_9280[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -2766,7 +793,7 @@ static const u32 ar9280Common_9280_2[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -3441,7 +1468,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
 };
 
 /* AR9285 Revsion 10*/
-static const u_int32_t ar9285Modes_9285[][6] = {
+static const u32 ar9285Modes_9285[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
     { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -3763,7 +1790,7 @@ static const u_int32_t ar9285Modes_9285[][6] = {
     { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
 };
 
-static const u_int32_t ar9285Common_9285[][2] = {
+static const u32 ar9285Common_9285[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020045 },
     { 0x00000034, 0x00000005 },
@@ -3936,7 +1963,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -4096,7 +2123,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
     { 0x00007870, 0x10142c00 },
 };
 
-static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
+static const u32 ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -4109,7 +2136,7 @@ static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = {
     {0x00004044,  0x00000000 },
 };
 
-static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
+static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -4123,7 +2150,7 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
 };
 
 /* AR9285 v1_2 PCI Register Writes.  Created: 04/13/09 */
-static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+static const u32 ar9285Modes_9285_1_2[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -4184,7 +2211,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
     { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
     { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+    { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
     { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
     { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
     { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
@@ -4198,8 +2225,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
     { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
     { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+    { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
+    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
     { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
     { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
     { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
@@ -4312,7 +2339,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
     { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
     { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
     { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
     { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
     { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
@@ -4326,8 +2353,8 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
     { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
     { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
+    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
     { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
     { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
     { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
@@ -4429,7 +2456,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
 };
 
-static const u_int32_t ar9285Common_9285_1_2[][2] = {
+static const u32 ar9285Common_9285_1_2[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020045 },
     { 0x00000034, 0x00000005 },
@@ -4731,17 +2758,12 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00007808, 0x54214514 },
     { 0x0000780c, 0x02025830 },
     { 0x00007810, 0x71c0d388 },
-    { 0x00007814, 0x924934a8 },
     { 0x0000781c, 0x00000000 },
     { 0x00007824, 0x00d86fff },
-    { 0x00007828, 0x26d2491b },
     { 0x0000782c, 0x6e36d97b },
-    { 0x00007830, 0xedb6d96e },
     { 0x00007834, 0x71400087 },
-    { 0x0000783c, 0x0001fffe },
-    { 0x00007840, 0xffeb1a20 },
     { 0x00007844, 0x000c0db6 },
-    { 0x00007848, 0x6db61b6f },
+    { 0x00007848, 0x6db6246f },
     { 0x0000784c, 0x6d9b66db },
     { 0x00007850, 0x6d8c6dba },
     { 0x00007854, 0x00040000 },
@@ -4753,7 +2775,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00007870, 0x10142c00 },
 };
 
-static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
+static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
@@ -4777,7 +2799,12 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
     { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
+    { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
+    { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
     { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
+    { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
+    { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
     { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
     { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
     { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
@@ -4789,7 +2816,7 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
     { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
 };
 
-static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
+static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
@@ -4813,7 +2840,52 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
     { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8 },
+    { 0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b },
+    { 0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e },
     { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 },
+    { 0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe },
+    { 0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20 },
+    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
+    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
+    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
+    { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
+    { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+    { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+};
+
+static const u32 ar9285Modes_XE2_0_normal_power[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
+    { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
+    { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae },
+    { 0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441 },
+    { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
+    { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
     { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
     { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
     { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
@@ -4825,7 +2897,47 @@ static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
     { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
 };
 
-static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
+static const u32 ar9285Modes_XE2_0_high_power[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8 },
+    { 0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b },
+    { 0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e },
+    { 0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443 },
+    { 0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe },
+    { 0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c },
+    { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
+    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+    { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+    { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+};
+
+static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -4838,7 +2950,7 @@ static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
     {0x00004044,  0x00000000 },
 };
 
-static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
+static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -4852,7 +2964,7 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
 };
 
 /* AR9287 Revision 10 */
-static const u_int32_t ar9287Modes_9287_1_0[][6] = {
+static const u32 ar9287Modes_9287_1_0[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -4899,7 +3011,7 @@ static const u_int32_t ar9287Modes_9287_1_0[][6] = {
     { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
 };
 
-static const u_int32_t ar9287Common_9287_1_0[][2] = {
+static const u32 ar9287Common_9287_1_0[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020015 },
     { 0x00000034, 0x00000005 },
@@ -5073,7 +3185,7 @@ static const u_int32_t ar9287Common_9287_1_0[][2] = {
     { 0x00008258, 0x00000000 },
     { 0x0000825c, 0x400000ff },
     { 0x00008260, 0x00080922 },
-    { 0x00008264, 0xa8a00010 },
+    { 0x00008264, 0x88a00010 },
     { 0x00008270, 0x00000000 },
     { 0x00008274, 0x40000000 },
     { 0x00008278, 0x003e4180 },
@@ -5270,7 +3382,7 @@ static const u_int32_t ar9287Common_9287_1_0[][2] = {
     { 0x000078b8, 0x2a850160 },
 };
 
-static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = {
+static const u32 ar9287Modes_tx_gain_9287_1_0[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
@@ -5320,7 +3432,7 @@ static const u_int32_t ar9287Modes_tx_gain_9287_1_0[][6] = {
 };
 
 
-static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = {
+static const u32 ar9287Modes_rx_gain_9287_1_0[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
     { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
@@ -5582,7 +3694,7 @@ static const u_int32_t ar9287Modes_rx_gain_9287_1_0[][6] = {
     { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
 };
 
-static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
+static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -5595,7 +3707,7 @@ static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_0[][2] = {
     {0x00004044,  0x00000000 },
 };
 
-static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
+static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -5610,7 +3722,7 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_0[][2] = {
 
 /* AR9287 Revision 11 */
 
-static const u_int32_t ar9287Modes_9287_1_1[][6] = {
+static const u32 ar9287Modes_9287_1_1[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -5657,7 +3769,7 @@ static const u_int32_t ar9287Modes_9287_1_1[][6] = {
     { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
 };
 
-static const u_int32_t ar9287Common_9287_1_1[][2] = {
+static const u32 ar9287Common_9287_1_1[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020015 },
     { 0x00000034, 0x00000005 },
@@ -6027,21 +4139,22 @@ static const u_int32_t ar9287Common_9287_1_1[][2] = {
 
 /*
  * For Japanese regulatory requirements, 2484 MHz requires the following three
- * registers be programmed differently from the channel between 2412 and 2472 MHz.
+ * registers be programmed differently from the channel between 2412 and
+ * 2472 MHz.
  */
-static const u_int32_t ar9287Common_normal_cck_fir_coeff_92871_1[][2] = {
+static const u32 ar9287Common_normal_cck_fir_coeff_92871_1[][2] = {
     { 0x0000a1f4, 0x00fffeff },
     { 0x0000a1f8, 0x00f5f9ff },
     { 0x0000a1fc, 0xb79f6427 },
 };
 
-static const u_int32_t ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = {
+static const u32 ar9287Common_japan_2484_cck_fir_coeff_92871_1[][2] = {
     { 0x0000a1f4, 0x00000000 },
     { 0x0000a1f8, 0xefff0301 },
     { 0x0000a1fc, 0xca9228ee },
 };
 
-static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = {
+static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
     { 0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002 },
@@ -6090,7 +4203,7 @@ static const u_int32_t ar9287Modes_tx_gain_9287_1_1[][6] = {
     { 0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000 },
 };
 
-static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = {
+static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = {
     /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
     { 0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120 },
     { 0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124 },
@@ -6352,7 +4465,7 @@ static const u_int32_t ar9287Modes_rx_gain_9287_1_1[][6] = {
     { 0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067 },
 };
 
-static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
+static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -6365,7 +4478,7 @@ static const u_int32_t ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = {
     {0x00004044,  0x00000000 },
 };
 
-static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
+static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
     {0x00004040,  0xa8000019 },
@@ -6380,7 +4493,7 @@ static const u_int32_t ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
 
 
 /* AR9271 initialization values automaticaly created: 06/04/09 */
-static const u_int32_t ar9271Modes_9271[][6] = {
+static const u32 ar9271Modes_9271[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
     { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -6441,7 +4554,7 @@ static const u_int32_t ar9271Modes_9271[][6] = {
     { 0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
     { 0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
     { 0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x00009a50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+    { 0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
     { 0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
     { 0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
     { 0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
@@ -6455,8 +4568,8 @@ static const u_int32_t ar9271Modes_9271[][6] = {
     { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
     { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
     { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x00009a88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+    { 0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
+    { 0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
     { 0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
     { 0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
     { 0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
@@ -6569,7 +4682,7 @@ static const u_int32_t ar9271Modes_9271[][6] = {
     { 0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000 },
     { 0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000 },
     { 0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000 },
-    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058220, 0x00058220, 0x00000000 },
+    { 0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000 },
     { 0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000 },
     { 0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000 },
     { 0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000 },
@@ -6583,8 +4696,8 @@ static const u_int32_t ar9271Modes_9271[][6] = {
     { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 },
     { 0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 },
     { 0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 },
-    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
-    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
+    { 0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000 },
+    { 0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000 },
     { 0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000 },
     { 0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000 },
     { 0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000 },
@@ -6683,29 +4796,10 @@ static const u_int32_t ar9271Modes_9271[][6] = {
     { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
     { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
     { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 },
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 },
-    { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
-    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
 };
 
-static const u_int32_t ar9271Common_9271[][2] = {
+static const u32 ar9271Common_9271[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020045 },
     { 0x00000034, 0x00000005 },
@@ -6910,13 +5004,10 @@ static const u_int32_t ar9271Common_9271[][2] = {
     { 0x00007810, 0x71c0d388 },
     { 0x00007814, 0x924934a8 },
     { 0x0000781c, 0x00000000 },
-    { 0x00007820, 0x00000c04 },
-    { 0x00007824, 0x00d8abff },
     { 0x00007828, 0x66964300 },
     { 0x0000782c, 0x8db6d961 },
     { 0x00007830, 0x8db6d96c },
     { 0x00007834, 0x6140008b },
-    { 0x00007838, 0x00000029 },
     { 0x0000783c, 0x72ee0a72 },
     { 0x00007840, 0xbbfffffc },
     { 0x00007844, 0x000c0db6 },
@@ -6929,7 +5020,6 @@ static const u_int32_t ar9271Common_9271[][2] = {
     { 0x00007860, 0x21084210 },
     { 0x00007864, 0xf7d7ffde },
     { 0x00007868, 0xc2034080 },
-    { 0x0000786c, 0x48609eb4 },
     { 0x00007870, 0x10142c00 },
     { 0x00009808, 0x00000000 },
     { 0x0000980c, 0xafe68e30 },
@@ -6982,9 +5072,6 @@ static const u_int32_t ar9271Common_9271[][2] = {
     { 0x000099e8, 0x3c466478 },
     { 0x000099ec, 0x0cc80caa },
     { 0x000099f0, 0x00000000 },
-    { 0x0000a1f4, 0x00000000 },
-    { 0x0000a1f8, 0x71733d01 },
-    { 0x0000a1fc, 0xd0ad5c12 },
     { 0x0000a208, 0x803e68c8 },
     { 0x0000a210, 0x4080a333 },
     { 0x0000a214, 0x00206c10 },
@@ -7004,13 +5091,9 @@ static const u_int32_t ar9271Common_9271[][2] = {
     { 0x0000a260, 0xdfa90f01 },
     { 0x0000a268, 0x00000000 },
     { 0x0000a26c, 0x0ebae9e6 },
-    { 0x0000a278, 0x3bdef7bd },
-    { 0x0000a27c, 0x050e83bd },
     { 0x0000a388, 0x0c000000 },
     { 0x0000a38c, 0x20202020 },
     { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x3bdef7bd },
-    { 0x0000a398, 0x000003bd },
     { 0x0000a39c, 0x00000001 },
     { 0x0000a3a0, 0x00000000 },
     { 0x0000a3a4, 0x00000000 },
@@ -7025,8 +5108,6 @@ static const u_int32_t ar9271Common_9271[][2] = {
     { 0x0000a3cc, 0x20202020 },
     { 0x0000a3d0, 0x20202020 },
     { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x3bdef7bd },
-    { 0x0000a3e0, 0x000003bd },
     { 0x0000a3e4, 0x00000000 },
     { 0x0000a3e8, 0x18c43433 },
     { 0x0000a3ec, 0x00f70081 },
@@ -7046,7 +5127,104 @@ static const u_int32_t ar9271Common_9271[][2] = {
     { 0x0000d384, 0xf3307ff0 },
 };
 
-static const u_int32_t ar9271Modes_9271_1_0_only[][6] = {
+static const u32 ar9271Common_normal_cck_fir_coeff_9271[][2] = {
+    { 0x0000a1f4, 0x00fffeff },
+    { 0x0000a1f8, 0x00f5f9ff },
+    { 0x0000a1fc, 0xb79f6427 },
+};
+
+static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = {
+    { 0x0000a1f4, 0x00000000 },
+    { 0x0000a1f8, 0xefff0301 },
+    { 0x0000a1fc, 0xca9228ee },
+};
+
+static const u32 ar9271Modes_9271_1_0_only[][6] = {
     { 0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311 },
     { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 },
 };
+
+static const u32 ar9271Modes_9271_ANI_reg[][6] = {
+    { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
+    { 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
+    { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
+    { 0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881 },
+    { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 },
+    { 0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8 },
+    { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d },
+    { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
+};
+
+static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000 },
+    { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029 },
+    { 0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff },
+    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
+    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
+    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652 },
+    { 0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
+    { 0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd },
+    { 0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
+    { 0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd },
+    { 0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd },
+    { 0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd },
+};
+
+static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = {
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000 },
+    { 0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b },
+    { 0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff },
+    { 0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6 },
+    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a212652, 0x0a212652, 0x0a22a652 },
+    { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+    { 0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063 },
+    { 0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
+    { 0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 },
+    { 0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
+    { 0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063 },
+};
+
+#endif /* INITVALS_9002_10_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
new file mode 100644 (file)
index 0000000..2be20d2
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * 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 "hw.h"
+
+#define AR_BufLen           0x00000fff
+
+static void ar9002_hw_rx_enable(struct ath_hw *ah)
+{
+       REG_WRITE(ah, AR_CR, AR_CR_RXE);
+}
+
+static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)
+{
+       ((struct ath_desc*) ds)->ds_link = ds_link;
+}
+
+static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
+{
+       *ds_link = &((struct ath_desc *)ds)->ds_link;
+}
+
+static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+       u32 isr = 0;
+       u32 mask2 = 0;
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
+       u32 sync_cause = 0;
+       bool fatal_int = false;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (!AR_SREV_9100(ah)) {
+               if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+                       if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
+                           == AR_RTC_STATUS_ON) {
+                               isr = REG_READ(ah, AR_ISR);
+                       }
+               }
+
+               sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) &
+                       AR_INTR_SYNC_DEFAULT;
+
+               *masked = 0;
+
+               if (!isr && !sync_cause)
+                       return false;
+       } else {
+               *masked = 0;
+               isr = REG_READ(ah, AR_ISR);
+       }
+
+       if (isr) {
+               if (isr & AR_ISR_BCNMISC) {
+                       u32 isr2;
+                       isr2 = REG_READ(ah, AR_ISR_S2);
+                       if (isr2 & AR_ISR_S2_TIM)
+                               mask2 |= ATH9K_INT_TIM;
+                       if (isr2 & AR_ISR_S2_DTIM)
+                               mask2 |= ATH9K_INT_DTIM;
+                       if (isr2 & AR_ISR_S2_DTIMSYNC)
+                               mask2 |= ATH9K_INT_DTIMSYNC;
+                       if (isr2 & (AR_ISR_S2_CABEND))
+                               mask2 |= ATH9K_INT_CABEND;
+                       if (isr2 & AR_ISR_S2_GTT)
+                               mask2 |= ATH9K_INT_GTT;
+                       if (isr2 & AR_ISR_S2_CST)
+                               mask2 |= ATH9K_INT_CST;
+                       if (isr2 & AR_ISR_S2_TSFOOR)
+                               mask2 |= ATH9K_INT_TSFOOR;
+               }
+
+               isr = REG_READ(ah, AR_ISR_RAC);
+               if (isr == 0xffffffff) {
+                       *masked = 0;
+                       return false;
+               }
+
+               *masked = isr & ATH9K_INT_COMMON;
+
+               if (ah->config.rx_intr_mitigation) {
+                       if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+                               *masked |= ATH9K_INT_RX;
+               }
+
+               if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
+                       *masked |= ATH9K_INT_RX;
+               if (isr &
+                   (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
+                    AR_ISR_TXEOL)) {
+                       u32 s0_s, s1_s;
+
+                       *masked |= ATH9K_INT_TX;
+
+                       s0_s = REG_READ(ah, AR_ISR_S0_S);
+                       ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
+                       ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
+
+                       s1_s = REG_READ(ah, AR_ISR_S1_S);
+                       ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
+                       ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
+               }
+
+               if (isr & AR_ISR_RXORN) {
+                       ath_print(common, ATH_DBG_INTERRUPT,
+                                 "receive FIFO overrun interrupt\n");
+               }
+
+               if (!AR_SREV_9100(ah)) {
+                       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+                               u32 isr5 = REG_READ(ah, AR_ISR_S5_S);
+                               if (isr5 & AR_ISR_S5_TIM_TIMER)
+                                       *masked |= ATH9K_INT_TIM_TIMER;
+                       }
+               }
+
+               *masked |= mask2;
+       }
+
+       if (AR_SREV_9100(ah))
+               return true;
+
+       if (isr & AR_ISR_GENTMR) {
+               u32 s5_s;
+
+               s5_s = REG_READ(ah, AR_ISR_S5_S);
+               if (isr & AR_ISR_GENTMR) {
+                       ah->intr_gen_timer_trigger =
+                               MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
+
+                       ah->intr_gen_timer_thresh =
+                               MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
+
+                       if (ah->intr_gen_timer_trigger)
+                               *masked |= ATH9K_INT_GENTIMER;
+
+               }
+       }
+
+       if (sync_cause) {
+               fatal_int =
+                       (sync_cause &
+                        (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
+                       ? true : false;
+
+               if (fatal_int) {
+                       if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
+                               ath_print(common, ATH_DBG_ANY,
+                                         "received PCI FATAL interrupt\n");
+                       }
+                       if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
+                               ath_print(common, ATH_DBG_ANY,
+                                         "received PCI PERR interrupt\n");
+                       }
+                       *masked |= ATH9K_INT_FATAL;
+               }
+               if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
+                       ath_print(common, ATH_DBG_INTERRUPT,
+                                 "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
+                       REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
+                       REG_WRITE(ah, AR_RC, 0);
+                       *masked |= ATH9K_INT_FATAL;
+               }
+               if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
+                       ath_print(common, ATH_DBG_INTERRUPT,
+                                 "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+               }
+
+               REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+               (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
+       }
+
+       return true;
+}
+
+static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
+                                 bool is_firstseg, bool is_lastseg,
+                                 const void *ds0, dma_addr_t buf_addr,
+                                 unsigned int qcu)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_data = buf_addr;
+
+       if (is_firstseg) {
+               ads->ds_ctl1 |= seglen | (is_lastseg ? 0 : AR_TxMore);
+       } else if (is_lastseg) {
+               ads->ds_ctl0 = 0;
+               ads->ds_ctl1 = seglen;
+               ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
+               ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
+       } else {
+               ads->ds_ctl0 = 0;
+               ads->ds_ctl1 = seglen | AR_TxMore;
+               ads->ds_ctl2 = 0;
+               ads->ds_ctl3 = 0;
+       }
+       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+
+static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds,
+                                struct ath_tx_status *ts)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       if ((ads->ds_txstatus9 & AR_TxDone) == 0)
+               return -EINPROGRESS;
+
+       ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
+       ts->ts_tstamp = ads->AR_SendTimestamp;
+       ts->ts_status = 0;
+       ts->ts_flags = 0;
+
+       if (ads->ds_txstatus1 & AR_FrmXmitOK)
+               ts->ts_status |= ATH9K_TX_ACKED;
+       if (ads->ds_txstatus1 & AR_ExcessiveRetries)
+               ts->ts_status |= ATH9K_TXERR_XRETRY;
+       if (ads->ds_txstatus1 & AR_Filtered)
+               ts->ts_status |= ATH9K_TXERR_FILT;
+       if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
+               ts->ts_status |= ATH9K_TXERR_FIFO;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->ds_txstatus9 & AR_TxOpExceeded)
+               ts->ts_status |= ATH9K_TXERR_XTXOP;
+       if (ads->ds_txstatus1 & AR_TxTimerExpired)
+               ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+       if (ads->ds_txstatus1 & AR_DescCfgErr)
+               ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+       if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
+               ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
+               ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->ds_txstatus0 & AR_TxBaStatus) {
+               ts->ts_flags |= ATH9K_TX_BA;
+               ts->ba_low = ads->AR_BaBitmapLow;
+               ts->ba_high = ads->AR_BaBitmapHigh;
+       }
+
+       ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
+       switch (ts->ts_rateindex) {
+       case 0:
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
+               break;
+       case 1:
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
+               break;
+       case 2:
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
+               break;
+       case 3:
+               ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
+               break;
+       }
+
+       ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
+       ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
+       ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
+       ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
+       ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
+       ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
+       ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
+       ts->evm0 = ads->AR_TxEVM0;
+       ts->evm1 = ads->AR_TxEVM1;
+       ts->evm2 = ads->AR_TxEVM2;
+       ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
+       ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
+       ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
+       ts->ts_antenna = 0;
+
+       return 0;
+}
+
+static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
+                                   u32 pktLen, enum ath9k_pkt_type type,
+                                   u32 txPower, u32 keyIx,
+                                   enum ath9k_key_type keyType, u32 flags)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       txPower += ah->txpower_indexoffset;
+       if (txPower > 63)
+               txPower = 63;
+
+       ads->ds_ctl0 = (pktLen & AR_FrameLen)
+               | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+               | SM(txPower, AR_XmitPower)
+               | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+               | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+               | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
+               | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
+
+       ads->ds_ctl1 =
+               (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+               | SM(type, AR_FrameType)
+               | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+               | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+               | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+       ads->ds_ctl6 = SM(keyType, AR_EncrType);
+
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
+               ads->ds_ctl8 = 0;
+               ads->ds_ctl9 = 0;
+               ads->ds_ctl10 = 0;
+               ads->ds_ctl11 = 0;
+       }
+}
+
+static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
+                                         void *lastds,
+                                         u32 durUpdateEn, u32 rtsctsRate,
+                                         u32 rtsctsDuration,
+                                         struct ath9k_11n_rate_series series[],
+                                         u32 nseries, u32 flags)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       struct ar5416_desc *last_ads = AR5416DESC(lastds);
+       u32 ds_ctl0;
+
+       if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+               ds_ctl0 = ads->ds_ctl0;
+
+               if (flags & ATH9K_TXDESC_RTSENA) {
+                       ds_ctl0 &= ~AR_CTSEnable;
+                       ds_ctl0 |= AR_RTSEnable;
+               } else {
+                       ds_ctl0 &= ~AR_RTSEnable;
+                       ds_ctl0 |= AR_CTSEnable;
+               }
+
+               ads->ds_ctl0 = ds_ctl0;
+       } else {
+               ads->ds_ctl0 =
+                       (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
+       }
+
+       ads->ds_ctl2 = set11nTries(series, 0)
+               | set11nTries(series, 1)
+               | set11nTries(series, 2)
+               | set11nTries(series, 3)
+               | (durUpdateEn ? AR_DurUpdateEna : 0)
+               | SM(0, AR_BurstDur);
+
+       ads->ds_ctl3 = set11nRate(series, 0)
+               | set11nRate(series, 1)
+               | set11nRate(series, 2)
+               | set11nRate(series, 3);
+
+       ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
+               | set11nPktDurRTSCTS(series, 1);
+
+       ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
+               | set11nPktDurRTSCTS(series, 3);
+
+       ads->ds_ctl7 = set11nRateFlags(series, 0)
+               | set11nRateFlags(series, 1)
+               | set11nRateFlags(series, 2)
+               | set11nRateFlags(series, 3)
+               | SM(rtsctsRate, AR_RTSCTSRate);
+       last_ads->ds_ctl2 = ads->ds_ctl2;
+       last_ads->ds_ctl3 = ads->ds_ctl3;
+}
+
+static void ar9002_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
+                                       u32 aggrLen)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+       ads->ds_ctl6 &= ~AR_AggrLen;
+       ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
+}
+
+static void ar9002_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
+                                        u32 numDelims)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       unsigned int ctl6;
+
+       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
+
+       ctl6 = ads->ds_ctl6;
+       ctl6 &= ~AR_PadDelim;
+       ctl6 |= SM(numDelims, AR_PadDelim);
+       ads->ds_ctl6 = ctl6;
+}
+
+static void ar9002_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl1 |= AR_IsAggr;
+       ads->ds_ctl1 &= ~AR_MoreAggr;
+       ads->ds_ctl6 &= ~AR_PadDelim;
+}
+
+static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
+                                          u32 burstDuration)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_ctl2 &= ~AR_BurstDur;
+       ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
+}
+
+static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
+                                           u32 vmf)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       if (vmf)
+               ads->ds_ctl0 |= AR_VirtMoreFrag;
+       else
+               ads->ds_ctl0 &= ~AR_VirtMoreFrag;
+}
+
+void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
+                         u32 size, u32 flags)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
+
+       ads->ds_ctl1 = size & AR_BufLen;
+       if (flags & ATH9K_RXDESC_INTREQ)
+               ads->ds_ctl1 |= AR_RxIntrReq;
+
+       ads->ds_rxstatus8 &= ~AR_RxDone;
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+               memset(&(ads->u), 0, sizeof(ads->u));
+}
+EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
+
+void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
+{
+       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+       ops->rx_enable = ar9002_hw_rx_enable;
+       ops->set_desc_link = ar9002_hw_set_desc_link;
+       ops->get_desc_link = ar9002_hw_get_desc_link;
+       ops->get_isr = ar9002_hw_get_isr;
+       ops->fill_txdesc = ar9002_hw_fill_txdesc;
+       ops->proc_txdesc = ar9002_hw_proc_txdesc;
+       ops->set11n_txdesc = ar9002_hw_set11n_txdesc;
+       ops->set11n_ratescenario = ar9002_hw_set11n_ratescenario;
+       ops->set11n_aggr_first = ar9002_hw_set11n_aggr_first;
+       ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle;
+       ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
+       ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
+       ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
+       ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
new file mode 100644 (file)
index 0000000..ed314e8
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2008-2010 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.
+ */
+
+/**
+ * DOC: Programming Atheros 802.11n analog front end radios
+ *
+ * AR5416 MAC based PCI devices and AR518 MAC based PCI-Express
+ * devices have either an external AR2133 analog front end radio for single
+ * band 2.4 GHz communication or an AR5133 analog front end radio for dual
+ * band 2.4 GHz / 5 GHz communication.
+ *
+ * All devices after the AR5416 and AR5418 family starting with the AR9280
+ * have their analog front radios, MAC/BB and host PCIe/USB interface embedded
+ * into a single-chip and require less programming.
+ *
+ * The following single-chips exist with a respective embedded radio:
+ *
+ * AR9280 - 11n dual-band 2x2 MIMO for PCIe
+ * AR9281 - 11n single-band 1x2 MIMO for PCIe
+ * AR9285 - 11n single-band 1x1 for PCIe
+ * AR9287 - 11n single-band 2x2 MIMO for PCIe
+ *
+ * AR9220 - 11n dual-band 2x2 MIMO for PCI
+ * AR9223 - 11n single-band 2x2 MIMO for PCI
+ *
+ * AR9287 - 11n single-band 1x1 MIMO for USB
+ */
+
+#include "hw.h"
+#include "ar9002_phy.h"
+
+/**
+ * ar9002_hw_set_channel - set channel on single-chip device
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * This is the function to change channel on single-chip devices, that is
+ * all devices after ar9280.
+ *
+ * This function takes the channel value in MHz and sets
+ * hardware channel value. Assumes writes have been enabled to analog bus.
+ *
+ * Actual Expression,
+ *
+ * For 2GHz channel,
+ * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
+ * (freq_ref = 40MHz)
+ *
+ * For 5GHz channel,
+ * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
+ * (freq_ref = 40MHz/(24>>amodeRefSel))
+ */
+static int ar9002_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       u16 bMode, fracMode, aModeRefSel = 0;
+       u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
+       struct chan_centers centers;
+       u32 refDivA = 24;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = centers.synth_center;
+
+       reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
+       reg32 &= 0xc0000000;
+
+       if (freq < 4800) { /* 2 GHz, fractional mode */
+               u32 txctl;
+               int regWrites = 0;
+
+               bMode = 1;
+               fracMode = 1;
+               aModeRefSel = 0;
+               channelSel = CHANSEL_2G(freq);
+
+               if (AR_SREV_9287_11_OR_LATER(ah)) {
+                       if (freq == 2484) {
+                               /* Enable channel spreading for channel 14 */
+                               REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
+                                               1, regWrites);
+                       } else {
+                               REG_WRITE_ARRAY(&ah->iniCckfirNormal,
+                                               1, regWrites);
+                       }
+               } else {
+                       txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
+                       if (freq == 2484) {
+                               /* Enable channel spreading for channel 14 */
+                               REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+                                         txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
+                       } else {
+                               REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
+                                         txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
+                       }
+               }
+       } else {
+               bMode = 0;
+               fracMode = 0;
+
+               switch (ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
+               case 0:
+                       if ((freq % 20) == 0)
+                               aModeRefSel = 3;
+                       else if ((freq % 10) == 0)
+                               aModeRefSel = 2;
+                       if (aModeRefSel)
+                               break;
+               case 1:
+               default:
+                       aModeRefSel = 0;
+                       /*
+                        * Enable 2G (fractional) mode for channels
+                        * which are 5MHz spaced.
+                        */
+                       fracMode = 1;
+                       refDivA = 1;
+                       channelSel = CHANSEL_5G(freq);
+
+                       /* RefDivA setting */
+                       REG_RMW_FIELD(ah, AR_AN_SYNTH9,
+                                     AR_AN_SYNTH9_REFDIVA, refDivA);
+
+               }
+
+               if (!fracMode) {
+                       ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
+                       channelSel = ndiv & 0x1ff;
+                       channelFrac = (ndiv & 0xfffffe00) * 2;
+                       channelSel = (channelSel << 17) | channelFrac;
+               }
+       }
+
+       reg32 = reg32 |
+           (bMode << 29) |
+           (fracMode << 28) | (aModeRefSel << 26) | (channelSel);
+
+       REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
+
+       ah->curchan = chan;
+       ah->curchan_rad_index = -1;
+
+       return 0;
+}
+
+/**
+ * ar9002_hw_spur_mitigate - convert baseband spur frequency
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ */
+static void ar9002_hw_spur_mitigate(struct ath_hw *ah,
+                                   struct ath9k_channel *chan)
+{
+       int bb_spur = AR_NO_SPUR;
+       int freq;
+       int bin, cur_bin;
+       int bb_spur_off, spur_subchannel_sd;
+       int spur_freq_sd;
+       int spur_delta_phase;
+       int denominator;
+       int upper, lower, cur_vit_mask;
+       int tmp, newVal;
+       int i;
+       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
+                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
+       };
+       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
+                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
+       };
+       int inc[4] = { 0, 100, 0, 0 };
+       struct chan_centers centers;
+
+       int8_t mask_m[123];
+       int8_t mask_p[123];
+       int8_t mask_amt;
+       int tmp_mask;
+       int cur_bb_spur;
+       bool is2GHz = IS_CHAN_2GHZ(chan);
+
+       memset(&mask_m, 0, sizeof(int8_t) * 123);
+       memset(&mask_p, 0, sizeof(int8_t) * 123);
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = centers.synth_center;
+
+       ah->config.spurmode = SPUR_ENABLE_EEPROM;
+       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
+               cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
+
+               if (is2GHz)
+                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
+               else
+                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
+
+               if (AR_NO_SPUR == cur_bb_spur)
+                       break;
+               cur_bb_spur = cur_bb_spur - freq;
+
+               if (IS_CHAN_HT40(chan)) {
+                       if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
+                           (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
+                               bb_spur = cur_bb_spur;
+                               break;
+                       }
+               } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
+                          (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
+                       bb_spur = cur_bb_spur;
+                       break;
+               }
+       }
+
+       if (AR_NO_SPUR == bb_spur) {
+               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+               return;
+       } else {
+               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
+                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
+       }
+
+       bin = bb_spur * 320;
+
+       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
+       newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
+                       AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
+                       AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
+                       AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
+       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
+
+       newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
+                 AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
+                 AR_PHY_SPUR_REG_MASK_RATE_SELECT |
+                 AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
+                 SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
+       REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
+
+       if (IS_CHAN_HT40(chan)) {
+               if (bb_spur < 0) {
+                       spur_subchannel_sd = 1;
+                       bb_spur_off = bb_spur + 10;
+               } else {
+                       spur_subchannel_sd = 0;
+                       bb_spur_off = bb_spur - 10;
+               }
+       } else {
+               spur_subchannel_sd = 0;
+               bb_spur_off = bb_spur;
+       }
+
+       if (IS_CHAN_HT40(chan))
+               spur_delta_phase =
+                       ((bb_spur * 262144) /
+                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+       else
+               spur_delta_phase =
+                       ((bb_spur * 524288) /
+                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
+
+       denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
+       spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
+
+       newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
+                 SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
+                 SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
+       REG_WRITE(ah, AR_PHY_TIMING11, newVal);
+
+       newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
+       REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
+
+       cur_bin = -6000;
+       upper = bin + 100;
+       lower = bin - 100;
+
+       for (i = 0; i < 4; i++) {
+               int pilot_mask = 0;
+               int chan_mask = 0;
+               int bp = 0;
+               for (bp = 0; bp < 30; bp++) {
+                       if ((cur_bin > lower) && (cur_bin < upper)) {
+                               pilot_mask = pilot_mask | 0x1 << bp;
+                               chan_mask = chan_mask | 0x1 << bp;
+                       }
+                       cur_bin += 100;
+               }
+               cur_bin += inc[i];
+               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
+               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
+       }
+
+       cur_vit_mask = 6100;
+       upper = bin + 120;
+       lower = bin - 120;
+
+       for (i = 0; i < 123; i++) {
+               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
+
+                       /* workaround for gcc bug #37014 */
+                       volatile int tmp_v = abs(cur_vit_mask - bin);
+
+                       if (tmp_v < 75)
+                               mask_amt = 1;
+                       else
+                               mask_amt = 0;
+                       if (cur_vit_mask < 0)
+                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
+                       else
+                               mask_p[cur_vit_mask / 100] = mask_amt;
+               }
+               cur_vit_mask -= 100;
+       }
+
+       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
+               | (mask_m[48] << 26) | (mask_m[49] << 24)
+               | (mask_m[50] << 22) | (mask_m[51] << 20)
+               | (mask_m[52] << 18) | (mask_m[53] << 16)
+               | (mask_m[54] << 14) | (mask_m[55] << 12)
+               | (mask_m[56] << 10) | (mask_m[57] << 8)
+               | (mask_m[58] << 6) | (mask_m[59] << 4)
+               | (mask_m[60] << 2) | (mask_m[61] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
+
+       tmp_mask = (mask_m[31] << 28)
+               | (mask_m[32] << 26) | (mask_m[33] << 24)
+               | (mask_m[34] << 22) | (mask_m[35] << 20)
+               | (mask_m[36] << 18) | (mask_m[37] << 16)
+               | (mask_m[48] << 14) | (mask_m[39] << 12)
+               | (mask_m[40] << 10) | (mask_m[41] << 8)
+               | (mask_m[42] << 6) | (mask_m[43] << 4)
+               | (mask_m[44] << 2) | (mask_m[45] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
+
+       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
+               | (mask_m[18] << 26) | (mask_m[18] << 24)
+               | (mask_m[20] << 22) | (mask_m[20] << 20)
+               | (mask_m[22] << 18) | (mask_m[22] << 16)
+               | (mask_m[24] << 14) | (mask_m[24] << 12)
+               | (mask_m[25] << 10) | (mask_m[26] << 8)
+               | (mask_m[27] << 6) | (mask_m[28] << 4)
+               | (mask_m[29] << 2) | (mask_m[30] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
+
+       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
+               | (mask_m[2] << 26) | (mask_m[3] << 24)
+               | (mask_m[4] << 22) | (mask_m[5] << 20)
+               | (mask_m[6] << 18) | (mask_m[7] << 16)
+               | (mask_m[8] << 14) | (mask_m[9] << 12)
+               | (mask_m[10] << 10) | (mask_m[11] << 8)
+               | (mask_m[12] << 6) | (mask_m[13] << 4)
+               | (mask_m[14] << 2) | (mask_m[15] << 0);
+       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
+
+       tmp_mask = (mask_p[15] << 28)
+               | (mask_p[14] << 26) | (mask_p[13] << 24)
+               | (mask_p[12] << 22) | (mask_p[11] << 20)
+               | (mask_p[10] << 18) | (mask_p[9] << 16)
+               | (mask_p[8] << 14) | (mask_p[7] << 12)
+               | (mask_p[6] << 10) | (mask_p[5] << 8)
+               | (mask_p[4] << 6) | (mask_p[3] << 4)
+               | (mask_p[2] << 2) | (mask_p[1] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
+
+       tmp_mask = (mask_p[30] << 28)
+               | (mask_p[29] << 26) | (mask_p[28] << 24)
+               | (mask_p[27] << 22) | (mask_p[26] << 20)
+               | (mask_p[25] << 18) | (mask_p[24] << 16)
+               | (mask_p[23] << 14) | (mask_p[22] << 12)
+               | (mask_p[21] << 10) | (mask_p[20] << 8)
+               | (mask_p[19] << 6) | (mask_p[18] << 4)
+               | (mask_p[17] << 2) | (mask_p[16] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
+
+       tmp_mask = (mask_p[45] << 28)
+               | (mask_p[44] << 26) | (mask_p[43] << 24)
+               | (mask_p[42] << 22) | (mask_p[41] << 20)
+               | (mask_p[40] << 18) | (mask_p[39] << 16)
+               | (mask_p[38] << 14) | (mask_p[37] << 12)
+               | (mask_p[36] << 10) | (mask_p[35] << 8)
+               | (mask_p[34] << 6) | (mask_p[33] << 4)
+               | (mask_p[32] << 2) | (mask_p[31] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
+
+       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
+               | (mask_p[59] << 26) | (mask_p[58] << 24)
+               | (mask_p[57] << 22) | (mask_p[56] << 20)
+               | (mask_p[55] << 18) | (mask_p[54] << 16)
+               | (mask_p[53] << 14) | (mask_p[52] << 12)
+               | (mask_p[51] << 10) | (mask_p[50] << 8)
+               | (mask_p[49] << 6) | (mask_p[48] << 4)
+               | (mask_p[47] << 2) | (mask_p[46] << 0);
+       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
+       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+}
+
+static void ar9002_olc_init(struct ath_hw *ah)
+{
+       u32 i;
+
+       if (!OLC_FOR_AR9280_20_LATER)
+               return;
+
+       if (OLC_FOR_AR9287_10_LATER) {
+               REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9,
+                               AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
+               ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0,
+                               AR9287_AN_TXPC0_TXPCMODE,
+                               AR9287_AN_TXPC0_TXPCMODE_S,
+                               AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
+               udelay(100);
+       } else {
+               for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
+                       ah->originalGain[i] =
+                               MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
+                                               AR_PHY_TX_GAIN);
+               ah->PDADCdelta = 0;
+       }
+}
+
+static u32 ar9002_hw_compute_pll_control(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       u32 pll;
+
+       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
+
+       if (chan && IS_CHAN_HALF_RATE(chan))
+               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
+       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
+
+       if (chan && IS_CHAN_5GHZ(chan)) {
+               if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+                       pll = 0x142c;
+               else if (AR_SREV_9280_20(ah))
+                       pll = 0x2850;
+               else
+                       pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
+       } else {
+               pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
+       }
+
+       return pll;
+}
+
+static void ar9002_hw_do_getnf(struct ath_hw *ah,
+                             int16_t nfarray[NUM_NF_READINGS])
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       int16_t nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
+
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 0] is %d\n", nf);
+
+       if (AR_SREV_9271(ah) && (nf >= -114))
+               nf = -116;
+
+       nfarray[0] = nf;
+
+       if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
+               nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
+                               AR9280_PHY_CH1_MINCCA_PWR);
+
+               if (nf & 0x100)
+                       nf = 0 - ((nf ^ 0x1ff) + 1);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "NF calibrated [ctl] [chain 1] is %d\n", nf);
+               nfarray[1] = nf;
+       }
+
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 0] is %d\n", nf);
+
+       if (AR_SREV_9271(ah) && (nf >= -114))
+               nf = -116;
+
+       nfarray[3] = nf;
+
+       if (!AR_SREV_9285(ah) && !AR_SREV_9271(ah)) {
+               nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
+                               AR9280_PHY_CH1_EXT_MINCCA_PWR);
+
+               if (nf & 0x100)
+                       nf = 0 - ((nf ^ 0x1ff) + 1);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "NF calibrated [ext] [chain 1] is %d\n", nf);
+               nfarray[4] = nf;
+       }
+}
+
+void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+
+       priv_ops->set_rf_regs = NULL;
+       priv_ops->rf_alloc_ext_banks = NULL;
+       priv_ops->rf_free_ext_banks = NULL;
+       priv_ops->rf_set_freq = ar9002_hw_set_channel;
+       priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
+       priv_ops->olc_init = ar9002_olc_init;
+       priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
+       priv_ops->do_getnf = ar9002_hw_do_getnf;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
new file mode 100644 (file)
index 0000000..81bf6e5
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2008-2010 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.
+ */
+#ifndef AR9002_PHY_H
+#define AR9002_PHY_H
+
+#define AR_PHY_TEST             0x9800
+#define PHY_AGC_CLR             0x10000000
+#define RFSILENT_BB             0x00002000
+
+#define AR_PHY_TURBO                0x9804
+#define AR_PHY_FC_TURBO_MODE        0x00000001
+#define AR_PHY_FC_TURBO_SHORT       0x00000002
+#define AR_PHY_FC_DYN2040_EN        0x00000004
+#define AR_PHY_FC_DYN2040_PRI_ONLY  0x00000008
+#define AR_PHY_FC_DYN2040_PRI_CH    0x00000010
+/* For 25 MHz channel spacing -- not used but supported by hw */
+#define AR_PHY_FC_DYN2040_EXT_CH    0x00000020
+#define AR_PHY_FC_HT_EN             0x00000040
+#define AR_PHY_FC_SHORT_GI_40       0x00000080
+#define AR_PHY_FC_WALSH             0x00000100
+#define AR_PHY_FC_SINGLE_HT_LTF1    0x00000200
+#define AR_PHY_FC_ENABLE_DAC_FIFO   0x00000800
+
+#define AR_PHY_TEST2                   0x9808
+
+#define AR_PHY_TIMING2           0x9810
+#define AR_PHY_TIMING3           0x9814
+#define AR_PHY_TIMING3_DSC_MAN   0xFFFE0000
+#define AR_PHY_TIMING3_DSC_MAN_S 17
+#define AR_PHY_TIMING3_DSC_EXP   0x0001E000
+#define AR_PHY_TIMING3_DSC_EXP_S 13
+
+#define AR_PHY_CHIP_ID_REV_0      0x80
+#define AR_PHY_CHIP_ID_REV_1      0x81
+#define AR_PHY_CHIP_ID_9160_REV_0 0xb0
+
+#define AR_PHY_ACTIVE       0x981C
+#define AR_PHY_ACTIVE_EN    0x00000001
+#define AR_PHY_ACTIVE_DIS   0x00000000
+
+#define AR_PHY_RF_CTL2             0x9824
+#define AR_PHY_TX_END_DATA_START   0x000000FF
+#define AR_PHY_TX_END_DATA_START_S 0
+#define AR_PHY_TX_END_PA_ON        0x0000FF00
+#define AR_PHY_TX_END_PA_ON_S      8
+
+#define AR_PHY_RF_CTL3                  0x9828
+#define AR_PHY_TX_END_TO_A2_RX_ON       0x00FF0000
+#define AR_PHY_TX_END_TO_A2_RX_ON_S     16
+
+#define AR_PHY_ADC_CTL                  0x982C
+#define AR_PHY_ADC_CTL_OFF_INBUFGAIN    0x00000003
+#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S  0
+#define AR_PHY_ADC_CTL_OFF_PWDDAC       0x00002000
+#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP   0x00004000
+#define AR_PHY_ADC_CTL_OFF_PWDADC       0x00008000
+#define AR_PHY_ADC_CTL_ON_INBUFGAIN     0x00030000
+#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S   16
+
+#define AR_PHY_ADC_SERIAL_CTL       0x9830
+#define AR_PHY_SEL_INTERNAL_ADDAC   0x00000000
+#define AR_PHY_SEL_EXTERNAL_RADIO   0x00000001
+
+#define AR_PHY_RF_CTL4                    0x9834
+#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF    0xFF000000
+#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S  24
+#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF    0x00FF0000
+#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S  16
+#define AR_PHY_RF_CTL4_FRAME_XPAB_ON      0x0000FF00
+#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S    8
+#define AR_PHY_RF_CTL4_FRAME_XPAA_ON      0x000000FF
+#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S    0
+
+#define AR_PHY_TSTDAC_CONST               0x983c
+
+#define AR_PHY_SETTLING          0x9844
+#define AR_PHY_SETTLING_SWITCH   0x00003F80
+#define AR_PHY_SETTLING_SWITCH_S 7
+
+#define AR_PHY_RXGAIN                   0x9848
+#define AR_PHY_RXGAIN_TXRX_ATTEN        0x0003F000
+#define AR_PHY_RXGAIN_TXRX_ATTEN_S      12
+#define AR_PHY_RXGAIN_TXRX_RF_MAX       0x007C0000
+#define AR_PHY_RXGAIN_TXRX_RF_MAX_S     18
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN    0x00003F80
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S  7
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN   0x001FC000
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14
+
+#define AR_PHY_DESIRED_SZ           0x9850
+#define AR_PHY_DESIRED_SZ_ADC       0x000000FF
+#define AR_PHY_DESIRED_SZ_ADC_S     0
+#define AR_PHY_DESIRED_SZ_PGA       0x0000FF00
+#define AR_PHY_DESIRED_SZ_PGA_S     8
+#define AR_PHY_DESIRED_SZ_TOT_DES   0x0FF00000
+#define AR_PHY_DESIRED_SZ_TOT_DES_S 20
+
+#define AR_PHY_FIND_SIG           0x9858
+#define AR_PHY_FIND_SIG_FIRSTEP   0x0003F000
+#define AR_PHY_FIND_SIG_FIRSTEP_S 12
+#define AR_PHY_FIND_SIG_FIRPWR    0x03FC0000
+#define AR_PHY_FIND_SIG_FIRPWR_S  18
+
+#define AR_PHY_AGC_CTL1                  0x985C
+#define AR_PHY_AGC_CTL1_COARSE_LOW       0x00007F80
+#define AR_PHY_AGC_CTL1_COARSE_LOW_S     7
+#define AR_PHY_AGC_CTL1_COARSE_HIGH      0x003F8000
+#define AR_PHY_AGC_CTL1_COARSE_HIGH_S    15
+
+#define AR_PHY_CCA                  0x9864
+#define AR_PHY_MINCCA_PWR           0x0FF80000
+#define AR_PHY_MINCCA_PWR_S         19
+#define AR_PHY_CCA_THRESH62         0x0007F000
+#define AR_PHY_CCA_THRESH62_S       12
+#define AR9280_PHY_MINCCA_PWR       0x1FF00000
+#define AR9280_PHY_MINCCA_PWR_S     20
+#define AR9280_PHY_CCA_THRESH62     0x000FF000
+#define AR9280_PHY_CCA_THRESH62_S   12
+
+#define AR_PHY_SFCORR_LOW                    0x986C
+#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW  0x00000001
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW    0x00003F00
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S  8
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW      0x001FC000
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S    14
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW      0x0FE00000
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S    21
+
+#define AR_PHY_SFCORR                0x9868
+#define AR_PHY_SFCORR_M2COUNT_THR    0x0000001F
+#define AR_PHY_SFCORR_M2COUNT_THR_S  0
+#define AR_PHY_SFCORR_M1_THRESH      0x00FE0000
+#define AR_PHY_SFCORR_M1_THRESH_S    17
+#define AR_PHY_SFCORR_M2_THRESH      0x7F000000
+#define AR_PHY_SFCORR_M2_THRESH_S    24
+
+#define AR_PHY_SLEEP_CTR_CONTROL    0x9870
+#define AR_PHY_SLEEP_CTR_LIMIT      0x9874
+#define AR_PHY_SYNTH_CONTROL        0x9874
+#define AR_PHY_SLEEP_SCAL           0x9878
+
+#define AR_PHY_PLL_CTL          0x987c
+#define AR_PHY_PLL_CTL_40       0xaa
+#define AR_PHY_PLL_CTL_40_5413  0x04
+#define AR_PHY_PLL_CTL_44       0xab
+#define AR_PHY_PLL_CTL_44_2133  0xeb
+#define AR_PHY_PLL_CTL_40_2133  0xea
+
+#define AR_PHY_SPECTRAL_SCAN                   0x9910  /* AR9280 spectral scan configuration register */
+#define        AR_PHY_SPECTRAL_SCAN_ENABLE             0x1
+#define AR_PHY_SPECTRAL_SCAN_ENA               0x00000001  /* Enable spectral scan, reg 68, bit 0 */
+#define AR_PHY_SPECTRAL_SCAN_ENA_S             0  /* Enable spectral scan, reg 68, bit 0 */
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE            0x00000002  /* Activate spectral scan reg 68, bit 1*/
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S          1  /* Activate spectral scan reg 68, bit 1*/
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD                0x000000F0  /* Interval for FFT reports, reg 68, bits 4-7*/
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S      4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD            0x0000FF00  /* Interval for FFT reports, reg 68, bits 8-15*/
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S          8
+#define AR_PHY_SPECTRAL_SCAN_COUNT             0x00FF0000  /* Number of reports, reg 68, bits 16-23*/
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S           16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT      0x01000000  /* Short repeat, reg 68, bit 24*/
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S    24  /* Short repeat, reg 68, bit 24*/
+
+#define AR_PHY_RX_DELAY           0x9914
+#define AR_PHY_SEARCH_START_DELAY 0x9918
+#define AR_PHY_RX_DELAY_DELAY     0x00003FFF
+
+#define AR_PHY_TIMING_CTRL4(_i)     (0x9920 + ((_i) << 12))
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S   0
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0
+#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S   5
+#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE   0x800
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000
+#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S   12
+#define AR_PHY_TIMING_CTRL4_DO_CAL    0x10000
+
+#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI   0x80000000
+#define        AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER  0x40000000
+#define        AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK    0x20000000
+#define        AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK   0x10000000
+
+#define AR_PHY_TIMING5               0x9924
+#define AR_PHY_TIMING5_CYCPWR_THR1   0x000000FE
+#define AR_PHY_TIMING5_CYCPWR_THR1_S 1
+
+#define AR_PHY_POWER_TX_RATE1               0x9934
+#define AR_PHY_POWER_TX_RATE2               0x9938
+#define AR_PHY_POWER_TX_RATE_MAX            0x993c
+#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
+
+#define AR_PHY_FRAME_CTL            0x9944
+#define AR_PHY_FRAME_CTL_TX_CLIP    0x00000038
+#define AR_PHY_FRAME_CTL_TX_CLIP_S  3
+
+#define AR_PHY_TXPWRADJ                   0x994C
+#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA    0x00000FC0
+#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S  6
+#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX   0x00FC0000
+#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18
+
+#define AR_PHY_RADAR_EXT      0x9940
+#define AR_PHY_RADAR_EXT_ENA  0x00004000
+
+#define AR_PHY_RADAR_0          0x9954
+#define AR_PHY_RADAR_0_ENA      0x00000001
+#define AR_PHY_RADAR_0_FFT_ENA  0x80000000
+#define AR_PHY_RADAR_0_INBAND   0x0000003e
+#define AR_PHY_RADAR_0_INBAND_S 1
+#define AR_PHY_RADAR_0_PRSSI    0x00000FC0
+#define AR_PHY_RADAR_0_PRSSI_S  6
+#define AR_PHY_RADAR_0_HEIGHT   0x0003F000
+#define AR_PHY_RADAR_0_HEIGHT_S 12
+#define AR_PHY_RADAR_0_RRSSI    0x00FC0000
+#define AR_PHY_RADAR_0_RRSSI_S  18
+#define AR_PHY_RADAR_0_FIRPWR   0x7F000000
+#define AR_PHY_RADAR_0_FIRPWR_S 24
+
+#define AR_PHY_RADAR_1                  0x9958
+#define AR_PHY_RADAR_1_RELPWR_ENA       0x00800000
+#define AR_PHY_RADAR_1_USE_FIR128       0x00400000
+#define AR_PHY_RADAR_1_RELPWR_THRESH    0x003F0000
+#define AR_PHY_RADAR_1_RELPWR_THRESH_S  16
+#define AR_PHY_RADAR_1_BLOCK_CHECK      0x00008000
+#define AR_PHY_RADAR_1_MAX_RRSSI        0x00004000
+#define AR_PHY_RADAR_1_RELSTEP_CHECK    0x00002000
+#define AR_PHY_RADAR_1_RELSTEP_THRESH   0x00001F00
+#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8
+#define AR_PHY_RADAR_1_MAXLEN           0x000000FF
+#define AR_PHY_RADAR_1_MAXLEN_S         0
+
+#define AR_PHY_SWITCH_CHAIN_0     0x9960
+#define AR_PHY_SWITCH_COM         0x9964
+
+#define AR_PHY_SIGMA_DELTA            0x996C
+#define AR_PHY_SIGMA_DELTA_ADC_SEL    0x00000003
+#define AR_PHY_SIGMA_DELTA_ADC_SEL_S  0
+#define AR_PHY_SIGMA_DELTA_FILT2      0x000000F8
+#define AR_PHY_SIGMA_DELTA_FILT2_S    3
+#define AR_PHY_SIGMA_DELTA_FILT1      0x00001F00
+#define AR_PHY_SIGMA_DELTA_FILT1_S    8
+#define AR_PHY_SIGMA_DELTA_ADC_CLIP   0x01FFE000
+#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13
+
+#define AR_PHY_RESTART          0x9970
+#define AR_PHY_RESTART_DIV_GC   0x001C0000
+#define AR_PHY_RESTART_DIV_GC_S 18
+
+#define AR_PHY_RFBUS_REQ        0x997C
+#define AR_PHY_RFBUS_REQ_EN     0x00000001
+
+#define        AR_PHY_TIMING7                  0x9980
+#define        AR_PHY_TIMING8                  0x9984
+#define        AR_PHY_TIMING8_PILOT_MASK_2     0x000FFFFF
+#define        AR_PHY_TIMING8_PILOT_MASK_2_S   0
+
+#define        AR_PHY_BIN_MASK2_1      0x9988
+#define        AR_PHY_BIN_MASK2_2      0x998c
+#define        AR_PHY_BIN_MASK2_3      0x9990
+#define        AR_PHY_BIN_MASK2_4      0x9994
+
+#define        AR_PHY_BIN_MASK_1       0x9900
+#define        AR_PHY_BIN_MASK_2       0x9904
+#define        AR_PHY_BIN_MASK_3       0x9908
+
+#define        AR_PHY_MASK_CTL         0x990c
+
+#define        AR_PHY_BIN_MASK2_4_MASK_4       0x00003FFF
+#define        AR_PHY_BIN_MASK2_4_MASK_4_S     0
+
+#define        AR_PHY_TIMING9                  0x9998
+#define        AR_PHY_TIMING10                 0x999c
+#define        AR_PHY_TIMING10_PILOT_MASK_2    0x000FFFFF
+#define        AR_PHY_TIMING10_PILOT_MASK_2_S  0
+
+#define        AR_PHY_TIMING11                         0x99a0
+#define        AR_PHY_TIMING11_SPUR_DELTA_PHASE        0x000FFFFF
+#define        AR_PHY_TIMING11_SPUR_DELTA_PHASE_S      0
+#define AR_PHY_TIMING11_USE_SPUR_IN_AGC                0x40000000
+#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR    0x80000000
+
+#define AR_PHY_RX_CHAINMASK     0x99a4
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12))
+#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
+#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
+
+#define AR_PHY_MULTICHAIN_GAIN_CTL          0x99ac
+#define AR_PHY_9285_ANT_DIV_CTL_ALL         0x7f000000
+#define AR_PHY_9285_ANT_DIV_CTL             0x01000000
+#define AR_PHY_9285_ANT_DIV_CTL_S           24
+#define AR_PHY_9285_ANT_DIV_ALT_LNACONF     0x06000000
+#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S   25
+#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF    0x18000000
+#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S  27
+#define AR_PHY_9285_ANT_DIV_ALT_GAINTB      0x20000000
+#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S    29
+#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB     0x40000000
+#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S   30
+#define AR_PHY_9285_ANT_DIV_LNA1            2
+#define AR_PHY_9285_ANT_DIV_LNA2            1
+#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2  3
+#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
+#define AR_PHY_9285_ANT_DIV_GAINTB_0        0
+#define AR_PHY_9285_ANT_DIV_GAINTB_1        1
+
+#define AR_PHY_EXT_CCA0             0x99b8
+#define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
+#define AR_PHY_EXT_CCA0_THRESH62_S  0
+
+#define AR_PHY_EXT_CCA                  0x99bc
+#define AR_PHY_EXT_CCA_CYCPWR_THR1      0x0000FE00
+#define AR_PHY_EXT_CCA_CYCPWR_THR1_S    9
+#define AR_PHY_EXT_CCA_THRESH62         0x007F0000
+#define AR_PHY_EXT_CCA_THRESH62_S       16
+#define AR_PHY_EXT_MINCCA_PWR           0xFF800000
+#define AR_PHY_EXT_MINCCA_PWR_S         23
+#define AR9280_PHY_EXT_MINCCA_PWR       0x01FF0000
+#define AR9280_PHY_EXT_MINCCA_PWR_S     16
+
+#define AR_PHY_SFCORR_EXT                 0x99c0
+#define AR_PHY_SFCORR_EXT_M1_THRESH       0x0000007F
+#define AR_PHY_SFCORR_EXT_M1_THRESH_S     0
+#define AR_PHY_SFCORR_EXT_M2_THRESH       0x00003F80
+#define AR_PHY_SFCORR_EXT_M2_THRESH_S     7
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW   0x001FC000
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW   0x0FE00000
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
+#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S   28
+
+#define AR_PHY_HALFGI           0x99D0
+#define AR_PHY_HALFGI_DSC_MAN   0x0007FFF0
+#define AR_PHY_HALFGI_DSC_MAN_S 4
+#define AR_PHY_HALFGI_DSC_EXP   0x0000000F
+#define AR_PHY_HALFGI_DSC_EXP_S 0
+
+#define AR_PHY_CHAN_INFO_MEMORY               0x99DC
+#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK  0x0001
+
+#define AR_PHY_HEAVY_CLIP_ENABLE         0x99E0
+
+#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS    0x99EC
+#define AR_PHY_RIFS_INIT_DELAY         0x03ff0000
+
+#define AR_PHY_M_SLEEP      0x99f0
+#define AR_PHY_REFCLKDLY    0x99f4
+#define AR_PHY_REFCLKPD     0x99f8
+
+#define AR_PHY_CALMODE      0x99f0
+
+#define AR_PHY_CALMODE_IQ           0x00000000
+#define AR_PHY_CALMODE_ADC_GAIN     0x00000001
+#define AR_PHY_CALMODE_ADC_DC_PER   0x00000002
+#define AR_PHY_CALMODE_ADC_DC_INIT  0x00000003
+
+#define AR_PHY_CAL_MEAS_0(_i)     (0x9c10 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_1(_i)     (0x9c14 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_2(_i)     (0x9c18 + ((_i) << 12))
+#define AR_PHY_CAL_MEAS_3(_i)     (0x9c1c + ((_i) << 12))
+
+#define AR_PHY_CURRENT_RSSI 0x9c1c
+#define AR9280_PHY_CURRENT_RSSI 0x9c3c
+
+#define AR_PHY_RFBUS_GRANT       0x9C20
+#define AR_PHY_RFBUS_GRANT_EN    0x00000001
+
+#define AR_PHY_CHAN_INFO_GAIN_DIFF             0x9CF4
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
+
+#define AR_PHY_CHAN_INFO_GAIN          0x9CFC
+
+#define AR_PHY_MODE         0xA200
+#define AR_PHY_MODE_ASYNCFIFO 0x80
+#define AR_PHY_MODE_AR2133  0x08
+#define AR_PHY_MODE_AR5111  0x00
+#define AR_PHY_MODE_AR5112  0x08
+#define AR_PHY_MODE_DYNAMIC 0x04
+#define AR_PHY_MODE_RF2GHZ  0x02
+#define AR_PHY_MODE_RF5GHZ  0x00
+#define AR_PHY_MODE_CCK     0x01
+#define AR_PHY_MODE_OFDM    0x00
+#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100
+
+#define AR_PHY_CCK_TX_CTRL       0xA204
+#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
+#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK         0x0000000C
+#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S       2
+
+#define AR_PHY_CCK_DETECT                           0xA208
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0
+/* [12:6] settling time for antenna switch */
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S         6
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV    0x2000
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S  13
+
+#define AR_PHY_GAIN_2GHZ                0xA20C
+#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN    0x00FC0000
+#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S  18
+#define AR_PHY_GAIN_2GHZ_BSW_MARGIN     0x00003C00
+#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S   10
+#define AR_PHY_GAIN_2GHZ_BSW_ATTEN      0x0000001F
+#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S    0
+
+#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN     0x003E0000
+#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S   17
+#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN     0x0001F000
+#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S   12
+#define AR_PHY_GAIN_2GHZ_XATTEN2_DB         0x00000FC0
+#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S       6
+#define AR_PHY_GAIN_2GHZ_XATTEN1_DB         0x0000003F
+#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S       0
+
+#define AR_PHY_CCK_RXCTRL4  0xA21C
+#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT   0x01F80000
+#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19
+
+#define AR_PHY_DAG_CTRLCCK  0xA228
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR  0x00000200
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR     0x0001FC00
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
+
+#define AR_PHY_FORCE_CLKEN_CCK              0xA22C
+#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX      0x00000040
+
+#define AR_PHY_POWER_TX_RATE3   0xA234
+#define AR_PHY_POWER_TX_RATE4   0xA238
+
+#define AR_PHY_SCRM_SEQ_XR       0xA23C
+#define AR_PHY_HEADER_DETECT_XR  0xA240
+#define AR_PHY_CHIRP_DETECTED_XR 0xA244
+#define AR_PHY_BLUETOOTH         0xA254
+
+#define AR_PHY_TPCRG1   0xA258
+#define AR_PHY_TPCRG1_NUM_PD_GAIN   0x0000c000
+#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14
+
+#define AR_PHY_TPCRG1_PD_GAIN_1    0x00030000
+#define AR_PHY_TPCRG1_PD_GAIN_1_S  16
+#define AR_PHY_TPCRG1_PD_GAIN_2    0x000C0000
+#define AR_PHY_TPCRG1_PD_GAIN_2_S  18
+#define AR_PHY_TPCRG1_PD_GAIN_3    0x00300000
+#define AR_PHY_TPCRG1_PD_GAIN_3_S  20
+
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE   0x00400000
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22
+
+#define AR_PHY_TX_PWRCTRL4       0xa264
+#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID     0x00000001
+#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S   0
+#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT       0x000001FE
+#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S     1
+
+#define AR_PHY_TX_PWRCTRL6_0     0xa270
+#define AR_PHY_TX_PWRCTRL6_1     0xb270
+#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE     0x03000000
+#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S   24
+
+#define AR_PHY_TX_PWRCTRL7       0xa274
+#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN     0x01F80000
+#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S   19
+
+#define AR_PHY_TX_PWRCTRL9       0xa27C
+#define AR_PHY_TX_DESIRED_SCALE_CCK        0x00007C00
+#define AR_PHY_TX_DESIRED_SCALE_CCK_S      10
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL  0x80000000
+#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
+
+#define AR_PHY_TX_GAIN_TBL1      0xa300
+#define AR_PHY_TX_GAIN                     0x0007F000
+#define AR_PHY_TX_GAIN_S                   12
+
+#define AR_PHY_CH0_TX_PWRCTRL11  0xa398
+#define AR_PHY_CH1_TX_PWRCTRL11  0xb398
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP   0x0000FC00
+#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
+
+#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
+#define AR_PHY_MASK2_M_31_45     0xa3a4
+#define AR_PHY_MASK2_M_16_30     0xa3a8
+#define AR_PHY_MASK2_M_00_15     0xa3ac
+#define AR_PHY_MASK2_P_15_01     0xa3b8
+#define AR_PHY_MASK2_P_30_16     0xa3bc
+#define AR_PHY_MASK2_P_45_31     0xa3c0
+#define AR_PHY_MASK2_P_61_45     0xa3c4
+#define AR_PHY_SPUR_REG          0x994c
+
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL       (0xFF << 18)
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S     18
+
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM      0x20000
+#define AR_PHY_SPUR_REG_MASK_RATE_SELECT     (0xFF << 9)
+#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S   9
+#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH     0x7F
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S   0
+
+#define AR_PHY_PILOT_MASK_01_30   0xa3b0
+#define AR_PHY_PILOT_MASK_31_60   0xa3b4
+
+#define AR_PHY_CHANNEL_MASK_01_30 0x99d4
+#define AR_PHY_CHANNEL_MASK_31_60 0x99d8
+
+#define AR_PHY_ANALOG_SWAP      0xa268
+#define AR_PHY_SWAP_ALT_CHAIN   0x00000040
+
+#define AR_PHY_TPCRG5   0xA26C
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP       0x0000000F
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S     0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1    0x000003F0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S  4
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2    0x0000FC00
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S  10
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3    0x003F0000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S  16
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4    0x0FC00000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S  22
+
+/* Carrier leak calibration control, do it after AGC calibration */
+#define AR_PHY_CL_CAL_CTL       0xA358
+#define AR_PHY_CL_CAL_ENABLE    0x00000002
+#define AR_PHY_PARALLEL_CAL_ENABLE    0x00000001
+
+#define AR_PHY_POWER_TX_RATE5   0xA38C
+#define AR_PHY_POWER_TX_RATE6   0xA390
+
+#define AR_PHY_CAL_CHAINMASK    0xA39C
+
+#define AR_PHY_POWER_TX_SUB     0xA3C8
+#define AR_PHY_POWER_TX_RATE7   0xA3CC
+#define AR_PHY_POWER_TX_RATE8   0xA3D0
+#define AR_PHY_POWER_TX_RATE9   0xA3D4
+
+#define AR_PHY_XPA_CFG         0xA3D8
+#define AR_PHY_FORCE_XPA_CFG   0x000000001
+#define AR_PHY_FORCE_XPA_CFG_S 0
+
+#define AR_PHY_CH1_CCA          0xa864
+#define AR_PHY_CH1_MINCCA_PWR   0x0FF80000
+#define AR_PHY_CH1_MINCCA_PWR_S 19
+#define AR9280_PHY_CH1_MINCCA_PWR   0x1FF00000
+#define AR9280_PHY_CH1_MINCCA_PWR_S 20
+
+#define AR_PHY_CH2_CCA          0xb864
+#define AR_PHY_CH2_MINCCA_PWR   0x0FF80000
+#define AR_PHY_CH2_MINCCA_PWR_S 19
+
+#define AR_PHY_CH1_EXT_CCA          0xa9bc
+#define AR_PHY_CH1_EXT_MINCCA_PWR   0xFF800000
+#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23
+#define AR9280_PHY_CH1_EXT_MINCCA_PWR   0x01FF0000
+#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16
+
+#define AR_PHY_CH2_EXT_CCA          0xb9bc
+#define AR_PHY_CH2_EXT_MINCCA_PWR   0xFF800000
+#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
new file mode 100644 (file)
index 0000000..56a9e5f
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * Copyright (c) 2010 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 "hw.h"
+#include "hw-ops.h"
+#include "ar9003_phy.h"
+
+static void ar9003_hw_setup_calibration(struct ath_hw *ah,
+                                       struct ath9k_cal_list *currCal)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       /* Select calibration to run */
+       switch (currCal->calData->calType) {
+       case IQ_MISMATCH_CAL:
+               /*
+                * Start calibration with
+                * 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples
+                */
+               REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                             AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX,
+               currCal->calData->calCountMax);
+               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "starting IQ Mismatch Calibration\n");
+
+               /* Kick-off cal */
+               REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL);
+               break;
+       case TEMP_COMP_CAL:
+               REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
+                             AR_PHY_65NM_CH0_THERM_LOCAL, 1);
+               REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM,
+                             AR_PHY_65NM_CH0_THERM_START, 1);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "starting Temperature Compensation Calibration\n");
+               break;
+       case ADC_DC_INIT_CAL:
+       case ADC_GAIN_CAL:
+       case ADC_DC_CAL:
+               /* Not yet */
+               break;
+       }
+}
+
+/*
+ * Generic calibration routine.
+ * Recalibrate the lower PHY chips to account for temperature/environment
+ * changes.
+ */
+static bool ar9003_hw_per_calibration(struct ath_hw *ah,
+                                     struct ath9k_channel *ichan,
+                                     u8 rxchainmask,
+                                     struct ath9k_cal_list *currCal)
+{
+       /* Cal is assumed not done until explicitly set below */
+       bool iscaldone = false;
+
+       /* Calibration in progress. */
+       if (currCal->calState == CAL_RUNNING) {
+               /* Check to see if it has finished. */
+               if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) {
+                       /*
+                       * Accumulate cal measures for active chains
+                       */
+                       currCal->calData->calCollect(ah);
+                       ah->cal_samples++;
+
+                       if (ah->cal_samples >=
+                           currCal->calData->calNumSamples) {
+                               unsigned int i, numChains = 0;
+                               for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+                                       if (rxchainmask & (1 << i))
+                                               numChains++;
+                               }
+
+                               /*
+                               * Process accumulated data
+                               */
+                               currCal->calData->calPostProc(ah, numChains);
+
+                               /* Calibration has finished. */
+                               ichan->CalValid |= currCal->calData->calType;
+                               currCal->calState = CAL_DONE;
+                               iscaldone = true;
+                       } else {
+                       /*
+                        * Set-up collection of another sub-sample until we
+                        * get desired number
+                        */
+                       ar9003_hw_setup_calibration(ah, currCal);
+                       }
+               }
+       } else if (!(ichan->CalValid & currCal->calData->calType)) {
+               /* If current cal is marked invalid in channel, kick it off */
+               ath9k_hw_reset_calibration(ah, currCal);
+       }
+
+       return iscaldone;
+}
+
+static bool ar9003_hw_calibrate(struct ath_hw *ah,
+                               struct ath9k_channel *chan,
+                               u8 rxchainmask,
+                               bool longcal)
+{
+       bool iscaldone = true;
+       struct ath9k_cal_list *currCal = ah->cal_list_curr;
+
+       /*
+        * For given calibration:
+        * 1. Call generic cal routine
+        * 2. When this cal is done (isCalDone) if we have more cals waiting
+        *    (eg after reset), mask this to upper layers by not propagating
+        *    isCalDone if it is set to TRUE.
+        *    Instead, change isCalDone to FALSE and setup the waiting cal(s)
+        *    to be run.
+        */
+       if (currCal &&
+           (currCal->calState == CAL_RUNNING ||
+            currCal->calState == CAL_WAITING)) {
+               iscaldone = ar9003_hw_per_calibration(ah, chan,
+                                                     rxchainmask, currCal);
+               if (iscaldone) {
+                       ah->cal_list_curr = currCal = currCal->calNext;
+
+                       if (currCal->calState == CAL_WAITING) {
+                               iscaldone = false;
+                               ath9k_hw_reset_calibration(ah, currCal);
+                       }
+               }
+       }
+
+       /* Do NF cal only at longer intervals */
+       if (longcal) {
+               /*
+                * Load the NF from history buffer of the current channel.
+                * NF is slow time-variant, so it is OK to use a historical
+                * value.
+                */
+               ath9k_hw_loadnf(ah, ah->curchan);
+
+               /* start NF calibration, without updating BB NF register */
+               ath9k_hw_start_nfcal(ah);
+       }
+
+       return iscaldone;
+}
+
+static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
+{
+       int i;
+
+       /* Accumulate IQ cal measures for active chains */
+       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+               ah->totalPowerMeasI[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+               ah->totalPowerMeasQ[i] +=
+                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+               ah->totalIqCorrMeas[i] +=
+                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+                         "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+                         ah->cal_samples, i, ah->totalPowerMeasI[i],
+                         ah->totalPowerMeasQ[i],
+                         ah->totalIqCorrMeas[i]);
+       }
+}
+
+static void ar9003_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 powerMeasQ, powerMeasI, iqCorrMeas;
+       u32 qCoffDenom, iCoffDenom;
+       int32_t qCoff, iCoff;
+       int iqCorrNeg, i;
+       const u_int32_t offset_array[3] = {
+               AR_PHY_RX_IQCAL_CORR_B0,
+               AR_PHY_RX_IQCAL_CORR_B1,
+               AR_PHY_RX_IQCAL_CORR_B2,
+       };
+
+       for (i = 0; i < numChains; i++) {
+               powerMeasI = ah->totalPowerMeasI[i];
+               powerMeasQ = ah->totalPowerMeasQ[i];
+               iqCorrMeas = ah->totalIqCorrMeas[i];
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Starting IQ Cal and Correction for Chain %d\n",
+                         i);
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Orignal: Chn %diq_corr_meas = 0x%08x\n",
+                         i, ah->totalIqCorrMeas[i]);
+
+               iqCorrNeg = 0;
+
+               if (iqCorrMeas > 0x80000000) {
+                       iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
+                       iqCorrNeg = 1;
+               }
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
+               ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
+                         iqCorrNeg);
+
+               iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 256;
+               qCoffDenom = powerMeasQ / 64;
+
+               if ((iCoffDenom != 0) && (qCoffDenom != 0)) {
+                       iCoff = iqCorrMeas / iCoffDenom;
+                       qCoff = powerMeasI / qCoffDenom - 64;
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d iCoff = 0x%08x\n", i, iCoff);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d qCoff = 0x%08x\n", i, qCoff);
+
+                       /* Force bounds on iCoff */
+                       if (iCoff >= 63)
+                               iCoff = 63;
+                       else if (iCoff <= -63)
+                               iCoff = -63;
+
+                       /* Negate iCoff if iqCorrNeg == 0 */
+                       if (iqCorrNeg == 0x0)
+                               iCoff = -iCoff;
+
+                       /* Force bounds on qCoff */
+                       if (qCoff >= 63)
+                               qCoff = 63;
+                       else if (qCoff <= -63)
+                               qCoff = -63;
+
+                       iCoff = iCoff & 0x7f;
+                       qCoff = qCoff & 0x7f;
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
+                                 i, iCoff, qCoff);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Register offset (0x%04x) "
+                                 "before update = 0x%x\n",
+                                 offset_array[i],
+                                 REG_READ(ah, offset_array[i]));
+
+                       REG_RMW_FIELD(ah, offset_array[i],
+                                     AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
+                                     iCoff);
+                       REG_RMW_FIELD(ah, offset_array[i],
+                                     AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
+                                     qCoff);
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Register offset (0x%04x) QI COFF "
+                                 "(bitfields 0x%08x) after update = 0x%x\n",
+                                 offset_array[i],
+                                 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF,
+                                 REG_READ(ah, offset_array[i]));
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Register offset (0x%04x) QQ COFF "
+                                 "(bitfields 0x%08x) after update = 0x%x\n",
+                                 offset_array[i],
+                                 AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF,
+                                 REG_READ(ah, offset_array[i]));
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "IQ Cal and Correction done for Chain %d\n",
+                                 i);
+               }
+       }
+
+       REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0,
+                   AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "IQ Cal and Correction (offset 0x%04x) enabled "
+                 "(bit position 0x%08x). New Value 0x%08x\n",
+                 (unsigned) (AR_PHY_RX_IQCAL_CORR_B0),
+                 AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE,
+                 REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0));
+}
+
+static const struct ath9k_percal_data iq_cal_single_sample = {
+       IQ_MISMATCH_CAL,
+       MIN_CAL_SAMPLES,
+       PER_MAX_LOG_COUNT,
+       ar9003_hw_iqcal_collect,
+       ar9003_hw_iqcalibrate
+};
+
+static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
+{
+       ah->iq_caldata.calData = &iq_cal_single_sample;
+       ah->supp_cals = IQ_MISMATCH_CAL;
+}
+
+static bool ar9003_hw_iscal_supported(struct ath_hw *ah,
+                                     enum ath9k_cal_types calType)
+{
+       switch (calType & ah->supp_cals) {
+       case IQ_MISMATCH_CAL:
+               /*
+                * XXX: Run IQ Mismatch for non-CCK only
+                * Note that CHANNEL_B is never set though.
+                */
+               return true;
+       case ADC_GAIN_CAL:
+       case ADC_DC_CAL:
+               return false;
+       case TEMP_COMP_CAL:
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * solve 4x4 linear equation used in loopback iq cal.
+ */
+static bool ar9003_hw_solve_iq_cal(struct ath_hw *ah,
+                                  s32 sin_2phi_1,
+                                  s32 cos_2phi_1,
+                                  s32 sin_2phi_2,
+                                  s32 cos_2phi_2,
+                                  s32 mag_a0_d0,
+                                  s32 phs_a0_d0,
+                                  s32 mag_a1_d0,
+                                  s32 phs_a1_d0,
+                                  s32 solved_eq[])
+{
+       s32 f1 = cos_2phi_1 - cos_2phi_2,
+           f3 = sin_2phi_1 - sin_2phi_2,
+           f2;
+       s32 mag_tx, phs_tx, mag_rx, phs_rx;
+       const s32 result_shift = 1 << 15;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       f2 = (f1 * f1 + f3 * f3) / result_shift;
+
+       if (!f2) {
+               ath_print(common, ATH_DBG_CALIBRATE, "Divide by 0\n");
+               return false;
+       }
+
+       /* mag mismatch, tx */
+       mag_tx = f1 * (mag_a0_d0  - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0);
+       /* phs mismatch, tx */
+       phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0);
+
+       mag_tx = (mag_tx / f2);
+       phs_tx = (phs_tx / f2);
+
+       /* mag mismatch, rx */
+       mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) /
+                result_shift;
+       /* phs mismatch, rx */
+       phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) /
+                result_shift;
+
+       solved_eq[0] = mag_tx;
+       solved_eq[1] = phs_tx;
+       solved_eq[2] = mag_rx;
+       solved_eq[3] = phs_rx;
+
+       return true;
+}
+
+static s32 ar9003_hw_find_mag_approx(struct ath_hw *ah, s32 in_re, s32 in_im)
+{
+       s32 abs_i = abs(in_re),
+           abs_q = abs(in_im),
+           max_abs, min_abs;
+
+       if (abs_i > abs_q) {
+               max_abs = abs_i;
+               min_abs = abs_q;
+       } else {
+               max_abs = abs_q;
+               min_abs = abs_i;
+       }
+
+       return max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4);
+}
+
+#define DELPT 32
+
+static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
+                                  s32 chain_idx,
+                                  const s32 iq_res[],
+                                  s32 iqc_coeff[])
+{
+       s32 i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0,
+           i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1,
+           i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0,
+           i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1;
+       s32 mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1,
+           phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1,
+           sin_2phi_1, cos_2phi_1,
+           sin_2phi_2, cos_2phi_2;
+       s32 mag_tx, phs_tx, mag_rx, phs_rx;
+       s32 solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx,
+           q_q_coff, q_i_coff;
+       const s32 res_scale = 1 << 15;
+       const s32 delpt_shift = 1 << 8;
+       s32 mag1, mag2;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       i2_m_q2_a0_d0 = iq_res[0] & 0xfff;
+       i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff;
+       iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8);
+
+       if (i2_m_q2_a0_d0 > 0x800)
+               i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1);
+
+       if (i2_p_q2_a0_d0 > 0x800)
+               i2_p_q2_a0_d0 = -((0xfff - i2_p_q2_a0_d0) + 1);
+
+       if (iq_corr_a0_d0 > 0x800)
+               iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1);
+
+       i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff;
+       i2_p_q2_a0_d1 = (iq_res[2] & 0xfff);
+       iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff;
+
+       if (i2_m_q2_a0_d1 > 0x800)
+               i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1);
+
+       if (i2_p_q2_a0_d1 > 0x800)
+               i2_p_q2_a0_d1 = -((0xfff - i2_p_q2_a0_d1) + 1);
+
+       if (iq_corr_a0_d1 > 0x800)
+               iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1);
+
+       i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8);
+       i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff;
+       iq_corr_a1_d0 = iq_res[4] & 0xfff;
+
+       if (i2_m_q2_a1_d0 > 0x800)
+               i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1);
+
+       if (i2_p_q2_a1_d0 > 0x800)
+               i2_p_q2_a1_d0 = -((0xfff - i2_p_q2_a1_d0) + 1);
+
+       if (iq_corr_a1_d0 > 0x800)
+               iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1);
+
+       i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff;
+       i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8);
+       iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff;
+
+       if (i2_m_q2_a1_d1 > 0x800)
+               i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1);
+
+       if (i2_p_q2_a1_d1 > 0x800)
+               i2_p_q2_a1_d1 = -((0xfff - i2_p_q2_a1_d1) + 1);
+
+       if (iq_corr_a1_d1 > 0x800)
+               iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1);
+
+       if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) ||
+           (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Divide by 0:\na0_d0=%d\n"
+                         "a0_d1=%d\na2_d0=%d\na1_d1=%d\n",
+                         i2_p_q2_a0_d0, i2_p_q2_a0_d1,
+                         i2_p_q2_a1_d0, i2_p_q2_a1_d1);
+               return false;
+       }
+
+       mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0;
+       phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0;
+
+       mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1;
+       phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1;
+
+       mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0;
+       phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0;
+
+       mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1;
+       phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1;
+
+       /* w/o analog phase shift */
+       sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT);
+       /* w/o analog phase shift */
+       cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT);
+       /* w/  analog phase shift */
+       sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT);
+       /* w/  analog phase shift */
+       cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT);
+
+       /*
+        * force sin^2 + cos^2 = 1;
+        * find magnitude by approximation
+        */
+       mag1 = ar9003_hw_find_mag_approx(ah, cos_2phi_1, sin_2phi_1);
+       mag2 = ar9003_hw_find_mag_approx(ah, cos_2phi_2, sin_2phi_2);
+
+       if ((mag1 == 0) || (mag2 == 0)) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Divide by 0: mag1=%d, mag2=%d\n",
+                         mag1, mag2);
+               return false;
+       }
+
+       /* normalization sin and cos by mag */
+       sin_2phi_1 = (sin_2phi_1 * res_scale / mag1);
+       cos_2phi_1 = (cos_2phi_1 * res_scale / mag1);
+       sin_2phi_2 = (sin_2phi_2 * res_scale / mag2);
+       cos_2phi_2 = (cos_2phi_2 * res_scale / mag2);
+
+       /* calculate IQ mismatch */
+       if (!ar9003_hw_solve_iq_cal(ah,
+                            sin_2phi_1, cos_2phi_1,
+                            sin_2phi_2, cos_2phi_2,
+                            mag_a0_d0, phs_a0_d0,
+                            mag_a1_d0,
+                            phs_a1_d0, solved_eq)) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Call to ar9003_hw_solve_iq_cal() failed.\n");
+               return false;
+       }
+
+       mag_tx = solved_eq[0];
+       phs_tx = solved_eq[1];
+       mag_rx = solved_eq[2];
+       phs_rx = solved_eq[3];
+
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "chain %d: mag mismatch=%d phase mismatch=%d\n",
+                 chain_idx, mag_tx/res_scale, phs_tx/res_scale);
+
+       if (res_scale == mag_tx) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Divide by 0: mag_tx=%d, res_scale=%d\n",
+                         mag_tx, res_scale);
+               return false;
+       }
+
+       /* calculate and quantize Tx IQ correction factor */
+       mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx);
+       phs_corr_tx = -phs_tx;
+
+       q_q_coff = (mag_corr_tx * 128 / res_scale);
+       q_i_coff = (phs_corr_tx * 256 / res_scale);
+
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "tx chain %d: mag corr=%d  phase corr=%d\n",
+                 chain_idx, q_q_coff, q_i_coff);
+
+       if (q_i_coff < -63)
+               q_i_coff = -63;
+       if (q_i_coff > 63)
+               q_i_coff = 63;
+       if (q_q_coff < -63)
+               q_q_coff = -63;
+       if (q_q_coff > 63)
+               q_q_coff = 63;
+
+       iqc_coeff[0] = (q_q_coff * 128) + q_i_coff;
+
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "tx chain %d: iq corr coeff=%x\n",
+                 chain_idx, iqc_coeff[0]);
+
+       if (-mag_rx == res_scale) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Divide by 0: mag_rx=%d, res_scale=%d\n",
+                         mag_rx, res_scale);
+               return false;
+       }
+
+       /* calculate and quantize Rx IQ correction factors */
+       mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx);
+       phs_corr_rx = -phs_rx;
+
+       q_q_coff = (mag_corr_rx * 128 / res_scale);
+       q_i_coff = (phs_corr_rx * 256 / res_scale);
+
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "rx chain %d: mag corr=%d  phase corr=%d\n",
+                 chain_idx, q_q_coff, q_i_coff);
+
+       if (q_i_coff < -63)
+               q_i_coff = -63;
+       if (q_i_coff > 63)
+               q_i_coff = 63;
+       if (q_q_coff < -63)
+               q_q_coff = -63;
+       if (q_q_coff > 63)
+               q_q_coff = 63;
+
+       iqc_coeff[1] = (q_q_coff * 128) + q_i_coff;
+
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "rx chain %d: iq corr coeff=%x\n",
+                 chain_idx, iqc_coeff[1]);
+
+       return true;
+}
+
+static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+               AR_PHY_TX_IQCAL_STATUS_B0,
+               AR_PHY_TX_IQCAL_STATUS_B1,
+               AR_PHY_TX_IQCAL_STATUS_B2,
+       };
+       const u32 tx_corr_coeff[AR9300_MAX_CHAINS] = {
+               AR_PHY_TX_IQCAL_CORR_COEFF_01_B0,
+               AR_PHY_TX_IQCAL_CORR_COEFF_01_B1,
+               AR_PHY_TX_IQCAL_CORR_COEFF_01_B2,
+       };
+       const u32 rx_corr[AR9300_MAX_CHAINS] = {
+               AR_PHY_RX_IQCAL_CORR_B0,
+               AR_PHY_RX_IQCAL_CORR_B1,
+               AR_PHY_RX_IQCAL_CORR_B2,
+       };
+       const u_int32_t chan_info_tab[] = {
+               AR_PHY_CHAN_INFO_TAB_0,
+               AR_PHY_CHAN_INFO_TAB_1,
+               AR_PHY_CHAN_INFO_TAB_2,
+       };
+       s32 iq_res[6];
+       s32 iqc_coeff[2];
+       s32 i, j;
+       u32 num_chains = 0;
+
+       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+               if (ah->txchainmask & (1 << i))
+                       num_chains++;
+       }
+
+       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+                     AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+                     DELPT);
+       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+                     AR_PHY_TX_IQCAL_START_DO_CAL,
+                     AR_PHY_TX_IQCAL_START_DO_CAL);
+
+       if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+                          AR_PHY_TX_IQCAL_START_DO_CAL,
+                          0, AH_WAIT_TIMEOUT)) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Tx IQ Cal not complete.\n");
+               goto TX_IQ_CAL_FAILED;
+       }
+
+       for (i = 0; i < num_chains; i++) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "Doing Tx IQ Cal for chain %d.\n", i);
+
+               if (REG_READ(ah, txiqcal_status[i]) &
+                            AR_PHY_TX_IQCAL_STATUS_FAILED) {
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Tx IQ Cal failed for chain %d.\n", i);
+                       goto TX_IQ_CAL_FAILED;
+               }
+
+               for (j = 0; j < 3; j++) {
+                       u_int8_t idx = 2 * j,
+                       offset = 4 * j;
+
+                       REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+                                     AR_PHY_CHAN_INFO_TAB_S2_READ, 0);
+
+                       /* 32 bits */
+                       iq_res[idx] = REG_READ(ah, chan_info_tab[i] + offset);
+
+                       REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+                                     AR_PHY_CHAN_INFO_TAB_S2_READ, 1);
+
+                       /* 16 bits */
+                       iq_res[idx+1] = 0xffff & REG_READ(ah,
+                                                         chan_info_tab[i] +
+                                                         offset);
+
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
+                                 idx, iq_res[idx], idx+1, iq_res[idx+1]);
+               }
+
+               if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, iqc_coeff)) {
+                       ath_print(common, ATH_DBG_CALIBRATE,
+                                 "Failed in calculation of IQ correction.\n");
+                       goto TX_IQ_CAL_FAILED;
+               }
+
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "IQ_COEFF[0] = 0x%x IQ_COEFF[1] = 0x%x\n",
+                         iqc_coeff[0], iqc_coeff[1]);
+
+               REG_RMW_FIELD(ah, tx_corr_coeff[i],
+                             AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE,
+                             iqc_coeff[0]);
+               REG_RMW_FIELD(ah, rx_corr[i],
+                             AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF,
+                             iqc_coeff[1] >> 7);
+               REG_RMW_FIELD(ah, rx_corr[i],
+                             AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF,
+                             iqc_coeff[1]);
+       }
+
+       REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
+                     AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
+                     AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
+
+       return;
+
+TX_IQ_CAL_FAILED:
+       ath_print(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
+}
+
+static bool ar9003_hw_init_cal(struct ath_hw *ah,
+                              struct ath9k_channel *chan)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       /*
+        * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain mode before
+        * running AGC/TxIQ cals
+        */
+       ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+
+       /* Calibrate the AGC */
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                 AR_PHY_AGC_CONTROL_CAL);
+
+       /* Poll for offset calibration complete */
+       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+                          0, AH_WAIT_TIMEOUT)) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "offset calibration failed to "
+                         "complete in 1ms; noisy environment?\n");
+               return false;
+       }
+
+       /* Do Tx IQ Calibration */
+       if (ah->config.tx_iq_calibration)
+               ar9003_hw_tx_iq_cal(ah);
+
+       /* Revert chainmasks to their original values before NF cal */
+       ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+
+       /* Initialize list pointers */
+       ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
+
+       if (ar9003_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
+               INIT_CAL(&ah->iq_caldata);
+               INSERT_CAL(ah, &ah->iq_caldata);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "enabling IQ Calibration.\n");
+       }
+
+       if (ar9003_hw_iscal_supported(ah, TEMP_COMP_CAL)) {
+               INIT_CAL(&ah->tempCompCalData);
+               INSERT_CAL(ah, &ah->tempCompCalData);
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "enabling Temperature Compensation Calibration.\n");
+       }
+
+       /* Initialize current pointer to first element in list */
+       ah->cal_list_curr = ah->cal_list;
+
+       if (ah->cal_list_curr)
+               ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
+
+       chan->CalValid = 0;
+
+       return true;
+}
+
+void ar9003_hw_attach_calib_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+       priv_ops->init_cal_settings = ar9003_hw_init_cal_settings;
+       priv_ops->init_cal = ar9003_hw_init_cal;
+       priv_ops->setup_calibration = ar9003_hw_setup_calibration;
+       priv_ops->iscal_supported = ar9003_hw_iscal_supported;
+
+       ops->calibrate = ar9003_hw_calibrate;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
new file mode 100644 (file)
index 0000000..23eb60e
--- /dev/null
@@ -0,0 +1,1838 @@
+/*
+ * Copyright (c) 2010 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 "hw.h"
+#include "ar9003_phy.h"
+#include "ar9003_eeprom.h"
+
+#define COMP_HDR_LEN 4
+#define COMP_CKSUM_LEN 2
+
+#define AR_CH0_TOP (0x00016288)
+#define AR_CH0_TOP_XPABIASLVL (0x3)
+#define AR_CH0_TOP_XPABIASLVL_S (8)
+
+#define AR_CH0_THERM (0x00016290)
+#define AR_CH0_THERM_SPARE (0x3f)
+#define AR_CH0_THERM_SPARE_S (0)
+
+#define AR_SWITCH_TABLE_COM_ALL (0xffff)
+#define AR_SWITCH_TABLE_COM_ALL_S (0)
+
+#define AR_SWITCH_TABLE_COM2_ALL (0xffffff)
+#define AR_SWITCH_TABLE_COM2_ALL_S (0)
+
+#define AR_SWITCH_TABLE_ALL (0xfff)
+#define AR_SWITCH_TABLE_ALL_S (0)
+
+#define LE16(x) __constant_cpu_to_le16(x)
+#define LE32(x) __constant_cpu_to_le32(x)
+
+static const struct ar9300_eeprom ar9300_default = {
+       .eepromVersion = 2,
+       .templateVersion = 2,
+       .macAddr = {1, 2, 3, 4, 5, 6},
+       .custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+       .baseEepHeader = {
+               .regDmn = { LE16(0), LE16(0x1f) },
+               .txrxMask =  0x77, /* 4 bits tx and 4 bits rx */
+               .opCapFlags = {
+                       .opFlags = AR9300_OPFLAGS_11G | AR9300_OPFLAGS_11A,
+                       .eepMisc = 0,
+               },
+               .rfSilent = 0,
+               .blueToothOptions = 0,
+               .deviceCap = 0,
+               .deviceType = 5, /* takes lower byte in eeprom location */
+               .pwrTableOffset = AR9300_PWR_TABLE_OFFSET,
+               .params_for_tuning_caps = {0, 0},
+               .featureEnable = 0x0c,
+                /*
+                 * bit0 - enable tx temp comp - disabled
+                 * bit1 - enable tx volt comp - disabled
+                 * bit2 - enable fastClock - enabled
+                 * bit3 - enable doubling - enabled
+                 * bit4 - enable internal regulator - disabled
+                 */
+               .miscConfiguration = 0, /* bit0 - turn down drivestrength */
+               .eepromWriteEnableGpio = 3,
+               .wlanDisableGpio = 0,
+               .wlanLedGpio = 8,
+               .rxBandSelectGpio = 0xff,
+               .txrxgain = 0,
+               .swreg = 0,
+        },
+       .modalHeader2G = {
+       /* ar9300_modal_eep_header  2g */
+               /* 4 idle,t1,t2,b(4 bits per setting) */
+               .antCtrlCommon = LE32(0x110),
+               /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+               .antCtrlCommon2 = LE32(0x22222),
+
+               /*
+                * antCtrlChain[AR9300_MAX_CHAINS]; 6 idle, t, r,
+                * rx1, rx12, b (2 bits each)
+                */
+               .antCtrlChain = { LE16(0x150), LE16(0x150), LE16(0x150) },
+
+               /*
+                * xatten1DB[AR9300_MAX_CHAINS];  3 xatten1_db
+                * for ar9280 (0xa20c/b20c 5:0)
+                */
+               .xatten1DB = {0, 0, 0},
+
+               /*
+                * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+                * for ar9280 (0xa20c/b20c 16:12
+                */
+               .xatten1Margin = {0, 0, 0},
+               .tempSlope = 36,
+               .voltSlope = 0,
+
+               /*
+                * spurChans[OSPREY_EEPROM_MODAL_SPURS]; spur
+                * channels in usual fbin coding format
+                */
+               .spurChans = {0, 0, 0, 0, 0},
+
+               /*
+                * noiseFloorThreshCh[AR9300_MAX_CHAINS]; 3 Check
+                * if the register is per chain
+                */
+               .noiseFloorThreshCh = {-1, 0, 0},
+               .ob = {1, 1, 1},/* 3 chain */
+               .db_stage2 = {1, 1, 1}, /* 3 chain  */
+               .db_stage3 = {0, 0, 0},
+               .db_stage4 = {0, 0, 0},
+               .xpaBiasLvl = 0,
+               .txFrameToDataStart = 0x0e,
+               .txFrameToPaOn = 0x0e,
+               .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+               .antennaGain = 0,
+               .switchSettling = 0x2c,
+               .adcDesiredSize = -30,
+               .txEndToXpaOff = 0,
+               .txEndToRxOn = 0x2,
+               .txFrameToXpaOn = 0xe,
+               .thresh62 = 28,
+               .futureModal = { /* [32] */
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+               },
+        },
+       .calFreqPier2G = {
+               FREQ2FBIN(2412, 1),
+               FREQ2FBIN(2437, 1),
+               FREQ2FBIN(2472, 1),
+        },
+       /* ar9300_cal_data_per_freq_op_loop 2g */
+       .calPierData2G = {
+               { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+               { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+               { {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0} },
+        },
+       .calTarget_freqbin_Cck = {
+               FREQ2FBIN(2412, 1),
+               FREQ2FBIN(2484, 1),
+        },
+       .calTarget_freqbin_2G = {
+               FREQ2FBIN(2412, 1),
+               FREQ2FBIN(2437, 1),
+               FREQ2FBIN(2472, 1)
+        },
+       .calTarget_freqbin_2GHT20 = {
+               FREQ2FBIN(2412, 1),
+               FREQ2FBIN(2437, 1),
+               FREQ2FBIN(2472, 1)
+        },
+       .calTarget_freqbin_2GHT40 = {
+               FREQ2FBIN(2412, 1),
+               FREQ2FBIN(2437, 1),
+               FREQ2FBIN(2472, 1)
+        },
+       .calTargetPowerCck = {
+                /* 1L-5L,5S,11L,11S */
+                { {36, 36, 36, 36} },
+                { {36, 36, 36, 36} },
+       },
+       .calTargetPower2G = {
+                /* 6-24,36,48,54 */
+                { {32, 32, 28, 24} },
+                { {32, 32, 28, 24} },
+                { {32, 32, 28, 24} },
+       },
+       .calTargetPower2GHT20 = {
+               { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+               { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+               { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+       },
+       .calTargetPower2GHT40 = {
+               { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+               { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+               { {32, 32, 32, 32, 28, 20, 32, 32, 28, 20, 32, 32, 28, 20} },
+       },
+       .ctlIndex_2G =  {
+               0x11, 0x12, 0x15, 0x17, 0x41, 0x42,
+               0x45, 0x47, 0x31, 0x32, 0x35, 0x37,
+       },
+       .ctl_freqbin_2G = {
+               {
+                       FREQ2FBIN(2412, 1),
+                       FREQ2FBIN(2417, 1),
+                       FREQ2FBIN(2457, 1),
+                       FREQ2FBIN(2462, 1)
+               },
+               {
+                       FREQ2FBIN(2412, 1),
+                       FREQ2FBIN(2417, 1),
+                       FREQ2FBIN(2462, 1),
+                       0xFF,
+               },
+
+               {
+                       FREQ2FBIN(2412, 1),
+                       FREQ2FBIN(2417, 1),
+                       FREQ2FBIN(2462, 1),
+                       0xFF,
+               },
+               {
+                       FREQ2FBIN(2422, 1),
+                       FREQ2FBIN(2427, 1),
+                       FREQ2FBIN(2447, 1),
+                       FREQ2FBIN(2452, 1)
+               },
+
+               {
+                       /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+                       /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+                       /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+                       /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(2484, 1),
+               },
+
+               {
+                       /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+                       /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+                       /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+                       0,
+               },
+
+               {
+                       /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+                       /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+                       FREQ2FBIN(2472, 1),
+                       0,
+               },
+
+               {
+                       /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+                       /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+                       /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+                       /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(2462, 1),
+               },
+
+               {
+                       /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+                       /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+                       /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+               },
+
+               {
+                       /* Data[9].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+                       /* Data[9].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+                       /* Data[9].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+                       0
+               },
+
+               {
+                       /* Data[10].ctlEdges[0].bChannel */ FREQ2FBIN(2412, 1),
+                       /* Data[10].ctlEdges[1].bChannel */ FREQ2FBIN(2417, 1),
+                       /* Data[10].ctlEdges[2].bChannel */ FREQ2FBIN(2472, 1),
+                       0
+               },
+
+               {
+                       /* Data[11].ctlEdges[0].bChannel */ FREQ2FBIN(2422, 1),
+                       /* Data[11].ctlEdges[1].bChannel */ FREQ2FBIN(2427, 1),
+                       /* Data[11].ctlEdges[2].bChannel */ FREQ2FBIN(2447, 1),
+                       /* Data[11].ctlEdges[3].bChannel */
+                       FREQ2FBIN(2462, 1),
+               }
+        },
+       .ctlPowerData_2G = {
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+
+                { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+
+                { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+
+                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+        },
+       .modalHeader5G = {
+               /* 4 idle,t1,t2,b (4 bits per setting) */
+               .antCtrlCommon = LE32(0x110),
+               /* 4 ra1l1, ra2l1, ra1l2,ra2l2,ra12 */
+               .antCtrlCommon2 = LE32(0x22222),
+                /* antCtrlChain 6 idle, t,r,rx1,rx12,b (2 bits each) */
+               .antCtrlChain = {
+                       LE16(0x000), LE16(0x000), LE16(0x000),
+               },
+                /* xatten1DB 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+               .xatten1DB = {0, 0, 0},
+
+               /*
+                * xatten1Margin[AR9300_MAX_CHAINS]; 3 xatten1_margin
+                * for merlin (0xa20c/b20c 16:12
+                */
+               .xatten1Margin = {0, 0, 0},
+               .tempSlope = 68,
+               .voltSlope = 0,
+               /* spurChans spur channels in usual fbin coding format */
+               .spurChans = {0, 0, 0, 0, 0},
+               /* noiseFloorThreshCh Check if the register is per chain */
+               .noiseFloorThreshCh = {-1, 0, 0},
+               .ob = {3, 3, 3}, /* 3 chain */
+               .db_stage2 = {3, 3, 3}, /* 3 chain */
+               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
+               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .xpaBiasLvl = 0,
+               .txFrameToDataStart = 0x0e,
+               .txFrameToPaOn = 0x0e,
+               .txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
+               .antennaGain = 0,
+               .switchSettling = 0x2d,
+               .adcDesiredSize = -30,
+               .txEndToXpaOff = 0,
+               .txEndToRxOn = 0x2,
+               .txFrameToXpaOn = 0xe,
+               .thresh62 = 28,
+               .futureModal = {
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+               },
+        },
+       .calFreqPier5G = {
+               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5220, 0),
+               FREQ2FBIN(5320, 0),
+               FREQ2FBIN(5400, 0),
+               FREQ2FBIN(5500, 0),
+               FREQ2FBIN(5600, 0),
+               FREQ2FBIN(5725, 0),
+               FREQ2FBIN(5825, 0)
+       },
+       .calPierData5G = {
+                       {
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                       },
+                       {
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                       },
+                       {
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                               {0, 0, 0, 0, 0},
+                       },
+
+       },
+       .calTarget_freqbin_5G = {
+               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5220, 0),
+               FREQ2FBIN(5320, 0),
+               FREQ2FBIN(5400, 0),
+               FREQ2FBIN(5500, 0),
+               FREQ2FBIN(5600, 0),
+               FREQ2FBIN(5725, 0),
+               FREQ2FBIN(5825, 0)
+       },
+       .calTarget_freqbin_5GHT20 = {
+               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5240, 0),
+               FREQ2FBIN(5320, 0),
+               FREQ2FBIN(5500, 0),
+               FREQ2FBIN(5700, 0),
+               FREQ2FBIN(5745, 0),
+               FREQ2FBIN(5725, 0),
+               FREQ2FBIN(5825, 0)
+       },
+       .calTarget_freqbin_5GHT40 = {
+               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5240, 0),
+               FREQ2FBIN(5320, 0),
+               FREQ2FBIN(5500, 0),
+               FREQ2FBIN(5700, 0),
+               FREQ2FBIN(5745, 0),
+               FREQ2FBIN(5725, 0),
+               FREQ2FBIN(5825, 0)
+        },
+       .calTargetPower5G = {
+               /* 6-24,36,48,54 */
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+               { {20, 20, 20, 10} },
+        },
+       .calTargetPower5GHT20 = {
+               /*
+                * 0_8_16,1-3_9-11_17-19,
+                * 4,5,6,7,12,13,14,15,20,21,22,23
+                */
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+        },
+       .calTargetPower5GHT40 =  {
+               /*
+                * 0_8_16,1-3_9-11_17-19,
+                * 4,5,6,7,12,13,14,15,20,21,22,23
+                */
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+               { {20, 20, 10, 10, 0, 0, 10, 10, 0, 0, 10, 10, 0, 0} },
+        },
+       .ctlIndex_5G =  {
+               0x10, 0x16, 0x18, 0x40, 0x46,
+               0x48, 0x30, 0x36, 0x38
+       },
+       .ctl_freqbin_5G =  {
+               {
+                       /* Data[0].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+                       /* Data[0].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+                       /* Data[0].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+                       /* Data[0].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+                       /* Data[0].ctlEdges[4].bChannel */ FREQ2FBIN(5600, 0),
+                       /* Data[0].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+                       /* Data[0].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+                       /* Data[0].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+               },
+               {
+                       /* Data[1].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+                       /* Data[1].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+                       /* Data[1].ctlEdges[2].bChannel */ FREQ2FBIN(5280, 0),
+                       /* Data[1].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+                       /* Data[1].ctlEdges[4].bChannel */ FREQ2FBIN(5520, 0),
+                       /* Data[1].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+                       /* Data[1].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+                       /* Data[1].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+               },
+
+               {
+                       /* Data[2].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+                       /* Data[2].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+                       /* Data[2].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+                       /* Data[2].ctlEdges[3].bChannel */ FREQ2FBIN(5310, 0),
+                       /* Data[2].ctlEdges[4].bChannel */ FREQ2FBIN(5510, 0),
+                       /* Data[2].ctlEdges[5].bChannel */ FREQ2FBIN(5550, 0),
+                       /* Data[2].ctlEdges[6].bChannel */ FREQ2FBIN(5670, 0),
+                       /* Data[2].ctlEdges[7].bChannel */ FREQ2FBIN(5755, 0)
+               },
+
+               {
+                       /* Data[3].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+                       /* Data[3].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+                       /* Data[3].ctlEdges[2].bChannel */ FREQ2FBIN(5260, 0),
+                       /* Data[3].ctlEdges[3].bChannel */ FREQ2FBIN(5320, 0),
+                       /* Data[3].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+                       /* Data[3].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+                       /* Data[3].ctlEdges[6].bChannel */ 0xFF,
+                       /* Data[3].ctlEdges[7].bChannel */ 0xFF,
+               },
+
+               {
+                       /* Data[4].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+                       /* Data[4].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+                       /* Data[4].ctlEdges[2].bChannel */ FREQ2FBIN(5500, 0),
+                       /* Data[4].ctlEdges[3].bChannel */ FREQ2FBIN(5700, 0),
+                       /* Data[4].ctlEdges[4].bChannel */ 0xFF,
+                       /* Data[4].ctlEdges[5].bChannel */ 0xFF,
+                       /* Data[4].ctlEdges[6].bChannel */ 0xFF,
+                       /* Data[4].ctlEdges[7].bChannel */ 0xFF,
+               },
+
+               {
+                       /* Data[5].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+                       /* Data[5].ctlEdges[1].bChannel */ FREQ2FBIN(5270, 0),
+                       /* Data[5].ctlEdges[2].bChannel */ FREQ2FBIN(5310, 0),
+                       /* Data[5].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+                       /* Data[5].ctlEdges[4].bChannel */ FREQ2FBIN(5590, 0),
+                       /* Data[5].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+                       /* Data[5].ctlEdges[6].bChannel */ 0xFF,
+                       /* Data[5].ctlEdges[7].bChannel */ 0xFF
+               },
+
+               {
+                       /* Data[6].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+                       /* Data[6].ctlEdges[1].bChannel */ FREQ2FBIN(5200, 0),
+                       /* Data[6].ctlEdges[2].bChannel */ FREQ2FBIN(5220, 0),
+                       /* Data[6].ctlEdges[3].bChannel */ FREQ2FBIN(5260, 0),
+                       /* Data[6].ctlEdges[4].bChannel */ FREQ2FBIN(5500, 0),
+                       /* Data[6].ctlEdges[5].bChannel */ FREQ2FBIN(5600, 0),
+                       /* Data[6].ctlEdges[6].bChannel */ FREQ2FBIN(5700, 0),
+                       /* Data[6].ctlEdges[7].bChannel */ FREQ2FBIN(5745, 0)
+               },
+
+               {
+                       /* Data[7].ctlEdges[0].bChannel */ FREQ2FBIN(5180, 0),
+                       /* Data[7].ctlEdges[1].bChannel */ FREQ2FBIN(5260, 0),
+                       /* Data[7].ctlEdges[2].bChannel */ FREQ2FBIN(5320, 0),
+                       /* Data[7].ctlEdges[3].bChannel */ FREQ2FBIN(5500, 0),
+                       /* Data[7].ctlEdges[4].bChannel */ FREQ2FBIN(5560, 0),
+                       /* Data[7].ctlEdges[5].bChannel */ FREQ2FBIN(5700, 0),
+                       /* Data[7].ctlEdges[6].bChannel */ FREQ2FBIN(5745, 0),
+                       /* Data[7].ctlEdges[7].bChannel */ FREQ2FBIN(5825, 0)
+               },
+
+               {
+                       /* Data[8].ctlEdges[0].bChannel */ FREQ2FBIN(5190, 0),
+                       /* Data[8].ctlEdges[1].bChannel */ FREQ2FBIN(5230, 0),
+                       /* Data[8].ctlEdges[2].bChannel */ FREQ2FBIN(5270, 0),
+                       /* Data[8].ctlEdges[3].bChannel */ FREQ2FBIN(5510, 0),
+                       /* Data[8].ctlEdges[4].bChannel */ FREQ2FBIN(5550, 0),
+                       /* Data[8].ctlEdges[5].bChannel */ FREQ2FBIN(5670, 0),
+                       /* Data[8].ctlEdges[6].bChannel */ FREQ2FBIN(5755, 0),
+                       /* Data[8].ctlEdges[7].bChannel */ FREQ2FBIN(5795, 0)
+               }
+        },
+       .ctlPowerData_5G = {
+               {
+                       {
+                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                       }
+               },
+               {
+                       {
+                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                       }
+               },
+               {
+                       {
+                               {60, 0}, {60, 1}, {60, 0}, {60, 1},
+                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                       }
+               },
+               {
+                       {
+                               {60, 0}, {60, 1}, {60, 1}, {60, 0},
+                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                       }
+               },
+               {
+                       {
+                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               {60, 0}, {60, 0}, {60, 0}, {60, 0},
+                       }
+               },
+               {
+                       {
+                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                       }
+               },
+               {
+                       {
+                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                       }
+               },
+               {
+                       {
+                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                       }
+               },
+               {
+                       {
+                               {60, 1}, {60, 0}, {60, 1}, {60, 1},
+                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                       }
+               },
+        }
+};
+
+static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah)
+{
+       return 0;
+}
+
+static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
+                                     enum eeprom_param param)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct ar9300_base_eep_hdr *pBase = &eep->baseEepHeader;
+
+       switch (param) {
+       case EEP_MAC_LSW:
+               return eep->macAddr[0] << 8 | eep->macAddr[1];
+       case EEP_MAC_MID:
+               return eep->macAddr[2] << 8 | eep->macAddr[3];
+       case EEP_MAC_MSW:
+               return eep->macAddr[4] << 8 | eep->macAddr[5];
+       case EEP_REG_0:
+               return le16_to_cpu(pBase->regDmn[0]);
+       case EEP_REG_1:
+               return le16_to_cpu(pBase->regDmn[1]);
+       case EEP_OP_CAP:
+               return pBase->deviceCap;
+       case EEP_OP_MODE:
+               return pBase->opCapFlags.opFlags;
+       case EEP_RF_SILENT:
+               return pBase->rfSilent;
+       case EEP_TX_MASK:
+               return (pBase->txrxMask >> 4) & 0xf;
+       case EEP_RX_MASK:
+               return pBase->txrxMask & 0xf;
+       case EEP_DRIVE_STRENGTH:
+#define AR9300_EEP_BASE_DRIV_STRENGTH  0x1
+               return pBase->miscConfiguration & AR9300_EEP_BASE_DRIV_STRENGTH;
+       case EEP_INTERNAL_REGULATOR:
+               /* Bit 4 is internal regulator flag */
+               return (pBase->featureEnable & 0x10) >> 4;
+       case EEP_SWREG:
+               return le32_to_cpu(pBase->swreg);
+       default:
+               return 0;
+       }
+}
+
+static bool ar9300_eeprom_read_byte(struct ath_common *common, int address,
+                                   u8 *buffer)
+{
+       u16 val;
+
+       if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
+               return false;
+
+       *buffer = (val >> (8 * (address % 2))) & 0xff;
+       return true;
+}
+
+static bool ar9300_eeprom_read_word(struct ath_common *common, int address,
+                                   u8 *buffer)
+{
+       u16 val;
+
+       if (unlikely(!ath9k_hw_nvram_read(common, address / 2, &val)))
+               return false;
+
+       buffer[0] = val >> 8;
+       buffer[1] = val & 0xff;
+
+       return true;
+}
+
+static bool ar9300_read_eeprom(struct ath_hw *ah, int address, u8 *buffer,
+                              int count)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       int i;
+
+       if ((address < 0) || ((address + count) / 2 > AR9300_EEPROM_SIZE - 1)) {
+               ath_print(common, ATH_DBG_EEPROM,
+                         "eeprom address not in range\n");
+               return false;
+       }
+
+       /*
+        * Since we're reading the bytes in reverse order from a little-endian
+        * word stream, an even address means we only use the lower half of
+        * the 16-bit word at that address
+        */
+       if (address % 2 == 0) {
+               if (!ar9300_eeprom_read_byte(common, address--, buffer++))
+                       goto error;
+
+               count--;
+       }
+
+       for (i = 0; i < count / 2; i++) {
+               if (!ar9300_eeprom_read_word(common, address, buffer))
+                       goto error;
+
+               address -= 2;
+               buffer += 2;
+       }
+
+       if (count % 2)
+               if (!ar9300_eeprom_read_byte(common, address, buffer))
+                       goto error;
+
+       return true;
+
+error:
+       ath_print(common, ATH_DBG_EEPROM,
+                 "unable to read eeprom region at offset %d\n", address);
+       return false;
+}
+
+static void ar9300_comp_hdr_unpack(u8 *best, int *code, int *reference,
+                                  int *length, int *major, int *minor)
+{
+       unsigned long value[4];
+
+       value[0] = best[0];
+       value[1] = best[1];
+       value[2] = best[2];
+       value[3] = best[3];
+       *code = ((value[0] >> 5) & 0x0007);
+       *reference = (value[0] & 0x001f) | ((value[1] >> 2) & 0x0020);
+       *length = ((value[1] << 4) & 0x07f0) | ((value[2] >> 4) & 0x000f);
+       *major = (value[2] & 0x000f);
+       *minor = (value[3] & 0x00ff);
+}
+
+static u16 ar9300_comp_cksum(u8 *data, int dsize)
+{
+       int it, checksum = 0;
+
+       for (it = 0; it < dsize; it++) {
+               checksum += data[it];
+               checksum &= 0xffff;
+       }
+
+       return checksum;
+}
+
+static bool ar9300_uncompress_block(struct ath_hw *ah,
+                                   u8 *mptr,
+                                   int mdataSize,
+                                   u8 *block,
+                                   int size)
+{
+       int it;
+       int spot;
+       int offset;
+       int length;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       spot = 0;
+
+       for (it = 0; it < size; it += (length+2)) {
+               offset = block[it];
+               offset &= 0xff;
+               spot += offset;
+               length = block[it+1];
+               length &= 0xff;
+
+               if (length > 0 && spot >= 0 && spot+length < mdataSize) {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "Restore at %d: spot=%d "
+                                 "offset=%d length=%d\n",
+                                  it, spot, offset, length);
+                       memcpy(&mptr[spot], &block[it+2], length);
+                       spot += length;
+               } else if (length > 0) {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "Bad restore at %d: spot=%d "
+                                 "offset=%d length=%d\n",
+                                 it, spot, offset, length);
+                       return false;
+               }
+       }
+       return true;
+}
+
+static int ar9300_compress_decision(struct ath_hw *ah,
+                                   int it,
+                                   int code,
+                                   int reference,
+                                   u8 *mptr,
+                                   u8 *word, int length, int mdata_size)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u8 *dptr;
+
+       switch (code) {
+       case _CompressNone:
+               if (length != mdata_size) {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "EEPROM structure size mismatch"
+                                 "memory=%d eeprom=%d\n", mdata_size, length);
+                       return -1;
+               }
+               memcpy(mptr, (u8 *) (word + COMP_HDR_LEN), length);
+               ath_print(common, ATH_DBG_EEPROM, "restored eeprom %d:"
+                         " uncompressed, length %d\n", it, length);
+               break;
+       case _CompressBlock:
+               if (reference == 0) {
+                       dptr = mptr;
+               } else {
+                       if (reference != 2) {
+                               ath_print(common, ATH_DBG_EEPROM,
+                                         "cant find reference eeprom"
+                                         "struct %d\n", reference);
+                               return -1;
+                       }
+                       memcpy(mptr, &ar9300_default, mdata_size);
+               }
+               ath_print(common, ATH_DBG_EEPROM,
+                         "restore eeprom %d: block, reference %d,"
+                         " length %d\n", it, reference, length);
+               ar9300_uncompress_block(ah, mptr, mdata_size,
+                                       (u8 *) (word + COMP_HDR_LEN), length);
+               break;
+       default:
+               ath_print(common, ATH_DBG_EEPROM, "unknown compression"
+                         " code %d\n", code);
+               return -1;
+       }
+       return 0;
+}
+
+/*
+ * Read the configuration data from the eeprom.
+ * The data can be put in any specified memory buffer.
+ *
+ * Returns -1 on error.
+ * Returns address of next memory location on success.
+ */
+static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
+                                         u8 *mptr, int mdata_size)
+{
+#define MDEFAULT 15
+#define MSTATE 100
+       int cptr;
+       u8 *word;
+       int code;
+       int reference, length, major, minor;
+       int osize;
+       int it;
+       u16 checksum, mchecksum;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       word = kzalloc(2048, GFP_KERNEL);
+       if (!word)
+               return -1;
+
+       memcpy(mptr, &ar9300_default, mdata_size);
+
+       cptr = AR9300_BASE_ADDR;
+       for (it = 0; it < MSTATE; it++) {
+               if (!ar9300_read_eeprom(ah, cptr, word, COMP_HDR_LEN))
+                       goto fail;
+
+               if ((word[0] == 0 && word[1] == 0 && word[2] == 0 &&
+                    word[3] == 0) || (word[0] == 0xff && word[1] == 0xff
+                                      && word[2] == 0xff && word[3] == 0xff))
+                       break;
+
+               ar9300_comp_hdr_unpack(word, &code, &reference,
+                                      &length, &major, &minor);
+               ath_print(common, ATH_DBG_EEPROM,
+                         "Found block at %x: code=%d ref=%d"
+                         "length=%d major=%d minor=%d\n", cptr, code,
+                         reference, length, major, minor);
+               if (length >= 1024) {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "Skipping bad header\n");
+                       cptr -= COMP_HDR_LEN;
+                       continue;
+               }
+
+               osize = length;
+               ar9300_read_eeprom(ah, cptr, word,
+                                  COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
+               checksum = ar9300_comp_cksum(&word[COMP_HDR_LEN], length);
+               mchecksum = word[COMP_HDR_LEN + osize] |
+                   (word[COMP_HDR_LEN + osize + 1] << 8);
+               ath_print(common, ATH_DBG_EEPROM,
+                         "checksum %x %x\n", checksum, mchecksum);
+               if (checksum == mchecksum) {
+                       ar9300_compress_decision(ah, it, code, reference, mptr,
+                                                word, length, mdata_size);
+               } else {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "skipping block with bad checksum\n");
+               }
+               cptr -= (COMP_HDR_LEN + osize + COMP_CKSUM_LEN);
+       }
+
+       kfree(word);
+       return cptr;
+
+fail:
+       kfree(word);
+       return -1;
+}
+
+/*
+ * Restore the configuration structure by reading the eeprom.
+ * This function destroys any existing in-memory structure
+ * content.
+ */
+static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah)
+{
+       u8 *mptr = (u8 *) &ah->eeprom.ar9300_eep;
+
+       if (ar9300_eeprom_restore_internal(ah, mptr,
+                       sizeof(struct ar9300_eeprom)) < 0)
+               return false;
+
+       return true;
+}
+
+/* XXX: review hardware docs */
+static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah)
+{
+       return ah->eeprom.ar9300_eep.eepromVersion;
+}
+
+/* XXX: could be read from the eepromVersion, not sure yet */
+static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah)
+{
+       return 0;
+}
+
+static u8 ath9k_hw_ar9300_get_num_ant_config(struct ath_hw *ah,
+                                            enum ieee80211_band freq_band)
+{
+       return 1;
+}
+
+static u16 ath9k_hw_ar9300_get_eeprom_antenna_cfg(struct ath_hw *ah,
+                                                 struct ath9k_channel *chan)
+{
+       return -EINVAL;
+}
+
+static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, bool is2ghz)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+       if (is2ghz)
+               return eep->modalHeader2G.xpaBiasLvl;
+       else
+               return eep->modalHeader5G.xpaBiasLvl;
+}
+
+static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
+{
+       int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz);
+       REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, (bias & 0x3));
+       REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_SPARE,
+                     ((bias >> 2) & 0x3));
+}
+
+static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       __le32 val;
+
+       if (is2ghz)
+               val = eep->modalHeader2G.antCtrlCommon;
+       else
+               val = eep->modalHeader5G.antCtrlCommon;
+       return le32_to_cpu(val);
+}
+
+static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       __le32 val;
+
+       if (is2ghz)
+               val = eep->modalHeader2G.antCtrlCommon2;
+       else
+               val = eep->modalHeader5G.antCtrlCommon2;
+       return le32_to_cpu(val);
+}
+
+static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
+                                       int chain,
+                                       bool is2ghz)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       __le16 val = 0;
+
+       if (chain >= 0 && chain < AR9300_MAX_CHAINS) {
+               if (is2ghz)
+                       val = eep->modalHeader2G.antCtrlChain[chain];
+               else
+                       val = eep->modalHeader5G.antCtrlChain[chain];
+       }
+
+       return le16_to_cpu(val);
+}
+
+static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
+{
+       u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
+       REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value);
+
+       value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
+       REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
+
+       value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz);
+       REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value);
+
+       value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
+       REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, value);
+
+       value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz);
+       REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, value);
+}
+
+static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
+{
+       int drive_strength;
+       unsigned long reg;
+
+       drive_strength = ath9k_hw_ar9300_get_eeprom(ah, EEP_DRIVE_STRENGTH);
+
+       if (!drive_strength)
+               return;
+
+       reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS1);
+       reg &= ~0x00ffffc0;
+       reg |= 0x5 << 21;
+       reg |= 0x5 << 18;
+       reg |= 0x5 << 15;
+       reg |= 0x5 << 12;
+       reg |= 0x5 << 9;
+       reg |= 0x5 << 6;
+       REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS1, reg);
+
+       reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS2);
+       reg &= ~0xffffffe0;
+       reg |= 0x5 << 29;
+       reg |= 0x5 << 26;
+       reg |= 0x5 << 23;
+       reg |= 0x5 << 20;
+       reg |= 0x5 << 17;
+       reg |= 0x5 << 14;
+       reg |= 0x5 << 11;
+       reg |= 0x5 << 8;
+       reg |= 0x5 << 5;
+       REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS2, reg);
+
+       reg = REG_READ(ah, AR_PHY_65NM_CH0_BIAS4);
+       reg &= ~0xff800000;
+       reg |= 0x5 << 29;
+       reg |= 0x5 << 26;
+       reg |= 0x5 << 23;
+       REG_WRITE(ah, AR_PHY_65NM_CH0_BIAS4, reg);
+}
+
+static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
+{
+       int internal_regulator =
+               ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR);
+
+       if (internal_regulator) {
+               /* Internal regulator is ON. Write swreg register. */
+               int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG);
+               REG_WRITE(ah, AR_RTC_REG_CONTROL1,
+               REG_READ(ah, AR_RTC_REG_CONTROL1) &
+                        (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM));
+               REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg);
+               /* Set REG_CONTROL1.SWREG_PROGRAM */
+               REG_WRITE(ah, AR_RTC_REG_CONTROL1,
+                         REG_READ(ah,
+                                  AR_RTC_REG_CONTROL1) |
+                                  AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
+       } else {
+               REG_WRITE(ah, AR_RTC_SLEEP_CLK,
+                         (REG_READ(ah,
+                                   AR_RTC_SLEEP_CLK) |
+                                   AR_RTC_FORCE_SWREG_PRD));
+       }
+}
+
+static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
+                                            struct ath9k_channel *chan)
+{
+       ar9003_hw_xpa_bias_level_apply(ah, IS_CHAN_2GHZ(chan));
+       ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
+       ar9003_hw_drive_strength_apply(ah);
+       ar9003_hw_internal_regulator_apply(ah);
+}
+
+static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah,
+                                     struct ath9k_channel *chan)
+{
+}
+
+/*
+ * Returns the interpolated y value corresponding to the specified x value
+ * from the np ordered pairs of data (px,py).
+ * The pairs do not have to be in any order.
+ * If the specified x value is less than any of the px,
+ * the returned y value is equal to the py for the lowest px.
+ * If the specified x value is greater than any of the px,
+ * the returned y value is equal to the py for the highest px.
+ */
+static int ar9003_hw_power_interpolate(int32_t x,
+                                      int32_t *px, int32_t *py, u_int16_t np)
+{
+       int ip = 0;
+       int lx = 0, ly = 0, lhave = 0;
+       int hx = 0, hy = 0, hhave = 0;
+       int dx = 0;
+       int y = 0;
+
+       lhave = 0;
+       hhave = 0;
+
+       /* identify best lower and higher x calibration measurement */
+       for (ip = 0; ip < np; ip++) {
+               dx = x - px[ip];
+
+               /* this measurement is higher than our desired x */
+               if (dx <= 0) {
+                       if (!hhave || dx > (x - hx)) {
+                               /* new best higher x measurement */
+                               hx = px[ip];
+                               hy = py[ip];
+                               hhave = 1;
+                       }
+               }
+               /* this measurement is lower than our desired x */
+               if (dx >= 0) {
+                       if (!lhave || dx < (x - lx)) {
+                               /* new best lower x measurement */
+                               lx = px[ip];
+                               ly = py[ip];
+                               lhave = 1;
+                       }
+               }
+       }
+
+       /* the low x is good */
+       if (lhave) {
+               /* so is the high x */
+               if (hhave) {
+                       /* they're the same, so just pick one */
+                       if (hx == lx)
+                               y = ly;
+                       else    /* interpolate  */
+                               y = ly + (((x - lx) * (hy - ly)) / (hx - lx));
+               } else          /* only low is good, use it */
+                       y = ly;
+       } else if (hhave)       /* only high is good, use it */
+               y = hy;
+       else /* nothing is good,this should never happen unless np=0, ???? */
+               y = -(1 << 30);
+       return y;
+}
+
+static u8 ar9003_hw_eeprom_get_tgt_pwr(struct ath_hw *ah,
+                                      u16 rateIndex, u16 freq, bool is2GHz)
+{
+       u16 numPiers, i;
+       s32 targetPowerArray[AR9300_NUM_5G_20_TARGET_POWERS];
+       s32 freqArray[AR9300_NUM_5G_20_TARGET_POWERS];
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct cal_tgt_pow_legacy *pEepromTargetPwr;
+       u8 *pFreqBin;
+
+       if (is2GHz) {
+               numPiers = AR9300_NUM_2G_20_TARGET_POWERS;
+               pEepromTargetPwr = eep->calTargetPower2G;
+               pFreqBin = eep->calTarget_freqbin_2G;
+       } else {
+               numPiers = AR9300_NUM_5G_20_TARGET_POWERS;
+               pEepromTargetPwr = eep->calTargetPower5G;
+               pFreqBin = eep->calTarget_freqbin_5G;
+       }
+
+       /*
+        * create array of channels and targetpower from
+        * targetpower piers stored on eeprom
+        */
+       for (i = 0; i < numPiers; i++) {
+               freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz);
+               targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+       }
+
+       /* interpolate to get target power for given frequency */
+       return (u8) ar9003_hw_power_interpolate((s32) freq,
+                                                freqArray,
+                                                targetPowerArray, numPiers);
+}
+
+static u8 ar9003_hw_eeprom_get_ht20_tgt_pwr(struct ath_hw *ah,
+                                           u16 rateIndex,
+                                           u16 freq, bool is2GHz)
+{
+       u16 numPiers, i;
+       s32 targetPowerArray[AR9300_NUM_5G_20_TARGET_POWERS];
+       s32 freqArray[AR9300_NUM_5G_20_TARGET_POWERS];
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct cal_tgt_pow_ht *pEepromTargetPwr;
+       u8 *pFreqBin;
+
+       if (is2GHz) {
+               numPiers = AR9300_NUM_2G_20_TARGET_POWERS;
+               pEepromTargetPwr = eep->calTargetPower2GHT20;
+               pFreqBin = eep->calTarget_freqbin_2GHT20;
+       } else {
+               numPiers = AR9300_NUM_5G_20_TARGET_POWERS;
+               pEepromTargetPwr = eep->calTargetPower5GHT20;
+               pFreqBin = eep->calTarget_freqbin_5GHT20;
+       }
+
+       /*
+        * create array of channels and targetpower
+        * from targetpower piers stored on eeprom
+        */
+       for (i = 0; i < numPiers; i++) {
+               freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz);
+               targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+       }
+
+       /* interpolate to get target power for given frequency */
+       return (u8) ar9003_hw_power_interpolate((s32) freq,
+                                                freqArray,
+                                                targetPowerArray, numPiers);
+}
+
+static u8 ar9003_hw_eeprom_get_ht40_tgt_pwr(struct ath_hw *ah,
+                                           u16 rateIndex,
+                                           u16 freq, bool is2GHz)
+{
+       u16 numPiers, i;
+       s32 targetPowerArray[AR9300_NUM_5G_40_TARGET_POWERS];
+       s32 freqArray[AR9300_NUM_5G_40_TARGET_POWERS];
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct cal_tgt_pow_ht *pEepromTargetPwr;
+       u8 *pFreqBin;
+
+       if (is2GHz) {
+               numPiers = AR9300_NUM_2G_40_TARGET_POWERS;
+               pEepromTargetPwr = eep->calTargetPower2GHT40;
+               pFreqBin = eep->calTarget_freqbin_2GHT40;
+       } else {
+               numPiers = AR9300_NUM_5G_40_TARGET_POWERS;
+               pEepromTargetPwr = eep->calTargetPower5GHT40;
+               pFreqBin = eep->calTarget_freqbin_5GHT40;
+       }
+
+       /*
+        * create array of channels and targetpower from
+        * targetpower piers stored on eeprom
+        */
+       for (i = 0; i < numPiers; i++) {
+               freqArray[i] = FBIN2FREQ(pFreqBin[i], is2GHz);
+               targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+       }
+
+       /* interpolate to get target power for given frequency */
+       return (u8) ar9003_hw_power_interpolate((s32) freq,
+                                                freqArray,
+                                                targetPowerArray, numPiers);
+}
+
+static u8 ar9003_hw_eeprom_get_cck_tgt_pwr(struct ath_hw *ah,
+                                          u16 rateIndex, u16 freq)
+{
+       u16 numPiers = AR9300_NUM_2G_CCK_TARGET_POWERS, i;
+       s32 targetPowerArray[AR9300_NUM_2G_CCK_TARGET_POWERS];
+       s32 freqArray[AR9300_NUM_2G_CCK_TARGET_POWERS];
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct cal_tgt_pow_legacy *pEepromTargetPwr = eep->calTargetPowerCck;
+       u8 *pFreqBin = eep->calTarget_freqbin_Cck;
+
+       /*
+        * create array of channels and targetpower from
+        * targetpower piers stored on eeprom
+        */
+       for (i = 0; i < numPiers; i++) {
+               freqArray[i] = FBIN2FREQ(pFreqBin[i], 1);
+               targetPowerArray[i] = pEepromTargetPwr[i].tPow2x[rateIndex];
+       }
+
+       /* interpolate to get target power for given frequency */
+       return (u8) ar9003_hw_power_interpolate((s32) freq,
+                                                freqArray,
+                                                targetPowerArray, numPiers);
+}
+
+/* Set tx power registers to array of values passed in */
+static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
+{
+#define POW_SM(_r, _s)     (((_r) & 0x3f) << (_s))
+       /* make sure forced gain is not set */
+       REG_WRITE(ah, 0xa458, 0);
+
+       /* Write the OFDM power per rate set */
+
+       /* 6 (LSB), 9, 12, 18 (MSB) */
+       REG_WRITE(ah, 0xa3c0,
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0));
+
+       /* 24 (LSB), 36, 48, 54 (MSB) */
+       REG_WRITE(ah, 0xa3c4,
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_54], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_48], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_36], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 0));
+
+       /* Write the CCK power per rate set */
+
+       /* 1L (LSB), reserved, 2L, 2S (MSB) */
+       REG_WRITE(ah, 0xa3c8,
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
+                 /* POW_SM(txPowerTimes2,  8) | this is reserved for AR9003 */
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0));
+
+       /* 5.5L (LSB), 5.5S, 11L, 11S (MSB) */
+       REG_WRITE(ah, 0xa3cc,
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_11S], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_11L], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_5S], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
+           );
+
+       /* Write the HT20 power per rate set */
+
+       /* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
+       REG_WRITE(ah, 0xa3d0,
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_5], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_4], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_1_3_9_11_17_19], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_0_8_16], 0)
+           );
+
+       /* 6 (LSB), 7, 12, 13 (MSB) */
+       REG_WRITE(ah, 0xa3d4,
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_13], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_12], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_7], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_6], 0)
+           );
+
+       /* 14 (LSB), 15, 20, 21 */
+       REG_WRITE(ah, 0xa3e4,
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_21], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_20], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_15], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_14], 0)
+           );
+
+       /* Mixed HT20 and HT40 rates */
+
+       /* HT20 22 (LSB), HT20 23, HT40 22, HT40 23 (MSB) */
+       REG_WRITE(ah, 0xa3e8,
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_23], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_22], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_23], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT20_22], 0)
+           );
+
+       /*
+        * Write the HT40 power per rate set
+        * correct PAR difference between HT40 and HT20/LEGACY
+        * 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB)
+        */
+       REG_WRITE(ah, 0xa3d8,
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_5], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_4], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_1_3_9_11_17_19], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_0_8_16], 0)
+           );
+
+       /* 6 (LSB), 7, 12, 13 (MSB) */
+       REG_WRITE(ah, 0xa3dc,
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_13], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_12], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_7], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_6], 0)
+           );
+
+       /* 14 (LSB), 15, 20, 21 */
+       REG_WRITE(ah, 0xa3ec,
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_21], 24) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_20], 16) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_15], 8) |
+                 POW_SM(pPwrArray[ALL_TARGET_HT40_14], 0)
+           );
+
+       return 0;
+#undef POW_SM
+}
+
+static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq)
+{
+       u8 targetPowerValT2[ar9300RateSize];
+       /* XXX: hard code for now, need to get from eeprom struct */
+       u8 ht40PowerIncForPdadc = 0;
+       bool is2GHz = false;
+       unsigned int i = 0;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (freq < 4000)
+               is2GHz = true;
+
+       targetPowerValT2[ALL_TARGET_LEGACY_6_24] =
+           ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_6_24, freq,
+                                        is2GHz);
+       targetPowerValT2[ALL_TARGET_LEGACY_36] =
+           ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_36, freq,
+                                        is2GHz);
+       targetPowerValT2[ALL_TARGET_LEGACY_48] =
+           ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_48, freq,
+                                        is2GHz);
+       targetPowerValT2[ALL_TARGET_LEGACY_54] =
+           ar9003_hw_eeprom_get_tgt_pwr(ah, LEGACY_TARGET_RATE_54, freq,
+                                        is2GHz);
+       targetPowerValT2[ALL_TARGET_LEGACY_1L_5L] =
+           ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_1L_5L,
+                                            freq);
+       targetPowerValT2[ALL_TARGET_LEGACY_5S] =
+           ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_5S, freq);
+       targetPowerValT2[ALL_TARGET_LEGACY_11L] =
+           ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11L, freq);
+       targetPowerValT2[ALL_TARGET_LEGACY_11S] =
+           ar9003_hw_eeprom_get_cck_tgt_pwr(ah, LEGACY_TARGET_RATE_11S, freq);
+       targetPowerValT2[ALL_TARGET_HT20_0_8_16] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_1_3_9_11_17_19] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_1_3_9_11_17_19,
+                                             freq, is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_4] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_4, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_5] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_5, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_6] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_6, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_7] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_7, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_12] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_12, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_13] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_13, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_14] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_14, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_15] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_15, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_20] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_20, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_21] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_21, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_22] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_22, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT20_23] =
+           ar9003_hw_eeprom_get_ht20_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
+                                             is2GHz);
+       targetPowerValT2[ALL_TARGET_HT40_0_8_16] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_0_8_16, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_1_3_9_11_17_19] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_1_3_9_11_17_19,
+                                             freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_4] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_4, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_5] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_5, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_6] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_6, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_7] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_7, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_12] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_12, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_13] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_13, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_14] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_14, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_15] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_15, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_20] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_20, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_21] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_21, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_22] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_22, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+       targetPowerValT2[ALL_TARGET_HT40_23] =
+           ar9003_hw_eeprom_get_ht40_tgt_pwr(ah, HT_TARGET_RATE_23, freq,
+                                             is2GHz) + ht40PowerIncForPdadc;
+
+       while (i < ar9300RateSize) {
+               ath_print(common, ATH_DBG_EEPROM,
+                         "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
+               i++;
+
+               ath_print(common, ATH_DBG_EEPROM,
+                         "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
+               i++;
+
+               ath_print(common, ATH_DBG_EEPROM,
+                         "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
+               i++;
+
+               ath_print(common, ATH_DBG_EEPROM,
+                         "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
+               i++;
+       }
+
+       /* Write target power array to registers */
+       ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
+}
+
+static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
+                                 int mode,
+                                 int ipier,
+                                 int ichain,
+                                 int *pfrequency,
+                                 int *pcorrection,
+                                 int *ptemperature, int *pvoltage)
+{
+       u8 *pCalPier;
+       struct ar9300_cal_data_per_freq_op_loop *pCalPierStruct;
+       int is2GHz;
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (ichain >= AR9300_MAX_CHAINS) {
+               ath_print(common, ATH_DBG_EEPROM,
+                         "Invalid chain index, must be less than %d\n",
+                         AR9300_MAX_CHAINS);
+               return -1;
+       }
+
+       if (mode) {             /* 5GHz */
+               if (ipier >= AR9300_NUM_5G_CAL_PIERS) {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "Invalid 5GHz cal pier index, must "
+                                 "be less than %d\n",
+                                 AR9300_NUM_5G_CAL_PIERS);
+                       return -1;
+               }
+               pCalPier = &(eep->calFreqPier5G[ipier]);
+               pCalPierStruct = &(eep->calPierData5G[ichain][ipier]);
+               is2GHz = 0;
+       } else {
+               if (ipier >= AR9300_NUM_2G_CAL_PIERS) {
+                       ath_print(common, ATH_DBG_EEPROM,
+                                 "Invalid 2GHz cal pier index, must "
+                                 "be less than %d\n", AR9300_NUM_2G_CAL_PIERS);
+                       return -1;
+               }
+
+               pCalPier = &(eep->calFreqPier2G[ipier]);
+               pCalPierStruct = &(eep->calPierData2G[ichain][ipier]);
+               is2GHz = 1;
+       }
+
+       *pfrequency = FBIN2FREQ(*pCalPier, is2GHz);
+       *pcorrection = pCalPierStruct->refPower;
+       *ptemperature = pCalPierStruct->tempMeas;
+       *pvoltage = pCalPierStruct->voltMeas;
+
+       return 0;
+}
+
+static int ar9003_hw_power_control_override(struct ath_hw *ah,
+                                           int frequency,
+                                           int *correction,
+                                           int *voltage, int *temperature)
+{
+       int tempSlope = 0;
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+       REG_RMW(ah, AR_PHY_TPC_11_B0,
+               (correction[0] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+               AR_PHY_TPC_OLPC_GAIN_DELTA);
+       REG_RMW(ah, AR_PHY_TPC_11_B1,
+               (correction[1] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+               AR_PHY_TPC_OLPC_GAIN_DELTA);
+       REG_RMW(ah, AR_PHY_TPC_11_B2,
+               (correction[2] << AR_PHY_TPC_OLPC_GAIN_DELTA_S),
+               AR_PHY_TPC_OLPC_GAIN_DELTA);
+
+       /* enable open loop power control on chip */
+       REG_RMW(ah, AR_PHY_TPC_6_B0,
+               (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+               AR_PHY_TPC_6_ERROR_EST_MODE);
+       REG_RMW(ah, AR_PHY_TPC_6_B1,
+               (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+               AR_PHY_TPC_6_ERROR_EST_MODE);
+       REG_RMW(ah, AR_PHY_TPC_6_B2,
+               (3 << AR_PHY_TPC_6_ERROR_EST_MODE_S),
+               AR_PHY_TPC_6_ERROR_EST_MODE);
+
+       /*
+        * enable temperature compensation
+        * Need to use register names
+        */
+       if (frequency < 4000)
+               tempSlope = eep->modalHeader2G.tempSlope;
+       else
+               tempSlope = eep->modalHeader5G.tempSlope;
+
+       REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope);
+       REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE,
+                     temperature[0]);
+
+       return 0;
+}
+
+/* Apply the recorded correction values. */
+static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
+{
+       int ichain, ipier, npier;
+       int mode;
+       int lfrequency[AR9300_MAX_CHAINS],
+           lcorrection[AR9300_MAX_CHAINS],
+           ltemperature[AR9300_MAX_CHAINS], lvoltage[AR9300_MAX_CHAINS];
+       int hfrequency[AR9300_MAX_CHAINS],
+           hcorrection[AR9300_MAX_CHAINS],
+           htemperature[AR9300_MAX_CHAINS], hvoltage[AR9300_MAX_CHAINS];
+       int fdiff;
+       int correction[AR9300_MAX_CHAINS],
+           voltage[AR9300_MAX_CHAINS], temperature[AR9300_MAX_CHAINS];
+       int pfrequency, pcorrection, ptemperature, pvoltage;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       mode = (frequency >= 4000);
+       if (mode)
+               npier = AR9300_NUM_5G_CAL_PIERS;
+       else
+               npier = AR9300_NUM_2G_CAL_PIERS;
+
+       for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
+               lfrequency[ichain] = 0;
+               hfrequency[ichain] = 100000;
+       }
+       /* identify best lower and higher frequency calibration measurement */
+       for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
+               for (ipier = 0; ipier < npier; ipier++) {
+                       if (!ar9003_hw_cal_pier_get(ah, mode, ipier, ichain,
+                                                   &pfrequency, &pcorrection,
+                                                   &ptemperature, &pvoltage)) {
+                               fdiff = frequency - pfrequency;
+
+                               /*
+                                * this measurement is higher than
+                                * our desired frequency
+                                */
+                               if (fdiff <= 0) {
+                                       if (hfrequency[ichain] <= 0 ||
+                                           hfrequency[ichain] >= 100000 ||
+                                           fdiff >
+                                           (frequency - hfrequency[ichain])) {
+                                               /*
+                                                * new best higher
+                                                * frequency measurement
+                                                */
+                                               hfrequency[ichain] = pfrequency;
+                                               hcorrection[ichain] =
+                                                   pcorrection;
+                                               htemperature[ichain] =
+                                                   ptemperature;
+                                               hvoltage[ichain] = pvoltage;
+                                       }
+                               }
+                               if (fdiff >= 0) {
+                                       if (lfrequency[ichain] <= 0
+                                           || fdiff <
+                                           (frequency - lfrequency[ichain])) {
+                                               /*
+                                                * new best lower
+                                                * frequency measurement
+                                                */
+                                               lfrequency[ichain] = pfrequency;
+                                               lcorrection[ichain] =
+                                                   pcorrection;
+                                               ltemperature[ichain] =
+                                                   ptemperature;
+                                               lvoltage[ichain] = pvoltage;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* interpolate  */
+       for (ichain = 0; ichain < AR9300_MAX_CHAINS; ichain++) {
+               ath_print(common, ATH_DBG_EEPROM,
+                         "ch=%d f=%d low=%d %d h=%d %d\n",
+                         ichain, frequency, lfrequency[ichain],
+                         lcorrection[ichain], hfrequency[ichain],
+                         hcorrection[ichain]);
+               /* they're the same, so just pick one */
+               if (hfrequency[ichain] == lfrequency[ichain]) {
+                       correction[ichain] = lcorrection[ichain];
+                       voltage[ichain] = lvoltage[ichain];
+                       temperature[ichain] = ltemperature[ichain];
+               }
+               /* the low frequency is good */
+               else if (frequency - lfrequency[ichain] < 1000) {
+                       /* so is the high frequency, interpolate */
+                       if (hfrequency[ichain] - frequency < 1000) {
+
+                               correction[ichain] = lcorrection[ichain] +
+                                   (((frequency - lfrequency[ichain]) *
+                                     (hcorrection[ichain] -
+                                      lcorrection[ichain])) /
+                                    (hfrequency[ichain] - lfrequency[ichain]));
+
+                               temperature[ichain] = ltemperature[ichain] +
+                                   (((frequency - lfrequency[ichain]) *
+                                     (htemperature[ichain] -
+                                      ltemperature[ichain])) /
+                                    (hfrequency[ichain] - lfrequency[ichain]));
+
+                               voltage[ichain] =
+                                   lvoltage[ichain] +
+                                   (((frequency -
+                                      lfrequency[ichain]) * (hvoltage[ichain] -
+                                                             lvoltage[ichain]))
+                                    / (hfrequency[ichain] -
+                                       lfrequency[ichain]));
+                       }
+                       /* only low is good, use it */
+                       else {
+                               correction[ichain] = lcorrection[ichain];
+                               temperature[ichain] = ltemperature[ichain];
+                               voltage[ichain] = lvoltage[ichain];
+                       }
+               }
+               /* only high is good, use it */
+               else if (hfrequency[ichain] - frequency < 1000) {
+                       correction[ichain] = hcorrection[ichain];
+                       temperature[ichain] = htemperature[ichain];
+                       voltage[ichain] = hvoltage[ichain];
+               } else {        /* nothing is good, presume 0???? */
+                       correction[ichain] = 0;
+                       temperature[ichain] = 0;
+                       voltage[ichain] = 0;
+               }
+       }
+
+       ar9003_hw_power_control_override(ah, frequency, correction, voltage,
+                                        temperature);
+
+       ath_print(common, ATH_DBG_EEPROM,
+                 "for frequency=%d, calibration correction = %d %d %d\n",
+                 frequency, correction[0], correction[1], correction[2]);
+
+       return 0;
+}
+
+static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
+                                       struct ath9k_channel *chan, u16 cfgCtl,
+                                       u8 twiceAntennaReduction,
+                                       u8 twiceMaxRegulatoryPower,
+                                       u8 powerLimit)
+{
+       ah->txpower_limit = powerLimit;
+       ar9003_hw_set_target_power_eeprom(ah, chan->channel);
+       ar9003_hw_calibration_apply(ah, chan->channel);
+}
+
+static u16 ath9k_hw_ar9300_get_spur_channel(struct ath_hw *ah,
+                                           u16 i, bool is2GHz)
+{
+       return AR_NO_SPUR;
+}
+
+s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+       return (eep->baseEepHeader.txrxgain >> 4) & 0xf; /* bits 7:4 */
+}
+
+s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+       return (eep->baseEepHeader.txrxgain) & 0xf; /* bits 3:0 */
+}
+
+const struct eeprom_ops eep_ar9300_ops = {
+       .check_eeprom = ath9k_hw_ar9300_check_eeprom,
+       .get_eeprom = ath9k_hw_ar9300_get_eeprom,
+       .fill_eeprom = ath9k_hw_ar9300_fill_eeprom,
+       .get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver,
+       .get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev,
+       .get_num_ant_config = ath9k_hw_ar9300_get_num_ant_config,
+       .get_eeprom_antenna_cfg = ath9k_hw_ar9300_get_eeprom_antenna_cfg,
+       .set_board_values = ath9k_hw_ar9300_set_board_values,
+       .set_addac = ath9k_hw_ar9300_set_addac,
+       .set_txpower = ath9k_hw_ar9300_set_txpower,
+       .get_spur_channel = ath9k_hw_ar9300_get_spur_channel
+};
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
new file mode 100644 (file)
index 0000000..23fb353
--- /dev/null
@@ -0,0 +1,323 @@
+#ifndef AR9003_EEPROM_H
+#define AR9003_EEPROM_H
+
+#include <linux/types.h>
+
+#define AR9300_EEP_VER               0xD000
+#define AR9300_EEP_VER_MINOR_MASK    0xFFF
+#define AR9300_EEP_MINOR_VER_1       0x1
+#define AR9300_EEP_MINOR_VER         AR9300_EEP_MINOR_VER_1
+
+/* 16-bit offset location start of calibration struct */
+#define AR9300_EEP_START_LOC         256
+#define AR9300_NUM_5G_CAL_PIERS      8
+#define AR9300_NUM_2G_CAL_PIERS      3
+#define AR9300_NUM_5G_20_TARGET_POWERS  8
+#define AR9300_NUM_5G_40_TARGET_POWERS  8
+#define AR9300_NUM_2G_CCK_TARGET_POWERS 2
+#define AR9300_NUM_2G_20_TARGET_POWERS  3
+#define AR9300_NUM_2G_40_TARGET_POWERS  3
+/* #define AR9300_NUM_CTLS              21 */
+#define AR9300_NUM_CTLS_5G           9
+#define AR9300_NUM_CTLS_2G           12
+#define AR9300_CTL_MODE_M            0xF
+#define AR9300_NUM_BAND_EDGES_5G     8
+#define AR9300_NUM_BAND_EDGES_2G     4
+#define AR9300_NUM_PD_GAINS          4
+#define AR9300_PD_GAINS_IN_MASK      4
+#define AR9300_PD_GAIN_ICEPTS        5
+#define AR9300_EEPROM_MODAL_SPURS    5
+#define AR9300_MAX_RATE_POWER        63
+#define AR9300_NUM_PDADC_VALUES      128
+#define AR9300_NUM_RATES             16
+#define AR9300_BCHAN_UNUSED          0xFF
+#define AR9300_MAX_PWR_RANGE_IN_HALF_DB 64
+#define AR9300_OPFLAGS_11A           0x01
+#define AR9300_OPFLAGS_11G           0x02
+#define AR9300_OPFLAGS_5G_HT40       0x04
+#define AR9300_OPFLAGS_2G_HT40       0x08
+#define AR9300_OPFLAGS_5G_HT20       0x10
+#define AR9300_OPFLAGS_2G_HT20       0x20
+#define AR9300_EEPMISC_BIG_ENDIAN    0x01
+#define AR9300_EEPMISC_WOW           0x02
+#define AR9300_CUSTOMER_DATA_SIZE    20
+
+#define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
+#define FBIN2FREQ(x, y) ((y) ? (2300 + x) : (4800 + 5 * x))
+#define AR9300_MAX_CHAINS            3
+#define AR9300_ANT_16S               25
+#define AR9300_FUTURE_MODAL_SZ       6
+
+#define AR9300_NUM_ANT_CHAIN_FIELDS     7
+#define AR9300_NUM_ANT_COMMON_FIELDS    4
+#define AR9300_SIZE_ANT_CHAIN_FIELD     3
+#define AR9300_SIZE_ANT_COMMON_FIELD    4
+#define AR9300_ANT_CHAIN_MASK           0x7
+#define AR9300_ANT_COMMON_MASK          0xf
+#define AR9300_CHAIN_0_IDX              0
+#define AR9300_CHAIN_1_IDX              1
+#define AR9300_CHAIN_2_IDX              2
+
+#define AR928X_NUM_ANT_CHAIN_FIELDS     6
+#define AR928X_SIZE_ANT_CHAIN_FIELD     2
+#define AR928X_ANT_CHAIN_MASK           0x3
+
+/* Delta from which to start power to pdadc table */
+/* This offset is used in both open loop and closed loop power control
+ * schemes. In open loop power control, it is not really needed, but for
+ * the "sake of consistency" it was kept. For certain AP designs, this
+ * value is overwritten by the value in the flag "pwrTableOffset" just
+ * before writing the pdadc vs pwr into the chip registers.
+ */
+#define AR9300_PWR_TABLE_OFFSET  0
+
+/* enable flags for voltage and temp compensation */
+#define ENABLE_TEMP_COMPENSATION 0x01
+#define ENABLE_VOLT_COMPENSATION 0x02
+/* byte addressable */
+#define AR9300_EEPROM_SIZE (16*1024)
+#define FIXED_CCA_THRESHOLD 15
+
+#define AR9300_BASE_ADDR 0x3ff
+
+enum targetPowerHTRates {
+       HT_TARGET_RATE_0_8_16,
+       HT_TARGET_RATE_1_3_9_11_17_19,
+       HT_TARGET_RATE_4,
+       HT_TARGET_RATE_5,
+       HT_TARGET_RATE_6,
+       HT_TARGET_RATE_7,
+       HT_TARGET_RATE_12,
+       HT_TARGET_RATE_13,
+       HT_TARGET_RATE_14,
+       HT_TARGET_RATE_15,
+       HT_TARGET_RATE_20,
+       HT_TARGET_RATE_21,
+       HT_TARGET_RATE_22,
+       HT_TARGET_RATE_23
+};
+
+enum targetPowerLegacyRates {
+       LEGACY_TARGET_RATE_6_24,
+       LEGACY_TARGET_RATE_36,
+       LEGACY_TARGET_RATE_48,
+       LEGACY_TARGET_RATE_54
+};
+
+enum targetPowerCckRates {
+       LEGACY_TARGET_RATE_1L_5L,
+       LEGACY_TARGET_RATE_5S,
+       LEGACY_TARGET_RATE_11L,
+       LEGACY_TARGET_RATE_11S
+};
+
+enum ar9300_Rates {
+       ALL_TARGET_LEGACY_6_24,
+       ALL_TARGET_LEGACY_36,
+       ALL_TARGET_LEGACY_48,
+       ALL_TARGET_LEGACY_54,
+       ALL_TARGET_LEGACY_1L_5L,
+       ALL_TARGET_LEGACY_5S,
+       ALL_TARGET_LEGACY_11L,
+       ALL_TARGET_LEGACY_11S,
+       ALL_TARGET_HT20_0_8_16,
+       ALL_TARGET_HT20_1_3_9_11_17_19,
+       ALL_TARGET_HT20_4,
+       ALL_TARGET_HT20_5,
+       ALL_TARGET_HT20_6,
+       ALL_TARGET_HT20_7,
+       ALL_TARGET_HT20_12,
+       ALL_TARGET_HT20_13,
+       ALL_TARGET_HT20_14,
+       ALL_TARGET_HT20_15,
+       ALL_TARGET_HT20_20,
+       ALL_TARGET_HT20_21,
+       ALL_TARGET_HT20_22,
+       ALL_TARGET_HT20_23,
+       ALL_TARGET_HT40_0_8_16,
+       ALL_TARGET_HT40_1_3_9_11_17_19,
+       ALL_TARGET_HT40_4,
+       ALL_TARGET_HT40_5,
+       ALL_TARGET_HT40_6,
+       ALL_TARGET_HT40_7,
+       ALL_TARGET_HT40_12,
+       ALL_TARGET_HT40_13,
+       ALL_TARGET_HT40_14,
+       ALL_TARGET_HT40_15,
+       ALL_TARGET_HT40_20,
+       ALL_TARGET_HT40_21,
+       ALL_TARGET_HT40_22,
+       ALL_TARGET_HT40_23,
+       ar9300RateSize,
+};
+
+
+struct eepFlags {
+       u8 opFlags;
+       u8 eepMisc;
+} __packed;
+
+enum CompressAlgorithm {
+       _CompressNone = 0,
+       _CompressLzma,
+       _CompressPairs,
+       _CompressBlock,
+       _Compress4,
+       _Compress5,
+       _Compress6,
+       _Compress7,
+};
+
+struct ar9300_base_eep_hdr {
+       __le16 regDmn[2];
+       /* 4 bits tx and 4 bits rx */
+       u8 txrxMask;
+       struct eepFlags opCapFlags;
+       u8 rfSilent;
+       u8 blueToothOptions;
+       u8 deviceCap;
+       /* takes lower byte in eeprom location */
+       u8 deviceType;
+       /* offset in dB to be added to beginning
+        * of pdadc table in calibration
+        */
+       int8_t pwrTableOffset;
+       u8 params_for_tuning_caps[2];
+       /*
+        * bit0 - enable tx temp comp
+        * bit1 - enable tx volt comp
+        * bit2 - enable fastClock - default to 1
+        * bit3 - enable doubling - default to 1
+        * bit4 - enable internal regulator - default to 1
+        */
+       u8 featureEnable;
+       /* misc flags: bit0 - turn down drivestrength */
+       u8 miscConfiguration;
+       u8 eepromWriteEnableGpio;
+       u8 wlanDisableGpio;
+       u8 wlanLedGpio;
+       u8 rxBandSelectGpio;
+       u8 txrxgain;
+       /* SW controlled internal regulator fields */
+       __le32 swreg;
+} __packed;
+
+struct ar9300_modal_eep_header {
+       /* 4 idle, t1, t2, b (4 bits per setting) */
+       __le32 antCtrlCommon;
+       /* 4 ra1l1, ra2l1, ra1l2, ra2l2, ra12 */
+       __le32 antCtrlCommon2;
+       /* 6 idle, t, r, rx1, rx12, b (2 bits each) */
+       __le16 antCtrlChain[AR9300_MAX_CHAINS];
+       /* 3 xatten1_db for AR9280 (0xa20c/b20c 5:0) */
+       u8 xatten1DB[AR9300_MAX_CHAINS];
+       /* 3  xatten1_margin for merlin (0xa20c/b20c 16:12 */
+       u8 xatten1Margin[AR9300_MAX_CHAINS];
+       int8_t tempSlope;
+       int8_t voltSlope;
+       /* spur channels in usual fbin coding format */
+       u8 spurChans[AR9300_EEPROM_MODAL_SPURS];
+       /* 3  Check if the register is per chain */
+       int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS];
+       u8 ob[AR9300_MAX_CHAINS];
+       u8 db_stage2[AR9300_MAX_CHAINS];
+       u8 db_stage3[AR9300_MAX_CHAINS];
+       u8 db_stage4[AR9300_MAX_CHAINS];
+       u8 xpaBiasLvl;
+       u8 txFrameToDataStart;
+       u8 txFrameToPaOn;
+       u8 txClip;
+       int8_t antennaGain;
+       u8 switchSettling;
+       int8_t adcDesiredSize;
+       u8 txEndToXpaOff;
+       u8 txEndToRxOn;
+       u8 txFrameToXpaOn;
+       u8 thresh62;
+       u8 futureModal[32];
+} __packed;
+
+struct ar9300_cal_data_per_freq_op_loop {
+       int8_t refPower;
+       /* pdadc voltage at power measurement */
+       u8 voltMeas;
+       /* pcdac used for power measurement   */
+       u8 tempMeas;
+       /* range is -60 to -127 create a mapping equation 1db resolution */
+       int8_t rxNoisefloorCal;
+       /*range is same as noisefloor */
+       int8_t rxNoisefloorPower;
+       /* temp measured when noisefloor cal was performed */
+       u8 rxTempMeas;
+} __packed;
+
+struct cal_tgt_pow_legacy {
+       u8 tPow2x[4];
+} __packed;
+
+struct cal_tgt_pow_ht {
+       u8 tPow2x[14];
+} __packed;
+
+struct cal_ctl_edge_pwr {
+       u8 tPower:6,
+          flag:2;
+} __packed;
+
+struct cal_ctl_data_2g {
+       struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G];
+} __packed;
+
+struct cal_ctl_data_5g {
+       struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+} __packed;
+
+struct ar9300_eeprom {
+       u8 eepromVersion;
+       u8 templateVersion;
+       u8 macAddr[6];
+       u8 custData[AR9300_CUSTOMER_DATA_SIZE];
+
+       struct ar9300_base_eep_hdr baseEepHeader;
+
+       struct ar9300_modal_eep_header modalHeader2G;
+       u8 calFreqPier2G[AR9300_NUM_2G_CAL_PIERS];
+       struct ar9300_cal_data_per_freq_op_loop
+        calPierData2G[AR9300_MAX_CHAINS][AR9300_NUM_2G_CAL_PIERS];
+       u8 calTarget_freqbin_Cck[AR9300_NUM_2G_CCK_TARGET_POWERS];
+       u8 calTarget_freqbin_2G[AR9300_NUM_2G_20_TARGET_POWERS];
+       u8 calTarget_freqbin_2GHT20[AR9300_NUM_2G_20_TARGET_POWERS];
+       u8 calTarget_freqbin_2GHT40[AR9300_NUM_2G_40_TARGET_POWERS];
+       struct cal_tgt_pow_legacy
+        calTargetPowerCck[AR9300_NUM_2G_CCK_TARGET_POWERS];
+       struct cal_tgt_pow_legacy
+        calTargetPower2G[AR9300_NUM_2G_20_TARGET_POWERS];
+       struct cal_tgt_pow_ht
+        calTargetPower2GHT20[AR9300_NUM_2G_20_TARGET_POWERS];
+       struct cal_tgt_pow_ht
+        calTargetPower2GHT40[AR9300_NUM_2G_40_TARGET_POWERS];
+       u8 ctlIndex_2G[AR9300_NUM_CTLS_2G];
+       u8 ctl_freqbin_2G[AR9300_NUM_CTLS_2G][AR9300_NUM_BAND_EDGES_2G];
+       struct cal_ctl_data_2g ctlPowerData_2G[AR9300_NUM_CTLS_2G];
+       struct ar9300_modal_eep_header modalHeader5G;
+       u8 calFreqPier5G[AR9300_NUM_5G_CAL_PIERS];
+       struct ar9300_cal_data_per_freq_op_loop
+        calPierData5G[AR9300_MAX_CHAINS][AR9300_NUM_5G_CAL_PIERS];
+       u8 calTarget_freqbin_5G[AR9300_NUM_5G_20_TARGET_POWERS];
+       u8 calTarget_freqbin_5GHT20[AR9300_NUM_5G_20_TARGET_POWERS];
+       u8 calTarget_freqbin_5GHT40[AR9300_NUM_5G_40_TARGET_POWERS];
+       struct cal_tgt_pow_legacy
+        calTargetPower5G[AR9300_NUM_5G_20_TARGET_POWERS];
+       struct cal_tgt_pow_ht
+        calTargetPower5GHT20[AR9300_NUM_5G_20_TARGET_POWERS];
+       struct cal_tgt_pow_ht
+        calTargetPower5GHT40[AR9300_NUM_5G_40_TARGET_POWERS];
+       u8 ctlIndex_5G[AR9300_NUM_CTLS_5G];
+       u8 ctl_freqbin_5G[AR9300_NUM_CTLS_5G][AR9300_NUM_BAND_EDGES_5G];
+       struct cal_ctl_data_5g ctlPowerData_5G[AR9300_NUM_CTLS_5G];
+} __packed;
+
+s32 ar9003_hw_get_tx_gain_idx(struct ath_hw *ah);
+s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah);
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
new file mode 100644 (file)
index 0000000..b15309c
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2008-2010 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 "hw.h"
+#include "ar9003_mac.h"
+#include "ar9003_initvals.h"
+
+/* General hardware code for the AR9003 hadware family */
+
+static bool ar9003_hw_macversion_supported(u32 macversion)
+{
+       switch (macversion) {
+       case AR_SREV_VERSION_9300:
+               return true;
+       default:
+               break;
+       }
+       return false;
+}
+
+/* AR9003 2.0 - new INI format (pre, core, post arrays per subsystem) */
+/*
+ * XXX: move TX/RX gain INI to its own init_mode_gain_regs after
+ * ensuring it does not affect hardware bring up
+ */
+static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+{
+       /* mac */
+       INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+       INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+                      ar9300_2p0_mac_core,
+                      ARRAY_SIZE(ar9300_2p0_mac_core), 2);
+       INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+                      ar9300_2p0_mac_postamble,
+                      ARRAY_SIZE(ar9300_2p0_mac_postamble), 5);
+
+       /* bb */
+       INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+       INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+                      ar9300_2p0_baseband_core,
+                      ARRAY_SIZE(ar9300_2p0_baseband_core), 2);
+       INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+                      ar9300_2p0_baseband_postamble,
+                      ARRAY_SIZE(ar9300_2p0_baseband_postamble), 5);
+
+       /* radio */
+       INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+       INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+                      ar9300_2p0_radio_core,
+                      ARRAY_SIZE(ar9300_2p0_radio_core), 2);
+       INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+                      ar9300_2p0_radio_postamble,
+                      ARRAY_SIZE(ar9300_2p0_radio_postamble), 5);
+
+       /* soc */
+       INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+                      ar9300_2p0_soc_preamble,
+                      ARRAY_SIZE(ar9300_2p0_soc_preamble), 2);
+       INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+       INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+                      ar9300_2p0_soc_postamble,
+                      ARRAY_SIZE(ar9300_2p0_soc_postamble), 5);
+
+       /* rx/tx gain */
+       INIT_INI_ARRAY(&ah->iniModesRxGain,
+                      ar9300Common_rx_gain_table_2p0,
+                      ARRAY_SIZE(ar9300Common_rx_gain_table_2p0), 2);
+       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                      ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
+                      ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
+                      5);
+
+       /* Load PCIE SERDES settings from INI */
+
+       /* Awake Setting */
+
+       INIT_INI_ARRAY(&ah->iniPcieSerdes,
+                      ar9300PciePhy_pll_on_clkreq_disable_L1_2p0,
+                      ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p0),
+                      2);
+
+       /* Sleep Setting */
+
+       INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+                      ar9300PciePhy_clkreq_enable_L1_2p0,
+                      ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p0),
+                      2);
+
+       /* Fast clock modal settings */
+       INIT_INI_ARRAY(&ah->iniModesAdditional,
+                      ar9300Modes_fast_clock_2p0,
+                      ARRAY_SIZE(ar9300Modes_fast_clock_2p0),
+                      3);
+}
+
+static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
+{
+       switch (ar9003_hw_get_tx_gain_idx(ah)) {
+       case 0:
+       default:
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
+                              ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
+                              5);
+               break;
+       case 1:
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9300Modes_high_ob_db_tx_gain_table_2p0,
+                              ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
+                              5);
+               break;
+       case 2:
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              ar9300Modes_low_ob_db_tx_gain_table_2p0,
+                              ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
+                              5);
+               break;
+       }
+}
+
+static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
+{
+       switch (ar9003_hw_get_rx_gain_idx(ah)) {
+       case 0:
+       default:
+               INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p0,
+                              ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
+                              2);
+               break;
+       case 1:
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              ar9300Common_wo_xlna_rx_gain_table_2p0,
+                              ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
+                              2);
+               break;
+       }
+}
+
+/* set gain table pointers according to values read from the eeprom */
+static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+       ar9003_tx_gain_table_apply(ah);
+       ar9003_rx_gain_table_apply(ah);
+}
+
+/*
+ * Helper for ASPM support.
+ *
+ * Disable PLL when in L0s as well as receiver clock when in L1.
+ * This power saving option must be enabled through the SerDes.
+ *
+ * Programming the SerDes must go through the same 288 bit serial shift
+ * register as the other analog registers.  Hence the 9 writes.
+ */
+static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
+                                        int restore,
+                                        int power_off)
+{
+       if (ah->is_pciexpress != true)
+               return;
+
+       /* Do not touch SerDes registers */
+       if (ah->config.pcie_powersave_enable == 2)
+               return;
+
+       /* Nothing to do on restore for 11N */
+       if (!restore) {
+               /* set bit 19 to allow forcing of pcie core into L1 state */
+               REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+
+               /* Several PCIe massages to ensure proper behaviour */
+               if (ah->config.pcie_waen)
+                       REG_WRITE(ah, AR_WA, ah->config.pcie_waen);
+       }
+}
+
+/* Sets up the AR9003 hardware familiy callbacks */
+void ar9003_hw_attach_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+       priv_ops->init_mode_regs = ar9003_hw_init_mode_regs;
+       priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
+       priv_ops->macversion_supported = ar9003_hw_macversion_supported;
+
+       ops->config_pci_powersave = ar9003_hw_configpcipowersave;
+
+       ar9003_hw_attach_phy_ops(ah);
+       ar9003_hw_attach_calib_ops(ah);
+       ar9003_hw_attach_mac_ops(ah);
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_initvals.h
new file mode 100644 (file)
index 0000000..db019dd
--- /dev/null
@@ -0,0 +1,1784 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef INITVALS_9003_H
+#define INITVALS_9003_H
+
+/* AR9003 2.0 */
+
+static const u32 ar9300_2p0_radio_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
+       {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
+       {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
+       {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p0[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+       {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+       {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+       {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+       {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+       {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+       {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+       {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+       {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+       {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+       {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+       {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+       {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+       {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+       {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+       {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+       {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+       {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+       {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+       {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+       {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+       {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+       {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+       {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+       {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+       {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+       {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+       {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+       {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+       {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+       {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+       {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+       {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+       {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_fast_clock_2p0[][3] = {
+       /* Addr      5G_HT20     5G_HT40   */
+       {0x00001030, 0x00000268, 0x000004d0},
+       {0x00001070, 0x0000018c, 0x00000318},
+       {0x000010b0, 0x00000fd0, 0x00001fa0},
+       {0x00008014, 0x044c044c, 0x08980898},
+       {0x0000801c, 0x148ec02b, 0x148ec057},
+       {0x00008318, 0x000044c0, 0x00008980},
+       {0x00009e00, 0x03721821, 0x03721821},
+       {0x0000a230, 0x0000000b, 0x00000016},
+       {0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9300_2p0_radio_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00016000, 0x36db6db6},
+       {0x00016004, 0x6db6db40},
+       {0x00016008, 0x73f00000},
+       {0x0001600c, 0x00000000},
+       {0x00016040, 0x7f80fff8},
+       {0x0001604c, 0x76d005b5},
+       {0x00016050, 0x556cf031},
+       {0x00016054, 0x13449440},
+       {0x00016058, 0x0c51c92c},
+       {0x0001605c, 0x3db7fffc},
+       {0x00016060, 0xfffffffc},
+       {0x00016064, 0x000f0278},
+       {0x0001606c, 0x6db60000},
+       {0x00016080, 0x00000000},
+       {0x00016084, 0x0e48048c},
+       {0x00016088, 0x54214514},
+       {0x0001608c, 0x119f481e},
+       {0x00016090, 0x24926490},
+       {0x00016098, 0xd2888888},
+       {0x000160a0, 0x0a108ffe},
+       {0x000160a4, 0x812fc370},
+       {0x000160a8, 0x423c8000},
+       {0x000160b4, 0x92480080},
+       {0x000160c0, 0x00adb6d0},
+       {0x000160c4, 0x6db6db60},
+       {0x000160c8, 0x6db6db6c},
+       {0x000160cc, 0x01e6c000},
+       {0x00016100, 0x3fffbe01},
+       {0x00016104, 0xfff80000},
+       {0x00016108, 0x00080010},
+       {0x00016144, 0x02084080},
+       {0x00016148, 0x00000000},
+       {0x00016280, 0x058a0001},
+       {0x00016284, 0x3d840208},
+       {0x00016288, 0x05a20408},
+       {0x0001628c, 0x00038c07},
+       {0x00016290, 0x40000004},
+       {0x00016294, 0x458aa14f},
+       {0x00016380, 0x00000000},
+       {0x00016384, 0x00000000},
+       {0x00016388, 0x00800700},
+       {0x0001638c, 0x00800700},
+       {0x00016390, 0x00800700},
+       {0x00016394, 0x00000000},
+       {0x00016398, 0x00000000},
+       {0x0001639c, 0x00000000},
+       {0x000163a0, 0x00000001},
+       {0x000163a4, 0x00000001},
+       {0x000163a8, 0x00000000},
+       {0x000163ac, 0x00000000},
+       {0x000163b0, 0x00000000},
+       {0x000163b4, 0x00000000},
+       {0x000163b8, 0x00000000},
+       {0x000163bc, 0x00000000},
+       {0x000163c0, 0x000000a0},
+       {0x000163c4, 0x000c0000},
+       {0x000163c8, 0x14021402},
+       {0x000163cc, 0x00001402},
+       {0x000163d0, 0x00000000},
+       {0x000163d4, 0x00000000},
+       {0x00016400, 0x36db6db6},
+       {0x00016404, 0x6db6db40},
+       {0x00016408, 0x73f00000},
+       {0x0001640c, 0x00000000},
+       {0x00016440, 0x7f80fff8},
+       {0x0001644c, 0x76d005b5},
+       {0x00016450, 0x556cf031},
+       {0x00016454, 0x13449440},
+       {0x00016458, 0x0c51c92c},
+       {0x0001645c, 0x3db7fffc},
+       {0x00016460, 0xfffffffc},
+       {0x00016464, 0x000f0278},
+       {0x0001646c, 0x6db60000},
+       {0x00016500, 0x3fffbe01},
+       {0x00016504, 0xfff80000},
+       {0x00016508, 0x00080010},
+       {0x00016544, 0x02084080},
+       {0x00016548, 0x00000000},
+       {0x00016780, 0x00000000},
+       {0x00016784, 0x00000000},
+       {0x00016788, 0x00800700},
+       {0x0001678c, 0x00800700},
+       {0x00016790, 0x00800700},
+       {0x00016794, 0x00000000},
+       {0x00016798, 0x00000000},
+       {0x0001679c, 0x00000000},
+       {0x000167a0, 0x00000001},
+       {0x000167a4, 0x00000001},
+       {0x000167a8, 0x00000000},
+       {0x000167ac, 0x00000000},
+       {0x000167b0, 0x00000000},
+       {0x000167b4, 0x00000000},
+       {0x000167b8, 0x00000000},
+       {0x000167bc, 0x00000000},
+       {0x000167c0, 0x000000a0},
+       {0x000167c4, 0x000c0000},
+       {0x000167c8, 0x14021402},
+       {0x000167cc, 0x00001402},
+       {0x000167d0, 0x00000000},
+       {0x000167d4, 0x00000000},
+       {0x00016800, 0x36db6db6},
+       {0x00016804, 0x6db6db40},
+       {0x00016808, 0x73f00000},
+       {0x0001680c, 0x00000000},
+       {0x00016840, 0x7f80fff8},
+       {0x0001684c, 0x76d005b5},
+       {0x00016850, 0x556cf031},
+       {0x00016854, 0x13449440},
+       {0x00016858, 0x0c51c92c},
+       {0x0001685c, 0x3db7fffc},
+       {0x00016860, 0xfffffffc},
+       {0x00016864, 0x000f0278},
+       {0x0001686c, 0x6db60000},
+       {0x00016900, 0x3fffbe01},
+       {0x00016904, 0xfff80000},
+       {0x00016908, 0x00080010},
+       {0x00016944, 0x02084080},
+       {0x00016948, 0x00000000},
+       {0x00016b80, 0x00000000},
+       {0x00016b84, 0x00000000},
+       {0x00016b88, 0x00800700},
+       {0x00016b8c, 0x00800700},
+       {0x00016b90, 0x00800700},
+       {0x00016b94, 0x00000000},
+       {0x00016b98, 0x00000000},
+       {0x00016b9c, 0x00000000},
+       {0x00016ba0, 0x00000001},
+       {0x00016ba4, 0x00000001},
+       {0x00016ba8, 0x00000000},
+       {0x00016bac, 0x00000000},
+       {0x00016bb0, 0x00000000},
+       {0x00016bb4, 0x00000000},
+       {0x00016bb8, 0x00000000},
+       {0x00016bbc, 0x00000000},
+       {0x00016bc0, 0x000000a0},
+       {0x00016bc4, 0x000c0000},
+       {0x00016bc8, 0x14021402},
+       {0x00016bcc, 0x00001402},
+       {0x00016bd0, 0x00000000},
+       {0x00016bd4, 0x00000000},
+};
+
+static const u32 ar9300Common_rx_gain_table_merlin_2p0[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a000, 0x02000101},
+       {0x0000a004, 0x02000102},
+       {0x0000a008, 0x02000103},
+       {0x0000a00c, 0x02000104},
+       {0x0000a010, 0x02000200},
+       {0x0000a014, 0x02000201},
+       {0x0000a018, 0x02000202},
+       {0x0000a01c, 0x02000203},
+       {0x0000a020, 0x02000204},
+       {0x0000a024, 0x02000205},
+       {0x0000a028, 0x02000208},
+       {0x0000a02c, 0x02000302},
+       {0x0000a030, 0x02000303},
+       {0x0000a034, 0x02000304},
+       {0x0000a038, 0x02000400},
+       {0x0000a03c, 0x02010300},
+       {0x0000a040, 0x02010301},
+       {0x0000a044, 0x02010302},
+       {0x0000a048, 0x02000500},
+       {0x0000a04c, 0x02010400},
+       {0x0000a050, 0x02020300},
+       {0x0000a054, 0x02020301},
+       {0x0000a058, 0x02020302},
+       {0x0000a05c, 0x02020303},
+       {0x0000a060, 0x02020400},
+       {0x0000a064, 0x02030300},
+       {0x0000a068, 0x02030301},
+       {0x0000a06c, 0x02030302},
+       {0x0000a070, 0x02030303},
+       {0x0000a074, 0x02030400},
+       {0x0000a078, 0x02040300},
+       {0x0000a07c, 0x02040301},
+       {0x0000a080, 0x02040302},
+       {0x0000a084, 0x02040303},
+       {0x0000a088, 0x02030500},
+       {0x0000a08c, 0x02040400},
+       {0x0000a090, 0x02050203},
+       {0x0000a094, 0x02050204},
+       {0x0000a098, 0x02050205},
+       {0x0000a09c, 0x02040500},
+       {0x0000a0a0, 0x02050301},
+       {0x0000a0a4, 0x02050302},
+       {0x0000a0a8, 0x02050303},
+       {0x0000a0ac, 0x02050400},
+       {0x0000a0b0, 0x02050401},
+       {0x0000a0b4, 0x02050402},
+       {0x0000a0b8, 0x02050403},
+       {0x0000a0bc, 0x02050500},
+       {0x0000a0c0, 0x02050501},
+       {0x0000a0c4, 0x02050502},
+       {0x0000a0c8, 0x02050503},
+       {0x0000a0cc, 0x02050504},
+       {0x0000a0d0, 0x02050600},
+       {0x0000a0d4, 0x02050601},
+       {0x0000a0d8, 0x02050602},
+       {0x0000a0dc, 0x02050603},
+       {0x0000a0e0, 0x02050604},
+       {0x0000a0e4, 0x02050700},
+       {0x0000a0e8, 0x02050701},
+       {0x0000a0ec, 0x02050702},
+       {0x0000a0f0, 0x02050703},
+       {0x0000a0f4, 0x02050704},
+       {0x0000a0f8, 0x02050705},
+       {0x0000a0fc, 0x02050708},
+       {0x0000a100, 0x02050709},
+       {0x0000a104, 0x0205070a},
+       {0x0000a108, 0x0205070b},
+       {0x0000a10c, 0x0205070c},
+       {0x0000a110, 0x0205070d},
+       {0x0000a114, 0x02050710},
+       {0x0000a118, 0x02050711},
+       {0x0000a11c, 0x02050712},
+       {0x0000a120, 0x02050713},
+       {0x0000a124, 0x02050714},
+       {0x0000a128, 0x02050715},
+       {0x0000a12c, 0x02050730},
+       {0x0000a130, 0x02050731},
+       {0x0000a134, 0x02050732},
+       {0x0000a138, 0x02050733},
+       {0x0000a13c, 0x02050734},
+       {0x0000a140, 0x02050735},
+       {0x0000a144, 0x02050750},
+       {0x0000a148, 0x02050751},
+       {0x0000a14c, 0x02050752},
+       {0x0000a150, 0x02050753},
+       {0x0000a154, 0x02050754},
+       {0x0000a158, 0x02050755},
+       {0x0000a15c, 0x02050770},
+       {0x0000a160, 0x02050771},
+       {0x0000a164, 0x02050772},
+       {0x0000a168, 0x02050773},
+       {0x0000a16c, 0x02050774},
+       {0x0000a170, 0x02050775},
+       {0x0000a174, 0x00000776},
+       {0x0000a178, 0x00000776},
+       {0x0000a17c, 0x00000776},
+       {0x0000a180, 0x00000776},
+       {0x0000a184, 0x00000776},
+       {0x0000a188, 0x00000776},
+       {0x0000a18c, 0x00000776},
+       {0x0000a190, 0x00000776},
+       {0x0000a194, 0x00000776},
+       {0x0000a198, 0x00000776},
+       {0x0000a19c, 0x00000776},
+       {0x0000a1a0, 0x00000776},
+       {0x0000a1a4, 0x00000776},
+       {0x0000a1a8, 0x00000776},
+       {0x0000a1ac, 0x00000776},
+       {0x0000a1b0, 0x00000776},
+       {0x0000a1b4, 0x00000776},
+       {0x0000a1b8, 0x00000776},
+       {0x0000a1bc, 0x00000776},
+       {0x0000a1c0, 0x00000776},
+       {0x0000a1c4, 0x00000776},
+       {0x0000a1c8, 0x00000776},
+       {0x0000a1cc, 0x00000776},
+       {0x0000a1d0, 0x00000776},
+       {0x0000a1d4, 0x00000776},
+       {0x0000a1d8, 0x00000776},
+       {0x0000a1dc, 0x00000776},
+       {0x0000a1e0, 0x00000776},
+       {0x0000a1e4, 0x00000776},
+       {0x0000a1e8, 0x00000776},
+       {0x0000a1ec, 0x00000776},
+       {0x0000a1f0, 0x00000776},
+       {0x0000a1f4, 0x00000776},
+       {0x0000a1f8, 0x00000776},
+       {0x0000a1fc, 0x00000776},
+       {0x0000b000, 0x02000101},
+       {0x0000b004, 0x02000102},
+       {0x0000b008, 0x02000103},
+       {0x0000b00c, 0x02000104},
+       {0x0000b010, 0x02000200},
+       {0x0000b014, 0x02000201},
+       {0x0000b018, 0x02000202},
+       {0x0000b01c, 0x02000203},
+       {0x0000b020, 0x02000204},
+       {0x0000b024, 0x02000205},
+       {0x0000b028, 0x02000208},
+       {0x0000b02c, 0x02000302},
+       {0x0000b030, 0x02000303},
+       {0x0000b034, 0x02000304},
+       {0x0000b038, 0x02000400},
+       {0x0000b03c, 0x02010300},
+       {0x0000b040, 0x02010301},
+       {0x0000b044, 0x02010302},
+       {0x0000b048, 0x02000500},
+       {0x0000b04c, 0x02010400},
+       {0x0000b050, 0x02020300},
+       {0x0000b054, 0x02020301},
+       {0x0000b058, 0x02020302},
+       {0x0000b05c, 0x02020303},
+       {0x0000b060, 0x02020400},
+       {0x0000b064, 0x02030300},
+       {0x0000b068, 0x02030301},
+       {0x0000b06c, 0x02030302},
+       {0x0000b070, 0x02030303},
+       {0x0000b074, 0x02030400},
+       {0x0000b078, 0x02040300},
+       {0x0000b07c, 0x02040301},
+       {0x0000b080, 0x02040302},
+       {0x0000b084, 0x02040303},
+       {0x0000b088, 0x02030500},
+       {0x0000b08c, 0x02040400},
+       {0x0000b090, 0x02050203},
+       {0x0000b094, 0x02050204},
+       {0x0000b098, 0x02050205},
+       {0x0000b09c, 0x02040500},
+       {0x0000b0a0, 0x02050301},
+       {0x0000b0a4, 0x02050302},
+       {0x0000b0a8, 0x02050303},
+       {0x0000b0ac, 0x02050400},
+       {0x0000b0b0, 0x02050401},
+       {0x0000b0b4, 0x02050402},
+       {0x0000b0b8, 0x02050403},
+       {0x0000b0bc, 0x02050500},
+       {0x0000b0c0, 0x02050501},
+       {0x0000b0c4, 0x02050502},
+       {0x0000b0c8, 0x02050503},
+       {0x0000b0cc, 0x02050504},
+       {0x0000b0d0, 0x02050600},
+       {0x0000b0d4, 0x02050601},
+       {0x0000b0d8, 0x02050602},
+       {0x0000b0dc, 0x02050603},
+       {0x0000b0e0, 0x02050604},
+       {0x0000b0e4, 0x02050700},
+       {0x0000b0e8, 0x02050701},
+       {0x0000b0ec, 0x02050702},
+       {0x0000b0f0, 0x02050703},
+       {0x0000b0f4, 0x02050704},
+       {0x0000b0f8, 0x02050705},
+       {0x0000b0fc, 0x02050708},
+       {0x0000b100, 0x02050709},
+       {0x0000b104, 0x0205070a},
+       {0x0000b108, 0x0205070b},
+       {0x0000b10c, 0x0205070c},
+       {0x0000b110, 0x0205070d},
+       {0x0000b114, 0x02050710},
+       {0x0000b118, 0x02050711},
+       {0x0000b11c, 0x02050712},
+       {0x0000b120, 0x02050713},
+       {0x0000b124, 0x02050714},
+       {0x0000b128, 0x02050715},
+       {0x0000b12c, 0x02050730},
+       {0x0000b130, 0x02050731},
+       {0x0000b134, 0x02050732},
+       {0x0000b138, 0x02050733},
+       {0x0000b13c, 0x02050734},
+       {0x0000b140, 0x02050735},
+       {0x0000b144, 0x02050750},
+       {0x0000b148, 0x02050751},
+       {0x0000b14c, 0x02050752},
+       {0x0000b150, 0x02050753},
+       {0x0000b154, 0x02050754},
+       {0x0000b158, 0x02050755},
+       {0x0000b15c, 0x02050770},
+       {0x0000b160, 0x02050771},
+       {0x0000b164, 0x02050772},
+       {0x0000b168, 0x02050773},
+       {0x0000b16c, 0x02050774},
+       {0x0000b170, 0x02050775},
+       {0x0000b174, 0x00000776},
+       {0x0000b178, 0x00000776},
+       {0x0000b17c, 0x00000776},
+       {0x0000b180, 0x00000776},
+       {0x0000b184, 0x00000776},
+       {0x0000b188, 0x00000776},
+       {0x0000b18c, 0x00000776},
+       {0x0000b190, 0x00000776},
+       {0x0000b194, 0x00000776},
+       {0x0000b198, 0x00000776},
+       {0x0000b19c, 0x00000776},
+       {0x0000b1a0, 0x00000776},
+       {0x0000b1a4, 0x00000776},
+       {0x0000b1a8, 0x00000776},
+       {0x0000b1ac, 0x00000776},
+       {0x0000b1b0, 0x00000776},
+       {0x0000b1b4, 0x00000776},
+       {0x0000b1b8, 0x00000776},
+       {0x0000b1bc, 0x00000776},
+       {0x0000b1c0, 0x00000776},
+       {0x0000b1c4, 0x00000776},
+       {0x0000b1c8, 0x00000776},
+       {0x0000b1cc, 0x00000776},
+       {0x0000b1d0, 0x00000776},
+       {0x0000b1d4, 0x00000776},
+       {0x0000b1d8, 0x00000776},
+       {0x0000b1dc, 0x00000776},
+       {0x0000b1e0, 0x00000776},
+       {0x0000b1e4, 0x00000776},
+       {0x0000b1e8, 0x00000776},
+       {0x0000b1ec, 0x00000776},
+       {0x0000b1f0, 0x00000776},
+       {0x0000b1f4, 0x00000776},
+       {0x0000b1f8, 0x00000776},
+       {0x0000b1fc, 0x00000776},
+};
+
+static const u32 ar9300_2p0_mac_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9300_2p0_soc_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9200_merlin_2p0_radio_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00007800, 0x00040000},
+       {0x00007804, 0xdb005012},
+       {0x00007808, 0x04924914},
+       {0x0000780c, 0x21084210},
+       {0x00007810, 0x6d801300},
+       {0x00007814, 0x0019beff},
+       {0x00007818, 0x07e41000},
+       {0x0000781c, 0x00392000},
+       {0x00007820, 0x92592480},
+       {0x00007824, 0x00040000},
+       {0x00007828, 0xdb005012},
+       {0x0000782c, 0x04924914},
+       {0x00007830, 0x21084210},
+       {0x00007834, 0x6d801300},
+       {0x00007838, 0x0019beff},
+       {0x0000783c, 0x07e40000},
+       {0x00007840, 0x00392000},
+       {0x00007844, 0x92592480},
+       {0x00007848, 0x00100000},
+       {0x0000784c, 0x773f0567},
+       {0x00007850, 0x54214514},
+       {0x00007854, 0x12035828},
+       {0x00007858, 0x92592692},
+       {0x0000785c, 0x00000000},
+       {0x00007860, 0x56400000},
+       {0x00007864, 0x0a8e370e},
+       {0x00007868, 0xc0102850},
+       {0x0000786c, 0x812d4000},
+       {0x00007870, 0x807ec400},
+       {0x00007874, 0x001b6db0},
+       {0x00007878, 0x00376b63},
+       {0x0000787c, 0x06db6db6},
+       {0x00007880, 0x006d8000},
+       {0x00007884, 0xffeffffe},
+       {0x00007888, 0xffeffffe},
+       {0x0000788c, 0x00010000},
+       {0x00007890, 0x02060aeb},
+       {0x00007894, 0x5a108000},
+};
+
+static const u32 ar9300_2p0_baseband_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+       {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+       {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+       {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
+       {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+       {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+       {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+       {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+       {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+       {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+       {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
+       {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+       {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+       {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+       {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+       {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+       {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+       {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+       {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+       {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+       {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+       {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+       {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+       {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+       {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+       {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000be04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+       {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9300_2p0_baseband_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00009800, 0xafe68e30},
+       {0x00009804, 0xfd14e000},
+       {0x00009808, 0x9c0a9f6b},
+       {0x0000980c, 0x04900000},
+       {0x00009814, 0x9280c00a},
+       {0x00009818, 0x00000000},
+       {0x0000981c, 0x00020028},
+       {0x00009834, 0x5f3ca3de},
+       {0x00009838, 0x0108ecff},
+       {0x0000983c, 0x14750600},
+       {0x00009880, 0x201fff00},
+       {0x00009884, 0x00001042},
+       {0x000098a4, 0x00200400},
+       {0x000098b0, 0x52440bbe},
+       {0x000098d0, 0x004b6a8e},
+       {0x000098d4, 0x00000820},
+       {0x000098dc, 0x00000000},
+       {0x000098f0, 0x00000000},
+       {0x000098f4, 0x00000000},
+       {0x00009c04, 0xff55ff55},
+       {0x00009c08, 0x0320ff55},
+       {0x00009c0c, 0x00000000},
+       {0x00009c10, 0x00000000},
+       {0x00009c14, 0x00046384},
+       {0x00009c18, 0x05b6b440},
+       {0x00009c1c, 0x00b6b440},
+       {0x00009d00, 0xc080a333},
+       {0x00009d04, 0x40206c10},
+       {0x00009d08, 0x009c4060},
+       {0x00009d0c, 0x9883800a},
+       {0x00009d10, 0x01834061},
+       {0x00009d14, 0x00c0040b},
+       {0x00009d18, 0x00000000},
+       {0x00009e08, 0x0038230c},
+       {0x00009e24, 0x990bb515},
+       {0x00009e28, 0x0c6f0000},
+       {0x00009e30, 0x06336f77},
+       {0x00009e34, 0x6af6532f},
+       {0x00009e38, 0x0cc80c00},
+       {0x00009e3c, 0xcf946222},
+       {0x00009e40, 0x0d261820},
+       {0x00009e4c, 0x00001004},
+       {0x00009e50, 0x00ff03f1},
+       {0x00009e54, 0x00000000},
+       {0x00009fc0, 0x803e4788},
+       {0x00009fc4, 0x0001efb5},
+       {0x00009fcc, 0x40000014},
+       {0x00009fd0, 0x01193b93},
+       {0x0000a20c, 0x00000000},
+       {0x0000a220, 0x00000000},
+       {0x0000a224, 0x00000000},
+       {0x0000a228, 0x10002310},
+       {0x0000a22c, 0x01036a1e},
+       {0x0000a234, 0x10000fff},
+       {0x0000a23c, 0x00000000},
+       {0x0000a244, 0x0c000000},
+       {0x0000a2a0, 0x00000001},
+       {0x0000a2c0, 0x00000001},
+       {0x0000a2c8, 0x00000000},
+       {0x0000a2cc, 0x18c43433},
+       {0x0000a2d4, 0x00000000},
+       {0x0000a2dc, 0x00000000},
+       {0x0000a2e0, 0x00000000},
+       {0x0000a2e4, 0x00000000},
+       {0x0000a2e8, 0x00000000},
+       {0x0000a2ec, 0x00000000},
+       {0x0000a2f0, 0x00000000},
+       {0x0000a2f4, 0x00000000},
+       {0x0000a2f8, 0x00000000},
+       {0x0000a344, 0x00000000},
+       {0x0000a34c, 0x00000000},
+       {0x0000a350, 0x0000a000},
+       {0x0000a364, 0x00000000},
+       {0x0000a370, 0x00000000},
+       {0x0000a390, 0x00000001},
+       {0x0000a394, 0x00000444},
+       {0x0000a398, 0x001f0e0f},
+       {0x0000a39c, 0x0075393f},
+       {0x0000a3a0, 0xb79f6427},
+       {0x0000a3a4, 0x00000000},
+       {0x0000a3a8, 0xaaaaaaaa},
+       {0x0000a3ac, 0x3c466478},
+       {0x0000a3c0, 0x20202020},
+       {0x0000a3c4, 0x22222220},
+       {0x0000a3c8, 0x20200020},
+       {0x0000a3cc, 0x20202020},
+       {0x0000a3d0, 0x20202020},
+       {0x0000a3d4, 0x20202020},
+       {0x0000a3d8, 0x20202020},
+       {0x0000a3dc, 0x20202020},
+       {0x0000a3e0, 0x20202020},
+       {0x0000a3e4, 0x20202020},
+       {0x0000a3e8, 0x20202020},
+       {0x0000a3ec, 0x20202020},
+       {0x0000a3f0, 0x00000000},
+       {0x0000a3f4, 0x00000246},
+       {0x0000a3f8, 0x0cdbd380},
+       {0x0000a3fc, 0x000f0f01},
+       {0x0000a400, 0x8fa91f01},
+       {0x0000a404, 0x00000000},
+       {0x0000a408, 0x0e79e5c6},
+       {0x0000a40c, 0x00820820},
+       {0x0000a414, 0x1ce739ce},
+       {0x0000a418, 0x2d001dce},
+       {0x0000a41c, 0x1ce739ce},
+       {0x0000a420, 0x000001ce},
+       {0x0000a424, 0x1ce739ce},
+       {0x0000a428, 0x000001ce},
+       {0x0000a42c, 0x1ce739ce},
+       {0x0000a430, 0x1ce739ce},
+       {0x0000a434, 0x00000000},
+       {0x0000a438, 0x00001801},
+       {0x0000a43c, 0x00000000},
+       {0x0000a440, 0x00000000},
+       {0x0000a444, 0x00000000},
+       {0x0000a448, 0x04000080},
+       {0x0000a44c, 0x00000001},
+       {0x0000a450, 0x00010000},
+       {0x0000a458, 0x00000000},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x00000000},
+       {0x0000a610, 0x00000000},
+       {0x0000a614, 0x00000000},
+       {0x0000a618, 0x00000000},
+       {0x0000a61c, 0x00000000},
+       {0x0000a620, 0x00000000},
+       {0x0000a624, 0x00000000},
+       {0x0000a628, 0x00000000},
+       {0x0000a62c, 0x00000000},
+       {0x0000a630, 0x00000000},
+       {0x0000a634, 0x00000000},
+       {0x0000a638, 0x00000000},
+       {0x0000a63c, 0x00000000},
+       {0x0000a640, 0x00000000},
+       {0x0000a644, 0x3fad9d74},
+       {0x0000a648, 0x0048060a},
+       {0x0000a64c, 0x00000637},
+       {0x0000a670, 0x03020100},
+       {0x0000a674, 0x09080504},
+       {0x0000a678, 0x0d0c0b0a},
+       {0x0000a67c, 0x13121110},
+       {0x0000a680, 0x31301514},
+       {0x0000a684, 0x35343332},
+       {0x0000a688, 0x00000036},
+       {0x0000a690, 0x00000838},
+       {0x0000a7c0, 0x00000000},
+       {0x0000a7c4, 0xfffffffc},
+       {0x0000a7c8, 0x00000000},
+       {0x0000a7cc, 0x00000000},
+       {0x0000a7d0, 0x00000000},
+       {0x0000a7d4, 0x00000004},
+       {0x0000a7dc, 0x00000001},
+       {0x0000a8d0, 0x004b6a8e},
+       {0x0000a8d4, 0x00000820},
+       {0x0000a8dc, 0x00000000},
+       {0x0000a8f0, 0x00000000},
+       {0x0000a8f4, 0x00000000},
+       {0x0000b2d0, 0x00000080},
+       {0x0000b2d4, 0x00000000},
+       {0x0000b2dc, 0x00000000},
+       {0x0000b2e0, 0x00000000},
+       {0x0000b2e4, 0x00000000},
+       {0x0000b2e8, 0x00000000},
+       {0x0000b2ec, 0x00000000},
+       {0x0000b2f0, 0x00000000},
+       {0x0000b2f4, 0x00000000},
+       {0x0000b2f8, 0x00000000},
+       {0x0000b408, 0x0e79e5c0},
+       {0x0000b40c, 0x00820820},
+       {0x0000b420, 0x00000000},
+       {0x0000b8d0, 0x004b6a8e},
+       {0x0000b8d4, 0x00000820},
+       {0x0000b8dc, 0x00000000},
+       {0x0000b8f0, 0x00000000},
+       {0x0000b8f4, 0x00000000},
+       {0x0000c2d0, 0x00000080},
+       {0x0000c2d4, 0x00000000},
+       {0x0000c2dc, 0x00000000},
+       {0x0000c2e0, 0x00000000},
+       {0x0000c2e4, 0x00000000},
+       {0x0000c2e8, 0x00000000},
+       {0x0000c2ec, 0x00000000},
+       {0x0000c2f0, 0x00000000},
+       {0x0000c2f4, 0x00000000},
+       {0x0000c2f8, 0x00000000},
+       {0x0000c408, 0x0e79e5c0},
+       {0x0000c40c, 0x00820820},
+       {0x0000c420, 0x00000000},
+};
+
+static const u32 ar9300Modes_high_power_tx_gain_table_2p0[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
+       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
+       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
+       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
+       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
+       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
+       {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
+       {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
+       {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
+       {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
+       {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
+       {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
+       {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
+       {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
+       {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
+       {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
+       {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
+       {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
+       {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
+       {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
+       {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
+       {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
+       {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
+       {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
+       {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
+       {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
+       {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
+       {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
+       {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
+       {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
+       {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
+       {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+       {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+       {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+       {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+       {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+       {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+       {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+       {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+       {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+};
+
+static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p0[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
+       {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
+       {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
+       {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
+       {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
+       {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
+       {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
+       {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
+       {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
+       {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
+       {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
+       {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
+       {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
+       {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+       {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
+       {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
+       {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
+       {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
+       {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+       {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
+       {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
+       {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
+       {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
+       {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
+       {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
+       {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
+       {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
+       {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
+       {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
+       {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
+       {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
+       {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
+       {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
+       {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
+       {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
+       {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
+       {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
+       {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
+       {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+       {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+       {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+       {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+       {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Common_rx_gain_table_2p0[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a000, 0x00010000},
+       {0x0000a004, 0x00030002},
+       {0x0000a008, 0x00050004},
+       {0x0000a00c, 0x00810080},
+       {0x0000a010, 0x00830082},
+       {0x0000a014, 0x01810180},
+       {0x0000a018, 0x01830182},
+       {0x0000a01c, 0x01850184},
+       {0x0000a020, 0x01890188},
+       {0x0000a024, 0x018b018a},
+       {0x0000a028, 0x018d018c},
+       {0x0000a02c, 0x01910190},
+       {0x0000a030, 0x01930192},
+       {0x0000a034, 0x01950194},
+       {0x0000a038, 0x038a0196},
+       {0x0000a03c, 0x038c038b},
+       {0x0000a040, 0x0390038d},
+       {0x0000a044, 0x03920391},
+       {0x0000a048, 0x03940393},
+       {0x0000a04c, 0x03960395},
+       {0x0000a050, 0x00000000},
+       {0x0000a054, 0x00000000},
+       {0x0000a058, 0x00000000},
+       {0x0000a05c, 0x00000000},
+       {0x0000a060, 0x00000000},
+       {0x0000a064, 0x00000000},
+       {0x0000a068, 0x00000000},
+       {0x0000a06c, 0x00000000},
+       {0x0000a070, 0x00000000},
+       {0x0000a074, 0x00000000},
+       {0x0000a078, 0x00000000},
+       {0x0000a07c, 0x00000000},
+       {0x0000a080, 0x22222229},
+       {0x0000a084, 0x1d1d1d1d},
+       {0x0000a088, 0x1d1d1d1d},
+       {0x0000a08c, 0x1d1d1d1d},
+       {0x0000a090, 0x171d1d1d},
+       {0x0000a094, 0x11111717},
+       {0x0000a098, 0x00030311},
+       {0x0000a09c, 0x00000000},
+       {0x0000a0a0, 0x00000000},
+       {0x0000a0a4, 0x00000000},
+       {0x0000a0a8, 0x00000000},
+       {0x0000a0ac, 0x00000000},
+       {0x0000a0b0, 0x00000000},
+       {0x0000a0b4, 0x00000000},
+       {0x0000a0b8, 0x00000000},
+       {0x0000a0bc, 0x00000000},
+       {0x0000a0c0, 0x001f0000},
+       {0x0000a0c4, 0x01000101},
+       {0x0000a0c8, 0x011e011f},
+       {0x0000a0cc, 0x011c011d},
+       {0x0000a0d0, 0x02030204},
+       {0x0000a0d4, 0x02010202},
+       {0x0000a0d8, 0x021f0200},
+       {0x0000a0dc, 0x0302021e},
+       {0x0000a0e0, 0x03000301},
+       {0x0000a0e4, 0x031e031f},
+       {0x0000a0e8, 0x0402031d},
+       {0x0000a0ec, 0x04000401},
+       {0x0000a0f0, 0x041e041f},
+       {0x0000a0f4, 0x0502041d},
+       {0x0000a0f8, 0x05000501},
+       {0x0000a0fc, 0x051e051f},
+       {0x0000a100, 0x06010602},
+       {0x0000a104, 0x061f0600},
+       {0x0000a108, 0x061d061e},
+       {0x0000a10c, 0x07020703},
+       {0x0000a110, 0x07000701},
+       {0x0000a114, 0x00000000},
+       {0x0000a118, 0x00000000},
+       {0x0000a11c, 0x00000000},
+       {0x0000a120, 0x00000000},
+       {0x0000a124, 0x00000000},
+       {0x0000a128, 0x00000000},
+       {0x0000a12c, 0x00000000},
+       {0x0000a130, 0x00000000},
+       {0x0000a134, 0x00000000},
+       {0x0000a138, 0x00000000},
+       {0x0000a13c, 0x00000000},
+       {0x0000a140, 0x001f0000},
+       {0x0000a144, 0x01000101},
+       {0x0000a148, 0x011e011f},
+       {0x0000a14c, 0x011c011d},
+       {0x0000a150, 0x02030204},
+       {0x0000a154, 0x02010202},
+       {0x0000a158, 0x021f0200},
+       {0x0000a15c, 0x0302021e},
+       {0x0000a160, 0x03000301},
+       {0x0000a164, 0x031e031f},
+       {0x0000a168, 0x0402031d},
+       {0x0000a16c, 0x04000401},
+       {0x0000a170, 0x041e041f},
+       {0x0000a174, 0x0502041d},
+       {0x0000a178, 0x05000501},
+       {0x0000a17c, 0x051e051f},
+       {0x0000a180, 0x06010602},
+       {0x0000a184, 0x061f0600},
+       {0x0000a188, 0x061d061e},
+       {0x0000a18c, 0x07020703},
+       {0x0000a190, 0x07000701},
+       {0x0000a194, 0x00000000},
+       {0x0000a198, 0x00000000},
+       {0x0000a19c, 0x00000000},
+       {0x0000a1a0, 0x00000000},
+       {0x0000a1a4, 0x00000000},
+       {0x0000a1a8, 0x00000000},
+       {0x0000a1ac, 0x00000000},
+       {0x0000a1b0, 0x00000000},
+       {0x0000a1b4, 0x00000000},
+       {0x0000a1b8, 0x00000000},
+       {0x0000a1bc, 0x00000000},
+       {0x0000a1c0, 0x00000000},
+       {0x0000a1c4, 0x00000000},
+       {0x0000a1c8, 0x00000000},
+       {0x0000a1cc, 0x00000000},
+       {0x0000a1d0, 0x00000000},
+       {0x0000a1d4, 0x00000000},
+       {0x0000a1d8, 0x00000000},
+       {0x0000a1dc, 0x00000000},
+       {0x0000a1e0, 0x00000000},
+       {0x0000a1e4, 0x00000000},
+       {0x0000a1e8, 0x00000000},
+       {0x0000a1ec, 0x00000000},
+       {0x0000a1f0, 0x00000396},
+       {0x0000a1f4, 0x00000396},
+       {0x0000a1f8, 0x00000396},
+       {0x0000a1fc, 0x00000196},
+       {0x0000b000, 0x00010000},
+       {0x0000b004, 0x00030002},
+       {0x0000b008, 0x00050004},
+       {0x0000b00c, 0x00810080},
+       {0x0000b010, 0x00830082},
+       {0x0000b014, 0x01810180},
+       {0x0000b018, 0x01830182},
+       {0x0000b01c, 0x01850184},
+       {0x0000b020, 0x02810280},
+       {0x0000b024, 0x02830282},
+       {0x0000b028, 0x02850284},
+       {0x0000b02c, 0x02890288},
+       {0x0000b030, 0x028b028a},
+       {0x0000b034, 0x0388028c},
+       {0x0000b038, 0x038a0389},
+       {0x0000b03c, 0x038c038b},
+       {0x0000b040, 0x0390038d},
+       {0x0000b044, 0x03920391},
+       {0x0000b048, 0x03940393},
+       {0x0000b04c, 0x03960395},
+       {0x0000b050, 0x00000000},
+       {0x0000b054, 0x00000000},
+       {0x0000b058, 0x00000000},
+       {0x0000b05c, 0x00000000},
+       {0x0000b060, 0x00000000},
+       {0x0000b064, 0x00000000},
+       {0x0000b068, 0x00000000},
+       {0x0000b06c, 0x00000000},
+       {0x0000b070, 0x00000000},
+       {0x0000b074, 0x00000000},
+       {0x0000b078, 0x00000000},
+       {0x0000b07c, 0x00000000},
+       {0x0000b080, 0x32323232},
+       {0x0000b084, 0x2f2f3232},
+       {0x0000b088, 0x23282a2d},
+       {0x0000b08c, 0x1c1e2123},
+       {0x0000b090, 0x14171919},
+       {0x0000b094, 0x0e0e1214},
+       {0x0000b098, 0x03050707},
+       {0x0000b09c, 0x00030303},
+       {0x0000b0a0, 0x00000000},
+       {0x0000b0a4, 0x00000000},
+       {0x0000b0a8, 0x00000000},
+       {0x0000b0ac, 0x00000000},
+       {0x0000b0b0, 0x00000000},
+       {0x0000b0b4, 0x00000000},
+       {0x0000b0b8, 0x00000000},
+       {0x0000b0bc, 0x00000000},
+       {0x0000b0c0, 0x003f0020},
+       {0x0000b0c4, 0x00400041},
+       {0x0000b0c8, 0x0140005f},
+       {0x0000b0cc, 0x0160015f},
+       {0x0000b0d0, 0x017e017f},
+       {0x0000b0d4, 0x02410242},
+       {0x0000b0d8, 0x025f0240},
+       {0x0000b0dc, 0x027f0260},
+       {0x0000b0e0, 0x0341027e},
+       {0x0000b0e4, 0x035f0340},
+       {0x0000b0e8, 0x037f0360},
+       {0x0000b0ec, 0x04400441},
+       {0x0000b0f0, 0x0460045f},
+       {0x0000b0f4, 0x0541047f},
+       {0x0000b0f8, 0x055f0540},
+       {0x0000b0fc, 0x057f0560},
+       {0x0000b100, 0x06400641},
+       {0x0000b104, 0x0660065f},
+       {0x0000b108, 0x067e067f},
+       {0x0000b10c, 0x07410742},
+       {0x0000b110, 0x075f0740},
+       {0x0000b114, 0x077f0760},
+       {0x0000b118, 0x07800781},
+       {0x0000b11c, 0x07a0079f},
+       {0x0000b120, 0x07c107bf},
+       {0x0000b124, 0x000007c0},
+       {0x0000b128, 0x00000000},
+       {0x0000b12c, 0x00000000},
+       {0x0000b130, 0x00000000},
+       {0x0000b134, 0x00000000},
+       {0x0000b138, 0x00000000},
+       {0x0000b13c, 0x00000000},
+       {0x0000b140, 0x003f0020},
+       {0x0000b144, 0x00400041},
+       {0x0000b148, 0x0140005f},
+       {0x0000b14c, 0x0160015f},
+       {0x0000b150, 0x017e017f},
+       {0x0000b154, 0x02410242},
+       {0x0000b158, 0x025f0240},
+       {0x0000b15c, 0x027f0260},
+       {0x0000b160, 0x0341027e},
+       {0x0000b164, 0x035f0340},
+       {0x0000b168, 0x037f0360},
+       {0x0000b16c, 0x04400441},
+       {0x0000b170, 0x0460045f},
+       {0x0000b174, 0x0541047f},
+       {0x0000b178, 0x055f0540},
+       {0x0000b17c, 0x057f0560},
+       {0x0000b180, 0x06400641},
+       {0x0000b184, 0x0660065f},
+       {0x0000b188, 0x067e067f},
+       {0x0000b18c, 0x07410742},
+       {0x0000b190, 0x075f0740},
+       {0x0000b194, 0x077f0760},
+       {0x0000b198, 0x07800781},
+       {0x0000b19c, 0x07a0079f},
+       {0x0000b1a0, 0x07c107bf},
+       {0x0000b1a4, 0x000007c0},
+       {0x0000b1a8, 0x00000000},
+       {0x0000b1ac, 0x00000000},
+       {0x0000b1b0, 0x00000000},
+       {0x0000b1b4, 0x00000000},
+       {0x0000b1b8, 0x00000000},
+       {0x0000b1bc, 0x00000000},
+       {0x0000b1c0, 0x00000000},
+       {0x0000b1c4, 0x00000000},
+       {0x0000b1c8, 0x00000000},
+       {0x0000b1cc, 0x00000000},
+       {0x0000b1d0, 0x00000000},
+       {0x0000b1d4, 0x00000000},
+       {0x0000b1d8, 0x00000000},
+       {0x0000b1dc, 0x00000000},
+       {0x0000b1e0, 0x00000000},
+       {0x0000b1e4, 0x00000000},
+       {0x0000b1e8, 0x00000000},
+       {0x0000b1ec, 0x00000000},
+       {0x0000b1f0, 0x00000396},
+       {0x0000b1f4, 0x00000396},
+       {0x0000b1f8, 0x00000396},
+       {0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p0[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+       {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+       {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+       {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+       {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+       {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+       {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+       {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+       {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+       {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+       {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+       {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+       {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+       {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+       {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+       {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+       {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+       {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+       {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+       {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+       {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+       {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+       {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+       {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+       {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+       {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+       {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+       {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+       {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+       {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+       {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+       {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+       {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+       {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+       {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+       {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+       {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+       {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+       {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+       {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+       {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+       {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+       {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+       {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+       {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+       {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+       {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+       {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+       {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+       {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016048, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
+       {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016448, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
+       {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+       {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+       {0x00016848, 0x64000001, 0x64000001, 0x64000001, 0x64000001},
+       {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300_2p0_mac_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00000008, 0x00000000},
+       {0x00000030, 0x00020085},
+       {0x00000034, 0x00000005},
+       {0x00000040, 0x00000000},
+       {0x00000044, 0x00000000},
+       {0x00000048, 0x00000008},
+       {0x0000004c, 0x00000010},
+       {0x00000050, 0x00000000},
+       {0x00001040, 0x002ffc0f},
+       {0x00001044, 0x002ffc0f},
+       {0x00001048, 0x002ffc0f},
+       {0x0000104c, 0x002ffc0f},
+       {0x00001050, 0x002ffc0f},
+       {0x00001054, 0x002ffc0f},
+       {0x00001058, 0x002ffc0f},
+       {0x0000105c, 0x002ffc0f},
+       {0x00001060, 0x002ffc0f},
+       {0x00001064, 0x002ffc0f},
+       {0x000010f0, 0x00000100},
+       {0x00001270, 0x00000000},
+       {0x000012b0, 0x00000000},
+       {0x000012f0, 0x00000000},
+       {0x0000143c, 0x00000000},
+       {0x0000147c, 0x00000000},
+       {0x00008000, 0x00000000},
+       {0x00008004, 0x00000000},
+       {0x00008008, 0x00000000},
+       {0x0000800c, 0x00000000},
+       {0x00008018, 0x00000000},
+       {0x00008020, 0x00000000},
+       {0x00008038, 0x00000000},
+       {0x0000803c, 0x00000000},
+       {0x00008040, 0x00000000},
+       {0x00008044, 0x00000000},
+       {0x00008048, 0x00000000},
+       {0x0000804c, 0xffffffff},
+       {0x00008054, 0x00000000},
+       {0x00008058, 0x00000000},
+       {0x0000805c, 0x000fc78f},
+       {0x00008060, 0x0000000f},
+       {0x00008064, 0x00000000},
+       {0x00008070, 0x00000310},
+       {0x00008074, 0x00000020},
+       {0x00008078, 0x00000000},
+       {0x0000809c, 0x0000000f},
+       {0x000080a0, 0x00000000},
+       {0x000080a4, 0x02ff0000},
+       {0x000080a8, 0x0e070605},
+       {0x000080ac, 0x0000000d},
+       {0x000080b0, 0x00000000},
+       {0x000080b4, 0x00000000},
+       {0x000080b8, 0x00000000},
+       {0x000080bc, 0x00000000},
+       {0x000080c0, 0x2a800000},
+       {0x000080c4, 0x06900168},
+       {0x000080c8, 0x13881c20},
+       {0x000080cc, 0x01f40000},
+       {0x000080d0, 0x00252500},
+       {0x000080d4, 0x00a00000},
+       {0x000080d8, 0x00400000},
+       {0x000080dc, 0x00000000},
+       {0x000080e0, 0xffffffff},
+       {0x000080e4, 0x0000ffff},
+       {0x000080e8, 0x3f3f3f3f},
+       {0x000080ec, 0x00000000},
+       {0x000080f0, 0x00000000},
+       {0x000080f4, 0x00000000},
+       {0x000080fc, 0x00020000},
+       {0x00008100, 0x00000000},
+       {0x00008108, 0x00000052},
+       {0x0000810c, 0x00000000},
+       {0x00008110, 0x00000000},
+       {0x00008114, 0x000007ff},
+       {0x00008118, 0x000000aa},
+       {0x0000811c, 0x00003210},
+       {0x00008124, 0x00000000},
+       {0x00008128, 0x00000000},
+       {0x0000812c, 0x00000000},
+       {0x00008130, 0x00000000},
+       {0x00008134, 0x00000000},
+       {0x00008138, 0x00000000},
+       {0x0000813c, 0x0000ffff},
+       {0x00008144, 0xffffffff},
+       {0x00008168, 0x00000000},
+       {0x0000816c, 0x00000000},
+       {0x00008170, 0x18486200},
+       {0x00008174, 0x33332210},
+       {0x00008178, 0x00000000},
+       {0x0000817c, 0x00020000},
+       {0x000081c0, 0x00000000},
+       {0x000081c4, 0x33332210},
+       {0x000081c8, 0x00000000},
+       {0x000081cc, 0x00000000},
+       {0x000081d4, 0x00000000},
+       {0x000081ec, 0x00000000},
+       {0x000081f0, 0x00000000},
+       {0x000081f4, 0x00000000},
+       {0x000081f8, 0x00000000},
+       {0x000081fc, 0x00000000},
+       {0x00008240, 0x00100000},
+       {0x00008244, 0x0010f424},
+       {0x00008248, 0x00000800},
+       {0x0000824c, 0x0001e848},
+       {0x00008250, 0x00000000},
+       {0x00008254, 0x00000000},
+       {0x00008258, 0x00000000},
+       {0x0000825c, 0x40000000},
+       {0x00008260, 0x00080922},
+       {0x00008264, 0x98a00010},
+       {0x00008268, 0xffffffff},
+       {0x0000826c, 0x0000ffff},
+       {0x00008270, 0x00000000},
+       {0x00008274, 0x40000000},
+       {0x00008278, 0x003e4180},
+       {0x0000827c, 0x00000004},
+       {0x00008284, 0x0000002c},
+       {0x00008288, 0x0000002c},
+       {0x0000828c, 0x000000ff},
+       {0x00008294, 0x00000000},
+       {0x00008298, 0x00000000},
+       {0x0000829c, 0x00000000},
+       {0x00008300, 0x00000140},
+       {0x00008314, 0x00000000},
+       {0x0000831c, 0x0000010d},
+       {0x00008328, 0x00000000},
+       {0x0000832c, 0x00000007},
+       {0x00008330, 0x00000302},
+       {0x00008334, 0x00000700},
+       {0x00008338, 0x00ff0000},
+       {0x0000833c, 0x02400000},
+       {0x00008340, 0x000107ff},
+       {0x00008344, 0xaa48105b},
+       {0x00008348, 0x008f0000},
+       {0x0000835c, 0x00000000},
+       {0x00008360, 0xffffffff},
+       {0x00008364, 0xffffffff},
+       {0x00008368, 0x00000000},
+       {0x00008370, 0x00000000},
+       {0x00008374, 0x000000ff},
+       {0x00008378, 0x00000000},
+       {0x0000837c, 0x00000000},
+       {0x00008380, 0xffffffff},
+       {0x00008384, 0xffffffff},
+       {0x00008390, 0xffffffff},
+       {0x00008394, 0xffffffff},
+       {0x00008398, 0x00000000},
+       {0x0000839c, 0x00000000},
+       {0x000083a0, 0x00000000},
+       {0x000083a4, 0x0000fa14},
+       {0x000083a8, 0x000f0c00},
+       {0x000083ac, 0x33332210},
+       {0x000083b0, 0x33332210},
+       {0x000083b4, 0x33332210},
+       {0x000083b8, 0x33332210},
+       {0x000083bc, 0x00000000},
+       {0x000083c0, 0x00000000},
+       {0x000083c4, 0x00000000},
+       {0x000083c8, 0x00000000},
+       {0x000083cc, 0x00000200},
+       {0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9300Common_wo_xlna_rx_gain_table_2p0[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a000, 0x00010000},
+       {0x0000a004, 0x00030002},
+       {0x0000a008, 0x00050004},
+       {0x0000a00c, 0x00810080},
+       {0x0000a010, 0x00830082},
+       {0x0000a014, 0x01810180},
+       {0x0000a018, 0x01830182},
+       {0x0000a01c, 0x01850184},
+       {0x0000a020, 0x01890188},
+       {0x0000a024, 0x018b018a},
+       {0x0000a028, 0x018d018c},
+       {0x0000a02c, 0x03820190},
+       {0x0000a030, 0x03840383},
+       {0x0000a034, 0x03880385},
+       {0x0000a038, 0x038a0389},
+       {0x0000a03c, 0x038c038b},
+       {0x0000a040, 0x0390038d},
+       {0x0000a044, 0x03920391},
+       {0x0000a048, 0x03940393},
+       {0x0000a04c, 0x03960395},
+       {0x0000a050, 0x00000000},
+       {0x0000a054, 0x00000000},
+       {0x0000a058, 0x00000000},
+       {0x0000a05c, 0x00000000},
+       {0x0000a060, 0x00000000},
+       {0x0000a064, 0x00000000},
+       {0x0000a068, 0x00000000},
+       {0x0000a06c, 0x00000000},
+       {0x0000a070, 0x00000000},
+       {0x0000a074, 0x00000000},
+       {0x0000a078, 0x00000000},
+       {0x0000a07c, 0x00000000},
+       {0x0000a080, 0x29292929},
+       {0x0000a084, 0x29292929},
+       {0x0000a088, 0x29292929},
+       {0x0000a08c, 0x29292929},
+       {0x0000a090, 0x22292929},
+       {0x0000a094, 0x1d1d2222},
+       {0x0000a098, 0x0c111117},
+       {0x0000a09c, 0x00030303},
+       {0x0000a0a0, 0x00000000},
+       {0x0000a0a4, 0x00000000},
+       {0x0000a0a8, 0x00000000},
+       {0x0000a0ac, 0x00000000},
+       {0x0000a0b0, 0x00000000},
+       {0x0000a0b4, 0x00000000},
+       {0x0000a0b8, 0x00000000},
+       {0x0000a0bc, 0x00000000},
+       {0x0000a0c0, 0x001f0000},
+       {0x0000a0c4, 0x01000101},
+       {0x0000a0c8, 0x011e011f},
+       {0x0000a0cc, 0x011c011d},
+       {0x0000a0d0, 0x02030204},
+       {0x0000a0d4, 0x02010202},
+       {0x0000a0d8, 0x021f0200},
+       {0x0000a0dc, 0x0302021e},
+       {0x0000a0e0, 0x03000301},
+       {0x0000a0e4, 0x031e031f},
+       {0x0000a0e8, 0x0402031d},
+       {0x0000a0ec, 0x04000401},
+       {0x0000a0f0, 0x041e041f},
+       {0x0000a0f4, 0x0502041d},
+       {0x0000a0f8, 0x05000501},
+       {0x0000a0fc, 0x051e051f},
+       {0x0000a100, 0x06010602},
+       {0x0000a104, 0x061f0600},
+       {0x0000a108, 0x061d061e},
+       {0x0000a10c, 0x07020703},
+       {0x0000a110, 0x07000701},
+       {0x0000a114, 0x00000000},
+       {0x0000a118, 0x00000000},
+       {0x0000a11c, 0x00000000},
+       {0x0000a120, 0x00000000},
+       {0x0000a124, 0x00000000},
+       {0x0000a128, 0x00000000},
+       {0x0000a12c, 0x00000000},
+       {0x0000a130, 0x00000000},
+       {0x0000a134, 0x00000000},
+       {0x0000a138, 0x00000000},
+       {0x0000a13c, 0x00000000},
+       {0x0000a140, 0x001f0000},
+       {0x0000a144, 0x01000101},
+       {0x0000a148, 0x011e011f},
+       {0x0000a14c, 0x011c011d},
+       {0x0000a150, 0x02030204},
+       {0x0000a154, 0x02010202},
+       {0x0000a158, 0x021f0200},
+       {0x0000a15c, 0x0302021e},
+       {0x0000a160, 0x03000301},
+       {0x0000a164, 0x031e031f},
+       {0x0000a168, 0x0402031d},
+       {0x0000a16c, 0x04000401},
+       {0x0000a170, 0x041e041f},
+       {0x0000a174, 0x0502041d},
+       {0x0000a178, 0x05000501},
+       {0x0000a17c, 0x051e051f},
+       {0x0000a180, 0x06010602},
+       {0x0000a184, 0x061f0600},
+       {0x0000a188, 0x061d061e},
+       {0x0000a18c, 0x07020703},
+       {0x0000a190, 0x07000701},
+       {0x0000a194, 0x00000000},
+       {0x0000a198, 0x00000000},
+       {0x0000a19c, 0x00000000},
+       {0x0000a1a0, 0x00000000},
+       {0x0000a1a4, 0x00000000},
+       {0x0000a1a8, 0x00000000},
+       {0x0000a1ac, 0x00000000},
+       {0x0000a1b0, 0x00000000},
+       {0x0000a1b4, 0x00000000},
+       {0x0000a1b8, 0x00000000},
+       {0x0000a1bc, 0x00000000},
+       {0x0000a1c0, 0x00000000},
+       {0x0000a1c4, 0x00000000},
+       {0x0000a1c8, 0x00000000},
+       {0x0000a1cc, 0x00000000},
+       {0x0000a1d0, 0x00000000},
+       {0x0000a1d4, 0x00000000},
+       {0x0000a1d8, 0x00000000},
+       {0x0000a1dc, 0x00000000},
+       {0x0000a1e0, 0x00000000},
+       {0x0000a1e4, 0x00000000},
+       {0x0000a1e8, 0x00000000},
+       {0x0000a1ec, 0x00000000},
+       {0x0000a1f0, 0x00000396},
+       {0x0000a1f4, 0x00000396},
+       {0x0000a1f8, 0x00000396},
+       {0x0000a1fc, 0x00000196},
+       {0x0000b000, 0x00010000},
+       {0x0000b004, 0x00030002},
+       {0x0000b008, 0x00050004},
+       {0x0000b00c, 0x00810080},
+       {0x0000b010, 0x00830082},
+       {0x0000b014, 0x01810180},
+       {0x0000b018, 0x01830182},
+       {0x0000b01c, 0x01850184},
+       {0x0000b020, 0x02810280},
+       {0x0000b024, 0x02830282},
+       {0x0000b028, 0x02850284},
+       {0x0000b02c, 0x02890288},
+       {0x0000b030, 0x028b028a},
+       {0x0000b034, 0x0388028c},
+       {0x0000b038, 0x038a0389},
+       {0x0000b03c, 0x038c038b},
+       {0x0000b040, 0x0390038d},
+       {0x0000b044, 0x03920391},
+       {0x0000b048, 0x03940393},
+       {0x0000b04c, 0x03960395},
+       {0x0000b050, 0x00000000},
+       {0x0000b054, 0x00000000},
+       {0x0000b058, 0x00000000},
+       {0x0000b05c, 0x00000000},
+       {0x0000b060, 0x00000000},
+       {0x0000b064, 0x00000000},
+       {0x0000b068, 0x00000000},
+       {0x0000b06c, 0x00000000},
+       {0x0000b070, 0x00000000},
+       {0x0000b074, 0x00000000},
+       {0x0000b078, 0x00000000},
+       {0x0000b07c, 0x00000000},
+       {0x0000b080, 0x32323232},
+       {0x0000b084, 0x2f2f3232},
+       {0x0000b088, 0x23282a2d},
+       {0x0000b08c, 0x1c1e2123},
+       {0x0000b090, 0x14171919},
+       {0x0000b094, 0x0e0e1214},
+       {0x0000b098, 0x03050707},
+       {0x0000b09c, 0x00030303},
+       {0x0000b0a0, 0x00000000},
+       {0x0000b0a4, 0x00000000},
+       {0x0000b0a8, 0x00000000},
+       {0x0000b0ac, 0x00000000},
+       {0x0000b0b0, 0x00000000},
+       {0x0000b0b4, 0x00000000},
+       {0x0000b0b8, 0x00000000},
+       {0x0000b0bc, 0x00000000},
+       {0x0000b0c0, 0x003f0020},
+       {0x0000b0c4, 0x00400041},
+       {0x0000b0c8, 0x0140005f},
+       {0x0000b0cc, 0x0160015f},
+       {0x0000b0d0, 0x017e017f},
+       {0x0000b0d4, 0x02410242},
+       {0x0000b0d8, 0x025f0240},
+       {0x0000b0dc, 0x027f0260},
+       {0x0000b0e0, 0x0341027e},
+       {0x0000b0e4, 0x035f0340},
+       {0x0000b0e8, 0x037f0360},
+       {0x0000b0ec, 0x04400441},
+       {0x0000b0f0, 0x0460045f},
+       {0x0000b0f4, 0x0541047f},
+       {0x0000b0f8, 0x055f0540},
+       {0x0000b0fc, 0x057f0560},
+       {0x0000b100, 0x06400641},
+       {0x0000b104, 0x0660065f},
+       {0x0000b108, 0x067e067f},
+       {0x0000b10c, 0x07410742},
+       {0x0000b110, 0x075f0740},
+       {0x0000b114, 0x077f0760},
+       {0x0000b118, 0x07800781},
+       {0x0000b11c, 0x07a0079f},
+       {0x0000b120, 0x07c107bf},
+       {0x0000b124, 0x000007c0},
+       {0x0000b128, 0x00000000},
+       {0x0000b12c, 0x00000000},
+       {0x0000b130, 0x00000000},
+       {0x0000b134, 0x00000000},
+       {0x0000b138, 0x00000000},
+       {0x0000b13c, 0x00000000},
+       {0x0000b140, 0x003f0020},
+       {0x0000b144, 0x00400041},
+       {0x0000b148, 0x0140005f},
+       {0x0000b14c, 0x0160015f},
+       {0x0000b150, 0x017e017f},
+       {0x0000b154, 0x02410242},
+       {0x0000b158, 0x025f0240},
+       {0x0000b15c, 0x027f0260},
+       {0x0000b160, 0x0341027e},
+       {0x0000b164, 0x035f0340},
+       {0x0000b168, 0x037f0360},
+       {0x0000b16c, 0x04400441},
+       {0x0000b170, 0x0460045f},
+       {0x0000b174, 0x0541047f},
+       {0x0000b178, 0x055f0540},
+       {0x0000b17c, 0x057f0560},
+       {0x0000b180, 0x06400641},
+       {0x0000b184, 0x0660065f},
+       {0x0000b188, 0x067e067f},
+       {0x0000b18c, 0x07410742},
+       {0x0000b190, 0x075f0740},
+       {0x0000b194, 0x077f0760},
+       {0x0000b198, 0x07800781},
+       {0x0000b19c, 0x07a0079f},
+       {0x0000b1a0, 0x07c107bf},
+       {0x0000b1a4, 0x000007c0},
+       {0x0000b1a8, 0x00000000},
+       {0x0000b1ac, 0x00000000},
+       {0x0000b1b0, 0x00000000},
+       {0x0000b1b4, 0x00000000},
+       {0x0000b1b8, 0x00000000},
+       {0x0000b1bc, 0x00000000},
+       {0x0000b1c0, 0x00000000},
+       {0x0000b1c4, 0x00000000},
+       {0x0000b1c8, 0x00000000},
+       {0x0000b1cc, 0x00000000},
+       {0x0000b1d0, 0x00000000},
+       {0x0000b1d4, 0x00000000},
+       {0x0000b1d8, 0x00000000},
+       {0x0000b1dc, 0x00000000},
+       {0x0000b1e0, 0x00000000},
+       {0x0000b1e4, 0x00000000},
+       {0x0000b1e8, 0x00000000},
+       {0x0000b1ec, 0x00000000},
+       {0x0000b1f0, 0x00000396},
+       {0x0000b1f4, 0x00000396},
+       {0x0000b1f8, 0x00000396},
+       {0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300_2p0_soc_preamble[][2] = {
+       /* Addr      allmodes  */
+       {0x000040a4, 0x00a0c1c9},
+       {0x00007008, 0x00000000},
+       {0x00007020, 0x00000000},
+       {0x00007034, 0x00000002},
+       {0x00007038, 0x000004c2},
+};
+
+static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p0[][2] = {
+       /* Addr      allmodes  */
+       {0x00004040, 0x08212e5e},
+       {0x00004040, 0x0008003b},
+       {0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_enable_L1_2p0[][2] = {
+       /* Addr      allmodes  */
+       {0x00004040, 0x08253e5e},
+       {0x00004040, 0x0008003b},
+       {0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = {
+       /* Addr      allmodes  */
+       {0x00004040, 0x08213e5e},
+       {0x00004040, 0x0008003b},
+       {0x00004044, 0x00000000},
+};
+
+#endif /* INITVALS_9003_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
new file mode 100644 (file)
index 0000000..37ba374
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Copyright (c) 2010 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 "hw.h"
+#include "ar9003_mac.h"
+
+static void ar9003_hw_rx_enable(struct ath_hw *hw)
+{
+       REG_WRITE(hw, AR_CR, 0);
+}
+
+static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads)
+{
+       int checksum;
+
+       checksum = ads->info + ads->link
+               + ads->data0 + ads->ctl3
+               + ads->data1 + ads->ctl5
+               + ads->data2 + ads->ctl7
+               + ads->data3 + ads->ctl9;
+
+       return ((checksum & 0xffff) + (checksum >> 16)) & AR_TxPtrChkSum;
+}
+
+static void ar9003_hw_set_desc_link(void *ds, u32 ds_link)
+{
+       struct ar9003_txc *ads = ds;
+
+       ads->link = ds_link;
+       ads->ctl10 &= ~AR_TxPtrChkSum;
+       ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
+}
+
+static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link)
+{
+       struct ar9003_txc *ads = ds;
+
+       *ds_link = &ads->link;
+}
+
+static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+       u32 isr = 0;
+       u32 mask2 = 0;
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
+       u32 sync_cause = 0;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
+               if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
+                               == AR_RTC_STATUS_ON)
+                       isr = REG_READ(ah, AR_ISR);
+       }
+
+       sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT;
+
+       *masked = 0;
+
+       if (!isr && !sync_cause)
+               return false;
+
+       if (isr) {
+               if (isr & AR_ISR_BCNMISC) {
+                       u32 isr2;
+                       isr2 = REG_READ(ah, AR_ISR_S2);
+
+                       mask2 |= ((isr2 & AR_ISR_S2_TIM) >>
+                                 MAP_ISR_S2_TIM);
+                       mask2 |= ((isr2 & AR_ISR_S2_DTIM) >>
+                                 MAP_ISR_S2_DTIM);
+                       mask2 |= ((isr2 & AR_ISR_S2_DTIMSYNC) >>
+                                 MAP_ISR_S2_DTIMSYNC);
+                       mask2 |= ((isr2 & AR_ISR_S2_CABEND) >>
+                                 MAP_ISR_S2_CABEND);
+                       mask2 |= ((isr2 & AR_ISR_S2_GTT) <<
+                                 MAP_ISR_S2_GTT);
+                       mask2 |= ((isr2 & AR_ISR_S2_CST) <<
+                                 MAP_ISR_S2_CST);
+                       mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >>
+                                 MAP_ISR_S2_TSFOOR);
+
+                       if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+                               REG_WRITE(ah, AR_ISR_S2, isr2);
+                               isr &= ~AR_ISR_BCNMISC;
+                       }
+               }
+
+               if ((pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED))
+                       isr = REG_READ(ah, AR_ISR_RAC);
+
+               if (isr == 0xffffffff) {
+                       *masked = 0;
+                       return false;
+               }
+
+               *masked = isr & ATH9K_INT_COMMON;
+
+               if (ah->config.rx_intr_mitigation)
+                       if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
+                               *masked |= ATH9K_INT_RXLP;
+
+               if (ah->config.tx_intr_mitigation)
+                       if (isr & (AR_ISR_TXMINTR | AR_ISR_TXINTM))
+                               *masked |= ATH9K_INT_TX;
+
+               if (isr & (AR_ISR_LP_RXOK | AR_ISR_RXERR))
+                       *masked |= ATH9K_INT_RXLP;
+
+               if (isr & AR_ISR_HP_RXOK)
+                       *masked |= ATH9K_INT_RXHP;
+
+               if (isr & (AR_ISR_TXOK | AR_ISR_TXERR | AR_ISR_TXEOL)) {
+                       *masked |= ATH9K_INT_TX;
+
+                       if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+                               u32 s0, s1;
+                               s0 = REG_READ(ah, AR_ISR_S0);
+                               REG_WRITE(ah, AR_ISR_S0, s0);
+                               s1 = REG_READ(ah, AR_ISR_S1);
+                               REG_WRITE(ah, AR_ISR_S1, s1);
+
+                               isr &= ~(AR_ISR_TXOK | AR_ISR_TXERR |
+                                        AR_ISR_TXEOL);
+                       }
+               }
+
+               if (isr & AR_ISR_GENTMR) {
+                       u32 s5;
+
+                       if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)
+                               s5 = REG_READ(ah, AR_ISR_S5_S);
+                       else
+                               s5 = REG_READ(ah, AR_ISR_S5);
+
+                       ah->intr_gen_timer_trigger =
+                               MS(s5, AR_ISR_S5_GENTIMER_TRIG);
+
+                       ah->intr_gen_timer_thresh =
+                               MS(s5, AR_ISR_S5_GENTIMER_THRESH);
+
+                       if (ah->intr_gen_timer_trigger)
+                               *masked |= ATH9K_INT_GENTIMER;
+
+                       if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+                               REG_WRITE(ah, AR_ISR_S5, s5);
+                               isr &= ~AR_ISR_GENTMR;
+                       }
+
+               }
+
+               *masked |= mask2;
+
+               if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+                       REG_WRITE(ah, AR_ISR, isr);
+
+                       (void) REG_READ(ah, AR_ISR);
+               }
+       }
+
+       if (sync_cause) {
+               if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
+                       REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
+                       REG_WRITE(ah, AR_RC, 0);
+                       *masked |= ATH9K_INT_FATAL;
+               }
+
+               if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT)
+                       ath_print(common, ATH_DBG_INTERRUPT,
+                                 "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
+
+                       REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
+               (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
+
+       }
+       return true;
+}
+
+static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen,
+                                 bool is_firstseg, bool is_lastseg,
+                                 const void *ds0, dma_addr_t buf_addr,
+                                 unsigned int qcu)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+       unsigned int descid = 0;
+
+       ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) |
+                                    (1 << AR_TxRxDesc_S) |
+                                    (1 << AR_CtrlStat_S) |
+                                    (qcu << AR_TxQcuNum_S) | 0x17;
+
+       ads->data0 = buf_addr;
+       ads->data1 = 0;
+       ads->data2 = 0;
+       ads->data3 = 0;
+
+       ads->ctl3 = (seglen << AR_BufLen_S);
+       ads->ctl3 &= AR_BufLen;
+
+       /* Fill in pointer checksum and descriptor id */
+       ads->ctl10 = ar9003_calc_ptr_chksum(ads);
+       ads->ctl10 |= (descid << AR_TxDescId_S);
+
+       if (is_firstseg) {
+               ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore);
+       } else if (is_lastseg) {
+               ads->ctl11 = 0;
+               ads->ctl12 = 0;
+               ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13;
+               ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14;
+       } else {
+               /* XXX Intermediate descriptor in a multi-descriptor frame.*/
+               ads->ctl11 = 0;
+               ads->ctl12 = AR_TxMore;
+               ads->ctl13 = 0;
+               ads->ctl14 = 0;
+       }
+}
+
+static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds,
+                                struct ath_tx_status *ts)
+{
+       struct ar9003_txs *ads;
+
+       ads = &ah->ts_ring[ah->ts_tail];
+
+       if ((ads->status8 & AR_TxDone) == 0)
+               return -EINPROGRESS;
+
+       ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size;
+
+       if ((MS(ads->ds_info, AR_DescId) != ATHEROS_VENDOR_ID) ||
+           (MS(ads->ds_info, AR_TxRxDesc) != 1)) {
+               ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
+                         "Tx Descriptor error %x\n", ads->ds_info);
+               memset(ads, 0, sizeof(*ads));
+               return -EIO;
+       }
+
+       ts->qid = MS(ads->ds_info, AR_TxQcuNum);
+       ts->desc_id = MS(ads->status1, AR_TxDescId);
+       ts->ts_seqnum = MS(ads->status8, AR_SeqNum);
+       ts->ts_tstamp = ads->status4;
+       ts->ts_status = 0;
+       ts->ts_flags  = 0;
+
+       if (ads->status3 & AR_ExcessiveRetries)
+               ts->ts_status |= ATH9K_TXERR_XRETRY;
+       if (ads->status3 & AR_Filtered)
+               ts->ts_status |= ATH9K_TXERR_FILT;
+       if (ads->status3 & AR_FIFOUnderrun) {
+               ts->ts_status |= ATH9K_TXERR_FIFO;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->status8 & AR_TxOpExceeded)
+               ts->ts_status |= ATH9K_TXERR_XTXOP;
+       if (ads->status3 & AR_TxTimerExpired)
+               ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
+
+       if (ads->status3 & AR_DescCfgErr)
+               ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR;
+       if (ads->status3 & AR_TxDataUnderrun) {
+               ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->status3 & AR_TxDelimUnderrun) {
+               ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
+               ath9k_hw_updatetxtriglevel(ah, true);
+       }
+       if (ads->status2 & AR_TxBaStatus) {
+               ts->ts_flags |= ATH9K_TX_BA;
+               ts->ba_low = ads->status5;
+               ts->ba_high = ads->status6;
+       }
+
+       ts->ts_rateindex = MS(ads->status8, AR_FinalTxIdx);
+
+       ts->ts_rssi = MS(ads->status7, AR_TxRSSICombined);
+       ts->ts_rssi_ctl0 = MS(ads->status2, AR_TxRSSIAnt00);
+       ts->ts_rssi_ctl1 = MS(ads->status2, AR_TxRSSIAnt01);
+       ts->ts_rssi_ctl2 = MS(ads->status2, AR_TxRSSIAnt02);
+       ts->ts_rssi_ext0 = MS(ads->status7, AR_TxRSSIAnt10);
+       ts->ts_rssi_ext1 = MS(ads->status7, AR_TxRSSIAnt11);
+       ts->ts_rssi_ext2 = MS(ads->status7, AR_TxRSSIAnt12);
+       ts->ts_shortretry = MS(ads->status3, AR_RTSFailCnt);
+       ts->ts_longretry = MS(ads->status3, AR_DataFailCnt);
+       ts->ts_virtcol = MS(ads->status3, AR_VirtRetryCnt);
+       ts->ts_antenna = 0;
+
+       ts->tid = MS(ads->status8, AR_TxTid);
+
+       memset(ads, 0, sizeof(*ads));
+
+       return 0;
+}
+
+static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
+               u32 pktlen, enum ath9k_pkt_type type, u32 txpower,
+               u32 keyIx, enum ath9k_key_type keyType, u32 flags)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+       if (txpower > ah->txpower_limit)
+               txpower = ah->txpower_limit;
+
+       txpower += ah->txpower_indexoffset;
+       if (txpower > 63)
+               txpower = 63;
+
+       ads->ctl11 = (pktlen & AR_FrameLen)
+               | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
+               | SM(txpower, AR_XmitPower)
+               | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
+               | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
+               | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
+               | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
+
+       ads->ctl12 =
+               (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
+               | SM(type, AR_FrameType)
+               | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
+               | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
+               | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
+
+       ads->ctl17 = SM(keyType, AR_EncrType) |
+                    (flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0);
+       ads->ctl18 = 0;
+       ads->ctl19 = AR_Not_Sounding;
+
+       ads->ctl20 = 0;
+       ads->ctl21 = 0;
+       ads->ctl22 = 0;
+}
+
+static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
+                                         void *lastds,
+                                         u32 durUpdateEn, u32 rtsctsRate,
+                                         u32 rtsctsDuration,
+                                         struct ath9k_11n_rate_series series[],
+                                         u32 nseries, u32 flags)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+       struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds;
+       u_int32_t ctl11;
+
+       if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
+               ctl11 = ads->ctl11;
+
+               if (flags & ATH9K_TXDESC_RTSENA) {
+                       ctl11 &= ~AR_CTSEnable;
+                       ctl11 |= AR_RTSEnable;
+               } else {
+                       ctl11 &= ~AR_RTSEnable;
+                       ctl11 |= AR_CTSEnable;
+               }
+
+               ads->ctl11 = ctl11;
+       } else {
+               ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable));
+       }
+
+       ads->ctl13 = set11nTries(series, 0)
+               |  set11nTries(series, 1)
+               |  set11nTries(series, 2)
+               |  set11nTries(series, 3)
+               |  (durUpdateEn ? AR_DurUpdateEna : 0)
+               |  SM(0, AR_BurstDur);
+
+       ads->ctl14 = set11nRate(series, 0)
+               |  set11nRate(series, 1)
+               |  set11nRate(series, 2)
+               |  set11nRate(series, 3);
+
+       ads->ctl15 = set11nPktDurRTSCTS(series, 0)
+               |  set11nPktDurRTSCTS(series, 1);
+
+       ads->ctl16 = set11nPktDurRTSCTS(series, 2)
+               |  set11nPktDurRTSCTS(series, 3);
+
+       ads->ctl18 = set11nRateFlags(series, 0)
+               |  set11nRateFlags(series, 1)
+               |  set11nRateFlags(series, 2)
+               |  set11nRateFlags(series, 3)
+               | SM(rtsctsRate, AR_RTSCTSRate);
+       ads->ctl19 = AR_Not_Sounding;
+
+       last_ads->ctl13 = ads->ctl13;
+       last_ads->ctl14 = ads->ctl14;
+}
+
+static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
+                                       u32 aggrLen)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+       ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
+
+       ads->ctl17 &= ~AR_AggrLen;
+       ads->ctl17 |= SM(aggrLen, AR_AggrLen);
+}
+
+static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
+                                        u32 numDelims)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+       unsigned int ctl17;
+
+       ads->ctl12 |= (AR_IsAggr | AR_MoreAggr);
+
+       /*
+        * We use a stack variable to manipulate ctl6 to reduce uncached
+        * read modify, modfiy, write.
+        */
+       ctl17 = ads->ctl17;
+       ctl17 &= ~AR_PadDelim;
+       ctl17 |= SM(numDelims, AR_PadDelim);
+       ads->ctl17 = ctl17;
+}
+
+static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+       ads->ctl12 |= AR_IsAggr;
+       ads->ctl12 &= ~AR_MoreAggr;
+       ads->ctl17 &= ~AR_PadDelim;
+}
+
+static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+       ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr);
+}
+
+static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
+                                          u32 burstDuration)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+       ads->ctl13 &= ~AR_BurstDur;
+       ads->ctl13 |= SM(burstDuration, AR_BurstDur);
+
+}
+
+static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
+                                            u32 vmf)
+{
+       struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+       if (vmf)
+               ads->ctl11 |=  AR_VirtMoreFrag;
+       else
+               ads->ctl11 &= ~AR_VirtMoreFrag;
+}
+
+void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
+{
+       struct ath_hw_ops *ops = ath9k_hw_ops(hw);
+
+       ops->rx_enable = ar9003_hw_rx_enable;
+       ops->set_desc_link = ar9003_hw_set_desc_link;
+       ops->get_desc_link = ar9003_hw_get_desc_link;
+       ops->get_isr = ar9003_hw_get_isr;
+       ops->fill_txdesc = ar9003_hw_fill_txdesc;
+       ops->proc_txdesc = ar9003_hw_proc_txdesc;
+       ops->set11n_txdesc = ar9003_hw_set11n_txdesc;
+       ops->set11n_ratescenario = ar9003_hw_set11n_ratescenario;
+       ops->set11n_aggr_first = ar9003_hw_set11n_aggr_first;
+       ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle;
+       ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
+       ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
+       ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
+       ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
+}
+
+void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
+{
+       REG_WRITE(ah, AR_DATABUF_SIZE, buf_size & AR_DATABUF_SIZE_MASK);
+}
+EXPORT_SYMBOL(ath9k_hw_set_rx_bufsize);
+
+void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp,
+                           enum ath9k_rx_qtype qtype)
+{
+       if (qtype == ATH9K_RX_QUEUE_HP)
+               REG_WRITE(ah, AR_HP_RXDP, rxdp);
+       else
+               REG_WRITE(ah, AR_LP_RXDP, rxdp);
+}
+EXPORT_SYMBOL(ath9k_hw_addrxbuf_edma);
+
+int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs,
+                                void *buf_addr)
+{
+       struct ar9003_rxs *rxsp = (struct ar9003_rxs *) buf_addr;
+       unsigned int phyerr;
+
+       /* TODO: byte swap on big endian for ar9300_10 */
+
+       if ((rxsp->status11 & AR_RxDone) == 0)
+               return -EINPROGRESS;
+
+       if (MS(rxsp->ds_info, AR_DescId) != 0x168c)
+               return -EINVAL;
+
+       if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0)
+               return -EINPROGRESS;
+
+       if (!rxs)
+               return 0;
+
+       rxs->rs_status = 0;
+       rxs->rs_flags =  0;
+
+       rxs->rs_datalen = rxsp->status2 & AR_DataLen;
+       rxs->rs_tstamp =  rxsp->status3;
+
+       /* XXX: Keycache */
+       rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
+       rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
+       rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
+       rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
+       rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
+       rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
+       rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
+
+       if (rxsp->status11 & AR_RxKeyIdxValid)
+               rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);
+       else
+               rxs->rs_keyix = ATH9K_RXKEYIX_INVALID;
+
+       rxs->rs_rate = MS(rxsp->status1, AR_RxRate);
+       rxs->rs_more = (rxsp->status2 & AR_RxMore) ? 1 : 0;
+
+       rxs->rs_isaggr = (rxsp->status11 & AR_RxAggr) ? 1 : 0;
+       rxs->rs_moreaggr = (rxsp->status11 & AR_RxMoreAggr) ? 1 : 0;
+       rxs->rs_antenna = (MS(rxsp->status4, AR_RxAntenna) & 0x7);
+       rxs->rs_flags  = (rxsp->status4 & AR_GI) ? ATH9K_RX_GI : 0;
+       rxs->rs_flags  |= (rxsp->status4 & AR_2040) ? ATH9K_RX_2040 : 0;
+
+       rxs->evm0 = rxsp->status6;
+       rxs->evm1 = rxsp->status7;
+       rxs->evm2 = rxsp->status8;
+       rxs->evm3 = rxsp->status9;
+       rxs->evm4 = (rxsp->status10 & 0xffff);
+
+       if (rxsp->status11 & AR_PreDelimCRCErr)
+               rxs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+
+       if (rxsp->status11 & AR_PostDelimCRCErr)
+               rxs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+
+       if (rxsp->status11 & AR_DecryptBusyErr)
+               rxs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+
+       if ((rxsp->status11 & AR_RxFrameOK) == 0) {
+               if (rxsp->status11 & AR_CRCErr) {
+                       rxs->rs_status |= ATH9K_RXERR_CRC;
+               } else if (rxsp->status11 & AR_PHYErr) {
+                       rxs->rs_status |= ATH9K_RXERR_PHY;
+                       phyerr = MS(rxsp->status11, AR_PHYErrCode);
+                       rxs->rs_phyerr = phyerr;
+               } else if (rxsp->status11 & AR_DecryptCRCErr) {
+                       rxs->rs_status |= ATH9K_RXERR_DECRYPT;
+               } else if (rxsp->status11 & AR_MichaelErr) {
+                       rxs->rs_status |= ATH9K_RXERR_MIC;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ath9k_hw_process_rxdesc_edma);
+
+void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah)
+{
+       ah->ts_tail = 0;
+
+       memset((void *) ah->ts_ring, 0,
+               ah->ts_size * sizeof(struct ar9003_txs));
+
+       ath_print(ath9k_hw_common(ah), ATH_DBG_XMIT,
+                 "TS Start 0x%x End 0x%x Virt %p, Size %d\n",
+                  ah->ts_paddr_start, ah->ts_paddr_end,
+                  ah->ts_ring, ah->ts_size);
+
+       REG_WRITE(ah, AR_Q_STATUS_RING_START, ah->ts_paddr_start);
+       REG_WRITE(ah, AR_Q_STATUS_RING_END, ah->ts_paddr_end);
+}
+
+void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start,
+                              u32 ts_paddr_start,
+                              u8 size)
+{
+
+       ah->ts_paddr_start = ts_paddr_start;
+       ah->ts_paddr_end = ts_paddr_start + (size * sizeof(struct ar9003_txs));
+       ah->ts_size = size;
+       ah->ts_ring = (struct ar9003_txs *) ts_start;
+
+       ath9k_hw_reset_txstatus_ring(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_setup_statusring);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
new file mode 100644 (file)
index 0000000..f17558b
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef AR9003_MAC_H
+#define AR9003_MAC_H
+
+#define AR_DescId      0xffff0000
+#define AR_DescId_S    16
+#define AR_CtrlStat    0x00004000
+#define AR_CtrlStat_S  14
+#define AR_TxRxDesc    0x00008000
+#define AR_TxRxDesc_S  15
+#define AR_TxQcuNum    0x00000f00
+#define AR_TxQcuNum_S  8
+
+#define AR_BufLen      0x0fff0000
+#define AR_BufLen_S    16
+
+#define AR_TxDescId    0xffff0000
+#define AR_TxDescId_S  16
+#define AR_TxPtrChkSum 0x0000ffff
+
+#define AR_TxTid       0xf0000000
+#define AR_TxTid_S     28
+
+#define AR_LowRxChain  0x00004000
+
+#define AR_Not_Sounding        0x20000000
+
+#define MAP_ISR_S2_CST          6
+#define MAP_ISR_S2_GTT          6
+#define MAP_ISR_S2_TIM          3
+#define MAP_ISR_S2_CABEND       0
+#define MAP_ISR_S2_DTIMSYNC     7
+#define MAP_ISR_S2_DTIM         7
+#define MAP_ISR_S2_TSFOOR       4
+
+#define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds)
+
+struct ar9003_rxs {
+       u32 ds_info;
+       u32 status1;
+       u32 status2;
+       u32 status3;
+       u32 status4;
+       u32 status5;
+       u32 status6;
+       u32 status7;
+       u32 status8;
+       u32 status9;
+       u32 status10;
+       u32 status11;
+} __packed;
+
+/* Transmit Control Descriptor */
+struct ar9003_txc {
+       u32 info;   /* descriptor information */
+       u32 link;   /* link pointer */
+       u32 data0;  /* data pointer to 1st buffer */
+       u32 ctl3;   /* DMA control 3  */
+       u32 data1;  /* data pointer to 2nd buffer */
+       u32 ctl5;   /* DMA control 5  */
+       u32 data2;  /* data pointer to 3rd buffer */
+       u32 ctl7;   /* DMA control 7  */
+       u32 data3;  /* data pointer to 4th buffer */
+       u32 ctl9;   /* DMA control 9  */
+       u32 ctl10;  /* DMA control 10 */
+       u32 ctl11;  /* DMA control 11 */
+       u32 ctl12;  /* DMA control 12 */
+       u32 ctl13;  /* DMA control 13 */
+       u32 ctl14;  /* DMA control 14 */
+       u32 ctl15;  /* DMA control 15 */
+       u32 ctl16;  /* DMA control 16 */
+       u32 ctl17;  /* DMA control 17 */
+       u32 ctl18;  /* DMA control 18 */
+       u32 ctl19;  /* DMA control 19 */
+       u32 ctl20;  /* DMA control 20 */
+       u32 ctl21;  /* DMA control 21 */
+       u32 ctl22;  /* DMA control 22 */
+       u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */
+} __packed;
+
+struct ar9003_txs {
+       u32 ds_info;
+       u32 status1;
+       u32 status2;
+       u32 status3;
+       u32 status4;
+       u32 status5;
+       u32 status6;
+       u32 status7;
+       u32 status8;
+} __packed;
+
+void ar9003_hw_attach_mac_ops(struct ath_hw *hw);
+void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size);
+void ath9k_hw_addrxbuf_edma(struct ath_hw *ah, u32 rxdp,
+                           enum ath9k_rx_qtype qtype);
+
+int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah,
+                                struct ath_rx_status *rxs,
+                                void *buf_addr);
+void ath9k_hw_reset_txstatus_ring(struct ath_hw *ah);
+void ath9k_hw_setup_statusring(struct ath_hw *ah, void *ts_start,
+                              u32 ts_paddr_start,
+                              u8 size);
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
new file mode 100644 (file)
index 0000000..80431a2
--- /dev/null
@@ -0,0 +1,1134 @@
+/*
+ * Copyright (c) 2010 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 "hw.h"
+#include "ar9003_phy.h"
+
+/**
+ * ar9003_hw_set_channel - set channel on single-chip device
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * This is the function to change channel on single-chip devices, that is
+ * all devices after ar9280.
+ *
+ * This function takes the channel value in MHz and sets
+ * hardware channel value. Assumes writes have been enabled to analog bus.
+ *
+ * Actual Expression,
+ *
+ * For 2GHz channel,
+ * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
+ * (freq_ref = 40MHz)
+ *
+ * For 5GHz channel,
+ * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
+ * (freq_ref = 40MHz/(24>>amodeRefSel))
+ *
+ * For 5GHz channels which are 5MHz spaced,
+ * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
+ * (freq_ref = 40MHz)
+ */
+static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       u16 bMode, fracMode = 0, aModeRefSel = 0;
+       u32 freq, channelSel = 0, reg32 = 0;
+       struct chan_centers centers;
+       int loadSynthChannel;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       freq = centers.synth_center;
+
+       if (freq < 4800) {     /* 2 GHz, fractional mode */
+               channelSel = CHANSEL_2G(freq);
+               /* Set to 2G mode */
+               bMode = 1;
+       } else {
+               channelSel = CHANSEL_5G(freq);
+               /* Doubler is ON, so, divide channelSel by 2. */
+               channelSel >>= 1;
+               /* Set to 5G mode */
+               bMode = 0;
+       }
+
+       /* Enable fractional mode for all channels */
+       fracMode = 1;
+       aModeRefSel = 0;
+       loadSynthChannel = 0;
+
+       reg32 = (bMode << 29);
+       REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
+
+       /* Enable Long shift Select for Synthesizer */
+       REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH4,
+                     AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1);
+
+       /* Program Synth. setting */
+       reg32 = (channelSel << 2) | (fracMode << 30) |
+               (aModeRefSel << 28) | (loadSynthChannel << 31);
+       REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
+
+       /* Toggle Load Synth channel bit */
+       loadSynthChannel = 1;
+       reg32 = (channelSel << 2) | (fracMode << 30) |
+               (aModeRefSel << 28) | (loadSynthChannel << 31);
+       REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32);
+
+       ah->curchan = chan;
+       ah->curchan_rad_index = -1;
+
+       return 0;
+}
+
+/**
+ * ar9003_hw_spur_mitigate - convert baseband spur frequency
+ * @ah: atheros hardware structure
+ * @chan:
+ *
+ * For single-chip solutions. Converts to baseband spur frequency given the
+ * input channel frequency and compute register settings below.
+ *
+ * Spur mitigation for MRC CCK
+ */
+static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
+                                           struct ath9k_channel *chan)
+{
+       u32 spur_freq[4] = { 2420, 2440, 2464, 2480 };
+       int cur_bb_spur, negative = 0, cck_spur_freq;
+       int i;
+
+       /*
+        * Need to verify range +/- 10 MHz in control channel, otherwise spur
+        * is out-of-band and can be ignored.
+        */
+
+       for (i = 0; i < 4; i++) {
+               negative = 0;
+               cur_bb_spur = spur_freq[i] - chan->channel;
+
+               if (cur_bb_spur < 0) {
+                       negative = 1;
+                       cur_bb_spur = -cur_bb_spur;
+               }
+               if (cur_bb_spur < 10) {
+                       cck_spur_freq = (int)((cur_bb_spur << 19) / 11);
+
+                       if (negative == 1)
+                               cck_spur_freq = -cck_spur_freq;
+
+                       cck_spur_freq = cck_spur_freq & 0xfffff;
+
+                       REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL,
+                                     AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7);
+                       REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+                                     AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f);
+                       REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+                                     AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE,
+                                     0x2);
+                       REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+                                     AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT,
+                                     0x1);
+                       REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+                                     AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ,
+                                     cck_spur_freq);
+
+                       return;
+               }
+       }
+
+       REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL,
+                     AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5);
+       REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+                     AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0);
+       REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT,
+                     AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0);
+}
+
+/* Clean all spur register fields */
+static void ar9003_hw_spur_ofdm_clear(struct ath_hw *ah)
+{
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_SPUR_FREQ_SD, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0);
+       REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                     AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0);
+
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0);
+       REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+                     AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+                     AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0);
+       REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+                     AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0);
+       REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+                     AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0);
+       REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+                     AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+                     AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0);
+}
+
+static void ar9003_hw_spur_ofdm(struct ath_hw *ah,
+                               int freq_offset,
+                               int spur_freq_sd,
+                               int spur_delta_phase,
+                               int spur_subchannel_sd)
+{
+       int mask_index = 0;
+
+       /* OFDM Spur mitigation */
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase);
+       REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                     AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, spur_subchannel_sd);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING11,
+                     AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1);
+
+       if (REG_READ_FIELD(ah, AR_PHY_MODE,
+                          AR_PHY_MODE_DYNAMIC) == 0x1)
+               REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                             AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1);
+
+       mask_index = (freq_offset << 4) / 5;
+       if (mask_index < 0)
+               mask_index = mask_index - 1;
+
+       mask_index = mask_index & 0x7f;
+
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING4,
+                     AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+                     AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+                     AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, mask_index);
+       REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+                     AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index);
+       REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK,
+                     AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0xc);
+       REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK,
+                     AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0xc);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A,
+                     AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0);
+       REG_RMW_FIELD(ah, AR_PHY_SPUR_REG,
+                     AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff);
+}
+
+static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah,
+                                    struct ath9k_channel *chan,
+                                    int freq_offset)
+{
+       int spur_freq_sd = 0;
+       int spur_subchannel_sd = 0;
+       int spur_delta_phase = 0;
+
+       if (IS_CHAN_HT40(chan)) {
+               if (freq_offset < 0) {
+                       if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+                                          AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
+                               spur_subchannel_sd = 1;
+                       else
+                               spur_subchannel_sd = 0;
+
+                       spur_freq_sd = ((freq_offset + 10) << 9) / 11;
+
+               } else {
+                       if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+                           AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
+                               spur_subchannel_sd = 0;
+                       else
+                               spur_subchannel_sd = 1;
+
+                       spur_freq_sd = ((freq_offset - 10) << 9) / 11;
+
+               }
+
+               spur_delta_phase = (freq_offset << 17) / 5;
+
+       } else {
+               spur_subchannel_sd = 0;
+               spur_freq_sd = (freq_offset << 9) /11;
+               spur_delta_phase = (freq_offset << 18) / 5;
+       }
+
+       spur_freq_sd = spur_freq_sd & 0x3ff;
+       spur_delta_phase = spur_delta_phase & 0xfffff;
+
+       ar9003_hw_spur_ofdm(ah,
+                           freq_offset,
+                           spur_freq_sd,
+                           spur_delta_phase,
+                           spur_subchannel_sd);
+}
+
+/* Spur mitigation for OFDM */
+static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       int synth_freq;
+       int range = 10;
+       int freq_offset = 0;
+       int mode;
+       u8* spurChansPtr;
+       unsigned int i;
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+
+       if (IS_CHAN_5GHZ(chan)) {
+               spurChansPtr = &(eep->modalHeader5G.spurChans[0]);
+               mode = 0;
+       }
+       else {
+               spurChansPtr = &(eep->modalHeader2G.spurChans[0]);
+               mode = 1;
+       }
+
+       if (spurChansPtr[0] == 0)
+               return; /* No spur in the mode */
+
+       if (IS_CHAN_HT40(chan)) {
+               range = 19;
+               if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL,
+                                  AR_PHY_GC_DYN2040_PRI_CH) == 0x0)
+                       synth_freq = chan->channel - 10;
+               else
+                       synth_freq = chan->channel + 10;
+       } else {
+               range = 10;
+               synth_freq = chan->channel;
+       }
+
+       ar9003_hw_spur_ofdm_clear(ah);
+
+       for (i = 0; spurChansPtr[i] && i < 5; i++) {
+               freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq;
+               if (abs(freq_offset) < range) {
+                       ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
+                       break;
+               }
+       }
+}
+
+static void ar9003_hw_spur_mitigate(struct ath_hw *ah,
+                                   struct ath9k_channel *chan)
+{
+       ar9003_hw_spur_mitigate_mrc_cck(ah, chan);
+       ar9003_hw_spur_mitigate_ofdm(ah, chan);
+}
+
+static u32 ar9003_hw_compute_pll_control(struct ath_hw *ah,
+                                        struct ath9k_channel *chan)
+{
+       u32 pll;
+
+       pll = SM(0x5, AR_RTC_9300_PLL_REFDIV);
+
+       if (chan && IS_CHAN_HALF_RATE(chan))
+               pll |= SM(0x1, AR_RTC_9300_PLL_CLKSEL);
+       else if (chan && IS_CHAN_QUARTER_RATE(chan))
+               pll |= SM(0x2, AR_RTC_9300_PLL_CLKSEL);
+
+       pll |= SM(0x2c, AR_RTC_9300_PLL_DIV);
+
+       return pll;
+}
+
+static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
+                                      struct ath9k_channel *chan)
+{
+       u32 phymode;
+       u32 enableDacFifo = 0;
+
+       enableDacFifo =
+               (REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO);
+
+       /* Enable 11n HT, 20 MHz */
+       phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_WALSH |
+                 AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
+
+       /* Configure baseband for dynamic 20/40 operation */
+       if (IS_CHAN_HT40(chan)) {
+               phymode |= AR_PHY_GC_DYN2040_EN;
+               /* Configure control (primary) channel at +-10MHz */
+               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
+                   (chan->chanmode == CHANNEL_G_HT40PLUS))
+                       phymode |= AR_PHY_GC_DYN2040_PRI_CH;
+
+       }
+
+       /* make sure we preserve INI settings */
+       phymode |= REG_READ(ah, AR_PHY_GEN_CTRL);
+       /* turn off Green Field detection for STA for now */
+       phymode &= ~AR_PHY_GC_GF_DETECT_EN;
+
+       REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);
+
+       /* Configure MAC for 20/40 operation */
+       ath9k_hw_set11nmac2040(ah);
+
+       /* global transmit timeout (25 TUs default)*/
+       REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
+       /* carrier sense timeout */
+       REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
+}
+
+static void ar9003_hw_init_bb(struct ath_hw *ah,
+                             struct ath9k_channel *chan)
+{
+       u32 synthDelay;
+
+       /*
+        * Wait for the frequency synth to settle (synth goes on
+        * via AR_PHY_ACTIVE_EN).  Read the phy active delay register.
+        * Value is in 100ns increments.
+        */
+       synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+       if (IS_CHAN_B(chan))
+               synthDelay = (4 * synthDelay) / 22;
+       else
+               synthDelay /= 10;
+
+       /* Activate the PHY (includes baseband activate + synthesizer on) */
+       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+       /*
+        * There is an issue if the AP starts the calibration before
+        * the base band timeout completes.  This could result in the
+        * rx_clear false triggering.  As a workaround we add delay an
+        * extra BASE_ACTIVATE_DELAY usecs to ensure this condition
+        * does not happen.
+        */
+       udelay(synthDelay + BASE_ACTIVATE_DELAY);
+}
+
+void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
+{
+       switch (rx) {
+       case 0x5:
+               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+                           AR_PHY_SWAP_ALT_CHAIN);
+       case 0x3:
+       case 0x1:
+       case 0x2:
+       case 0x7:
+               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx);
+               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx);
+               break;
+       default:
+               break;
+       }
+
+       REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+       if (tx == 0x5) {
+               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
+                           AR_PHY_SWAP_ALT_CHAIN);
+       }
+}
+
+/*
+ * Override INI values with chip specific configuration.
+ */
+static void ar9003_hw_override_ini(struct ath_hw *ah)
+{
+       u32 val;
+
+       /*
+        * Set the RX_ABORT and RX_DIS and clear it only after
+        * RXE is set for MAC. This prevents frames with
+        * corrupted descriptor status.
+        */
+       REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
+
+       /*
+        * For AR9280 and above, there is a new feature that allows
+        * Multicast search based on both MAC Address and Key ID. By default,
+        * this feature is enabled. But since the driver is not using this
+        * feature, we switch it off; otherwise multicast search based on
+        * MAC addr only will fail.
+        */
+       val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
+       REG_WRITE(ah, AR_PCU_MISC_MODE2,
+                 val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE);
+}
+
+static void ar9003_hw_prog_ini(struct ath_hw *ah,
+                              struct ar5416IniArray *iniArr,
+                              int column)
+{
+       unsigned int i, regWrites = 0;
+
+       /* New INI format: Array may be undefined (pre, core, post arrays) */
+       if (!iniArr->ia_array)
+               return;
+
+       /*
+        * New INI format: Pre, core, and post arrays for a given subsystem
+        * may be modal (> 2 columns) or non-modal (2 columns). Determine if
+        * the array is non-modal and force the column to 1.
+        */
+       if (column >= iniArr->ia_columns)
+               column = 1;
+
+       for (i = 0; i < iniArr->ia_rows; i++) {
+               u32 reg = INI_RA(iniArr, i, 0);
+               u32 val = INI_RA(iniArr, i, column);
+
+               REG_WRITE(ah, reg, val);
+
+               /*
+                * Determine if this is a shift register value, and insert the
+                * configured delay if so.
+                */
+               if (reg >= 0x16000 && reg < 0x17000
+                   && ah->config.analog_shiftreg)
+                       udelay(100);
+
+               DO_DELAY(regWrites);
+       }
+}
+
+static int ar9003_hw_process_ini(struct ath_hw *ah,
+                                struct ath9k_channel *chan)
+{
+       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+       unsigned int regWrites = 0, i;
+       struct ieee80211_channel *channel = chan->chan;
+       u32 modesIndex, freqIndex;
+
+       switch (chan->chanmode) {
+       case CHANNEL_A:
+       case CHANNEL_A_HT20:
+               modesIndex = 1;
+               freqIndex = 1;
+               break;
+       case CHANNEL_A_HT40PLUS:
+       case CHANNEL_A_HT40MINUS:
+               modesIndex = 2;
+               freqIndex = 1;
+               break;
+       case CHANNEL_G:
+       case CHANNEL_G_HT20:
+       case CHANNEL_B:
+               modesIndex = 4;
+               freqIndex = 2;
+               break;
+       case CHANNEL_G_HT40PLUS:
+       case CHANNEL_G_HT40MINUS:
+               modesIndex = 3;
+               freqIndex = 2;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ATH_INI_NUM_SPLIT; i++) {
+               ar9003_hw_prog_ini(ah, &ah->iniSOC[i], modesIndex);
+               ar9003_hw_prog_ini(ah, &ah->iniMac[i], modesIndex);
+               ar9003_hw_prog_ini(ah, &ah->iniBB[i], modesIndex);
+               ar9003_hw_prog_ini(ah, &ah->iniRadio[i], modesIndex);
+       }
+
+       REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites);
+       REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
+
+       /*
+        * For 5GHz channels requiring Fast Clock, apply
+        * different modal values.
+        */
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+               REG_WRITE_ARRAY(&ah->iniModesAdditional,
+                               modesIndex, regWrites);
+
+       ar9003_hw_override_ini(ah);
+       ar9003_hw_set_channel_regs(ah, chan);
+       ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+
+       /* Set TX power */
+       ah->eep_ops->set_txpower(ah, chan,
+                                ath9k_regd_get_ctl(regulatory, chan),
+                                channel->max_antenna_gain * 2,
+                                channel->max_power * 2,
+                                min((u32) MAX_RATE_POWER,
+                                (u32) regulatory->power_limit));
+
+       return 0;
+}
+
+static void ar9003_hw_set_rfmode(struct ath_hw *ah,
+                                struct ath9k_channel *chan)
+{
+       u32 rfMode = 0;
+
+       if (chan == NULL)
+               return;
+
+       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
+               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+
+       if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+               rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
+
+       REG_WRITE(ah, AR_PHY_MODE, rfMode);
+}
+
+static void ar9003_hw_mark_phy_inactive(struct ath_hw *ah)
+{
+       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+}
+
+static void ar9003_hw_set_delta_slope(struct ath_hw *ah,
+                                     struct ath9k_channel *chan)
+{
+       u32 coef_scaled, ds_coef_exp, ds_coef_man;
+       u32 clockMhzScaled = 0x64000000;
+       struct chan_centers centers;
+
+       /*
+        * half and quarter rate can divide the scaled clock by 2 or 4
+        * scale for selected channel bandwidth
+        */
+       if (IS_CHAN_HALF_RATE(chan))
+               clockMhzScaled = clockMhzScaled >> 1;
+       else if (IS_CHAN_QUARTER_RATE(chan))
+               clockMhzScaled = clockMhzScaled >> 2;
+
+       /*
+        * ALGO -> coef = 1e8/fcarrier*fclock/40;
+        * scaled coef to provide precision for this floating calculation
+        */
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+       coef_scaled = clockMhzScaled / centers.synth_center;
+
+       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+                                     &ds_coef_exp);
+
+       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+                     AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
+       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
+                     AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
+
+       /*
+        * For Short GI,
+        * scaled coeff is 9/10 that of normal coeff
+        */
+       coef_scaled = (9 * coef_scaled) / 10;
+
+       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
+                                     &ds_coef_exp);
+
+       /* for short gi */
+       REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA,
+                     AR_PHY_SGI_DSC_MAN, ds_coef_man);
+       REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA,
+                     AR_PHY_SGI_DSC_EXP, ds_coef_exp);
+}
+
+static bool ar9003_hw_rfbus_req(struct ath_hw *ah)
+{
+       REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
+       return ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
+                            AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT);
+}
+
+/*
+ * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN).
+ * Read the phy active delay register. Value is in 100ns increments.
+ */
+static void ar9003_hw_rfbus_done(struct ath_hw *ah)
+{
+       u32 synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
+       if (IS_CHAN_B(ah->curchan))
+               synthDelay = (4 * synthDelay) / 22;
+       else
+               synthDelay /= 10;
+
+       udelay(synthDelay + BASE_ACTIVATE_DELAY);
+
+       REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+}
+
+/*
+ * Set the interrupt and GPIO values so the ISR can disable RF
+ * on a switch signal.  Assumes GPIO port and interrupt polarity
+ * are set prior to call.
+ */
+static void ar9003_hw_enable_rfkill(struct ath_hw *ah)
+{
+       /* Connect rfsilent_bb_l to baseband */
+       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+       /* Set input mux for rfsilent_bb_l to GPIO #0 */
+       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+                   AR_GPIO_INPUT_MUX2_RFSILENT);
+
+       /*
+        * Configure the desired GPIO port for input and
+        * enable baseband rf silence.
+        */
+       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
+       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+
+static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value)
+{
+       u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
+       if (value)
+               v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+       else
+               v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
+       REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
+}
+
+static bool ar9003_hw_ani_control(struct ath_hw *ah,
+                                 enum ath9k_ani_cmd cmd, int param)
+{
+       struct ar5416AniState *aniState = ah->curani;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       switch (cmd & ah->ani_function) {
+       case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
+                       ath_print(common, ATH_DBG_ANI,
+                                 "level out of range (%u > %u)\n",
+                                 level,
+                                 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
+                       return false;
+               }
+
+               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
+                             AR_PHY_DESIRED_SZ_TOT_DES,
+                             ah->totalSizeDesired[level]);
+               REG_RMW_FIELD(ah, AR_PHY_AGC,
+                             AR_PHY_AGC_COARSE_LOW,
+                             ah->coarse_low[level]);
+               REG_RMW_FIELD(ah, AR_PHY_AGC,
+                             AR_PHY_AGC_COARSE_HIGH,
+                             ah->coarse_high[level]);
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRPWR, ah->firpwr[level]);
+
+               if (level > aniState->noiseImmunityLevel)
+                       ah->stats.ast_ani_niup++;
+               else if (level < aniState->noiseImmunityLevel)
+                       ah->stats.ast_ani_nidown++;
+               aniState->noiseImmunityLevel = level;
+               break;
+       }
+       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
+               const int m1ThreshLow[] = { 127, 50 };
+               const int m2ThreshLow[] = { 127, 40 };
+               const int m1Thresh[] = { 127, 0x4d };
+               const int m2Thresh[] = { 127, 0x40 };
+               const int m2CountThr[] = { 31, 16 };
+               const int m2CountThrLow[] = { 63, 48 };
+               u32 on = param ? 1 : 0;
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
+                             m1ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
+                             m2ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M1_THRESH, m1Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2_THRESH, m2Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
+                             AR_PHY_SFCORR_M2COUNT_THR, m2CountThr[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
+                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
+                             m2CountThrLow[on]);
+
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2ThreshLow[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M1_THRESH, m1Thresh[on]);
+               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
+                             AR_PHY_SFCORR_EXT_M2_THRESH, m2Thresh[on]);
+
+               if (on)
+                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
+                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+               else
+                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
+                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
+
+               if (!on != aniState->ofdmWeakSigDetectOff) {
+                       if (on)
+                               ah->stats.ast_ani_ofdmon++;
+                       else
+                               ah->stats.ast_ani_ofdmoff++;
+                       aniState->ofdmWeakSigDetectOff = !on;
+               }
+               break;
+       }
+       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
+               const int weakSigThrCck[] = { 8, 6 };
+               u32 high = param ? 1 : 0;
+
+               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
+                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
+                             weakSigThrCck[high]);
+               if (high != aniState->cckWeakSigThreshold) {
+                       if (high)
+                               ah->stats.ast_ani_cckhigh++;
+                       else
+                               ah->stats.ast_ani_ccklow++;
+                       aniState->cckWeakSigThreshold = high;
+               }
+               break;
+       }
+       case ATH9K_ANI_FIRSTEP_LEVEL:{
+               const int firstep[] = { 0, 4, 8 };
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(firstep)) {
+                       ath_print(common, ATH_DBG_ANI,
+                                 "level out of range (%u > %u)\n",
+                                 level,
+                                 (unsigned) ARRAY_SIZE(firstep));
+                       return false;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
+                             AR_PHY_FIND_SIG_FIRSTEP,
+                             firstep[level]);
+               if (level > aniState->firstepLevel)
+                       ah->stats.ast_ani_stepup++;
+               else if (level < aniState->firstepLevel)
+                       ah->stats.ast_ani_stepdown++;
+               aniState->firstepLevel = level;
+               break;
+       }
+       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
+               const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 };
+               u32 level = param;
+
+               if (level >= ARRAY_SIZE(cycpwrThr1)) {
+                       ath_print(common, ATH_DBG_ANI,
+                                 "level out of range (%u > %u)\n",
+                                 level,
+                                 (unsigned) ARRAY_SIZE(cycpwrThr1));
+                       return false;
+               }
+               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
+                             AR_PHY_TIMING5_CYCPWR_THR1,
+                             cycpwrThr1[level]);
+               if (level > aniState->spurImmunityLevel)
+                       ah->stats.ast_ani_spurup++;
+               else if (level < aniState->spurImmunityLevel)
+                       ah->stats.ast_ani_spurdown++;
+               aniState->spurImmunityLevel = level;
+               break;
+       }
+       case ATH9K_ANI_PRESENT:
+               break;
+       default:
+               ath_print(common, ATH_DBG_ANI,
+                         "invalid cmd %u\n", cmd);
+               return false;
+       }
+
+       ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
+       ath_print(common, ATH_DBG_ANI,
+                 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
+                 "ofdmWeakSigDetectOff=%d\n",
+                 aniState->noiseImmunityLevel,
+                 aniState->spurImmunityLevel,
+                 !aniState->ofdmWeakSigDetectOff);
+       ath_print(common, ATH_DBG_ANI,
+                 "cckWeakSigThreshold=%d, "
+                 "firstepLevel=%d, listenTime=%d\n",
+                 aniState->cckWeakSigThreshold,
+                 aniState->firstepLevel,
+                 aniState->listenTime);
+       ath_print(common, ATH_DBG_ANI,
+               "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
+               aniState->cycleCount,
+               aniState->ofdmPhyErrCount,
+               aniState->cckPhyErrCount);
+
+       return true;
+}
+
+static void ar9003_hw_nf_sanitize_2g(struct ath_hw *ah, s16 *nf)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (*nf > ah->nf_2g_max) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "2 GHz NF (%d) > MAX (%d), "
+                         "correcting to MAX",
+                         *nf, ah->nf_2g_max);
+               *nf = ah->nf_2g_max;
+       } else if (*nf < ah->nf_2g_min) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "2 GHz NF (%d) < MIN (%d), "
+                         "correcting to MIN",
+                         *nf, ah->nf_2g_min);
+               *nf = ah->nf_2g_min;
+       }
+}
+
+static void ar9003_hw_nf_sanitize_5g(struct ath_hw *ah, s16 *nf)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       if (*nf > ah->nf_5g_max) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "5 GHz NF (%d) > MAX (%d), "
+                         "correcting to MAX",
+                         *nf, ah->nf_5g_max);
+               *nf = ah->nf_5g_max;
+       } else if (*nf < ah->nf_5g_min) {
+               ath_print(common, ATH_DBG_CALIBRATE,
+                         "5 GHz NF (%d) < MIN (%d), "
+                         "correcting to MIN",
+                         *nf, ah->nf_5g_min);
+               *nf = ah->nf_5g_min;
+       }
+}
+
+static void ar9003_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
+{
+       if (IS_CHAN_2GHZ(ah->curchan))
+               ar9003_hw_nf_sanitize_2g(ah, nf);
+       else
+               ar9003_hw_nf_sanitize_5g(ah, nf);
+}
+
+static void ar9003_hw_do_getnf(struct ath_hw *ah,
+                             int16_t nfarray[NUM_NF_READINGS])
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       int16_t nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 0] is %d\n", nf);
+       nfarray[0] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 1] is %d\n", nf);
+       nfarray[1] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 2] is %d\n", nf);
+       nfarray[2] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 0] is %d\n", nf);
+       nfarray[3] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 1] is %d\n", nf);
+       nfarray[4] = nf;
+
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+       ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 2] is %d\n", nf);
+       nfarray[5] = nf;
+}
+
+void ar9003_hw_set_nf_limits(struct ath_hw *ah)
+{
+       ah->nf_2g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
+       ah->nf_2g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
+       ah->nf_5g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
+       ah->nf_5g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
+}
+
+/*
+ * Find out which of the RX chains are enabled
+ */
+static u32 ar9003_hw_get_rx_chainmask(struct ath_hw *ah)
+{
+       u32 chain = REG_READ(ah, AR_PHY_RX_CHAINMASK);
+       /*
+        * The bits [2:0] indicate the rx chain mask and are to be
+        * interpreted as follows:
+        * 00x => Only chain 0 is enabled
+        * 01x => Chain 1 and 0 enabled
+        * 1xx => Chain 2,1 and 0 enabled
+        */
+       return chain & 0x7;
+}
+
+static void ar9003_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       struct ath9k_nfcal_hist *h;
+       unsigned i, j;
+       int32_t val;
+       const u32 ar9300_cca_regs[6] = {
+               AR_PHY_CCA_0,
+               AR_PHY_CCA_1,
+               AR_PHY_CCA_2,
+               AR_PHY_EXT_CCA,
+               AR_PHY_EXT_CCA_1,
+               AR_PHY_EXT_CCA_2,
+       };
+       u8 chainmask, rx_chain_status;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       rx_chain_status = ar9003_hw_get_rx_chainmask(ah);
+
+       chainmask = 0x3F;
+       h = ah->nfCalHist;
+
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
+                       val = REG_READ(ah, ar9300_cca_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
+                       REG_WRITE(ah, ar9300_cca_regs[i], val);
+               }
+       }
+
+       /*
+        * Load software filtered NF value into baseband internal minCCApwr
+        * variable.
+        */
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_ENABLE_NF);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+
+       /*
+        * Wait for load to complete, should be fast, a few 10s of us.
+        * The max delay was changed from an original 250us to 10000us
+        * since 250us often results in NF load timeout and causes deaf
+        * condition during stress testing 12/12/2009
+        */
+       for (j = 0; j < 1000; j++) {
+               if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
+                    AR_PHY_AGC_CONTROL_NF) == 0)
+                       break;
+               udelay(10);
+       }
+
+       /*
+        * We timed out waiting for the noisefloor to load, probably due to an
+        * in-progress rx. Simply return here and allow the load plenty of time
+        * to complete before the next calibration interval.  We need to avoid
+        * trying to load -50 (which happens below) while the previous load is
+        * still in progress as this can cause rx deafness. Instead by returning
+        * here, the baseband nf cal will just be capped by our present
+        * noisefloor until the next calibration timer.
+        */
+       if (j == 1000) {
+               ath_print(common, ATH_DBG_ANY, "Timeout while waiting for nf "
+                         "to load: AR_PHY_AGC_CONTROL=0x%x\n",
+                         REG_READ(ah, AR_PHY_AGC_CONTROL));
+               return;
+       }
+
+       /*
+        * Restore maxCCAPower register parameter again so that we're not capped
+        * by the median we just loaded.  This will be initial (and max) value
+        * of next noise floor calibration the baseband does.
+        */
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
+                       val = REG_READ(ah, ar9300_cca_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (-50) << 1) & 0x1ff);
+                       REG_WRITE(ah, ar9300_cca_regs[i], val);
+               }
+       }
+}
+
+void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+
+       priv_ops->rf_set_freq = ar9003_hw_set_channel;
+       priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
+       priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
+       priv_ops->set_channel_regs = ar9003_hw_set_channel_regs;
+       priv_ops->init_bb = ar9003_hw_init_bb;
+       priv_ops->process_ini = ar9003_hw_process_ini;
+       priv_ops->set_rfmode = ar9003_hw_set_rfmode;
+       priv_ops->mark_phy_inactive = ar9003_hw_mark_phy_inactive;
+       priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
+       priv_ops->rfbus_req = ar9003_hw_rfbus_req;
+       priv_ops->rfbus_done = ar9003_hw_rfbus_done;
+       priv_ops->enable_rfkill = ar9003_hw_enable_rfkill;
+       priv_ops->set_diversity = ar9003_hw_set_diversity;
+       priv_ops->ani_control = ar9003_hw_ani_control;
+       priv_ops->do_getnf = ar9003_hw_do_getnf;
+       priv_ops->loadnf = ar9003_hw_loadnf;
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
new file mode 100644 (file)
index 0000000..f08cc8b
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ * Copyright (c) 2002-2010 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.
+ */
+
+#ifndef AR9003_PHY_H
+#define AR9003_PHY_H
+
+/*
+ * Channel Register Map
+ */
+#define AR_CHAN_BASE   0x9800
+
+#define AR_PHY_TIMING1      (AR_CHAN_BASE + 0x0)
+#define AR_PHY_TIMING2      (AR_CHAN_BASE + 0x4)
+#define AR_PHY_TIMING3      (AR_CHAN_BASE + 0x8)
+#define AR_PHY_TIMING4      (AR_CHAN_BASE + 0xc)
+#define AR_PHY_TIMING5      (AR_CHAN_BASE + 0x10)
+#define AR_PHY_TIMING6      (AR_CHAN_BASE + 0x14)
+#define AR_PHY_TIMING11     (AR_CHAN_BASE + 0x18)
+#define AR_PHY_SPUR_REG     (AR_CHAN_BASE + 0x1c)
+#define AR_PHY_RX_IQCAL_CORR_B0    (AR_CHAN_BASE + 0xdc)
+#define AR_PHY_TX_IQCAL_CONTROL_3  (AR_CHAN_BASE + 0xb0)
+
+#define AR_PHY_TIMING11_SPUR_FREQ_SD    0x3FF00000
+#define AR_PHY_TIMING11_SPUR_FREQ_SD_S  20
+
+#define AR_PHY_TIMING11_SPUR_DELTA_PHASE 0x000FFFFF
+#define AR_PHY_TIMING11_SPUR_DELTA_PHASE_S 0
+
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC 0x40000000
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC_S 30
+
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR 0x80000000
+#define AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR_S 31
+
+#define AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT         0x4000000
+#define AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT_S       26
+
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM                         0x20000     /* bins move with freq offset */
+#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM_S                       17
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH            0x000000FF
+#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S          0
+#define AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI                        0x00000100
+#define AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI_S                      8
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL                          0x03FC0000
+#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S                       18
+
+#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN   0x20000000
+#define AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN_S         29
+
+#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN   0x80000000
+#define AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN_S         31
+
+#define AR_PHY_FIND_SIG_LOW  (AR_CHAN_BASE + 0x20)
+
+#define AR_PHY_SFCORR           (AR_CHAN_BASE + 0x24)
+#define AR_PHY_SFCORR_LOW       (AR_CHAN_BASE + 0x28)
+#define AR_PHY_SFCORR_EXT       (AR_CHAN_BASE + 0x2c)
+
+#define AR_PHY_EXT_CCA              (AR_CHAN_BASE + 0x30)
+#define AR_PHY_RADAR_0              (AR_CHAN_BASE + 0x34)
+#define AR_PHY_RADAR_1              (AR_CHAN_BASE + 0x38)
+#define AR_PHY_RADAR_EXT            (AR_CHAN_BASE + 0x3c)
+#define AR_PHY_MULTICHAIN_CTRL      (AR_CHAN_BASE + 0x80)
+#define AR_PHY_PERCHAIN_CSD         (AR_CHAN_BASE + 0x84)
+
+#define AR_PHY_TX_PHASE_RAMP_0      (AR_CHAN_BASE + 0xd0)
+#define AR_PHY_ADC_GAIN_DC_CORR_0   (AR_CHAN_BASE + 0xd4)
+#define AR_PHY_IQ_ADC_MEAS_0_B0     (AR_CHAN_BASE + 0xc0)
+#define AR_PHY_IQ_ADC_MEAS_1_B0     (AR_CHAN_BASE + 0xc4)
+#define AR_PHY_IQ_ADC_MEAS_2_B0     (AR_CHAN_BASE + 0xc8)
+#define AR_PHY_IQ_ADC_MEAS_3_B0     (AR_CHAN_BASE + 0xcc)
+
+/* The following registers changed position from AR9300 1.0 to AR9300 2.0 */
+#define AR_PHY_TX_PHASE_RAMP_0_9300_10      (AR_CHAN_BASE + 0xd0 - 0x10)
+#define AR_PHY_ADC_GAIN_DC_CORR_0_9300_10   (AR_CHAN_BASE + 0xd4 - 0x10)
+#define AR_PHY_IQ_ADC_MEAS_0_B0_9300_10     (AR_CHAN_BASE + 0xc0 + 0x8)
+#define AR_PHY_IQ_ADC_MEAS_1_B0_9300_10     (AR_CHAN_BASE + 0xc4 + 0x8)
+#define AR_PHY_IQ_ADC_MEAS_2_B0_9300_10     (AR_CHAN_BASE + 0xc8 + 0x8)
+#define AR_PHY_IQ_ADC_MEAS_3_B0_9300_10     (AR_CHAN_BASE + 0xcc + 0x8)
+
+#define AR_PHY_TX_CRC               (AR_CHAN_BASE + 0xa0)
+#define AR_PHY_TST_DAC_CONST        (AR_CHAN_BASE + 0xa4)
+#define AR_PHY_SPUR_REPORT_0        (AR_CHAN_BASE + 0xa8)
+#define AR_PHY_CHAN_INFO_TAB_0      (AR_CHAN_BASE + 0x300)
+
+/*
+ * Channel Field Definitions
+ */
+#define AR_PHY_TIMING2_USE_FORCE_PPM    0x00001000
+#define AR_PHY_TIMING2_FORCE_PPM_VAL    0x00000fff
+#define AR_PHY_TIMING3_DSC_MAN      0xFFFE0000
+#define AR_PHY_TIMING3_DSC_MAN_S    17
+#define AR_PHY_TIMING3_DSC_EXP      0x0001E000
+#define AR_PHY_TIMING3_DSC_EXP_S    13
+#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX 0xF000
+#define AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX_S   12
+#define AR_PHY_TIMING4_DO_CAL    0x10000
+
+#define AR_PHY_TIMING4_ENABLE_PILOT_MASK        0x10000000
+#define AR_PHY_TIMING4_ENABLE_PILOT_MASK_S      28
+#define AR_PHY_TIMING4_ENABLE_CHAN_MASK         0x20000000
+#define AR_PHY_TIMING4_ENABLE_CHAN_MASK_S       29
+
+#define AR_PHY_TIMING4_ENABLE_SPUR_FILTER 0x40000000
+#define AR_PHY_TIMING4_ENABLE_SPUR_FILTER_S 30
+#define AR_PHY_TIMING4_ENABLE_SPUR_RSSI 0x80000000
+#define AR_PHY_TIMING4_ENABLE_SPUR_RSSI_S 31
+
+#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
+#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
+#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW  0x00000001
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW    0x00003F00
+#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S  8
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW      0x001FC000
+#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S    14
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW      0x0FE00000
+#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S    21
+#define AR_PHY_SFCORR_M2COUNT_THR    0x0000001F
+#define AR_PHY_SFCORR_M2COUNT_THR_S  0
+#define AR_PHY_SFCORR_M1_THRESH      0x00FE0000
+#define AR_PHY_SFCORR_M1_THRESH_S    17
+#define AR_PHY_SFCORR_M2_THRESH      0x7F000000
+#define AR_PHY_SFCORR_M2_THRESH_S    24
+#define AR_PHY_SFCORR_EXT_M1_THRESH       0x0000007F
+#define AR_PHY_SFCORR_EXT_M1_THRESH_S     0
+#define AR_PHY_SFCORR_EXT_M2_THRESH       0x00003F80
+#define AR_PHY_SFCORR_EXT_M2_THRESH_S     7
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW   0x001FC000
+#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW   0x0FE00000
+#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
+#define AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD 0x10000000
+#define AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD_S 28
+#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S   28
+#define AR_PHY_EXT_CCA_THRESH62 0x007F0000
+#define AR_PHY_EXT_CCA_THRESH62_S       16
+#define AR_PHY_EXT_MINCCA_PWR   0x01FF0000
+#define AR_PHY_EXT_MINCCA_PWR_S 16
+#define AR_PHY_TIMING5_CYCPWR_THR1  0x000000FE
+#define AR_PHY_TIMING5_CYCPWR_THR1_S    1
+#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE  0x00000001
+#define AR_PHY_TIMING5_CYCPWR_THR1_ENABLE_S    0
+#define AR_PHY_TIMING5_CYCPWR_THR1A  0x007F0000
+#define AR_PHY_TIMING5_CYCPWR_THR1A_S    16
+#define AR_PHY_TIMING5_RSSI_THR1A     (0x7F << 16)
+#define AR_PHY_TIMING5_RSSI_THR1A_S   16
+#define AR_PHY_TIMING5_RSSI_THR1A_ENA (0x1 << 15)
+#define AR_PHY_RADAR_0_ENA  0x00000001
+#define AR_PHY_RADAR_0_FFT_ENA  0x80000000
+#define AR_PHY_RADAR_0_INBAND   0x0000003e
+#define AR_PHY_RADAR_0_INBAND_S 1
+#define AR_PHY_RADAR_0_PRSSI    0x00000FC0
+#define AR_PHY_RADAR_0_PRSSI_S  6
+#define AR_PHY_RADAR_0_HEIGHT   0x0003F000
+#define AR_PHY_RADAR_0_HEIGHT_S 12
+#define AR_PHY_RADAR_0_RRSSI    0x00FC0000
+#define AR_PHY_RADAR_0_RRSSI_S  18
+#define AR_PHY_RADAR_0_FIRPWR   0x7F000000
+#define AR_PHY_RADAR_0_FIRPWR_S 24
+#define AR_PHY_RADAR_1_RELPWR_ENA       0x00800000
+#define AR_PHY_RADAR_1_USE_FIR128       0x00400000
+#define AR_PHY_RADAR_1_RELPWR_THRESH    0x003F0000
+#define AR_PHY_RADAR_1_RELPWR_THRESH_S  16
+#define AR_PHY_RADAR_1_BLOCK_CHECK      0x00008000
+#define AR_PHY_RADAR_1_MAX_RRSSI        0x00004000
+#define AR_PHY_RADAR_1_RELSTEP_CHECK    0x00002000
+#define AR_PHY_RADAR_1_RELSTEP_THRESH   0x00001F00
+#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8
+#define AR_PHY_RADAR_1_MAXLEN           0x000000FF
+#define AR_PHY_RADAR_1_MAXLEN_S         0
+#define AR_PHY_RADAR_EXT_ENA            0x00004000
+#define AR_PHY_RADAR_DC_PWR_THRESH      0x007f8000
+#define AR_PHY_RADAR_DC_PWR_THRESH_S    15
+#define AR_PHY_RADAR_LB_DC_CAP          0x7f800000
+#define AR_PHY_RADAR_LB_DC_CAP_S        23
+#define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW (0x3f << 6)
+#define AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW_S   6
+#define AR_PHY_FIND_SIG_LOW_FIRPWR      (0x7f << 12)
+#define AR_PHY_FIND_SIG_LOW_FIRPWR_S    12
+#define AR_PHY_FIND_SIG_LOW_FIRPWR_SIGN_BIT 19
+#define AR_PHY_FIND_SIG_LOW_RELSTEP     0x1f
+#define AR_PHY_FIND_SIG_LOW_RELSTEP_S   0
+#define AR_PHY_FIND_SIG_LOW_RELSTEP_SIGN_BIT 5
+#define AR_PHY_CHAN_INFO_TAB_S2_READ    0x00000008
+#define AR_PHY_CHAN_INFO_TAB_S2_READ_S           3
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF 0x0000007F
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S   0
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF 0x00003F80
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S   7
+#define AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE   0x00004000
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF   0x003f8000
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_Q_COFF_S 15
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF   0x1fc00000
+#define AR_PHY_RX_IQCAL_CORR_LOOPBACK_IQCORR_Q_I_COFF_S 22
+
+/*
+ * MRC Register Map
+ */
+#define AR_MRC_BASE    0x9c00
+
+#define AR_PHY_TIMING_3A       (AR_MRC_BASE + 0x0)
+#define AR_PHY_LDPC_CNTL1      (AR_MRC_BASE + 0x4)
+#define AR_PHY_LDPC_CNTL2      (AR_MRC_BASE + 0x8)
+#define AR_PHY_PILOT_SPUR_MASK (AR_MRC_BASE + 0xc)
+#define AR_PHY_CHAN_SPUR_MASK  (AR_MRC_BASE + 0x10)
+#define AR_PHY_SGI_DELTA       (AR_MRC_BASE + 0x14)
+#define AR_PHY_ML_CNTL_1       (AR_MRC_BASE + 0x18)
+#define AR_PHY_ML_CNTL_2       (AR_MRC_BASE + 0x1c)
+#define AR_PHY_TST_ADC         (AR_MRC_BASE + 0x20)
+
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A              0x00000FE0
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A_S    5
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A                  0x1F
+#define AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A_S                0
+
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A        0x00000FE0
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A_S      5
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A            0x1F
+#define AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A_S         0
+
+/*
+ * MRC Feild Definitions
+ */
+#define AR_PHY_SGI_DSC_MAN   0x0007FFF0
+#define AR_PHY_SGI_DSC_MAN_S 4
+#define AR_PHY_SGI_DSC_EXP   0x0000000F
+#define AR_PHY_SGI_DSC_EXP_S 0
+/*
+ * BBB Register Map
+ */
+#define AR_BBB_BASE    0x9d00
+
+/*
+ * AGC Register Map
+ */
+#define AR_AGC_BASE    0x9e00
+
+#define AR_PHY_SETTLING         (AR_AGC_BASE + 0x0)
+#define AR_PHY_FORCEMAX_GAINS_0 (AR_AGC_BASE + 0x4)
+#define AR_PHY_GAINS_MINOFF0    (AR_AGC_BASE + 0x8)
+#define AR_PHY_DESIRED_SZ       (AR_AGC_BASE + 0xc)
+#define AR_PHY_FIND_SIG         (AR_AGC_BASE + 0x10)
+#define AR_PHY_AGC              (AR_AGC_BASE + 0x14)
+#define AR_PHY_EXT_ATTEN_CTL_0  (AR_AGC_BASE + 0x18)
+#define AR_PHY_CCA_0            (AR_AGC_BASE + 0x1c)
+#define AR_PHY_EXT_CCA0         (AR_AGC_BASE + 0x20)
+#define AR_PHY_RESTART          (AR_AGC_BASE + 0x24)
+#define AR_PHY_MC_GAIN_CTRL     (AR_AGC_BASE + 0x28)
+#define AR_PHY_EXTCHN_PWRTHR1   (AR_AGC_BASE + 0x2c)
+#define AR_PHY_EXT_CHN_WIN      (AR_AGC_BASE + 0x30)
+#define AR_PHY_20_40_DET_THR    (AR_AGC_BASE + 0x34)
+#define AR_PHY_RIFS_SRCH        (AR_AGC_BASE + 0x38)
+#define AR_PHY_PEAK_DET_CTRL_1  (AR_AGC_BASE + 0x3c)
+#define AR_PHY_PEAK_DET_CTRL_2  (AR_AGC_BASE + 0x40)
+#define AR_PHY_RX_GAIN_BOUNDS_1 (AR_AGC_BASE + 0x44)
+#define AR_PHY_RX_GAIN_BOUNDS_2 (AR_AGC_BASE + 0x48)
+#define AR_PHY_RSSI_0           (AR_AGC_BASE + 0x180)
+#define AR_PHY_SPUR_CCK_REP0    (AR_AGC_BASE + 0x184)
+#define AR_PHY_CCK_DETECT       (AR_AGC_BASE + 0x1c0)
+#define AR_PHY_DAG_CTRLCCK      (AR_AGC_BASE + 0x1c4)
+#define AR_PHY_IQCORR_CTRL_CCK  (AR_AGC_BASE + 0x1c8)
+
+#define AR_PHY_CCK_SPUR_MIT     (AR_AGC_BASE + 0x1cc)
+#define AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR                           0x000001fe
+#define AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR_S                                  1
+#define AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE                        0x60000000
+#define AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE_S                              29
+#define AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT                        0x00000001
+#define AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT_S                               0
+#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ                           0x1ffffe00
+#define AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ_S                                  9
+
+#define AR_PHY_RX_OCGAIN        (AR_AGC_BASE + 0x200)
+
+#define AR_PHY_CCA_NOM_VAL_9300_2GHZ          -110
+#define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125
+#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100
+
+/*
+ * AGC Field Definitions
+ */
+#define AR_PHY_EXT_ATTEN_CTL_RXTX_MARGIN    0x00FC0000
+#define AR_PHY_EXT_ATTEN_CTL_RXTX_MARGIN_S  18
+#define AR_PHY_EXT_ATTEN_CTL_BSW_MARGIN     0x00003C00
+#define AR_PHY_EXT_ATTEN_CTL_BSW_MARGIN_S   10
+#define AR_PHY_EXT_ATTEN_CTL_BSW_ATTEN      0x0000001F
+#define AR_PHY_EXT_ATTEN_CTL_BSW_ATTEN_S    0
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_MARGIN     0x003E0000
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_MARGIN_S   17
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN     0x0001F000
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN_S   12
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_DB         0x00000FC0
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN2_DB_S       6
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB         0x0000003F
+#define AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB_S       0
+#define AR_PHY_RXGAIN_TXRX_ATTEN    0x0003F000
+#define AR_PHY_RXGAIN_TXRX_ATTEN_S  12
+#define AR_PHY_RXGAIN_TXRX_RF_MAX   0x007C0000
+#define AR_PHY_RXGAIN_TXRX_RF_MAX_S 18
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN    0x00003F80
+#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S  7
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN   0x001FC000
+#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14
+#define AR_PHY_SETTLING_SWITCH  0x00003F80
+#define AR_PHY_SETTLING_SWITCH_S    7
+#define AR_PHY_DESIRED_SZ_ADC       0x000000FF
+#define AR_PHY_DESIRED_SZ_ADC_S     0
+#define AR_PHY_DESIRED_SZ_PGA       0x0000FF00
+#define AR_PHY_DESIRED_SZ_PGA_S     8
+#define AR_PHY_DESIRED_SZ_TOT_DES   0x0FF00000
+#define AR_PHY_DESIRED_SZ_TOT_DES_S 20
+#define AR_PHY_MINCCA_PWR       0x1FF00000
+#define AR_PHY_MINCCA_PWR_S     20
+#define AR_PHY_CCA_THRESH62     0x0007F000
+#define AR_PHY_CCA_THRESH62_S   12
+#define AR9280_PHY_MINCCA_PWR       0x1FF00000
+#define AR9280_PHY_MINCCA_PWR_S     20
+#define AR9280_PHY_CCA_THRESH62     0x000FF000
+#define AR9280_PHY_CCA_THRESH62_S   12
+#define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
+#define AR_PHY_EXT_CCA0_THRESH62_S  0
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
+#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0
+#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S         6
+#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV    0x2000
+
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR  0x00000200
+#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR_S  9
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR 0x0001FC00
+#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
+
+#define AR_PHY_RIFS_INIT_DELAY         0x3ff0000
+#define AR_PHY_AGC_COARSE_LOW       0x00007F80
+#define AR_PHY_AGC_COARSE_LOW_S     7
+#define AR_PHY_AGC_COARSE_HIGH      0x003F8000
+#define AR_PHY_AGC_COARSE_HIGH_S    15
+#define AR_PHY_AGC_COARSE_PWR_CONST 0x0000007F
+#define AR_PHY_AGC_COARSE_PWR_CONST_S   0
+#define AR_PHY_FIND_SIG_FIRSTEP  0x0003F000
+#define AR_PHY_FIND_SIG_FIRSTEP_S        12
+#define AR_PHY_FIND_SIG_FIRPWR   0x03FC0000
+#define AR_PHY_FIND_SIG_FIRPWR_S         18
+#define AR_PHY_FIND_SIG_FIRPWR_SIGN_BIT  25
+#define AR_PHY_FIND_SIG_RELPWR   (0x1f << 6)
+#define AR_PHY_FIND_SIG_RELPWR_S          6
+#define AR_PHY_FIND_SIG_RELPWR_SIGN_BIT  11
+#define AR_PHY_FIND_SIG_RELSTEP        0x1f
+#define AR_PHY_FIND_SIG_RELSTEP_S         0
+#define AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT  5
+#define AR_PHY_RESTART_DIV_GC   0x001C0000
+#define AR_PHY_RESTART_DIV_GC_S 18
+#define AR_PHY_RESTART_ENA      0x01
+#define AR_PHY_DC_RESTART_DIS   0x40000000
+
+#define AR_PHY_TPC_OLPC_GAIN_DELTA_PAL_ON       0xFF000000
+#define AR_PHY_TPC_OLPC_GAIN_DELTA_PAL_ON_S     24
+#define AR_PHY_TPC_OLPC_GAIN_DELTA              0x00FF0000
+#define AR_PHY_TPC_OLPC_GAIN_DELTA_S            16
+
+#define AR_PHY_TPC_6_ERROR_EST_MODE             0x03000000
+#define AR_PHY_TPC_6_ERROR_EST_MODE_S           24
+
+/*
+ * SM Register Map
+ */
+#define AR_SM_BASE     0xa200
+
+#define AR_PHY_D2_CHIP_ID        (AR_SM_BASE + 0x0)
+#define AR_PHY_GEN_CTRL          (AR_SM_BASE + 0x4)
+#define AR_PHY_MODE              (AR_SM_BASE + 0x8)
+#define AR_PHY_ACTIVE            (AR_SM_BASE + 0xc)
+#define AR_PHY_SPUR_MASK_A       (AR_SM_BASE + 0x20)
+#define AR_PHY_SPUR_MASK_B       (AR_SM_BASE + 0x24)
+#define AR_PHY_SPECTRAL_SCAN     (AR_SM_BASE + 0x28)
+#define AR_PHY_RADAR_BW_FILTER   (AR_SM_BASE + 0x2c)
+#define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30)
+#define AR_PHY_MAX_RX_LEN        (AR_SM_BASE + 0x34)
+#define AR_PHY_FRAME_CTL         (AR_SM_BASE + 0x38)
+#define AR_PHY_RFBUS_REQ         (AR_SM_BASE + 0x3c)
+#define AR_PHY_RFBUS_GRANT       (AR_SM_BASE + 0x40)
+#define AR_PHY_RIFS              (AR_SM_BASE + 0x44)
+#define AR_PHY_RX_CLR_DELAY      (AR_SM_BASE + 0x50)
+#define AR_PHY_RX_DELAY          (AR_SM_BASE + 0x54)
+
+#define AR_PHY_XPA_TIMING_CTL    (AR_SM_BASE + 0x64)
+#define AR_PHY_MISC_PA_CTL       (AR_SM_BASE + 0x80)
+#define AR_PHY_SWITCH_CHAIN_0    (AR_SM_BASE + 0x84)
+#define AR_PHY_SWITCH_COM        (AR_SM_BASE + 0x88)
+#define AR_PHY_SWITCH_COM_2      (AR_SM_BASE + 0x8c)
+#define AR_PHY_RX_CHAINMASK      (AR_SM_BASE + 0xa0)
+#define AR_PHY_CAL_CHAINMASK     (AR_SM_BASE + 0xc0)
+#define AR_PHY_CALMODE           (AR_SM_BASE + 0xc8)
+#define AR_PHY_FCAL_1            (AR_SM_BASE + 0xcc)
+#define AR_PHY_FCAL_2_0          (AR_SM_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_0    (AR_SM_BASE + 0xd4)
+#define AR_PHY_CL_CAL_CTL        (AR_SM_BASE + 0xd8)
+#define AR_PHY_CL_TAB_0          (AR_SM_BASE + 0x100)
+#define AR_PHY_SYNTH_CONTROL     (AR_SM_BASE + 0x140)
+#define AR_PHY_ADDAC_CLK_SEL     (AR_SM_BASE + 0x144)
+#define AR_PHY_PLL_CTL           (AR_SM_BASE + 0x148)
+#define AR_PHY_ANALOG_SWAP       (AR_SM_BASE + 0x14c)
+#define AR_PHY_ADDAC_PARA_CTL    (AR_SM_BASE + 0x150)
+#define AR_PHY_XPA_CFG           (AR_SM_BASE + 0x158)
+
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A           0x0001FC00
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A_S         10
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A                       0x3FF
+#define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S                     0
+
+#define AR_PHY_TEST              (AR_SM_BASE + 0x160)
+
+#define AR_PHY_TEST_BBB_OBS_SEL       0x780000
+#define AR_PHY_TEST_BBB_OBS_SEL_S     19
+
+#define AR_PHY_TEST_RX_OBS_SEL_BIT5_S 23
+#define AR_PHY_TEST_RX_OBS_SEL_BIT5   (1 << AR_PHY_TEST_RX_OBS_SEL_BIT5_S)
+
+#define AR_PHY_TEST_CHAIN_SEL      0xC0000000
+#define AR_PHY_TEST_CHAIN_SEL_S    30
+
+#define AR_PHY_TEST_CTL_STATUS   (AR_SM_BASE + 0x164)
+#define AR_PHY_TEST_CTL_TSTDAC_EN         0x1
+#define AR_PHY_TEST_CTL_TSTDAC_EN_S       0
+#define AR_PHY_TEST_CTL_TX_OBS_SEL        0x1C
+#define AR_PHY_TEST_CTL_TX_OBS_SEL_S      2
+#define AR_PHY_TEST_CTL_TX_OBS_MUX_SEL    0x60
+#define AR_PHY_TEST_CTL_TX_OBS_MUX_SEL_S  5
+#define AR_PHY_TEST_CTL_TSTADC_EN         0x100
+#define AR_PHY_TEST_CTL_TSTADC_EN_S       8
+#define AR_PHY_TEST_CTL_RX_OBS_SEL        0x3C00
+#define AR_PHY_TEST_CTL_RX_OBS_SEL_S      10
+
+
+#define AR_PHY_TSTDAC            (AR_SM_BASE + 0x168)
+
+#define AR_PHY_CHAN_STATUS       (AR_SM_BASE + 0x16c)
+#define AR_PHY_CHAN_INFO_MEMORY  (AR_SM_BASE + 0x170)
+#define AR_PHY_CHNINFO_NOISEPWR  (AR_SM_BASE + 0x174)
+#define AR_PHY_CHNINFO_GAINDIFF  (AR_SM_BASE + 0x178)
+#define AR_PHY_CHNINFO_FINETIM   (AR_SM_BASE + 0x17c)
+#define AR_PHY_CHAN_INFO_GAIN_0  (AR_SM_BASE + 0x180)
+#define AR_PHY_SCRAMBLER_SEED    (AR_SM_BASE + 0x190)
+#define AR_PHY_CCK_TX_CTRL       (AR_SM_BASE + 0x194)
+
+#define AR_PHY_HEAVYCLIP_CTL     (AR_SM_BASE + 0x1a4)
+#define AR_PHY_HEAVYCLIP_20      (AR_SM_BASE + 0x1a8)
+#define AR_PHY_HEAVYCLIP_40      (AR_SM_BASE + 0x1ac)
+#define AR_PHY_ILLEGAL_TXRATE    (AR_SM_BASE + 0x1b0)
+
+#define AR_PHY_PWRTX_MAX         (AR_SM_BASE + 0x1f0)
+#define AR_PHY_POWER_TX_SUB      (AR_SM_BASE + 0x1f4)
+
+#define AR_PHY_TPC_4_B0          (AR_SM_BASE + 0x204)
+#define AR_PHY_TPC_5_B0          (AR_SM_BASE + 0x208)
+#define AR_PHY_TPC_6_B0          (AR_SM_BASE + 0x20c)
+#define AR_PHY_TPC_11_B0         (AR_SM_BASE + 0x220)
+#define AR_PHY_TPC_18            (AR_SM_BASE + 0x23c)
+#define AR_PHY_TPC_19            (AR_SM_BASE + 0x240)
+
+#define AR_PHY_TX_FORCED_GAIN    (AR_SM_BASE + 0x258)
+
+#define AR_PHY_PDADC_TAB_0       (AR_SM_BASE + 0x280)
+
+#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + 0x448)
+#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + 0x440)
+#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + 0x48c)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0    (AR_SM_BASE + 0x450)
+
+#define AR_PHY_PANIC_WD_STATUS      (AR_SM_BASE + 0x5c0)
+#define AR_PHY_PANIC_WD_CTL_1       (AR_SM_BASE + 0x5c4)
+#define AR_PHY_PANIC_WD_CTL_2       (AR_SM_BASE + 0x5c8)
+#define AR_PHY_BT_CTL               (AR_SM_BASE + 0x5cc)
+#define AR_PHY_ONLY_WARMRESET       (AR_SM_BASE + 0x5d0)
+#define AR_PHY_ONLY_CTL             (AR_SM_BASE + 0x5d4)
+#define AR_PHY_ECO_CTRL             (AR_SM_BASE + 0x5dc)
+#define AR_PHY_BB_THERM_ADC_1       (AR_SM_BASE + 0x248)
+
+#define AR_PHY_65NM_CH0_SYNTH4      0x1608c
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT   0x00000002
+#define AR_PHY_SYNTH4_LONG_SHIFT_SELECT_S 1
+#define AR_PHY_65NM_CH0_SYNTH7      0x16098
+#define AR_PHY_65NM_CH0_BIAS1       0x160c0
+#define AR_PHY_65NM_CH0_BIAS2       0x160c4
+#define AR_PHY_65NM_CH0_BIAS4       0x160cc
+#define AR_PHY_65NM_CH0_RXTX4       0x1610c
+#define AR_PHY_65NM_CH0_THERM       0x16290
+
+#define AR_PHY_65NM_CH0_THERM_LOCAL   0x80000000
+#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
+#define AR_PHY_65NM_CH0_THERM_START   0x20000000
+#define AR_PHY_65NM_CH0_THERM_START_S 29
+#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT   0x0000ff00
+#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
+
+#define AR_PHY_65NM_CH0_RXTX1       0x16100
+#define AR_PHY_65NM_CH0_RXTX2       0x16104
+#define AR_PHY_65NM_CH1_RXTX1       0x16500
+#define AR_PHY_65NM_CH1_RXTX2       0x16504
+#define AR_PHY_65NM_CH2_RXTX1       0x16900
+#define AR_PHY_65NM_CH2_RXTX2       0x16904
+
+#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT         0x00380000
+#define AR_PHY_RX1DB_BIQUAD_LONG_SHIFT_S       19
+#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT         0x00c00000
+#define AR_PHY_RX6DB_BIQUAD_LONG_SHIFT_S       22
+#define AR_PHY_LNAGAIN_LONG_SHIFT              0xe0000000
+#define AR_PHY_LNAGAIN_LONG_SHIFT_S            29
+#define AR_PHY_MXRGAIN_LONG_SHIFT              0x03000000
+#define AR_PHY_MXRGAIN_LONG_SHIFT_S            24
+#define AR_PHY_VGAGAIN_LONG_SHIFT              0x1c000000
+#define AR_PHY_VGAGAIN_LONG_SHIFT_S            26
+#define AR_PHY_SCFIR_GAIN_LONG_SHIFT           0x00000001
+#define AR_PHY_SCFIR_GAIN_LONG_SHIFT_S         0
+#define AR_PHY_MANRXGAIN_LONG_SHIFT            0x00000002
+#define AR_PHY_MANRXGAIN_LONG_SHIFT_S          1
+
+/*
+ * SM Field Definitions
+ */
+#define AR_PHY_CL_CAL_ENABLE          0x00000002
+#define AR_PHY_PARALLEL_CAL_ENABLE    0x00000001
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE   0x00400000
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22
+
+#define AR_PHY_ADDAC_PARACTL_OFF_PWDADC 0x00008000
+
+#define AR_PHY_FCAL20_CAP_STATUS_0    0x01f00000
+#define AR_PHY_FCAL20_CAP_STATUS_0_S  20
+
+#define AR_PHY_RFBUS_REQ_EN     0x00000001  /* request for RF bus */
+#define AR_PHY_RFBUS_GRANT_EN   0x00000001  /* RF bus granted */
+#define AR_PHY_GC_TURBO_MODE       0x00000001  /* set turbo mode bits */
+#define AR_PHY_GC_TURBO_SHORT      0x00000002  /* set short symbols to turbo mode setting */
+#define AR_PHY_GC_DYN2040_EN       0x00000004  /* enable dyn 20/40 mode */
+#define AR_PHY_GC_DYN2040_PRI_ONLY 0x00000008  /* dyn 20/40 - primary only */
+#define AR_PHY_GC_DYN2040_PRI_CH   0x00000010  /* dyn 20/40 - primary ch offset (0=+10MHz, 1=-10MHz)*/
+#define AR_PHY_GC_DYN2040_PRI_CH_S 4
+#define AR_PHY_GC_DYN2040_EXT_CH   0x00000020  /* dyn 20/40 - ext ch spacing (0=20MHz/ 1=25MHz) */
+#define AR_PHY_GC_HT_EN            0x00000040  /* ht enable */
+#define AR_PHY_GC_SHORT_GI_40      0x00000080  /* allow short GI for HT 40 */
+#define AR_PHY_GC_WALSH            0x00000100  /* walsh spatial spreading for 2 chains,2 streams TX */
+#define AR_PHY_GC_SINGLE_HT_LTF1   0x00000200  /* single length (4us) 1st HT long training symbol */
+#define AR_PHY_GC_GF_DETECT_EN     0x00000400  /* enable Green Field detection. Only affects rx, not tx */
+#define AR_PHY_GC_ENABLE_DAC_FIFO  0x00000800  /* fifo between bb and dac */
+#define AR_PHY_RX_DELAY_DELAY      0x00003FFF  /* delay from wakeup to rx ena */
+
+#define AR_PHY_CALMODE_IQ           0x00000000
+#define AR_PHY_CALMODE_ADC_GAIN     0x00000001
+#define AR_PHY_CALMODE_ADC_DC_PER   0x00000002
+#define AR_PHY_CALMODE_ADC_DC_INIT  0x00000003
+#define AR_PHY_SWAP_ALT_CHAIN       0x00000040
+#define AR_PHY_MODE_OFDM            0x00000000
+#define AR_PHY_MODE_CCK             0x00000001
+#define AR_PHY_MODE_DYNAMIC         0x00000004
+#define AR_PHY_MODE_DYNAMIC_S       2
+#define AR_PHY_MODE_HALF            0x00000020
+#define AR_PHY_MODE_QUARTER         0x00000040
+#define AR_PHY_MAC_CLK_MODE         0x00000080
+#define AR_PHY_MODE_DYN_CCK_DISABLE 0x00000100
+#define AR_PHY_MODE_SVD_HALF        0x00000200
+#define AR_PHY_ACTIVE_EN    0x00000001
+#define AR_PHY_ACTIVE_DIS   0x00000000
+#define AR_PHY_FORCE_XPA_CFG    0x000000001
+#define AR_PHY_FORCE_XPA_CFG_S  0
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF    0xFF000000
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF_S  24
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF    0x00FF0000
+#define AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF_S  16
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON      0x0000FF00
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON_S    8
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON      0x000000FF
+#define AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON_S    0
+#define AR_PHY_TX_END_TO_A2_RX_ON       0x00FF0000
+#define AR_PHY_TX_END_TO_A2_RX_ON_S     16
+#define AR_PHY_TX_END_DATA_START  0x000000FF
+#define AR_PHY_TX_END_DATA_START_S  0
+#define AR_PHY_TX_END_PA_ON       0x0000FF00
+#define AR_PHY_TX_END_PA_ON_S       8
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP   0x0000000F
+#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S     0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1    0x000003F0
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S  4
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2    0x0000FC00
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S  10
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3    0x003F0000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S  16
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4    0x0FC00000
+#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S  22
+#define AR_PHY_TPCRG1_NUM_PD_GAIN   0x0000c000
+#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14
+#define AR_PHY_TPCRG1_PD_GAIN_1    0x00030000
+#define AR_PHY_TPCRG1_PD_GAIN_1_S  16
+#define AR_PHY_TPCRG1_PD_GAIN_2    0x000C0000
+#define AR_PHY_TPCRG1_PD_GAIN_2_S  18
+#define AR_PHY_TPCRG1_PD_GAIN_3    0x00300000
+#define AR_PHY_TPCRG1_PD_GAIN_3_S  20
+#define AR_PHY_TPCGR1_FORCED_DAC_GAIN   0x0000003e
+#define AR_PHY_TPCGR1_FORCED_DAC_GAIN_S 1
+#define AR_PHY_TPCGR1_FORCE_DAC_GAIN    0x00000001
+#define AR_PHY_TXGAIN_FORCE               0x00000001
+#define AR_PHY_TXGAIN_FORCED_PADVGNRA     0x00003c00
+#define AR_PHY_TXGAIN_FORCED_PADVGNRA_S   10
+#define AR_PHY_TXGAIN_FORCED_PADVGNRB     0x0003c000
+#define AR_PHY_TXGAIN_FORCED_PADVGNRB_S   14
+#define AR_PHY_TXGAIN_FORCED_PADVGNRD     0x00c00000
+#define AR_PHY_TXGAIN_FORCED_PADVGNRD_S   22
+#define AR_PHY_TXGAIN_FORCED_TXMXRGAIN    0x000003c0
+#define AR_PHY_TXGAIN_FORCED_TXMXRGAIN_S  6
+#define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN  0x0000000e
+#define AR_PHY_TXGAIN_FORCED_TXBB1DBGAIN_S 1
+
+#define AR_PHY_POWER_TX_RATE1   0x9934
+#define AR_PHY_POWER_TX_RATE2   0x9938
+#define AR_PHY_POWER_TX_RATE_MAX    0x993c
+#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
+#define PHY_AGC_CLR             0x10000000
+#define RFSILENT_BB             0x00002000
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_PPM_MASK          0xFFF
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_PPM_SIGNED_BIT    0x800
+#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT         320
+#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK         0x0001
+#define AR_PHY_RX_DELAY_DELAY   0x00003FFF
+#define AR_PHY_CCK_TX_CTRL_JAPAN    0x00000010
+#define AR_PHY_SPECTRAL_SCAN_ENABLE         0x00000001
+#define AR_PHY_SPECTRAL_SCAN_ENABLE_S       0
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE         0x00000002
+#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S       1
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD     0x000000F0
+#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S   4
+#define AR_PHY_SPECTRAL_SCAN_PERIOD         0x0000FF00
+#define AR_PHY_SPECTRAL_SCAN_PERIOD_S       8
+#define AR_PHY_SPECTRAL_SCAN_COUNT          0x00FF0000
+#define AR_PHY_SPECTRAL_SCAN_COUNT_S        16
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT   0x01000000
+#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+#define AR_PHY_CHANNEL_STATUS_RX_CLEAR      0x00000004
+#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT             0x01fc0000
+#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S                   18
+#define AR_PHY_TX_IQCAL_START_DO_CAL        0x00000001
+#define AR_PHY_TX_IQCAL_START_DO_CAL_S      0
+
+#define AR_PHY_TX_IQCAL_STATUS_FAILED    0x00000001
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE      0x00003fff
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE_S    0
+
+#define AR_PHY_TPC_18_THERM_CAL_VALUE           0xff
+#define AR_PHY_TPC_18_THERM_CAL_VALUE_S         0
+#define AR_PHY_TPC_19_ALPHA_THERM               0xff
+#define AR_PHY_TPC_19_ALPHA_THERM_S             0
+
+#define AR_PHY_65NM_CH0_RXTX4_THERM_ON          0x10000000
+#define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S        28
+
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM        0x000000ff
+#define AR_PHY_BB_THERM_ADC_1_INIT_THERM_S      0
+
+/*
+ * Channel 1 Register Map
+ */
+#define AR_CHAN1_BASE  0xa800
+
+#define AR_PHY_EXT_CCA_1            (AR_CHAN1_BASE + 0x30)
+#define AR_PHY_TX_PHASE_RAMP_1      (AR_CHAN1_BASE + 0xd0)
+#define AR_PHY_ADC_GAIN_DC_CORR_1   (AR_CHAN1_BASE + 0xd4)
+
+#define AR_PHY_SPUR_REPORT_1        (AR_CHAN1_BASE + 0xa8)
+#define AR_PHY_CHAN_INFO_TAB_1      (AR_CHAN1_BASE + 0x300)
+#define AR_PHY_RX_IQCAL_CORR_B1     (AR_CHAN1_BASE + 0xdc)
+
+/*
+ * Channel 1 Field Definitions
+ */
+#define AR_PHY_CH1_EXT_MINCCA_PWR   0x01FF0000
+#define AR_PHY_CH1_EXT_MINCCA_PWR_S 16
+
+/*
+ * AGC 1 Register Map
+ */
+#define AR_AGC1_BASE   0xae00
+
+#define AR_PHY_FORCEMAX_GAINS_1      (AR_AGC1_BASE + 0x4)
+#define AR_PHY_EXT_ATTEN_CTL_1       (AR_AGC1_BASE + 0x18)
+#define AR_PHY_CCA_1                 (AR_AGC1_BASE + 0x1c)
+#define AR_PHY_CCA_CTRL_1            (AR_AGC1_BASE + 0x20)
+#define AR_PHY_RSSI_1                (AR_AGC1_BASE + 0x180)
+#define AR_PHY_SPUR_CCK_REP_1        (AR_AGC1_BASE + 0x184)
+#define AR_PHY_RX_OCGAIN_2           (AR_AGC1_BASE + 0x200)
+
+/*
+ * AGC 1 Field Definitions
+ */
+#define AR_PHY_CH1_MINCCA_PWR   0x1FF00000
+#define AR_PHY_CH1_MINCCA_PWR_S 20
+
+/*
+ * SM 1 Register Map
+ */
+#define AR_SM1_BASE    0xb200
+
+#define AR_PHY_SWITCH_CHAIN_1    (AR_SM1_BASE + 0x84)
+#define AR_PHY_FCAL_2_1          (AR_SM1_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_1    (AR_SM1_BASE + 0xd4)
+#define AR_PHY_CL_TAB_1          (AR_SM1_BASE + 0x100)
+#define AR_PHY_CHAN_INFO_GAIN_1  (AR_SM1_BASE + 0x180)
+#define AR_PHY_TPC_4_B1          (AR_SM1_BASE + 0x204)
+#define AR_PHY_TPC_5_B1          (AR_SM1_BASE + 0x208)
+#define AR_PHY_TPC_6_B1          (AR_SM1_BASE + 0x20c)
+#define AR_PHY_TPC_11_B1         (AR_SM1_BASE + 0x220)
+#define AR_PHY_PDADC_TAB_1       (AR_SM1_BASE + 0x240)
+#define AR_PHY_TX_IQCAL_STATUS_B1   (AR_SM1_BASE + 0x48c)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B1    (AR_SM1_BASE + 0x450)
+
+/*
+ * Channel 2 Register Map
+ */
+#define AR_CHAN2_BASE  0xb800
+
+#define AR_PHY_EXT_CCA_2            (AR_CHAN2_BASE + 0x30)
+#define AR_PHY_TX_PHASE_RAMP_2      (AR_CHAN2_BASE + 0xd0)
+#define AR_PHY_ADC_GAIN_DC_CORR_2   (AR_CHAN2_BASE + 0xd4)
+
+#define AR_PHY_SPUR_REPORT_2        (AR_CHAN2_BASE + 0xa8)
+#define AR_PHY_CHAN_INFO_TAB_2      (AR_CHAN2_BASE + 0x300)
+#define AR_PHY_RX_IQCAL_CORR_B2     (AR_CHAN2_BASE + 0xdc)
+
+/*
+ * Channel 2 Field Definitions
+ */
+#define AR_PHY_CH2_EXT_MINCCA_PWR   0x01FF0000
+#define AR_PHY_CH2_EXT_MINCCA_PWR_S 16
+/*
+ * AGC 2 Register Map
+ */
+#define AR_AGC2_BASE   0xbe00
+
+#define AR_PHY_FORCEMAX_GAINS_2      (AR_AGC2_BASE + 0x4)
+#define AR_PHY_EXT_ATTEN_CTL_2       (AR_AGC2_BASE + 0x18)
+#define AR_PHY_CCA_2                 (AR_AGC2_BASE + 0x1c)
+#define AR_PHY_CCA_CTRL_2            (AR_AGC2_BASE + 0x20)
+#define AR_PHY_RSSI_2                (AR_AGC2_BASE + 0x180)
+
+/*
+ * AGC 2 Field Definitions
+ */
+#define AR_PHY_CH2_MINCCA_PWR   0x1FF00000
+#define AR_PHY_CH2_MINCCA_PWR_S 20
+
+/*
+ * SM 2 Register Map
+ */
+#define AR_SM2_BASE    0xc200
+
+#define AR_PHY_SWITCH_CHAIN_2    (AR_SM2_BASE + 0x84)
+#define AR_PHY_FCAL_2_2          (AR_SM2_BASE + 0xd0)
+#define AR_PHY_DFT_TONE_CTL_2    (AR_SM2_BASE + 0xd4)
+#define AR_PHY_CL_TAB_2          (AR_SM2_BASE + 0x100)
+#define AR_PHY_CHAN_INFO_GAIN_2  (AR_SM2_BASE + 0x180)
+#define AR_PHY_TPC_4_B2          (AR_SM2_BASE + 0x204)
+#define AR_PHY_TPC_5_B2          (AR_SM2_BASE + 0x208)
+#define AR_PHY_TPC_6_B2          (AR_SM2_BASE + 0x20c)
+#define AR_PHY_TPC_11_B2         (AR_SM2_BASE + 0x220)
+#define AR_PHY_PDADC_TAB_2       (AR_SM2_BASE + 0x240)
+#define AR_PHY_TX_IQCAL_STATUS_B2   (AR_SM2_BASE + 0x48c)
+#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B2    (AR_SM2_BASE + 0x450)
+
+#define AR_PHY_TX_IQCAL_STATUS_B2_FAILED    0x00000001
+
+/*
+ * AGC 3 Register Map
+ */
+#define AR_AGC3_BASE   0xce00
+
+#define AR_PHY_RSSI_3            (AR_AGC3_BASE + 0x180)
+
+/*
+ * Misc helper defines
+ */
+#define AR_PHY_CHAIN_OFFSET     (AR_CHAN1_BASE - AR_CHAN_BASE)
+
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (AR_PHY_ADC_GAIN_DC_CORR_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_NEW_ADC_DC_GAIN_CORR_9300_10(_i) (AR_PHY_ADC_GAIN_DC_CORR_0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_SWITCH_CHAIN(_i)     (AR_PHY_SWITCH_CHAIN_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_EXT_ATTEN_CTL(_i)    (AR_PHY_EXT_ATTEN_CTL_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+
+#define AR_PHY_RXGAIN(_i)           (AR_PHY_FORCEMAX_GAINS_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_TPCRG5(_i)           (AR_PHY_TPC_5_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_PDADC_TAB(_i)        (AR_PHY_PDADC_TAB_0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+
+#define AR_PHY_CAL_MEAS_0(_i)       (AR_PHY_IQ_ADC_MEAS_0_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_1(_i)       (AR_PHY_IQ_ADC_MEAS_1_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_2(_i)       (AR_PHY_IQ_ADC_MEAS_2_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_3(_i)       (AR_PHY_IQ_ADC_MEAS_3_B0 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_0_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_0_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_1_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_1_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+#define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
+
+#define AR_PHY_BB_PANIC_NON_IDLE_ENABLE 0x00000001
+#define AR_PHY_BB_PANIC_IDLE_ENABLE     0x00000002
+#define AR_PHY_BB_PANIC_IDLE_MASK       0xFFFF0000
+#define AR_PHY_BB_PANIC_NON_IDLE_MASK   0x0000FFFC
+
+#define AR_PHY_BB_PANIC_RST_ENABLE      0x00000002
+#define AR_PHY_BB_PANIC_IRQ_ENABLE      0x00000004
+#define AR_PHY_BB_PANIC_CNTL2_MASK      0xFFFFFFF9
+
+#define AR_PHY_BB_WD_STATUS             0x00000007
+#define AR_PHY_BB_WD_STATUS_S           0
+#define AR_PHY_BB_WD_DET_HANG           0x00000008
+#define AR_PHY_BB_WD_DET_HANG_S         3
+#define AR_PHY_BB_WD_RADAR_SM           0x000000F0
+#define AR_PHY_BB_WD_RADAR_SM_S         4
+#define AR_PHY_BB_WD_RX_OFDM_SM         0x00000F00
+#define AR_PHY_BB_WD_RX_OFDM_SM_S       8
+#define AR_PHY_BB_WD_RX_CCK_SM          0x0000F000
+#define AR_PHY_BB_WD_RX_CCK_SM_S        12
+#define AR_PHY_BB_WD_TX_OFDM_SM         0x000F0000
+#define AR_PHY_BB_WD_TX_OFDM_SM_S       16
+#define AR_PHY_BB_WD_TX_CCK_SM          0x00F00000
+#define AR_PHY_BB_WD_TX_CCK_SM_S        20
+#define AR_PHY_BB_WD_AGC_SM             0x0F000000
+#define AR_PHY_BB_WD_AGC_SM_S           24
+#define AR_PHY_BB_WD_SRCH_SM            0xF0000000
+#define AR_PHY_BB_WD_SRCH_SM_S          28
+
+#define AR_PHY_BB_WD_STATUS_CLR         0x00000008
+
+void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
+
+#endif  /* AR9003_PHY_H */
index 83c7ea4c007f7a9b8d3835226e41911b0c2acfc9..fbb7dec6ddebc11beb49a7b57b6e7342b38f9188 100644 (file)
@@ -114,8 +114,10 @@ enum buffer_type {
 #define bf_isretried(bf)       (bf->bf_state.bf_type & BUF_RETRY)
 #define bf_isxretried(bf)      (bf->bf_state.bf_type & BUF_XRETRY)
 
+#define ATH_TXSTATUS_RING_SIZE 64
+
 struct ath_descdma {
-       struct ath_desc *dd_desc;
+       void *dd_desc;
        dma_addr_t dd_desc_paddr;
        u32 dd_desc_len;
        struct ath_buf *dd_bufptr;
@@ -123,7 +125,7 @@ struct ath_descdma {
 
 int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                      struct list_head *head, const char *name,
-                     int nbuf, int ndesc);
+                     int nbuf, int ndesc, bool is_tx);
 void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
                         struct list_head *head);
 
@@ -178,9 +180,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 #define BAW_WITHIN(_start, _bawsz, _seqno) \
        ((((_seqno) - (_start)) & 4095) < (_bawsz))
 
-#define ATH_DS_BA_SEQ(_ds)         ((_ds)->ds_us.tx.ts_seqnum)
-#define ATH_DS_BA_BITMAP(_ds)      (&(_ds)->ds_us.tx.ba_low)
-#define ATH_DS_TX_BA(_ds)          ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
 #define ATH_AN_2_TID(_an, _tidno)  (&(_an)->tid[(_tidno)])
 
 #define ATH_TX_COMPLETE_POLL_INT       1000
@@ -191,6 +190,7 @@ enum ATH_AGGR_STATUS {
        ATH_AGGR_LIMITED,
 };
 
+#define ATH_TXFIFO_DEPTH 8
 struct ath_txq {
        u32 axq_qnum;
        u32 *axq_link;
@@ -200,6 +200,10 @@ struct ath_txq {
        bool stopped;
        bool axq_tx_inprogress;
        struct list_head axq_acq;
+       struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
+       struct list_head txq_fifo_pending;
+       u8 txq_headidx;
+       u8 txq_tailidx;
 };
 
 #define AGGR_CLEANUP         BIT(1)
@@ -226,6 +230,12 @@ struct ath_tx {
        struct ath_descdma txdma;
 };
 
+struct ath_rx_edma {
+       struct sk_buff_head rx_fifo;
+       struct sk_buff_head rx_buffers;
+       u32 rx_fifo_hwsize;
+};
+
 struct ath_rx {
        u8 defant;
        u8 rxotherant;
@@ -235,6 +245,8 @@ struct ath_rx {
        spinlock_t rxbuflock;
        struct list_head rxbuf;
        struct ath_descdma rxdma;
+       struct ath_buf *rx_bufptr;
+       struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
 };
 
 int ath_startrecv(struct ath_softc *sc);
@@ -243,7 +255,7 @@ void ath_flushrecv(struct ath_softc *sc);
 u32 ath_calcrxfilter(struct ath_softc *sc);
 int ath_rx_init(struct ath_softc *sc, int nbufs);
 void ath_rx_cleanup(struct ath_softc *sc);
-int ath_rx_tasklet(struct ath_softc *sc, int flush);
+int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp);
 struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype);
 void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq);
 int ath_tx_setup(struct ath_softc *sc, int haltype);
@@ -261,6 +273,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
 int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl);
 void ath_tx_tasklet(struct ath_softc *sc);
+void ath_tx_edma_tasklet(struct ath_softc *sc);
 void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
 bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
 void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -483,7 +496,6 @@ struct ath_softc {
        bool ps_enabled;
        bool ps_idle;
        unsigned long ps_usecount;
-       enum ath9k_int imask;
 
        struct ath_config config;
        struct ath_rx rx;
@@ -511,6 +523,8 @@ struct ath_softc {
        struct ath_beacon_config cur_beacon_conf;
        struct delayed_work tx_complete_work;
        struct ath_btcoex btcoex;
+
+       struct ath_descdma txsdma;
 };
 
 struct ath_wiphy {
index b4a31a43a62cf9aa00821dfe15123d2e10d25052..c8a4558f79ba0573a674829b53d6cfef2258e347 100644 (file)
@@ -93,8 +93,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
                antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
        }
 
-       ds->ds_data = bf->bf_buf_addr;
-
        sband = &sc->sbands[common->hw->conf.channel->band];
        rate = sband->bitrates[rateidx].hw_value;
        if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
@@ -109,7 +107,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
 
        /* NB: beacon's BufLen must be a multiple of 4 bytes */
        ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
-                           true, true, ds);
+                           true, true, ds, bf->bf_buf_addr,
+                           sc->beacon.beaconq);
 
        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
        series[0].Tries = 1;
@@ -524,6 +523,7 @@ static void ath9k_beacon_init(struct ath_softc *sc,
 static void ath_beacon_config_ap(struct ath_softc *sc,
                                 struct ath_beacon_config *conf)
 {
+       struct ath_hw *ah = sc->sc_ah;
        u32 nexttbtt, intval;
 
        /* NB: the beacon interval is kept internally in TU's */
@@ -539,15 +539,15 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
         * prepare beacon frames.
         */
        intval |= ATH9K_BEACON_ENA;
-       sc->imask |= ATH9K_INT_SWBA;
+       ah->imask |= ATH9K_INT_SWBA;
        ath_beaconq_config(sc);
 
        /* Set the computed AP beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_interrupts(ah, 0);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* Clear the reset TSF flag, so that subsequent beacon updation
           will not reset the HW TSF. */
@@ -566,7 +566,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
 static void ath_beacon_config_sta(struct ath_softc *sc,
                                  struct ath_beacon_config *conf)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_beacon_state bs;
        int dtimperiod, dtimcount, sleepduration;
        int cfpperiod, cfpcount;
@@ -605,7 +606,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
         * Pull nexttbtt forward to reflect the current
         * TSF and calculate dtim+cfp state for the result.
         */
-       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
 
        num_beacons = tsftu / intval + 1;
@@ -678,17 +679,18 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
 
        /* Set the computed STA beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
-       ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
-       sc->imask |= ATH9K_INT_BMISS;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, 0);
+       ath9k_hw_set_sta_beacon_timers(ah, &bs);
+       ah->imask |= ATH9K_INT_BMISS;
+       ath9k_hw_set_interrupts(ah, ah->imask);
 }
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
                                    struct ath_beacon_config *conf,
                                    struct ieee80211_vif *vif)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        u64 tsf;
        u32 tsftu, intval, nexttbtt;
 
@@ -703,7 +705,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         else if (intval)
                 nexttbtt = roundup(nexttbtt, intval);
 
-       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
        do {
                nexttbtt += intval;
@@ -719,20 +721,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         * self-linked tx descriptor and let the hardware deal with things.
         */
        intval |= ATH9K_BEACON_ENA;
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
-               sc->imask |= ATH9K_INT_SWBA;
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
+               ah->imask |= ATH9K_INT_SWBA;
 
        ath_beaconq_config(sc);
 
        /* Set the computed ADHOC beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_interrupts(ah, 0);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* FIXME: Handle properly when vif is NULL */
-       if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
+       if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
                ath_beacon_start_adhoc(sc, vif);
 }
 
index 238a5744d8e9ad0ab77049f1f013f407d1ad8060..07b8fa6fb62f3813edfcae71c97c24d62d736a5f 100644 (file)
@@ -15,6 +15,9 @@
  */
 
 #include "hw.h"
+#include "hw-ops.h"
+
+/* Common calibration code */
 
 /* We can tune this as we go by monitoring really low values */
 #define ATH9K_NF_TOO_LOW       -60
@@ -83,93 +86,11 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h,
                                ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
                }
        }
-       return;
 }
 
-static void ath9k_hw_do_getnf(struct ath_hw *ah,
-                             int16_t nfarray[NUM_NF_READINGS])
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       int16_t nf;
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR);
-       else
-               nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR);
-
-       if (nf & 0x100)
-               nf = 0 - ((nf ^ 0x1ff) + 1);
-       ath_print(common, ATH_DBG_CALIBRATE,
-                 "NF calibrated [ctl] [chain 0] is %d\n", nf);
-       nfarray[0] = nf;
-
-       if (!AR_SREV_9285(ah)) {
-               if (AR_SREV_9280_10_OR_LATER(ah))
-                       nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-                                       AR9280_PHY_CH1_MINCCA_PWR);
-               else
-                       nf = MS(REG_READ(ah, AR_PHY_CH1_CCA),
-                                       AR_PHY_CH1_MINCCA_PWR);
-
-               if (nf & 0x100)
-                       nf = 0 - ((nf ^ 0x1ff) + 1);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "NF calibrated [ctl] [chain 1] is %d\n", nf);
-               nfarray[1] = nf;
-
-               if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
-                       nf = MS(REG_READ(ah, AR_PHY_CH2_CCA),
-                                       AR_PHY_CH2_MINCCA_PWR);
-                       if (nf & 0x100)
-                               nf = 0 - ((nf ^ 0x1ff) + 1);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "NF calibrated [ctl] [chain 2] is %d\n", nf);
-                       nfarray[2] = nf;
-               }
-       }
-
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
-                       AR9280_PHY_EXT_MINCCA_PWR);
-       else
-               nf = MS(REG_READ(ah, AR_PHY_EXT_CCA),
-                       AR_PHY_EXT_MINCCA_PWR);
-
-       if (nf & 0x100)
-               nf = 0 - ((nf ^ 0x1ff) + 1);
-       ath_print(common, ATH_DBG_CALIBRATE,
-                 "NF calibrated [ext] [chain 0] is %d\n", nf);
-       nfarray[3] = nf;
-
-       if (!AR_SREV_9285(ah)) {
-               if (AR_SREV_9280_10_OR_LATER(ah))
-                       nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-                                       AR9280_PHY_CH1_EXT_MINCCA_PWR);
-               else
-                       nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA),
-                                       AR_PHY_CH1_EXT_MINCCA_PWR);
-
-               if (nf & 0x100)
-                       nf = 0 - ((nf ^ 0x1ff) + 1);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "NF calibrated [ext] [chain 1] is %d\n", nf);
-               nfarray[4] = nf;
-
-               if (!AR_SREV_9280(ah) && !AR_SREV_9287(ah)) {
-                       nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA),
-                                       AR_PHY_CH2_EXT_MINCCA_PWR);
-                       if (nf & 0x100)
-                               nf = 0 - ((nf ^ 0x1ff) + 1);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "NF calibrated [ext] [chain 2] is %d\n", nf);
-                       nfarray[5] = nf;
-               }
-       }
-}
-
-static bool getNoiseFloorThresh(struct ath_hw *ah,
-                               enum ieee80211_band band,
-                               int16_t *nft)
+static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
+                                  enum ieee80211_band band,
+                                  int16_t *nft)
 {
        switch (band) {
        case IEEE80211_BAND_5GHZ:
@@ -186,44 +107,8 @@ static bool getNoiseFloorThresh(struct ath_hw *ah,
        return true;
 }
 
-static void ath9k_hw_setup_calibration(struct ath_hw *ah,
-                                      struct ath9k_cal_list *currCal)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0),
-                     AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX,
-                     currCal->calData->calCountMax);
-
-       switch (currCal->calData->calType) {
-       case IQ_MISMATCH_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "starting IQ Mismatch Calibration\n");
-               break;
-       case ADC_GAIN_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "starting ADC Gain Calibration\n");
-               break;
-       case ADC_DC_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "starting ADC DC Calibration\n");
-               break;
-       case ADC_DC_INIT_CAL:
-               REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "starting Init ADC DC Calibration\n");
-               break;
-       }
-
-       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
-                   AR_PHY_TIMING_CTRL4_DO_CAL);
-}
-
-static void ath9k_hw_reset_calibration(struct ath_hw *ah,
-                                      struct ath9k_cal_list *currCal)
+void ath9k_hw_reset_calibration(struct ath_hw *ah,
+                               struct ath9k_cal_list *currCal)
 {
        int i;
 
@@ -241,324 +126,6 @@ static void ath9k_hw_reset_calibration(struct ath_hw *ah,
        ah->cal_samples = 0;
 }
 
-static bool ath9k_hw_per_calibration(struct ath_hw *ah,
-                                    struct ath9k_channel *ichan,
-                                    u8 rxchainmask,
-                                    struct ath9k_cal_list *currCal)
-{
-       bool iscaldone = false;
-
-       if (currCal->calState == CAL_RUNNING) {
-               if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) &
-                     AR_PHY_TIMING_CTRL4_DO_CAL)) {
-
-                       currCal->calData->calCollect(ah);
-                       ah->cal_samples++;
-
-                       if (ah->cal_samples >= currCal->calData->calNumSamples) {
-                               int i, numChains = 0;
-                               for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-                                       if (rxchainmask & (1 << i))
-                                               numChains++;
-                               }
-
-                               currCal->calData->calPostProc(ah, numChains);
-                               ichan->CalValid |= currCal->calData->calType;
-                               currCal->calState = CAL_DONE;
-                               iscaldone = true;
-                       } else {
-                               ath9k_hw_setup_calibration(ah, currCal);
-                       }
-               }
-       } else if (!(ichan->CalValid & currCal->calData->calType)) {
-               ath9k_hw_reset_calibration(ah, currCal);
-       }
-
-       return iscaldone;
-}
-
-/* Assumes you are talking about the currently configured channel */
-static bool ath9k_hw_iscal_supported(struct ath_hw *ah,
-                                    enum ath9k_cal_types calType)
-{
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
-
-       switch (calType & ah->supp_cals) {
-       case IQ_MISMATCH_CAL: /* Both 2 GHz and 5 GHz support OFDM */
-               return true;
-       case ADC_GAIN_CAL:
-       case ADC_DC_CAL:
-               if (!(conf->channel->band == IEEE80211_BAND_2GHZ &&
-                     conf_is_ht20(conf)))
-                       return true;
-               break;
-       }
-       return false;
-}
-
-static void ath9k_hw_iqcal_collect(struct ath_hw *ah)
-{
-       int i;
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ah->totalPowerMeasI[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-               ah->totalPowerMeasQ[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-               ah->totalIqCorrMeas[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-                         "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
-                         ah->cal_samples, i, ah->totalPowerMeasI[i],
-                         ah->totalPowerMeasQ[i],
-                         ah->totalIqCorrMeas[i]);
-       }
-}
-
-static void ath9k_hw_adc_gaincal_collect(struct ath_hw *ah)
-{
-       int i;
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ah->totalAdcIOddPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-               ah->totalAdcIEvenPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-               ah->totalAdcQOddPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-               ah->totalAdcQEvenPhase[i] +=
-                       REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
-               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
-                         "oddq=0x%08x; evenq=0x%08x;\n",
-                         ah->cal_samples, i,
-                         ah->totalAdcIOddPhase[i],
-                         ah->totalAdcIEvenPhase[i],
-                         ah->totalAdcQOddPhase[i],
-                         ah->totalAdcQEvenPhase[i]);
-       }
-}
-
-static void ath9k_hw_adc_dccal_collect(struct ath_hw *ah)
-{
-       int i;
-
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               ah->totalAdcDcOffsetIOddPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
-               ah->totalAdcDcOffsetIEvenPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
-               ah->totalAdcDcOffsetQOddPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
-               ah->totalAdcDcOffsetQEvenPhase[i] +=
-                       (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i));
-
-               ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
-                         "%d: Chn %d oddi=0x%08x; eveni=0x%08x; "
-                         "oddq=0x%08x; evenq=0x%08x;\n",
-                         ah->cal_samples, i,
-                         ah->totalAdcDcOffsetIOddPhase[i],
-                         ah->totalAdcDcOffsetIEvenPhase[i],
-                         ah->totalAdcDcOffsetQOddPhase[i],
-                         ah->totalAdcDcOffsetQEvenPhase[i]);
-       }
-}
-
-static void ath9k_hw_iqcalibrate(struct ath_hw *ah, u8 numChains)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 powerMeasQ, powerMeasI, iqCorrMeas;
-       u32 qCoffDenom, iCoffDenom;
-       int32_t qCoff, iCoff;
-       int iqCorrNeg, i;
-
-       for (i = 0; i < numChains; i++) {
-               powerMeasI = ah->totalPowerMeasI[i];
-               powerMeasQ = ah->totalPowerMeasQ[i];
-               iqCorrMeas = ah->totalIqCorrMeas[i];
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Starting IQ Cal and Correction for Chain %d\n",
-                         i);
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Orignal: Chn %diq_corr_meas = 0x%08x\n",
-                         i, ah->totalIqCorrMeas[i]);
-
-               iqCorrNeg = 0;
-
-               if (iqCorrMeas > 0x80000000) {
-                       iqCorrMeas = (0xffffffff - iqCorrMeas) + 1;
-                       iqCorrNeg = 1;
-               }
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ);
-               ath_print(common, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n",
-                         iqCorrNeg);
-
-               iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128;
-               qCoffDenom = powerMeasQ / 64;
-
-               if ((powerMeasQ != 0) && (iCoffDenom != 0) &&
-                   (qCoffDenom != 0)) {
-                       iCoff = iqCorrMeas / iCoffDenom;
-                       qCoff = powerMeasI / qCoffDenom - 64;
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "Chn %d iCoff = 0x%08x\n", i, iCoff);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "Chn %d qCoff = 0x%08x\n", i, qCoff);
-
-                       iCoff = iCoff & 0x3f;
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "New: Chn %d iCoff = 0x%08x\n", i, iCoff);
-                       if (iqCorrNeg == 0x0)
-                               iCoff = 0x40 - iCoff;
-
-                       if (qCoff > 15)
-                               qCoff = 15;
-                       else if (qCoff <= -16)
-                               qCoff = 16;
-
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "Chn %d : iCoff = 0x%x  qCoff = 0x%x\n",
-                                 i, iCoff, qCoff);
-
-                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
-                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
-                                     iCoff);
-                       REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i),
-                                     AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
-                                     qCoff);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "IQ Cal and Correction done for Chain %d\n",
-                                 i);
-               }
-       }
-
-       REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0),
-                   AR_PHY_TIMING_CTRL4_IQCORR_ENABLE);
-}
-
-static void ath9k_hw_adc_gaincal_calibrate(struct ath_hw *ah, u8 numChains)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset;
-       u32 qGainMismatch, iGainMismatch, val, i;
-
-       for (i = 0; i < numChains; i++) {
-               iOddMeasOffset = ah->totalAdcIOddPhase[i];
-               iEvenMeasOffset = ah->totalAdcIEvenPhase[i];
-               qOddMeasOffset = ah->totalAdcQOddPhase[i];
-               qEvenMeasOffset = ah->totalAdcQEvenPhase[i];
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Starting ADC Gain Cal for Chain %d\n", i);
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_odd_i = 0x%08x\n", i,
-                         iOddMeasOffset);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_even_i = 0x%08x\n", i,
-                         iEvenMeasOffset);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_odd_q = 0x%08x\n", i,
-                         qOddMeasOffset);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_even_q = 0x%08x\n", i,
-                         qEvenMeasOffset);
-
-               if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) {
-                       iGainMismatch =
-                               ((iEvenMeasOffset * 32) /
-                                iOddMeasOffset) & 0x3f;
-                       qGainMismatch =
-                               ((qOddMeasOffset * 32) /
-                                qEvenMeasOffset) & 0x3f;
-
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "Chn %d gain_mismatch_i = 0x%08x\n", i,
-                                 iGainMismatch);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "Chn %d gain_mismatch_q = 0x%08x\n", i,
-                                 qGainMismatch);
-
-                       val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
-                       val &= 0xfffff000;
-                       val |= (qGainMismatch) | (iGainMismatch << 6);
-                       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "ADC Gain Cal done for Chain %d\n", i);
-               }
-       }
-
-       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
-                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
-                 AR_PHY_NEW_ADC_GAIN_CORR_ENABLE);
-}
-
-static void ath9k_hw_adc_dccal_calibrate(struct ath_hw *ah, u8 numChains)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 iOddMeasOffset, iEvenMeasOffset, val, i;
-       int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch;
-       const struct ath9k_percal_data *calData =
-               ah->cal_list_curr->calData;
-       u32 numSamples =
-               (1 << (calData->calCountMax + 5)) * calData->calNumSamples;
-
-       for (i = 0; i < numChains; i++) {
-               iOddMeasOffset = ah->totalAdcDcOffsetIOddPhase[i];
-               iEvenMeasOffset = ah->totalAdcDcOffsetIEvenPhase[i];
-               qOddMeasOffset = ah->totalAdcDcOffsetQOddPhase[i];
-               qEvenMeasOffset = ah->totalAdcDcOffsetQEvenPhase[i];
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                          "Starting ADC DC Offset Cal for Chain %d\n", i);
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_odd_i = %d\n", i,
-                         iOddMeasOffset);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_even_i = %d\n", i,
-                         iEvenMeasOffset);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_odd_q = %d\n", i,
-                         qOddMeasOffset);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d pwr_meas_even_q = %d\n", i,
-                         qEvenMeasOffset);
-
-               iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) /
-                              numSamples) & 0x1ff;
-               qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) /
-                              numSamples) & 0x1ff;
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d dc_offset_mismatch_i = 0x%08x\n", i,
-                         iDcMismatch);
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "Chn %d dc_offset_mismatch_q = 0x%08x\n", i,
-                         qDcMismatch);
-
-               val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i));
-               val &= 0xc0000fff;
-               val |= (qDcMismatch << 12) | (iDcMismatch << 21);
-               REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val);
-
-               ath_print(common, ATH_DBG_CALIBRATE,
-                         "ADC DC Offset Cal done for Chain %d\n", i);
-       }
-
-       REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0),
-                 REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) |
-                 AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE);
-}
-
 /* This is done for the currently configured channel */
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
@@ -605,72 +172,6 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah)
        REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
 }
 
-void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       struct ath9k_nfcal_hist *h;
-       int i, j;
-       int32_t val;
-       const u32 ar5416_cca_regs[6] = {
-               AR_PHY_CCA,
-               AR_PHY_CH1_CCA,
-               AR_PHY_CH2_CCA,
-               AR_PHY_EXT_CCA,
-               AR_PHY_CH1_EXT_CCA,
-               AR_PHY_CH2_EXT_CCA
-       };
-       u8 chainmask, rx_chain_status;
-
-       rx_chain_status = REG_READ(ah, AR_PHY_RX_CHAINMASK);
-       if (AR_SREV_9285(ah))
-               chainmask = 0x9;
-       else if (AR_SREV_9280(ah) || AR_SREV_9287(ah)) {
-               if ((rx_chain_status & 0x2) || (rx_chain_status & 0x4))
-                       chainmask = 0x1B;
-               else
-                       chainmask = 0x09;
-       } else {
-               if (rx_chain_status & 0x4)
-                       chainmask = 0x3F;
-               else if (rx_chain_status & 0x2)
-                       chainmask = 0x1B;
-               else
-                       chainmask = 0x09;
-       }
-
-       h = ah->nfCalHist;
-
-       for (i = 0; i < NUM_NF_READINGS; i++) {
-               if (chainmask & (1 << i)) {
-                       val = REG_READ(ah, ar5416_cca_regs[i]);
-                       val &= 0xFFFFFE00;
-                       val |= (((u32) (h[i].privNF) << 1) & 0x1ff);
-                       REG_WRITE(ah, ar5416_cca_regs[i], val);
-               }
-       }
-
-       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-                   AR_PHY_AGC_CONTROL_ENABLE_NF);
-       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-                   AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-
-       for (j = 0; j < 5; j++) {
-               if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
-                    AR_PHY_AGC_CONTROL_NF) == 0)
-                       break;
-               udelay(50);
-       }
-
-       for (i = 0; i < NUM_NF_READINGS; i++) {
-               if (chainmask & (1 << i)) {
-                       val = REG_READ(ah, ar5416_cca_regs[i]);
-                       val &= 0xFFFFFE00;
-                       val |= (((u32) (-50) << 1) & 0x1ff);
-                       REG_WRITE(ah, ar5416_cca_regs[i], val);
-               }
-       }
-}
-
 int16_t ath9k_hw_getnf(struct ath_hw *ah,
                       struct ath9k_channel *chan)
 {
@@ -690,7 +191,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
        } else {
                ath9k_hw_do_getnf(ah, nfarray);
                nf = nfarray[0];
-               if (getNoiseFloorThresh(ah, c->band, &nfThresh)
+               if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
                    && nf > nfThresh) {
                        ath_print(common, ATH_DBG_CALIBRATE,
                                  "noise floor failed detected; "
@@ -715,7 +216,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
 
        if (AR_SREV_9280(ah))
                noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
-       else if (AR_SREV_9285(ah))
+       else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
                noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
        else if (AR_SREV_9287(ah))
                noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
@@ -748,508 +249,3 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
        return nf;
 }
 EXPORT_SYMBOL(ath9k_hw_getchan_noise);
-
-static void ath9k_olc_temp_compensation_9287(struct ath_hw *ah)
-{
-       u32 rddata;
-       int32_t delta, currPDADC, slope;
-
-       rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
-       currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
-
-       if (ah->initPDADC == 0 || currPDADC == 0) {
-               /*
-                * Zero value indicates that no frames have been transmitted yet,
-                * can't do temperature compensation until frames are transmitted.
-                */
-               return;
-       } else {
-               slope = ah->eep_ops->get_eeprom(ah, EEP_TEMPSENSE_SLOPE);
-
-               if (slope == 0) { /* to avoid divide by zero case */
-                       delta = 0;
-               } else {
-                       delta = ((currPDADC - ah->initPDADC)*4) / slope;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_CH0_TX_PWRCTRL11,
-                             AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
-               REG_RMW_FIELD(ah, AR_PHY_CH1_TX_PWRCTRL11,
-                             AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, delta);
-       }
-}
-
-static void ath9k_olc_temp_compensation(struct ath_hw *ah)
-{
-       u32 rddata, i;
-       int delta, currPDADC, regval;
-
-       if (OLC_FOR_AR9287_10_LATER) {
-               ath9k_olc_temp_compensation_9287(ah);
-       } else {
-               rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
-               currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
-
-               if (ah->initPDADC == 0 || currPDADC == 0) {
-                       return;
-               } else {
-                       if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
-                               delta = (currPDADC - ah->initPDADC + 4) / 8;
-                       else
-                               delta = (currPDADC - ah->initPDADC + 5) / 10;
-
-                       if (delta != ah->PDADCdelta) {
-                               ah->PDADCdelta = delta;
-                               for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
-                                       regval = ah->originalGain[i] - delta;
-                                       if (regval < 0)
-                                               regval = 0;
-
-                                       REG_RMW_FIELD(ah,
-                                                     AR_PHY_TX_GAIN_TBL1 + i * 4,
-                                                     AR_PHY_TX_GAIN, regval);
-                               }
-                       }
-               }
-       }
-}
-
-static void ath9k_hw_9271_pa_cal(struct ath_hw *ah, bool is_reset)
-{
-       u32 regVal;
-       unsigned int i;
-       u32 regList [][2] = {
-               { 0x786c, 0 },
-               { 0x7854, 0 },
-               { 0x7820, 0 },
-               { 0x7824, 0 },
-               { 0x7868, 0 },
-               { 0x783c, 0 },
-               { 0x7838, 0 } ,
-               { 0x7828, 0 } ,
-       };
-
-       for (i = 0; i < ARRAY_SIZE(regList); i++)
-               regList[i][1] = REG_READ(ah, regList[i][0]);
-
-       regVal = REG_READ(ah, 0x7834);
-       regVal &= (~(0x1));
-       REG_WRITE(ah, 0x7834, regVal);
-       regVal = REG_READ(ah, 0x9808);
-       regVal |= (0x1 << 27);
-       REG_WRITE(ah, 0x9808, regVal);
-
-       /* 786c,b23,1, pwddac=1 */
-       REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
-       /* 7854, b5,1, pdrxtxbb=1 */
-       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
-       /* 7854, b7,1, pdv2i=1 */
-       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
-       /* 7854, b8,1, pddacinterface=1 */
-       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
-       /* 7824,b12,0, offcal=0 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
-       /* 7838, b1,0, pwddb=0 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
-       /* 7820,b11,0, enpacal=0 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
-       /* 7820,b25,1, pdpadrv1=0 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
-       /* 7820,b24,0, pdpadrv2=0 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1,AR9285_AN_RF2G1_PDPADRV2,0);
-       /* 7820,b23,0, pdpaout=0 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
-       /* 783c,b14-16,7, padrvgn2tab_0=7 */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G8,AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
-       /*
-        * 7838,b29-31,0, padrvgn1tab_0=0
-        * does not matter since we turn it off
-        */
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G7,AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
-
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9271_AN_RF2G3_CCOMP, 0xfff);
-
-       /* Set:
-        * localmode=1,bmode=1,bmoderxtx=1,synthon=1,
-        * txon=1,paon=1,oscon=1,synthon_force=1
-        */
-       REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
-       udelay(30);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS, 0);
-
-       /* find off_6_1; */
-       for (i = 6; i > 0; i--) {
-               regVal = REG_READ(ah, 0x7834);
-               regVal |= (1 << (20 + i));
-               REG_WRITE(ah, 0x7834, regVal);
-               udelay(1);
-               //regVal = REG_READ(ah, 0x7834);
-               regVal &= (~(0x1 << (20 + i)));
-               regVal |= (MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9)
-                           << (20 + i));
-               REG_WRITE(ah, 0x7834, regVal);
-       }
-
-       regVal = (regVal >>20) & 0x7f;
-
-       /* Update PA cal info */
-       if ((!is_reset) && (ah->pacal_info.prev_offset == regVal)) {
-               if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
-                       ah->pacal_info.max_skipcount =
-                               2 * ah->pacal_info.max_skipcount;
-               ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
-       } else {
-               ah->pacal_info.max_skipcount = 1;
-               ah->pacal_info.skipcount = 0;
-               ah->pacal_info.prev_offset = regVal;
-       }
-
-       regVal = REG_READ(ah, 0x7834);
-       regVal |= 0x1;
-       REG_WRITE(ah, 0x7834, regVal);
-       regVal = REG_READ(ah, 0x9808);
-       regVal &= (~(0x1 << 27));
-       REG_WRITE(ah, 0x9808, regVal);
-
-       for (i = 0; i < ARRAY_SIZE(regList); i++)
-               REG_WRITE(ah, regList[i][0], regList[i][1]);
-}
-
-static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah, bool is_reset)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 regVal;
-       int i, offset, offs_6_1, offs_0;
-       u32 ccomp_org, reg_field;
-       u32 regList[][2] = {
-               { 0x786c, 0 },
-               { 0x7854, 0 },
-               { 0x7820, 0 },
-               { 0x7824, 0 },
-               { 0x7868, 0 },
-               { 0x783c, 0 },
-               { 0x7838, 0 },
-       };
-
-       ath_print(common, ATH_DBG_CALIBRATE, "Running PA Calibration\n");
-
-       /* PA CAL is not needed for high power solution */
-       if (ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE) ==
-           AR5416_EEP_TXGAIN_HIGH_POWER)
-               return;
-
-       if (AR_SREV_9285_11(ah)) {
-               REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
-               udelay(10);
-       }
-
-       for (i = 0; i < ARRAY_SIZE(regList); i++)
-               regList[i][1] = REG_READ(ah, regList[i][0]);
-
-       regVal = REG_READ(ah, 0x7834);
-       regVal &= (~(0x1));
-       REG_WRITE(ah, 0x7834, regVal);
-       regVal = REG_READ(ah, 0x9808);
-       regVal |= (0x1 << 27);
-       REG_WRITE(ah, 0x9808, regVal);
-
-       REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1);
-       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1);
-       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1);
-       REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0);
-       ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 0xf);
-
-       REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0);
-       udelay(30);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0);
-
-       for (i = 6; i > 0; i--) {
-               regVal = REG_READ(ah, 0x7834);
-               regVal |= (1 << (19 + i));
-               REG_WRITE(ah, 0x7834, regVal);
-               udelay(1);
-               regVal = REG_READ(ah, 0x7834);
-               regVal &= (~(0x1 << (19 + i)));
-               reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9);
-               regVal |= (reg_field << (19 + i));
-               REG_WRITE(ah, 0x7834, regVal);
-       }
-
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1);
-       udelay(1);
-       reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field);
-       offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS);
-       offs_0   = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP);
-
-       offset = (offs_6_1<<1) | offs_0;
-       offset = offset - 0;
-       offs_6_1 = offset>>1;
-       offs_0 = offset & 1;
-
-       if ((!is_reset) && (ah->pacal_info.prev_offset == offset)) {
-               if (ah->pacal_info.max_skipcount < MAX_PACAL_SKIPCOUNT)
-                       ah->pacal_info.max_skipcount =
-                               2 * ah->pacal_info.max_skipcount;
-               ah->pacal_info.skipcount = ah->pacal_info.max_skipcount;
-       } else {
-               ah->pacal_info.max_skipcount = 1;
-               ah->pacal_info.skipcount = 0;
-               ah->pacal_info.prev_offset = offset;
-       }
-
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1);
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0);
-
-       regVal = REG_READ(ah, 0x7834);
-       regVal |= 0x1;
-       REG_WRITE(ah, 0x7834, regVal);
-       regVal = REG_READ(ah, 0x9808);
-       regVal &= (~(0x1 << 27));
-       REG_WRITE(ah, 0x9808, regVal);
-
-       for (i = 0; i < ARRAY_SIZE(regList); i++)
-               REG_WRITE(ah, regList[i][0], regList[i][1]);
-
-       REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org);
-
-       if (AR_SREV_9285_11(ah))
-               REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT);
-
-}
-
-bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
-                       u8 rxchainmask, bool longcal)
-{
-       bool iscaldone = true;
-       struct ath9k_cal_list *currCal = ah->cal_list_curr;
-
-       if (currCal &&
-           (currCal->calState == CAL_RUNNING ||
-            currCal->calState == CAL_WAITING)) {
-               iscaldone = ath9k_hw_per_calibration(ah, chan,
-                                                    rxchainmask, currCal);
-               if (iscaldone) {
-                       ah->cal_list_curr = currCal = currCal->calNext;
-
-                       if (currCal->calState == CAL_WAITING) {
-                               iscaldone = false;
-                               ath9k_hw_reset_calibration(ah, currCal);
-                       }
-               }
-       }
-
-       /* Do NF cal only at longer intervals */
-       if (longcal) {
-               /* Do periodic PAOffset Cal */
-               if (AR_SREV_9271(ah))
-                       ath9k_hw_9271_pa_cal(ah, false);
-               else if (AR_SREV_9285_11_OR_LATER(ah)) {
-                       if (!ah->pacal_info.skipcount)
-                               ath9k_hw_9285_pa_cal(ah, false);
-                       else
-                               ah->pacal_info.skipcount--;
-               }
-
-               if (OLC_FOR_AR9280_20_LATER || OLC_FOR_AR9287_10_LATER)
-                       ath9k_olc_temp_compensation(ah);
-
-               /* Get the value from the previous NF cal and update history buffer */
-               ath9k_hw_getnf(ah, chan);
-
-               /*
-                * Load the NF from history buffer of the current channel.
-                * NF is slow time-variant, so it is OK to use a historical value.
-                */
-               ath9k_hw_loadnf(ah, ah->curchan);
-
-               ath9k_hw_start_nfcal(ah);
-       }
-
-       return iscaldone;
-}
-EXPORT_SYMBOL(ath9k_hw_calibrate);
-
-/* Carrier leakage Calibration fix */
-static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
-       if (IS_CHAN_HT20(chan)) {
-               REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
-               REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
-               REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-                           AR_PHY_AGC_CONTROL_FLTR_CAL);
-               REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
-               REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
-               if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
-                                 AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
-                       ath_print(common, ATH_DBG_CALIBRATE, "offset "
-                                 "calibration failed to complete in "
-                                 "1ms; noisy ??\n");
-                       return false;
-               }
-               REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
-               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
-               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
-       }
-       REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
-       REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
-       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
-       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
-                         0, AH_WAIT_TIMEOUT)) {
-               ath_print(common, ATH_DBG_CALIBRATE, "offset calibration "
-                         "failed to complete in 1ms; noisy ??\n");
-               return false;
-       }
-
-       REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
-       REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
-       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
-
-       return true;
-}
-
-bool ath9k_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       if (AR_SREV_9271(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
-               if (!ar9285_clc(ah, chan))
-                       return false;
-       } else {
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       if (!AR_SREV_9287_10_OR_LATER(ah))
-                               REG_CLR_BIT(ah, AR_PHY_ADC_CTL,
-                                           AR_PHY_ADC_CTL_OFF_PWDADC);
-                       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
-                                   AR_PHY_AGC_CONTROL_FLTR_CAL);
-               }
-
-               /* Calibrate the AGC */
-               REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-                         REG_READ(ah, AR_PHY_AGC_CONTROL) |
-                         AR_PHY_AGC_CONTROL_CAL);
-
-               /* Poll for offset calibration complete */
-               if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
-                                  0, AH_WAIT_TIMEOUT)) {
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "offset calibration failed to "
-                                 "complete in 1ms; noisy environment?\n");
-                       return false;
-               }
-
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       if (!AR_SREV_9287_10_OR_LATER(ah))
-                               REG_SET_BIT(ah, AR_PHY_ADC_CTL,
-                                           AR_PHY_ADC_CTL_OFF_PWDADC);
-                       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
-                                   AR_PHY_AGC_CONTROL_FLTR_CAL);
-               }
-       }
-
-       /* Do PA Calibration */
-       if (AR_SREV_9271(ah))
-               ath9k_hw_9271_pa_cal(ah, true);
-       else if (AR_SREV_9285_11_OR_LATER(ah))
-               ath9k_hw_9285_pa_cal(ah, true);
-
-       /* Do NF Calibration after DC offset and other calibrations */
-       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-                 REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);
-
-       ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
-
-       /* Enable IQ, ADC Gain and ADC DC offset CALs */
-       if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
-               if (ath9k_hw_iscal_supported(ah, ADC_GAIN_CAL)) {
-                       INIT_CAL(&ah->adcgain_caldata);
-                       INSERT_CAL(ah, &ah->adcgain_caldata);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "enabling ADC Gain Calibration.\n");
-               }
-               if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
-                       INIT_CAL(&ah->adcdc_caldata);
-                       INSERT_CAL(ah, &ah->adcdc_caldata);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "enabling ADC DC Calibration.\n");
-               }
-               if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
-                       INIT_CAL(&ah->iq_caldata);
-                       INSERT_CAL(ah, &ah->iq_caldata);
-                       ath_print(common, ATH_DBG_CALIBRATE,
-                                 "enabling IQ Calibration.\n");
-               }
-
-               ah->cal_list_curr = ah->cal_list;
-
-               if (ah->cal_list_curr)
-                       ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
-       }
-
-       chan->CalValid = 0;
-
-       return true;
-}
-
-const struct ath9k_percal_data iq_cal_multi_sample = {
-       IQ_MISMATCH_CAL,
-       MAX_CAL_SAMPLES,
-       PER_MIN_LOG_COUNT,
-       ath9k_hw_iqcal_collect,
-       ath9k_hw_iqcalibrate
-};
-const struct ath9k_percal_data iq_cal_single_sample = {
-       IQ_MISMATCH_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-       ath9k_hw_iqcal_collect,
-       ath9k_hw_iqcalibrate
-};
-const struct ath9k_percal_data adc_gain_cal_multi_sample = {
-       ADC_GAIN_CAL,
-       MAX_CAL_SAMPLES,
-       PER_MIN_LOG_COUNT,
-       ath9k_hw_adc_gaincal_collect,
-       ath9k_hw_adc_gaincal_calibrate
-};
-const struct ath9k_percal_data adc_gain_cal_single_sample = {
-       ADC_GAIN_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-       ath9k_hw_adc_gaincal_collect,
-       ath9k_hw_adc_gaincal_calibrate
-};
-const struct ath9k_percal_data adc_dc_cal_multi_sample = {
-       ADC_DC_CAL,
-       MAX_CAL_SAMPLES,
-       PER_MIN_LOG_COUNT,
-       ath9k_hw_adc_dccal_collect,
-       ath9k_hw_adc_dccal_calibrate
-};
-const struct ath9k_percal_data adc_dc_cal_single_sample = {
-       ADC_DC_CAL,
-       MIN_CAL_SAMPLES,
-       PER_MAX_LOG_COUNT,
-       ath9k_hw_adc_dccal_collect,
-       ath9k_hw_adc_dccal_calibrate
-};
-const struct ath9k_percal_data adc_init_dc_cal = {
-       ADC_DC_INIT_CAL,
-       MIN_CAL_SAMPLES,
-       INIT_LOG_COUNT,
-       ath9k_hw_adc_dccal_collect,
-       ath9k_hw_adc_dccal_calibrate
-};
index b2c873e974856895fbe77ff4138bc0b96be16a47..24538bdb9126c9239402206275bdbefddb1a4451 100644 (file)
 
 #include "hw.h"
 
-extern const struct ath9k_percal_data iq_cal_multi_sample;
-extern const struct ath9k_percal_data iq_cal_single_sample;
-extern const struct ath9k_percal_data adc_gain_cal_multi_sample;
-extern const struct ath9k_percal_data adc_gain_cal_single_sample;
-extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
-extern const struct ath9k_percal_data adc_dc_cal_single_sample;
-extern const struct ath9k_percal_data adc_init_dc_cal;
-
 #define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE       -85
 #define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE       -112
 #define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE       -118
@@ -76,7 +68,8 @@ enum ath9k_cal_types {
        ADC_DC_INIT_CAL = 0x1,
        ADC_GAIN_CAL = 0x2,
        ADC_DC_CAL = 0x4,
-       IQ_MISMATCH_CAL = 0x8
+       IQ_MISMATCH_CAL = 0x8,
+       TEMP_COMP_CAL = 0x10,
 };
 
 enum ath9k_cal_state {
@@ -122,14 +115,12 @@ struct ath9k_pacal_info{
 
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
 void ath9k_hw_start_nfcal(struct ath_hw *ah);
-void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
 int16_t ath9k_hw_getnf(struct ath_hw *ah,
                       struct ath9k_channel *chan);
 void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah);
 s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
-bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
-                       u8 rxchainmask, bool longcal);
-bool ath9k_hw_init_cal(struct ath_hw *ah,
-                      struct ath9k_channel *chan);
+void ath9k_hw_reset_calibration(struct ath_hw *ah,
+                               struct ath9k_cal_list *currCal);
+
 
 #endif /* CALIB_H */
index 4d775ae141db698755e9d80f962480940fc5dc6b..7707341cd0d3a70bbdee237fe8eccdf3eaf95447 100644 (file)
@@ -57,13 +57,19 @@ static bool ath9k_rx_accept(struct ath_common *common,
         * rs_more indicates chained descriptors which can be used
         * to link buffers together for a sort of scatter-gather
         * operation.
-        *
+        * reject the frame, we don't support scatter-gather yet and
+        * the frame is probably corrupt anyway
+        */
+       if (rx_stats->rs_more)
+               return false;
+
+       /*
         * The rx_stats->rs_status will not be set until the end of the
         * chained descriptors so it can be ignored if rs_more is set. The
         * rs_more will be false at the last element of the chained
         * descriptors.
         */
-       if (!rx_stats->rs_more && rx_stats->rs_status != 0) {
+       if (rx_stats->rs_status != 0) {
                if (rx_stats->rs_status & ATH9K_RXERR_CRC)
                        rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
                if (rx_stats->rs_status & ATH9K_RXERR_PHY)
@@ -102,11 +108,11 @@ static bool ath9k_rx_accept(struct ath_common *common,
        return true;
 }
 
-static u8 ath9k_process_rate(struct ath_common *common,
-                            struct ieee80211_hw *hw,
-                            struct ath_rx_status *rx_stats,
-                            struct ieee80211_rx_status *rxs,
-                            struct sk_buff *skb)
+static int ath9k_process_rate(struct ath_common *common,
+                             struct ieee80211_hw *hw,
+                             struct ath_rx_status *rx_stats,
+                             struct ieee80211_rx_status *rxs,
+                             struct sk_buff *skb)
 {
        struct ieee80211_supported_band *sband;
        enum ieee80211_band band;
@@ -122,25 +128,32 @@ static u8 ath9k_process_rate(struct ath_common *common,
                        rxs->flag |= RX_FLAG_40MHZ;
                if (rx_stats->rs_flags & ATH9K_RX_GI)
                        rxs->flag |= RX_FLAG_SHORT_GI;
-               return rx_stats->rs_rate & 0x7f;
+               rxs->rate_idx = rx_stats->rs_rate & 0x7f;
+               return 0;
        }
 
        for (i = 0; i < sband->n_bitrates; i++) {
-               if (sband->bitrates[i].hw_value == rx_stats->rs_rate)
-                       return i;
+               if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
+                       rxs->rate_idx = i;
+                       return 0;
+               }
                if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
                        rxs->flag |= RX_FLAG_SHORTPRE;
-                       return i;
+                       rxs->rate_idx = i;
+                       return 0;
                }
        }
 
-       /* No valid hardware bitrate found -- we should not get here */
+       /*
+        * No valid hardware bitrate found -- we should not get here
+        * because hardware has already validated this frame as OK.
+        */
        ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
                  "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
        if ((common->debug_mask & ATH_DBG_XMIT))
                print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len);
 
-        return 0;
+       return -EINVAL;
 }
 
 static void ath9k_process_rssi(struct ath_common *common,
@@ -202,17 +215,22 @@ int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
        struct ath_hw *ah = common->ah;
 
        memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+       /*
+        * everything but the rate is checked here, the rate check is done
+        * separately to avoid doing two lookups for a rate for each frame.
+        */
        if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error))
                return -EINVAL;
 
        ath9k_process_rssi(common, hw, skb, rx_stats);
 
-       rx_status->rate_idx = ath9k_process_rate(common, hw,
-                                                rx_stats, rx_status, skb);
+       if (ath9k_process_rate(common, hw, rx_stats, rx_status, skb))
+               return -EINVAL;
+
        rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
        rx_status->band = hw->conf.channel->band;
        rx_status->freq = hw->conf.channel->center_freq;
-       rx_status->noise = common->ani.noise_floor;
        rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
        rx_status->antenna = rx_stats->rs_antenna;
        rx_status->flag |= RX_FLAG_TSFT;
@@ -255,7 +273,8 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
 
        keyix = rx_stats->rs_keyix;
 
-       if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
+       if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+           ieee80211_has_protected(fc)) {
                rxs->flag |= RX_FLAG_DECRYPTED;
        } else if (ieee80211_has_protected(fc)
                   && !decrypt_error && skb->len >= hdrlen + 4) {
@@ -286,6 +305,345 @@ int ath9k_cmn_padpos(__le16 frame_control)
 }
 EXPORT_SYMBOL(ath9k_cmn_padpos);
 
+int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+       if (tx_info->control.hw_key) {
+               if (tx_info->control.hw_key->alg == ALG_WEP)
+                       return ATH9K_KEY_TYPE_WEP;
+               else if (tx_info->control.hw_key->alg == ALG_TKIP)
+                       return ATH9K_KEY_TYPE_TKIP;
+               else if (tx_info->control.hw_key->alg == ALG_CCMP)
+                       return ATH9K_KEY_TYPE_AES;
+       }
+
+       return ATH9K_KEY_TYPE_CLEAR;
+}
+EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype);
+
+static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan,
+                                enum nl80211_channel_type channel_type)
+{
+       u32 chanmode = 0;
+
+       switch (chan->band) {
+       case IEEE80211_BAND_2GHZ:
+               switch (channel_type) {
+               case NL80211_CHAN_NO_HT:
+               case NL80211_CHAN_HT20:
+                       chanmode = CHANNEL_G_HT20;
+                       break;
+               case NL80211_CHAN_HT40PLUS:
+                       chanmode = CHANNEL_G_HT40PLUS;
+                       break;
+               case NL80211_CHAN_HT40MINUS:
+                       chanmode = CHANNEL_G_HT40MINUS;
+                       break;
+               }
+               break;
+       case IEEE80211_BAND_5GHZ:
+               switch (channel_type) {
+               case NL80211_CHAN_NO_HT:
+               case NL80211_CHAN_HT20:
+                       chanmode = CHANNEL_A_HT20;
+                       break;
+               case NL80211_CHAN_HT40PLUS:
+                       chanmode = CHANNEL_A_HT40PLUS;
+                       break;
+               case NL80211_CHAN_HT40MINUS:
+                       chanmode = CHANNEL_A_HT40MINUS;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return chanmode;
+}
+
+/*
+ * Update internal channel flags.
+ */
+void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
+                              struct ath9k_channel *ichan)
+{
+       struct ieee80211_channel *chan = hw->conf.channel;
+       struct ieee80211_conf *conf = &hw->conf;
+
+       ichan->channel = chan->center_freq;
+       ichan->chan = chan;
+
+       if (chan->band == IEEE80211_BAND_2GHZ) {
+               ichan->chanmode = CHANNEL_G;
+               ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
+       } else {
+               ichan->chanmode = CHANNEL_A;
+               ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
+       }
+
+       if (conf_is_ht(conf))
+               ichan->chanmode = ath9k_get_extchanmode(chan,
+                                                       conf->channel_type);
+}
+EXPORT_SYMBOL(ath9k_cmn_update_ichannel);
+
+/*
+ * Get the internal channel reference.
+ */
+struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
+                                              struct ath_hw *ah)
+{
+       struct ieee80211_channel *curchan = hw->conf.channel;
+       struct ath9k_channel *channel;
+       u8 chan_idx;
+
+       chan_idx = curchan->hw_value;
+       channel = &ah->channels[chan_idx];
+       ath9k_cmn_update_ichannel(hw, channel);
+
+       return channel;
+}
+EXPORT_SYMBOL(ath9k_cmn_get_curchannel);
+
+static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
+                          struct ath9k_keyval *hk, const u8 *addr,
+                          bool authenticator)
+{
+       struct ath_hw *ah = common->ah;
+       const u8 *key_rxmic;
+       const u8 *key_txmic;
+
+       key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
+       key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
+
+       if (addr == NULL) {
+               /*
+                * Group key installation - only two key cache entries are used
+                * regardless of splitmic capability since group key is only
+                * used either for TX or RX.
+                */
+               if (authenticator) {
+                       memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+                       memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
+               } else {
+                       memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+                       memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
+               }
+               return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
+       }
+       if (!common->splitmic) {
+               /* TX and RX keys share the same key cache entry. */
+               memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+               memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
+               return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
+       }
+
+       /* Separate key cache entries for TX and RX */
+
+       /* TX key goes at first index, RX key at +32. */
+       memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+       if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
+               /* TX MIC entry failed. No need to proceed further */
+               ath_print(common, ATH_DBG_FATAL,
+                         "Setting TX MIC Key Failed\n");
+               return 0;
+       }
+
+       memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+       /* XXX delete tx key on failure? */
+       return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
+}
+
+static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
+{
+       int i;
+
+       for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
+               if (test_bit(i, common->keymap) ||
+                   test_bit(i + 64, common->keymap))
+                       continue; /* At least one part of TKIP key allocated */
+               if (common->splitmic &&
+                   (test_bit(i + 32, common->keymap) ||
+                    test_bit(i + 64 + 32, common->keymap)))
+                       continue; /* At least one part of TKIP key allocated */
+
+               /* Found a free slot for a TKIP key */
+               return i;
+       }
+       return -1;
+}
+
+static int ath_reserve_key_cache_slot(struct ath_common *common)
+{
+       int i;
+
+       /* First, try to find slots that would not be available for TKIP. */
+       if (common->splitmic) {
+               for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
+                       if (!test_bit(i, common->keymap) &&
+                           (test_bit(i + 32, common->keymap) ||
+                            test_bit(i + 64, common->keymap) ||
+                            test_bit(i + 64 + 32, common->keymap)))
+                               return i;
+                       if (!test_bit(i + 32, common->keymap) &&
+                           (test_bit(i, common->keymap) ||
+                            test_bit(i + 64, common->keymap) ||
+                            test_bit(i + 64 + 32, common->keymap)))
+                               return i + 32;
+                       if (!test_bit(i + 64, common->keymap) &&
+                           (test_bit(i , common->keymap) ||
+                            test_bit(i + 32, common->keymap) ||
+                            test_bit(i + 64 + 32, common->keymap)))
+                               return i + 64;
+                       if (!test_bit(i + 64 + 32, common->keymap) &&
+                           (test_bit(i, common->keymap) ||
+                            test_bit(i + 32, common->keymap) ||
+                            test_bit(i + 64, common->keymap)))
+                               return i + 64 + 32;
+               }
+       } else {
+               for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
+                       if (!test_bit(i, common->keymap) &&
+                           test_bit(i + 64, common->keymap))
+                               return i;
+                       if (test_bit(i, common->keymap) &&
+                           !test_bit(i + 64, common->keymap))
+                               return i + 64;
+               }
+       }
+
+       /* No partially used TKIP slots, pick any available slot */
+       for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
+               /* Do not allow slots that could be needed for TKIP group keys
+                * to be used. This limitation could be removed if we know that
+                * TKIP will not be used. */
+               if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
+                       continue;
+               if (common->splitmic) {
+                       if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
+                               continue;
+                       if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
+                               continue;
+               }
+
+               if (!test_bit(i, common->keymap))
+                       return i; /* Found a free slot for a key */
+       }
+
+       /* No free slot found */
+       return -1;
+}
+
+/*
+ * Configure encryption in the HW.
+ */
+int ath9k_cmn_key_config(struct ath_common *common,
+                        struct ieee80211_vif *vif,
+                        struct ieee80211_sta *sta,
+                        struct ieee80211_key_conf *key)
+{
+       struct ath_hw *ah = common->ah;
+       struct ath9k_keyval hk;
+       const u8 *mac = NULL;
+       int ret = 0;
+       int idx;
+
+       memset(&hk, 0, sizeof(hk));
+
+       switch (key->alg) {
+       case ALG_WEP:
+               hk.kv_type = ATH9K_CIPHER_WEP;
+               break;
+       case ALG_TKIP:
+               hk.kv_type = ATH9K_CIPHER_TKIP;
+               break;
+       case ALG_CCMP:
+               hk.kv_type = ATH9K_CIPHER_AES_CCM;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       hk.kv_len = key->keylen;
+       memcpy(hk.kv_val, key->key, key->keylen);
+
+       if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               /* For now, use the default keys for broadcast keys. This may
+                * need to change with virtual interfaces. */
+               idx = key->keyidx;
+       } else if (key->keyidx) {
+               if (WARN_ON(!sta))
+                       return -EOPNOTSUPP;
+               mac = sta->addr;
+
+               if (vif->type != NL80211_IFTYPE_AP) {
+                       /* Only keyidx 0 should be used with unicast key, but
+                        * allow this for client mode for now. */
+                       idx = key->keyidx;
+               } else
+                       return -EIO;
+       } else {
+               if (WARN_ON(!sta))
+                       return -EOPNOTSUPP;
+               mac = sta->addr;
+
+               if (key->alg == ALG_TKIP)
+                       idx = ath_reserve_key_cache_slot_tkip(common);
+               else
+                       idx = ath_reserve_key_cache_slot(common);
+               if (idx < 0)
+                       return -ENOSPC; /* no free key cache entries */
+       }
+
+       if (key->alg == ALG_TKIP)
+               ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
+                                     vif->type == NL80211_IFTYPE_AP);
+       else
+               ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
+
+       if (!ret)
+               return -EIO;
+
+       set_bit(idx, common->keymap);
+       if (key->alg == ALG_TKIP) {
+               set_bit(idx + 64, common->keymap);
+               if (common->splitmic) {
+                       set_bit(idx + 32, common->keymap);
+                       set_bit(idx + 64 + 32, common->keymap);
+               }
+       }
+
+       return idx;
+}
+EXPORT_SYMBOL(ath9k_cmn_key_config);
+
+/*
+ * Delete Key.
+ */
+void ath9k_cmn_key_delete(struct ath_common *common,
+                         struct ieee80211_key_conf *key)
+{
+       struct ath_hw *ah = common->ah;
+
+       ath9k_hw_keyreset(ah, key->hw_key_idx);
+       if (key->hw_key_idx < IEEE80211_WEP_NKID)
+               return;
+
+       clear_bit(key->hw_key_idx, common->keymap);
+       if (key->alg != ALG_TKIP)
+               return;
+
+       clear_bit(key->hw_key_idx + 64, common->keymap);
+       if (common->splitmic) {
+               ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
+               clear_bit(key->hw_key_idx + 32, common->keymap);
+               clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
+       }
+}
+EXPORT_SYMBOL(ath9k_cmn_key_delete);
+
 static int __init ath9k_cmn_init(void)
 {
        return 0;
index 042999c2fe9c58eb980c08eb65ddcaebe2b52c94..e08f7e5a26e0e90072a36c5ac46a311907e7a8a3 100644 (file)
 #include "../debug.h"
 
 #include "hw.h"
+#include "hw-ops.h"
 
 /* Common header for Atheros 802.11n base driver cores */
 
+#define IEEE80211_WEP_NKID 4
+
 #define WME_NUM_TID             16
 #define WME_BA_BMP_SIZE         64
 #define WME_MAX_BA              WME_BA_BMP_SIZE
@@ -74,11 +77,12 @@ struct ath_buf {
                                           an aggregate) */
        struct ath_buf *bf_next;        /* next subframe in the aggregate */
        struct sk_buff *bf_mpdu;        /* enclosing frame structure */
-       struct ath_desc *bf_desc;       /* virtual addr of desc */
+       void *bf_desc;                  /* virtual addr of desc */
        dma_addr_t bf_daddr;            /* physical addr of desc */
        dma_addr_t bf_buf_addr;         /* physical addr of data buffer */
        bool bf_stale;
        bool bf_isnullfunc;
+       bool bf_tx_aborted;
        u16 bf_flags;
        struct ath_buf_state bf_state;
        dma_addr_t bf_dmacontext;
@@ -125,3 +129,14 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
                                  bool decrypt_error);
 
 int ath9k_cmn_padpos(__le16 frame_control);
+int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
+void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
+                              struct ath9k_channel *ichan);
+struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
+                                              struct ath_hw *ah);
+int ath9k_cmn_key_config(struct ath_common *common,
+                        struct ieee80211_vif *vif,
+                        struct ieee80211_sta *sta,
+                        struct ieee80211_key_conf *key);
+void ath9k_cmn_key_delete(struct ath_common *common,
+                         struct ieee80211_key_conf *key);
index 081e0085ed4ce3460c82d2ba8f44eab5a090a4e7..29898f8d1893606627abdeb601966dc213cc61b8 100644 (file)
@@ -78,6 +78,90 @@ static const struct file_operations fops_debug = {
 
 #define DMA_BUF_LEN 1024
 
+static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_tx_chainmask(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       unsigned long mask;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &mask))
+               return -EINVAL;
+
+       common->tx_chainmask = mask;
+       sc->sc_ah->caps.tx_chainmask = mask;
+       return count;
+}
+
+static const struct file_operations fops_tx_chainmask = {
+       .read = read_file_tx_chainmask,
+       .write = write_file_tx_chainmask,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+
+static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_rx_chainmask(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       unsigned long mask;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &mask))
+               return -EINVAL;
+
+       common->rx_chainmask = mask;
+       sc->sc_ah->caps.rx_chainmask = mask;
+       return count;
+}
+
+static const struct file_operations fops_rx_chainmask = {
+       .read = read_file_rx_chainmask,
+       .write = write_file_rx_chainmask,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
 {
@@ -157,10 +241,10 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
                (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x \n",
+       len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n",
                        REG_READ_D(ah, AR_OBS_BUS_1));
        len += snprintf(buf + len, DMA_BUF_LEN - len,
-                       "AR_CR: 0x%x \n", REG_READ_D(ah, AR_CR));
+                       "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));
 
        ath9k_ps_restore(sc);
 
@@ -180,8 +264,15 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
 {
        if (status)
                sc->debug.stats.istats.total++;
-       if (status & ATH9K_INT_RX)
-               sc->debug.stats.istats.rxok++;
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               if (status & ATH9K_INT_RXLP)
+                       sc->debug.stats.istats.rxlp++;
+               if (status & ATH9K_INT_RXHP)
+                       sc->debug.stats.istats.rxhp++;
+       } else {
+               if (status & ATH9K_INT_RX)
+                       sc->debug.stats.istats.rxok++;
+       }
        if (status & ATH9K_INT_RXEOL)
                sc->debug.stats.istats.rxeol++;
        if (status & ATH9K_INT_RXORN)
@@ -223,8 +314,15 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
        char buf[512];
        unsigned int len = 0;
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-               "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               len += snprintf(buf + len, sizeof(buf) - len,
+                       "%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
+               len += snprintf(buf + len, sizeof(buf) - len,
+                       "%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
+       } else {
+               len += snprintf(buf + len, sizeof(buf) - len,
+                       "%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
+       }
        len += snprintf(buf + len, sizeof(buf) - len,
                "%8s: %10u\n", "RXEOL", sc->debug.stats.istats.rxeol);
        len += snprintf(buf + len, sizeof(buf) - len,
@@ -557,10 +655,8 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 }
 
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
-                      struct ath_buf *bf)
+                      struct ath_buf *bf, struct ath_tx_status *ts)
 {
-       struct ath_desc *ds = bf->bf_desc;
-
        if (bf_isampdu(bf)) {
                if (bf_isxretried(bf))
                        TX_STAT_INC(txq->axq_qnum, a_xretries);
@@ -570,17 +666,17 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq,
                TX_STAT_INC(txq->axq_qnum, completed);
        }
 
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO)
+       if (ts->ts_status & ATH9K_TXERR_FIFO)
                TX_STAT_INC(txq->axq_qnum, fifo_underrun);
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_XTXOP)
+       if (ts->ts_status & ATH9K_TXERR_XTXOP)
                TX_STAT_INC(txq->axq_qnum, xtxop);
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_TIMER_EXPIRED)
+       if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED)
                TX_STAT_INC(txq->axq_qnum, timer_exp);
-       if (ds->ds_txstat.ts_flags & ATH9K_TX_DESC_CFG_ERR)
+       if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR)
                TX_STAT_INC(txq->axq_qnum, desc_cfg_err);
-       if (ds->ds_txstat.ts_flags & ATH9K_TX_DATA_UNDERRUN)
+       if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN)
                TX_STAT_INC(txq->axq_qnum, data_underrun);
-       if (ds->ds_txstat.ts_flags & ATH9K_TX_DELIM_UNDERRUN)
+       if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN)
                TX_STAT_INC(txq->axq_qnum, delim_underrun);
 }
 
@@ -663,30 +759,29 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
 #undef PHY_ERR
 }
 
-void ath_debug_stat_rx(struct ath_softc *sc, struct ath_buf *bf)
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
 {
 #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)
+       if (rs->rs_status & ATH9K_RXERR_CRC)
                RX_STAT_INC(crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT)
+       if (rs->rs_status & ATH9K_RXERR_DECRYPT)
                RX_STAT_INC(decrypt_crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC)
+       if (rs->rs_status & ATH9K_RXERR_MIC)
                RX_STAT_INC(mic_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RX_DELIM_CRC_PRE)
+       if (rs->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)
+       if (rs->rs_status & ATH9K_RX_DELIM_CRC_POST)
                RX_STAT_INC(post_delim_crc_err);
-       if (ds->ds_rxstat.rs_status & ATH9K_RX_DECRYPT_BUSY)
+       if (rs->rs_status & ATH9K_RX_DECRYPT_BUSY)
                RX_STAT_INC(decrypt_busy_err);
 
-       if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) {
+       if (rs->rs_status & ATH9K_RXERR_PHY) {
                RX_STAT_INC(phy_err);
-               phyerr = ds->ds_rxstat.rs_phyerr & 0x24;
+               phyerr = rs->rs_phyerr & 0x24;
                RX_PHY_ERR_INC(phyerr);
        }
 
@@ -700,6 +795,86 @@ static const struct file_operations fops_recv = {
        .owner = THIS_MODULE
 };
 
+static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       unsigned long regidx;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &regidx))
+               return -EINVAL;
+
+       sc->debug.regidx = regidx;
+       return count;
+}
+
+static const struct file_operations fops_regidx = {
+       .read = read_file_regidx,
+       .write = write_file_regidx,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+static ssize_t read_file_regval(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_hw *ah = sc->sc_ah;
+       char buf[32];
+       unsigned int len;
+       u32 regval;
+
+       regval = REG_READ_D(ah, sc->debug.regidx);
+       len = snprintf(buf, sizeof(buf), "0x%08x\n", regval);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_hw *ah = sc->sc_ah;
+       unsigned long regval;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EINVAL;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &regval))
+               return -EINVAL;
+
+       REG_WRITE_D(ah, sc->debug.regidx, regval);
+       return count;
+}
+
+static const struct file_operations fops_regval = {
+       .read = read_file_regval,
+       .write = write_file_regval,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
 int ath9k_init_debug(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -711,54 +886,55 @@ int ath9k_init_debug(struct ath_hw *ah)
        sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
                                                      ath9k_debugfs_root);
        if (!sc->debug.debugfs_phy)
-               goto err;
+               return -ENOMEM;
 
 #ifdef CONFIG_ATH_DEBUG
-       sc->debug.debugfs_debug = debugfs_create_file("debug",
-               S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
-       if (!sc->debug.debugfs_debug)
+       if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_debug))
                goto err;
 #endif
 
-       sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
-                                      sc->debug.debugfs_phy, sc, &fops_dma);
-       if (!sc->debug.debugfs_dma)
+       if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_dma))
+               goto err;
+
+       if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_interrupt))
+               goto err;
+
+       if (!debugfs_create_file("rcstat", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_rcstat))
+               goto err;
+
+       if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_wiphy))
+               goto err;
+
+       if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_xmit))
                goto err;
 
-       sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
-                                                    S_IRUSR,
-                                                    sc->debug.debugfs_phy,
-                                                    sc, &fops_interrupt);
-       if (!sc->debug.debugfs_interrupt)
+       if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
+                       sc, &fops_recv))
                goto err;
 
-       sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
-                                                 S_IRUSR,
-                                                 sc->debug.debugfs_phy,
-                                                 sc, &fops_rcstat);
-       if (!sc->debug.debugfs_rcstat)
+       if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
                goto err;
 
-       sc->debug.debugfs_wiphy = debugfs_create_file(
-               "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
-               &fops_wiphy);
-       if (!sc->debug.debugfs_wiphy)
+       if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
                goto err;
 
-       sc->debug.debugfs_xmit = debugfs_create_file("xmit",
-                                                    S_IRUSR,
-                                                    sc->debug.debugfs_phy,
-                                                    sc, &fops_xmit);
-       if (!sc->debug.debugfs_xmit)
+       if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_regidx))
                goto err;
 
-       sc->debug.debugfs_recv = debugfs_create_file("recv",
-                                                    S_IRUSR,
-                                                    sc->debug.debugfs_phy,
-                                                    sc, &fops_recv);
-       if (!sc->debug.debugfs_recv)
+       if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
+                       sc->debug.debugfs_phy, sc, &fops_regval))
                goto err;
 
+       sc->debug.regidx = 0;
        return 0;
 err:
        ath9k_exit_debug(ah);
@@ -770,14 +946,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);
-       debugfs_remove(sc->debug.debugfs_interrupt);
-       debugfs_remove(sc->debug.debugfs_dma);
-       debugfs_remove(sc->debug.debugfs_debug);
-       debugfs_remove(sc->debug.debugfs_phy);
+       debugfs_remove_recursive(sc->debug.debugfs_phy);
 }
 
 int ath9k_debug_create_root(void)
index 86780e68b31e64ffeae8174354baabace6b80bfe..5147b8709e103bf0811390b9c0989f8485b9c361 100644 (file)
@@ -35,6 +35,8 @@ struct ath_buf;
  * struct ath_interrupt_stats - Contains statistics about interrupts
  * @total: Total no. of interrupts generated so far
  * @rxok: RX with no errors
+ * @rxlp: RX with low priority RX
+ * @rxhp: RX with high priority, uapsd only
  * @rxeol: RX with no more RXDESC available
  * @rxorn: RX FIFO overrun
  * @txok: TX completed at the requested rate
@@ -55,6 +57,8 @@ struct ath_buf;
 struct ath_interrupt_stats {
        u32 total;
        u32 rxok;
+       u32 rxlp;
+       u32 rxhp;
        u32 rxeol;
        u32 rxorn;
        u32 txok;
@@ -149,13 +153,7 @@ struct ath_stats {
 
 struct ath9k_debug {
        struct dentry *debugfs_phy;
-       struct dentry *debugfs_debug;
-       struct dentry *debugfs_dma;
-       struct dentry *debugfs_interrupt;
-       struct dentry *debugfs_rcstat;
-       struct dentry *debugfs_wiphy;
-       struct dentry *debugfs_xmit;
-       struct dentry *debugfs_recv;
+       u32 regidx;
        struct ath_stats stats;
 };
 
@@ -167,8 +165,8 @@ void ath9k_debug_remove_root(void);
 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);
+                      struct ath_buf *bf, struct ath_tx_status *ts);
+void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs);
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
                            int xretries, int retries, u8 per);
 
@@ -204,12 +202,13 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
 
 static inline void ath_debug_stat_tx(struct ath_softc *sc,
                                     struct ath_txq *txq,
-                                    struct ath_buf *bf)
+                                    struct ath_buf *bf,
+                                    struct ath_tx_status *ts)
 {
 }
 
 static inline void ath_debug_stat_rx(struct ath_softc *sc,
-                                    struct ath_buf *bf)
+                                    struct ath_rx_status *rs)
 {
 }
 
index dacaae9341480dc253d3c4a42bc00c508e431c05..ca8704a9d7ac6208bedec668b790e2c55f149001 100644 (file)
@@ -36,8 +36,6 @@ void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
 
        if (ah->config.analog_shiftreg)
                udelay(100);
-
-       return;
 }
 
 int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
@@ -256,14 +254,13 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah)
 {
        int status;
 
-       if (AR_SREV_9287(ah)) {
-               ah->eep_map = EEP_MAP_AR9287;
-               ah->eep_ops = &eep_AR9287_ops;
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               ah->eep_ops = &eep_ar9300_ops;
+       else if (AR_SREV_9287(ah)) {
+               ah->eep_ops = &eep_ar9287_ops;
        } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) {
-               ah->eep_map = EEP_MAP_4KBITS;
                ah->eep_ops = &eep_4k_ops;
        } else {
-               ah->eep_map = EEP_MAP_DEFAULT;
                ah->eep_ops = &eep_def_ops;
        }
 
index 2f2993b50e2ffb2159261ad97a4c4632ded5b31d..21354c15a9a9b1181fd2eaa6d7933c5706019b47 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "../ath.h"
 #include <net/cfg80211.h>
+#include "ar9003_eeprom.h"
 
 #define AH_USE_EEPROM   0x1
 
@@ -93,7 +94,6 @@
  */
 #define AR9285_RDEXT_DEFAULT    0x1F
 
-#define AR_EEPROM_MAC(i)       (0x1d+(i))
 #define ATH9K_POW_SM(_r, _s)   (((_r) & 0x3f) << (_s))
 #define FREQ2FBIN(x, y)                ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
 #define ath9k_hw_use_flash(_ah)        (!(_ah->ah_flags & AH_USE_EEPROM))
 #define AR5416_BCHAN_UNUSED             0xFF
 #define AR5416_MAX_PWR_RANGE_IN_HALF_DB 64
 #define AR5416_MAX_CHAINS               3
+#define AR9300_MAX_CHAINS              3
 #define AR5416_PWR_TABLE_OFFSET_DB     -5
 
 /* Rx gain type values */
@@ -249,16 +250,20 @@ enum eeprom_param {
        EEP_MINOR_REV,
        EEP_TX_MASK,
        EEP_RX_MASK,
+       EEP_FSTCLK_5G,
        EEP_RXGAIN_TYPE,
-       EEP_TXGAIN_TYPE,
        EEP_OL_PWRCTRL,
+       EEP_TXGAIN_TYPE,
        EEP_RC_CHAIN_MASK,
        EEP_DAC_HPWR_5G,
        EEP_FRAC_N_5G,
        EEP_DEV_TYPE,
        EEP_TEMPSENSE_SLOPE,
        EEP_TEMPSENSE_SLOPE_PAL_ON,
-       EEP_PWR_TABLE_OFFSET
+       EEP_PWR_TABLE_OFFSET,
+       EEP_DRIVE_STRENGTH,
+       EEP_INTERNAL_REGULATOR,
+       EEP_SWREG
 };
 
 enum ar5416_rates {
@@ -295,7 +300,8 @@ struct base_eep_header {
        u32 binBuildNumber;
        u8 deviceType;
        u8 pwdclkind;
-       u8 futureBase_1[2];
+       u8 fastClk5g;
+       u8 divChain;
        u8 rxGainType;
        u8 dacHiPwrMode_5G;
        u8 openLoopPwrCntl;
@@ -656,13 +662,6 @@ struct ath9k_country_entry {
        u8 iso[3];
 };
 
-enum ath9k_eep_map {
-       EEP_MAP_DEFAULT = 0x0,
-       EEP_MAP_4KBITS,
-       EEP_MAP_AR9287,
-       EEP_MAP_MAX
-};
-
 struct eeprom_ops {
        int (*check_eeprom)(struct ath_hw *hw);
        u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param);
@@ -713,6 +712,8 @@ int ath9k_hw_eeprom_init(struct ath_hw *ah);
 
 extern const struct eeprom_ops eep_def_ops;
 extern const struct eeprom_ops eep_4k_ops;
-extern const struct eeprom_ops eep_AR9287_ops;
+extern const struct eeprom_ops eep_ar9287_ops;
+extern const struct eeprom_ops eep_ar9287_ops;
+extern const struct eeprom_ops eep_ar9300_ops;
 
 #endif /* EEPROM_H */
index 68db16690abf962237d9e10044873a8da44db9bc..41a77d1bd43981a4e39a3b40bae55c2a1ae63664 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "hw.h"
+#include "ar9002_phy.h"
 
 static int ath9k_hw_4k_get_eeprom_ver(struct ath_hw *ah)
 {
@@ -43,7 +44,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah)
        for (addr = 0; addr < SIZE_EEPROM_4K; addr++) {
                if (!ath9k_hw_nvram_read(common, addr + eep_start_loc, eep_data)) {
                        ath_print(common, ATH_DBG_EEPROM,
-                                 "Unable to read eeprom region \n");
+                                 "Unable to read eeprom region\n");
                        return false;
                }
                eep_data++;
@@ -182,11 +183,11 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
        switch (param) {
        case EEP_NFTHRESH_2:
                return pModal->noiseFloorThreshCh[0];
-       case AR_EEPROM_MAC(0):
+       case EEP_MAC_LSW:
                return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-       case AR_EEPROM_MAC(1):
+       case EEP_MAC_MID:
                return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-       case AR_EEPROM_MAC(2):
+       case EEP_MAC_MSW:
                return pBase->macAddr[4] << 8 | pBase->macAddr[5];
        case EEP_REG_0:
                return pBase->regDmn[0];
@@ -453,6 +454,8 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
                                            &tMinCalPower, gainBoundaries,
                                            pdadcValues, numXpdGain);
 
+                       ENABLE_REGWRITE_BUFFER(ah);
+
                        if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
                                REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
                                          SM(pdGainOverlap_t2,
@@ -493,6 +496,9 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
 
                                regOffset += 4;
                        }
+
+                       REGWRITE_BUFFER_FLUSH(ah);
+                       DISABLE_REGWRITE_BUFFER(ah);
                }
        }
 
@@ -758,6 +764,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
                        ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
        }
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        /* OFDM power per rate */
        REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
                  ATH9K_POW_SM(ratesArray[rate18mb], 24)
@@ -820,6 +828,9 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
                          | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
                          | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
        }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
index 839d05a1df29f1c9d807ffceacace1ee1f276fc2..b471db5fb82d80d1b51564ad497b67e375a497f9 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "hw.h"
+#include "ar9002_phy.h"
 
 static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
 {
@@ -44,7 +45,7 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
                if (!ath9k_hw_nvram_read(common,
                                         addr + eep_start_loc, eep_data)) {
                        ath_print(common, ATH_DBG_EEPROM,
-                                 "Unable to read eeprom region \n");
+                                 "Unable to read eeprom region\n");
                        return false;
                }
                eep_data++;
@@ -172,11 +173,11 @@ static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
        switch (param) {
        case EEP_NFTHRESH_2:
                return pModal->noiseFloorThreshCh[0];
-       case AR_EEPROM_MAC(0):
+       case EEP_MAC_LSW:
                return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-       case AR_EEPROM_MAC(1):
+       case EEP_MAC_MID:
                return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-       case AR_EEPROM_MAC(2):
+       case EEP_MAC_MSW:
                return pBase->macAddr[4] << 8 | pBase->macAddr[5];
        case EEP_REG_0:
                return pBase->regDmn[0];
@@ -1169,7 +1170,7 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
 #undef EEP_MAP9287_SPURCHAN
 }
 
-const struct eeprom_ops eep_AR9287_ops = {
+const struct eeprom_ops eep_ar9287_ops = {
        .check_eeprom           = ath9k_hw_AR9287_check_eeprom,
        .get_eeprom             = ath9k_hw_AR9287_get_eeprom,
        .fill_eeprom            = ath9k_hw_AR9287_fill_eeprom,
index 404a0341242c4531e49777d1639cd7600afbfdb1..7e1ed78d0e64b0ec63006a8ef751a253628da249 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include "hw.h"
+#include "ar9002_phy.h"
 
 static void ath9k_get_txgain_index(struct ath_hw *ah,
                struct ath9k_channel *chan,
@@ -49,7 +50,6 @@ static void ath9k_get_txgain_index(struct ath_hw *ah,
                i++;
 
        *pcdacIdx = i;
-       return;
 }
 
 static void ath9k_olc_get_pdadcs(struct ath_hw *ah,
@@ -222,6 +222,12 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
                return -EINVAL;
        }
 
+       /* Enable fixup for AR_AN_TOP2 if necessary */
+       if (AR_SREV_9280_10_OR_LATER(ah) &&
+           (eep->baseEepHeader.version & 0xff) > 0x0a &&
+           eep->baseEepHeader.pwdclkind == 0)
+               ah->need_an_top2_fixup = 1;
+
        return 0;
 }
 
@@ -237,11 +243,11 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
                return pModal[0].noiseFloorThreshCh[0];
        case EEP_NFTHRESH_2:
                return pModal[1].noiseFloorThreshCh[0];
-       case AR_EEPROM_MAC(0):
+       case EEP_MAC_LSW:
                return pBase->macAddr[0] << 8 | pBase->macAddr[1];
-       case AR_EEPROM_MAC(1):
+       case EEP_MAC_MID:
                return pBase->macAddr[2] << 8 | pBase->macAddr[3];
-       case AR_EEPROM_MAC(2):
+       case EEP_MAC_MSW:
                return pBase->macAddr[4] << 8 | pBase->macAddr[5];
        case EEP_REG_0:
                return pBase->regDmn[0];
@@ -267,6 +273,8 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
                return pBase->txMask;
        case EEP_RX_MASK:
                return pBase->rxMask;
+       case EEP_FSTCLK_5G:
+               return pBase->fastClk5g;
        case EEP_RXGAIN_TYPE:
                return pBase->rxGainType;
        case EEP_TXGAIN_TYPE:
@@ -742,8 +750,6 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
                pPDADCValues[k] = pPDADCValues[k - 1];
                k++;
        }
-
-       return;
 }
 
 static int16_t ath9k_change_gain_boundary_setting(struct ath_hw *ah,
index deab8beb068010a7a7ec3de2ddd404d64ddce32a..0ee75e79fe35a38f9e0aa4c72c3570922fb17bf7 100644 (file)
@@ -283,22 +283,17 @@ static void ath9k_gen_timer_start(struct ath_hw *ah,
                                  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) {
+       if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
                ath9k_hw_set_interrupts(ah, 0);
-               sc->imask |= ATH9K_INT_GENTIMER;
-               ath9k_hw_set_interrupts(ah, sc->imask);
+               ah->imask |= ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah, ah->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);
@@ -306,8 +301,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *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);
+               ah->imask &= ~ATH9K_INT_GENTIMER;
+               ath9k_hw_set_interrupts(ah, ah->imask);
        }
 }
 
@@ -364,7 +359,7 @@ static void ath_btcoex_no_stomp_timer(void *arg)
        bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        ath_print(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
-                 "no stomp timer running \n");
+                 "no stomp timer running\n");
 
        spin_lock_bh(&btcoex->btcoex_lock);
 
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
new file mode 100644 (file)
index 0000000..46dc41a
--- /dev/null
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+#define ATH9K_FW_USB_DEV(devid, fw)                                    \
+       { USB_DEVICE(0x0cf3, devid), .driver_info = (unsigned long) fw }
+
+static struct usb_device_id ath9k_hif_usb_ids[] = {
+       ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"),
+       ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"),
+       { },
+};
+
+MODULE_DEVICE_TABLE(usb, ath9k_hif_usb_ids);
+
+static int __hif_usb_tx(struct hif_device_usb *hif_dev);
+
+static void hif_usb_regout_cb(struct urb *urb)
+{
+       struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ENODEV:
+       case -ESHUTDOWN:
+               goto free;
+       default:
+               break;
+       }
+
+       if (cmd) {
+               ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
+                                         cmd->skb, 1);
+               kfree(cmd);
+       }
+
+       return;
+free:
+       kfree_skb(cmd->skb);
+       kfree(cmd);
+}
+
+static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
+                              struct sk_buff *skb)
+{
+       struct urb *urb;
+       struct cmd_buf *cmd;
+       int ret = 0;
+
+       urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (urb == NULL)
+               return -ENOMEM;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       cmd->skb = skb;
+       cmd->hif_dev = hif_dev;
+
+       usb_fill_int_urb(urb, hif_dev->udev,
+                        usb_sndintpipe(hif_dev->udev, USB_REG_OUT_PIPE),
+                        skb->data, skb->len,
+                        hif_usb_regout_cb, cmd, 1);
+
+       usb_anchor_urb(urb, &hif_dev->regout_submitted);
+       ret = usb_submit_urb(urb, GFP_KERNEL);
+       if (ret) {
+               usb_unanchor_urb(urb);
+               kfree(cmd);
+       }
+       usb_free_urb(urb);
+
+       return ret;
+}
+
+static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
+                                        struct sk_buff_head *list)
+{
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(list)) != NULL) {
+               dev_kfree_skb_any(skb);
+               TX_STAT_INC(skb_dropped);
+       }
+}
+
+static void hif_usb_tx_cb(struct urb *urb)
+{
+       struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
+       struct hif_device_usb *hif_dev = tx_buf->hif_dev;
+       struct sk_buff *skb;
+
+       if (!hif_dev || !tx_buf)
+               return;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ENODEV:
+       case -ESHUTDOWN:
+               /*
+                * The URB has been killed, free the SKBs
+                * and return.
+                */
+               ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+               return;
+       default:
+               break;
+       }
+
+       /* Check if TX has been stopped */
+       spin_lock(&hif_dev->tx.tx_lock);
+       if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
+               spin_unlock(&hif_dev->tx.tx_lock);
+               ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+               goto add_free;
+       }
+       spin_unlock(&hif_dev->tx.tx_lock);
+
+       /* Complete the queued SKBs. */
+       while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
+               ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+                                         skb, 1);
+               TX_STAT_INC(skb_completed);
+       }
+
+add_free:
+       /* Re-initialize the SKB queue */
+       tx_buf->len = tx_buf->offset = 0;
+       __skb_queue_head_init(&tx_buf->skb_queue);
+
+       /* Add this TX buffer to the free list */
+       spin_lock(&hif_dev->tx.tx_lock);
+       list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
+       hif_dev->tx.tx_buf_cnt++;
+       if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
+               __hif_usb_tx(hif_dev); /* Check for pending SKBs */
+       TX_STAT_INC(buf_completed);
+       spin_unlock(&hif_dev->tx.tx_lock);
+}
+
+/* TX lock has to be taken */
+static int __hif_usb_tx(struct hif_device_usb *hif_dev)
+{
+       struct tx_buf *tx_buf = NULL;
+       struct sk_buff *nskb = NULL;
+       int ret = 0, i;
+       u16 *hdr, tx_skb_cnt = 0;
+       u8 *buf;
+
+       if (hif_dev->tx.tx_skb_cnt == 0)
+               return 0;
+
+       /* Check if a free TX buffer is available */
+       if (list_empty(&hif_dev->tx.tx_buf))
+               return 0;
+
+       tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list);
+       list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
+       hif_dev->tx.tx_buf_cnt--;
+
+       tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM);
+
+       for (i = 0; i < tx_skb_cnt; i++) {
+               nskb = __skb_dequeue(&hif_dev->tx.tx_skb_queue);
+
+               /* Should never be NULL */
+               BUG_ON(!nskb);
+
+               hif_dev->tx.tx_skb_cnt--;
+
+               buf = tx_buf->buf;
+               buf += tx_buf->offset;
+               hdr = (u16 *)buf;
+               *hdr++ = nskb->len;
+               *hdr++ = ATH_USB_TX_STREAM_MODE_TAG;
+               buf += 4;
+               memcpy(buf, nskb->data, nskb->len);
+               tx_buf->len = nskb->len + 4;
+
+               if (i < (tx_skb_cnt - 1))
+                       tx_buf->offset += (((tx_buf->len - 1) / 4) + 1) * 4;
+
+               if (i == (tx_skb_cnt - 1))
+                       tx_buf->len += tx_buf->offset;
+
+               __skb_queue_tail(&tx_buf->skb_queue, nskb);
+               TX_STAT_INC(skb_queued);
+       }
+
+       usb_fill_bulk_urb(tx_buf->urb, hif_dev->udev,
+                         usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
+                         tx_buf->buf, tx_buf->len,
+                         hif_usb_tx_cb, tx_buf);
+
+       ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
+       if (ret) {
+               tx_buf->len = tx_buf->offset = 0;
+               ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+               __skb_queue_head_init(&tx_buf->skb_queue);
+               list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
+               hif_dev->tx.tx_buf_cnt++;
+       }
+
+       if (!ret)
+               TX_STAT_INC(buf_queued);
+
+       return ret;
+}
+
+static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
+                          struct ath9k_htc_tx_ctl *tx_ctl)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+       if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
+               spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+               return -ENODEV;
+       }
+
+       /* Check if the max queue count has been reached */
+       if (hif_dev->tx.tx_skb_cnt > MAX_TX_BUF_NUM) {
+               spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+               return -ENOMEM;
+       }
+
+       __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
+       hif_dev->tx.tx_skb_cnt++;
+
+       /* Send normal frames immediately */
+       if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL)))
+               __hif_usb_tx(hif_dev);
+
+       /* Check if AMPDUs have to be sent immediately */
+       if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) &&
+           (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
+           (hif_dev->tx.tx_skb_cnt < 2)) {
+               __hif_usb_tx(hif_dev);
+       }
+
+       spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+
+       return 0;
+}
+
+static void hif_usb_start(void *hif_handle, u8 pipe_id)
+{
+       struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+       unsigned long flags;
+
+       hif_dev->flags |= HIF_USB_START;
+
+       spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+       hif_dev->tx.flags &= ~HIF_USB_TX_STOP;
+       spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+}
+
+static void hif_usb_stop(void *hif_handle, u8 pipe_id)
+{
+       struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+       ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
+       hif_dev->tx.tx_skb_cnt = 0;
+       hif_dev->tx.flags |= HIF_USB_TX_STOP;
+       spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+}
+
+static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
+                       struct ath9k_htc_tx_ctl *tx_ctl)
+{
+       struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+       int ret = 0;
+
+       switch (pipe_id) {
+       case USB_WLAN_TX_PIPE:
+               ret = hif_usb_send_tx(hif_dev, skb, tx_ctl);
+               break;
+       case USB_REG_OUT_PIPE:
+               ret = hif_usb_send_regout(hif_dev, skb);
+               break;
+       default:
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Invalid TX pipe: %d\n", pipe_id);
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static struct ath9k_htc_hif hif_usb = {
+       .transport = ATH9K_HIF_USB,
+       .name = "ath9k_hif_usb",
+
+       .control_ul_pipe = USB_REG_OUT_PIPE,
+       .control_dl_pipe = USB_REG_IN_PIPE,
+
+       .start = hif_usb_start,
+       .stop = hif_usb_stop,
+       .send = hif_usb_send,
+};
+
+static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
+                                   struct sk_buff *skb)
+{
+       struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
+       int index = 0, i = 0, chk_idx, len = skb->len;
+       int rx_remain_len = 0, rx_pkt_len = 0;
+       u16 pkt_len, pkt_tag, pool_index = 0;
+       u8 *ptr;
+
+       spin_lock(&hif_dev->rx_lock);
+
+       rx_remain_len = hif_dev->rx_remain_len;
+       rx_pkt_len = hif_dev->rx_transfer_len;
+
+       if (rx_remain_len != 0) {
+               struct sk_buff *remain_skb = hif_dev->remain_skb;
+
+               if (remain_skb) {
+                       ptr = (u8 *) remain_skb->data;
+
+                       index = rx_remain_len;
+                       rx_remain_len -= hif_dev->rx_pad_len;
+                       ptr += rx_pkt_len;
+
+                       memcpy(ptr, skb->data, rx_remain_len);
+
+                       rx_pkt_len += rx_remain_len;
+                       hif_dev->rx_remain_len = 0;
+                       skb_put(remain_skb, rx_pkt_len);
+
+                       skb_pool[pool_index++] = remain_skb;
+
+               } else {
+                       index = rx_remain_len;
+               }
+       }
+
+       spin_unlock(&hif_dev->rx_lock);
+
+       while (index < len) {
+               ptr = (u8 *) skb->data;
+
+               pkt_len = ptr[index] + (ptr[index+1] << 8);
+               pkt_tag = ptr[index+2] + (ptr[index+3] << 8);
+
+               if (pkt_tag == ATH_USB_RX_STREAM_MODE_TAG) {
+                       u16 pad_len;
+
+                       pad_len = 4 - (pkt_len & 0x3);
+                       if (pad_len == 4)
+                               pad_len = 0;
+
+                       chk_idx = index;
+                       index = index + 4 + pkt_len + pad_len;
+
+                       if (index > MAX_RX_BUF_SIZE) {
+                               spin_lock(&hif_dev->rx_lock);
+                               hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
+                               hif_dev->rx_transfer_len =
+                                       MAX_RX_BUF_SIZE - chk_idx - 4;
+                               hif_dev->rx_pad_len = pad_len;
+
+                               nskb = __dev_alloc_skb(pkt_len + 32,
+                                                      GFP_ATOMIC);
+                               if (!nskb) {
+                                       dev_err(&hif_dev->udev->dev,
+                                       "ath9k_htc: RX memory allocation"
+                                       " error\n");
+                                       spin_unlock(&hif_dev->rx_lock);
+                                       goto err;
+                               }
+                               skb_reserve(nskb, 32);
+                               RX_STAT_INC(skb_allocated);
+
+                               memcpy(nskb->data, &(skb->data[chk_idx+4]),
+                                      hif_dev->rx_transfer_len);
+
+                               /* Record the buffer pointer */
+                               hif_dev->remain_skb = nskb;
+                               spin_unlock(&hif_dev->rx_lock);
+                       } else {
+                               nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
+                               if (!nskb) {
+                                       dev_err(&hif_dev->udev->dev,
+                                       "ath9k_htc: RX memory allocation"
+                                       " error\n");
+                                       goto err;
+                               }
+                               skb_reserve(nskb, 32);
+                               RX_STAT_INC(skb_allocated);
+
+                               memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
+                               skb_put(nskb, pkt_len);
+                               skb_pool[pool_index++] = nskb;
+                       }
+               } else {
+                       RX_STAT_INC(skb_dropped);
+                       return;
+               }
+       }
+
+err:
+       for (i = 0; i < pool_index; i++) {
+               ath9k_htc_rx_msg(hif_dev->htc_handle, skb_pool[i],
+                                skb_pool[i]->len, USB_WLAN_RX_PIPE);
+               RX_STAT_INC(skb_completed);
+       }
+}
+
+static void ath9k_hif_usb_rx_cb(struct urb *urb)
+{
+       struct sk_buff *skb = (struct sk_buff *) urb->context;
+       struct hif_device_usb *hif_dev = (struct hif_device_usb *)
+               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+       int ret;
+
+       if (!skb)
+               return;
+
+       if (!hif_dev)
+               goto free;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ENODEV:
+       case -ESHUTDOWN:
+               goto free;
+       default:
+               goto resubmit;
+       }
+
+       if (likely(urb->actual_length != 0)) {
+               skb_put(skb, urb->actual_length);
+               ath9k_hif_usb_rx_stream(hif_dev, skb);
+       }
+
+resubmit:
+       skb_reset_tail_pointer(skb);
+       skb_trim(skb, 0);
+
+       usb_anchor_urb(urb, &hif_dev->rx_submitted);
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret) {
+               usb_unanchor_urb(urb);
+               goto free;
+       }
+
+       return;
+free:
+       kfree_skb(skb);
+}
+
+static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
+{
+       struct sk_buff *skb = (struct sk_buff *) urb->context;
+       struct sk_buff *nskb;
+       struct hif_device_usb *hif_dev = (struct hif_device_usb *)
+               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+       int ret;
+
+       if (!skb)
+               return;
+
+       if (!hif_dev)
+               goto free;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ENOENT:
+       case -ECONNRESET:
+       case -ENODEV:
+       case -ESHUTDOWN:
+               goto free;
+       default:
+               goto resubmit;
+       }
+
+       if (likely(urb->actual_length != 0)) {
+               skb_put(skb, urb->actual_length);
+
+               /* Process the command first */
+               ath9k_htc_rx_msg(hif_dev->htc_handle, skb,
+                                skb->len, USB_REG_IN_PIPE);
+
+
+               nskb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_ATOMIC);
+               if (!nskb) {
+                       dev_err(&hif_dev->udev->dev,
+                               "ath9k_htc: REG_IN memory allocation failure\n");
+                       urb->context = NULL;
+                       return;
+               }
+
+               usb_fill_int_urb(urb, hif_dev->udev,
+                                usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
+                                nskb->data, MAX_REG_IN_BUF_SIZE,
+                                ath9k_hif_usb_reg_in_cb, nskb, 1);
+
+               ret = usb_submit_urb(urb, GFP_ATOMIC);
+               if (ret) {
+                       kfree_skb(nskb);
+                       urb->context = NULL;
+               }
+
+               return;
+       }
+
+resubmit:
+       skb_reset_tail_pointer(skb);
+       skb_trim(skb, 0);
+
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+       if (ret)
+               goto free;
+
+       return;
+free:
+       kfree_skb(skb);
+       urb->context = NULL;
+}
+
+static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
+{
+       struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
+
+       list_for_each_entry_safe(tx_buf, tx_buf_tmp,
+                                &hif_dev->tx.tx_buf, list) {
+               usb_kill_urb(tx_buf->urb);
+               list_del(&tx_buf->list);
+               usb_free_urb(tx_buf->urb);
+               kfree(tx_buf->buf);
+               kfree(tx_buf);
+       }
+
+       list_for_each_entry_safe(tx_buf, tx_buf_tmp,
+                                &hif_dev->tx.tx_pending, list) {
+               usb_kill_urb(tx_buf->urb);
+               list_del(&tx_buf->list);
+               usb_free_urb(tx_buf->urb);
+               kfree(tx_buf->buf);
+               kfree(tx_buf);
+       }
+}
+
+static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
+{
+       struct tx_buf *tx_buf;
+       int i;
+
+       INIT_LIST_HEAD(&hif_dev->tx.tx_buf);
+       INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
+       spin_lock_init(&hif_dev->tx.tx_lock);
+       __skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
+
+       for (i = 0; i < MAX_TX_URB_NUM; i++) {
+               tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
+               if (!tx_buf)
+                       goto err;
+
+               tx_buf->buf = kzalloc(MAX_TX_BUF_SIZE, GFP_KERNEL);
+               if (!tx_buf->buf)
+                       goto err;
+
+               tx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!tx_buf->urb)
+                       goto err;
+
+               tx_buf->hif_dev = hif_dev;
+               __skb_queue_head_init(&tx_buf->skb_queue);
+
+               list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
+       }
+
+       hif_dev->tx.tx_buf_cnt = MAX_TX_URB_NUM;
+
+       return 0;
+err:
+       ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
+       return -ENOMEM;
+}
+
+static void ath9k_hif_usb_dealloc_rx_urbs(struct hif_device_usb *hif_dev)
+{
+       usb_kill_anchored_urbs(&hif_dev->rx_submitted);
+}
+
+static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
+{
+       struct urb *urb = NULL;
+       struct sk_buff *skb = NULL;
+       int i, ret;
+
+       init_usb_anchor(&hif_dev->rx_submitted);
+       spin_lock_init(&hif_dev->rx_lock);
+
+       for (i = 0; i < MAX_RX_URB_NUM; i++) {
+
+               /* Allocate URB */
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (urb == NULL) {
+                       ret = -ENOMEM;
+                       goto err_urb;
+               }
+
+               /* Allocate buffer */
+               skb = alloc_skb(MAX_RX_BUF_SIZE, GFP_KERNEL);
+               if (!skb) {
+                       ret = -ENOMEM;
+                       goto err_skb;
+               }
+
+               usb_fill_bulk_urb(urb, hif_dev->udev,
+                                 usb_rcvbulkpipe(hif_dev->udev,
+                                                 USB_WLAN_RX_PIPE),
+                                 skb->data, MAX_RX_BUF_SIZE,
+                                 ath9k_hif_usb_rx_cb, skb);
+
+               /* Anchor URB */
+               usb_anchor_urb(urb, &hif_dev->rx_submitted);
+
+               /* Submit URB */
+               ret = usb_submit_urb(urb, GFP_KERNEL);
+               if (ret) {
+                       usb_unanchor_urb(urb);
+                       goto err_submit;
+               }
+
+               /*
+                * Drop reference count.
+                * This ensures that the URB is freed when killing them.
+                */
+               usb_free_urb(urb);
+       }
+
+       return 0;
+
+err_submit:
+       kfree_skb(skb);
+err_skb:
+       usb_free_urb(urb);
+err_urb:
+       ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
+       return ret;
+}
+
+static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
+{
+       if (hif_dev->reg_in_urb) {
+               usb_kill_urb(hif_dev->reg_in_urb);
+               if (hif_dev->reg_in_urb->context)
+                       kfree_skb((void *)hif_dev->reg_in_urb->context);
+               usb_free_urb(hif_dev->reg_in_urb);
+               hif_dev->reg_in_urb = NULL;
+       }
+}
+
+static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
+{
+       struct sk_buff *skb;
+
+       hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (hif_dev->reg_in_urb == NULL)
+               return -ENOMEM;
+
+       skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
+       if (!skb)
+               goto err;
+
+       usb_fill_int_urb(hif_dev->reg_in_urb, hif_dev->udev,
+                        usb_rcvintpipe(hif_dev->udev, USB_REG_IN_PIPE),
+                        skb->data, MAX_REG_IN_BUF_SIZE,
+                        ath9k_hif_usb_reg_in_cb, skb, 1);
+
+       if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
+               goto err;
+
+       return 0;
+
+err:
+       ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+       return -ENOMEM;
+}
+
+static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
+{
+       /* Register Write */
+       init_usb_anchor(&hif_dev->regout_submitted);
+
+       /* TX */
+       if (ath9k_hif_usb_alloc_tx_urbs(hif_dev) < 0)
+               goto err;
+
+       /* RX */
+       if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0)
+               goto err;
+
+       /* Register Read */
+       if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
+               goto err;
+
+       return 0;
+err:
+       return -ENOMEM;
+}
+
+static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
+{
+       usb_kill_anchored_urbs(&hif_dev->regout_submitted);
+       ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+       ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
+       ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
+}
+
+static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
+{
+       int transfer, err;
+       const void *data = hif_dev->firmware->data;
+       size_t len = hif_dev->firmware->size;
+       u32 addr = AR9271_FIRMWARE;
+       u8 *buf = kzalloc(4096, GFP_KERNEL);
+
+       if (!buf)
+               return -ENOMEM;
+
+       while (len) {
+               transfer = min_t(int, len, 4096);
+               memcpy(buf, data, transfer);
+
+               err = usb_control_msg(hif_dev->udev,
+                                     usb_sndctrlpipe(hif_dev->udev, 0),
+                                     FIRMWARE_DOWNLOAD, 0x40 | USB_DIR_OUT,
+                                     addr >> 8, 0, buf, transfer, HZ);
+               if (err < 0) {
+                       kfree(buf);
+                       return err;
+               }
+
+               len -= transfer;
+               data += transfer;
+               addr += transfer;
+       }
+       kfree(buf);
+
+       /*
+        * Issue FW download complete command to firmware.
+        */
+       err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0),
+                             FIRMWARE_DOWNLOAD_COMP,
+                             0x40 | USB_DIR_OUT,
+                             AR9271_FIRMWARE_TEXT >> 8, 0, NULL, 0, HZ);
+       if (err)
+               return -EIO;
+
+       dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
+                "ar9271.fw", (unsigned long) hif_dev->firmware->size);
+
+       return 0;
+}
+
+static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
+                                 const char *fw_name)
+{
+       int ret;
+
+       /* Request firmware */
+       ret = request_firmware(&hif_dev->firmware, fw_name, &hif_dev->udev->dev);
+       if (ret) {
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Firmware - %s not found\n", fw_name);
+               goto err_fw_req;
+       }
+
+       /* Alloc URBs */
+       ret = ath9k_hif_usb_alloc_urbs(hif_dev);
+       if (ret) {
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Unable to allocate URBs\n");
+               goto err_urb;
+       }
+
+       /* Download firmware */
+       ret = ath9k_hif_usb_download_fw(hif_dev);
+       if (ret) {
+               dev_err(&hif_dev->udev->dev,
+                       "ath9k_htc: Firmware - %s download failed\n", fw_name);
+               goto err_fw_download;
+       }
+
+       return 0;
+
+err_fw_download:
+       ath9k_hif_usb_dealloc_urbs(hif_dev);
+err_urb:
+       release_firmware(hif_dev->firmware);
+err_fw_req:
+       hif_dev->firmware = NULL;
+       return ret;
+}
+
+static void ath9k_hif_usb_dev_deinit(struct hif_device_usb *hif_dev)
+{
+       ath9k_hif_usb_dealloc_urbs(hif_dev);
+       if (hif_dev->firmware)
+               release_firmware(hif_dev->firmware);
+}
+
+static int ath9k_hif_usb_probe(struct usb_interface *interface,
+                              const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct hif_device_usb *hif_dev;
+       const char *fw_name = (const char *) id->driver_info;
+       int ret = 0;
+
+       hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL);
+       if (!hif_dev) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       usb_get_dev(udev);
+       hif_dev->udev = udev;
+       hif_dev->interface = interface;
+       hif_dev->device_id = id->idProduct;
+#ifdef CONFIG_PM
+       udev->reset_resume = 1;
+#endif
+       usb_set_intfdata(interface, hif_dev);
+
+       hif_dev->htc_handle = ath9k_htc_hw_alloc(hif_dev, &hif_usb,
+                                                &hif_dev->udev->dev);
+       if (hif_dev->htc_handle == NULL) {
+               ret = -ENOMEM;
+               goto err_htc_hw_alloc;
+       }
+
+       ret = ath9k_hif_usb_dev_init(hif_dev, fw_name);
+       if (ret) {
+               ret = -EINVAL;
+               goto err_hif_init_usb;
+       }
+
+       ret = ath9k_htc_hw_init(hif_dev->htc_handle,
+                               &hif_dev->udev->dev, hif_dev->device_id);
+       if (ret) {
+               ret = -EINVAL;
+               goto err_htc_hw_init;
+       }
+
+       dev_info(&hif_dev->udev->dev, "ath9k_htc: USB layer initialized\n");
+
+       return 0;
+
+err_htc_hw_init:
+       ath9k_hif_usb_dev_deinit(hif_dev);
+err_hif_init_usb:
+       ath9k_htc_hw_free(hif_dev->htc_handle);
+err_htc_hw_alloc:
+       usb_set_intfdata(interface, NULL);
+       kfree(hif_dev);
+       usb_put_dev(udev);
+err_alloc:
+       return ret;
+}
+
+static void ath9k_hif_usb_reboot(struct usb_device *udev)
+{
+       u32 reboot_cmd = 0xffffffff;
+       void *buf;
+       int ret;
+
+       buf = kmalloc(4, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       memcpy(buf, &reboot_cmd, 4);
+
+       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
+                          buf, 4, NULL, HZ);
+       if (ret)
+               dev_err(&udev->dev, "ath9k_htc: USB reboot failed\n");
+
+       kfree(buf);
+}
+
+static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct hif_device_usb *hif_dev =
+               (struct hif_device_usb *) usb_get_intfdata(interface);
+
+       if (hif_dev) {
+               ath9k_htc_hw_deinit(hif_dev->htc_handle,
+                   (udev->state == USB_STATE_NOTATTACHED) ? true : false);
+               ath9k_htc_hw_free(hif_dev->htc_handle);
+               ath9k_hif_usb_dev_deinit(hif_dev);
+               usb_set_intfdata(interface, NULL);
+       }
+
+       if (hif_dev->flags & HIF_USB_START)
+               ath9k_hif_usb_reboot(udev);
+
+       kfree(hif_dev);
+       dev_info(&udev->dev, "ath9k_htc: USB layer deinitialized\n");
+       usb_put_dev(udev);
+}
+
+#ifdef CONFIG_PM
+static int ath9k_hif_usb_suspend(struct usb_interface *interface,
+                                pm_message_t message)
+{
+       struct hif_device_usb *hif_dev =
+               (struct hif_device_usb *) usb_get_intfdata(interface);
+
+       ath9k_hif_usb_dealloc_urbs(hif_dev);
+
+       return 0;
+}
+
+static int ath9k_hif_usb_resume(struct usb_interface *interface)
+{
+       struct hif_device_usb *hif_dev =
+               (struct hif_device_usb *) usb_get_intfdata(interface);
+       int ret;
+
+       ret = ath9k_hif_usb_alloc_urbs(hif_dev);
+       if (ret)
+               return ret;
+
+       if (hif_dev->firmware) {
+               ret = ath9k_hif_usb_download_fw(hif_dev);
+               if (ret)
+                       goto fail_resume;
+       } else {
+               ath9k_hif_usb_dealloc_urbs(hif_dev);
+               return -EIO;
+       }
+
+       mdelay(100);
+
+       ret = ath9k_htc_resume(hif_dev->htc_handle);
+
+       if (ret)
+               goto fail_resume;
+
+       return 0;
+
+fail_resume:
+       ath9k_hif_usb_dealloc_urbs(hif_dev);
+
+       return ret;
+}
+#endif
+
+static struct usb_driver ath9k_hif_usb_driver = {
+       .name = "ath9k_hif_usb",
+       .probe = ath9k_hif_usb_probe,
+       .disconnect = ath9k_hif_usb_disconnect,
+#ifdef CONFIG_PM
+       .suspend = ath9k_hif_usb_suspend,
+       .resume = ath9k_hif_usb_resume,
+       .reset_resume = ath9k_hif_usb_resume,
+#endif
+       .id_table = ath9k_hif_usb_ids,
+       .soft_unbind = 1,
+};
+
+int ath9k_hif_usb_init(void)
+{
+       return usb_register(&ath9k_hif_usb_driver);
+}
+
+void ath9k_hif_usb_exit(void)
+{
+       usb_deregister(&ath9k_hif_usb_driver);
+}
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
new file mode 100644 (file)
index 0000000..0aca49b
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef HTC_USB_H
+#define HTC_USB_H
+
+#define AR9271_FIRMWARE       0x501000
+#define AR9271_FIRMWARE_TEXT  0x903000
+
+#define FIRMWARE_DOWNLOAD       0x30
+#define FIRMWARE_DOWNLOAD_COMP  0x31
+
+#define ATH_USB_RX_STREAM_MODE_TAG 0x4e00
+#define ATH_USB_TX_STREAM_MODE_TAG 0x697e
+
+/* FIXME: Verify these numbers (with Windows) */
+#define MAX_TX_URB_NUM  8
+#define MAX_TX_BUF_NUM  1024
+#define MAX_TX_BUF_SIZE 32768
+#define MAX_TX_AGGR_NUM 20
+
+#define MAX_RX_URB_NUM  8
+#define MAX_RX_BUF_SIZE 16384
+#define MAX_PKT_NUM_IN_TRANSFER 10
+
+#define MAX_REG_OUT_URB_NUM  1
+#define MAX_REG_OUT_BUF_NUM  8
+
+#define MAX_REG_IN_BUF_SIZE 64
+
+/* USB Endpoint definition */
+#define USB_WLAN_TX_PIPE  1
+#define USB_WLAN_RX_PIPE  2
+#define USB_REG_IN_PIPE   3
+#define USB_REG_OUT_PIPE  4
+
+#define HIF_USB_MAX_RXPIPES 2
+#define HIF_USB_MAX_TXPIPES 4
+
+struct tx_buf {
+       u8 *buf;
+       u16 len;
+       u16 offset;
+       struct urb *urb;
+       struct sk_buff_head skb_queue;
+       struct hif_device_usb *hif_dev;
+       struct list_head list;
+};
+
+#define HIF_USB_TX_STOP  BIT(0)
+
+struct hif_usb_tx {
+       u8 flags;
+       u8 tx_buf_cnt;
+       u16 tx_skb_cnt;
+       struct sk_buff_head tx_skb_queue;
+       struct list_head tx_buf;
+       struct list_head tx_pending;
+       spinlock_t tx_lock;
+};
+
+struct cmd_buf {
+       struct sk_buff *skb;
+       struct hif_device_usb *hif_dev;
+};
+
+#define HIF_USB_START BIT(0)
+
+struct hif_device_usb {
+       u16 device_id;
+       struct usb_device *udev;
+       struct usb_interface *interface;
+       const struct firmware *firmware;
+       struct htc_target *htc_handle;
+       struct hif_usb_tx tx;
+       struct urb *reg_in_urb;
+       struct usb_anchor regout_submitted;
+       struct usb_anchor rx_submitted;
+       struct sk_buff *remain_skb;
+       int rx_remain_len;
+       int rx_pkt_len;
+       int rx_transfer_len;
+       int rx_pad_len;
+       spinlock_t rx_lock;
+       u8 flags; /* HIF_USB_* */
+};
+
+int ath9k_hif_usb_init(void);
+void ath9k_hif_usb_exit(void);
+
+#endif /* HTC_USB_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
new file mode 100644 (file)
index 0000000..ad556aa
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef HTC_H
+#define HTC_H
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/firmware.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/leds.h>
+#include <net/mac80211.h>
+
+#include "common.h"
+#include "htc_hst.h"
+#include "hif_usb.h"
+#include "wmi.h"
+
+#define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
+#define ATH_ANI_POLLINTERVAL      100     /* 100 ms */
+#define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
+#define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
+
+#define ATH_DEFAULT_BMISS_LIMIT 10
+#define IEEE80211_MS_TO_TU(x)   (((x) * 1000) / 1024)
+#define TSF_TO_TU(_h, _l) \
+       ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10))
+
+extern struct ieee80211_ops ath9k_htc_ops;
+extern int htc_modparam_nohwcrypt;
+
+enum htc_phymode {
+       HTC_MODE_AUTO           = 0,
+       HTC_MODE_11A            = 1,
+       HTC_MODE_11B            = 2,
+       HTC_MODE_11G            = 3,
+       HTC_MODE_FH             = 4,
+       HTC_MODE_TURBO_A        = 5,
+       HTC_MODE_TURBO_G        = 6,
+       HTC_MODE_11NA           = 7,
+       HTC_MODE_11NG           = 8
+};
+
+enum htc_opmode {
+       HTC_M_STA       = 1,
+       HTC_M_IBSS      = 0,
+       HTC_M_AHDEMO    = 3,
+       HTC_M_HOSTAP    = 6,
+       HTC_M_MONITOR   = 8,
+       HTC_M_WDS       = 2
+};
+
+#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr)
+#define ATH9K_HTC_AMPDU        1
+#define ATH9K_HTC_NORMAL 2
+
+#define ATH9K_HTC_TX_CTSONLY      0x1
+#define ATH9K_HTC_TX_RTSCTS       0x2
+#define ATH9K_HTC_TX_USE_MIN_RATE 0x100
+
+struct tx_frame_hdr {
+       u8 data_type;
+       u8 node_idx;
+       u8 vif_idx;
+       u8 tidno;
+       u32 flags; /* ATH9K_HTC_TX_* */
+       u8 key_type;
+       u8 keyix;
+       u8 reserved[26];
+} __packed;
+
+struct tx_mgmt_hdr {
+       u8 node_idx;
+       u8 vif_idx;
+       u8 tidno;
+       u8 flags;
+       u8 key_type;
+       u8 keyix;
+       u16 reserved;
+} __packed;
+
+struct tx_beacon_header {
+       u8 len_changed;
+       u8 vif_index;
+       u16 rev;
+} __packed;
+
+struct ath9k_htc_target_hw {
+       u32 flags;
+       u32 flags_ext;
+       u32 ampdu_limit;
+       u8 ampdu_subframes;
+       u8 tx_chainmask;
+       u8 tx_chainmask_legacy;
+       u8 rtscts_ratecode;
+       u8 protmode;
+} __packed;
+
+struct ath9k_htc_cap_target {
+       u32 flags;
+       u32 flags_ext;
+       u32 ampdu_limit;
+       u8 ampdu_subframes;
+       u8 tx_chainmask;
+       u8 tx_chainmask_legacy;
+       u8 rtscts_ratecode;
+       u8 protmode;
+} __packed;
+
+struct ath9k_htc_target_vif {
+       u8 index;
+       u8 des_bssid[ETH_ALEN];
+       __be32 opmode;
+       u8 myaddr[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       u32 flags;
+       u32 flags_ext;
+       u16 ps_sta;
+       __be16 rtsthreshold;
+       u8 ath_cap;
+       u8 node;
+       s8 mcast_rate;
+} __packed;
+
+#define ATH_HTC_STA_AUTH  0x0001
+#define ATH_HTC_STA_QOS   0x0002
+#define ATH_HTC_STA_ERP   0x0004
+#define ATH_HTC_STA_HT    0x0008
+
+/* FIXME: UAPSD variables */
+struct ath9k_htc_target_sta {
+       u16 associd;
+       u16 txpower;
+       u32 ucastkey;
+       u8 macaddr[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       u8 sta_index;
+       u8 vif_index;
+       u8 vif_sta;
+       __be16 flags; /* ATH_HTC_STA_* */
+       u16 htcap;
+       u8 valid;
+       u16 capinfo;
+       struct ath9k_htc_target_hw *hw;
+       struct ath9k_htc_target_vif *vif;
+       u16 txseqmgmt;
+       u8 is_vif_sta;
+       u16 maxampdu;
+       u16 iv16;
+       u32 iv32;
+} __packed;
+
+struct ath9k_htc_target_aggr {
+       u8 sta_index;
+       u8 tidno;
+       u8 aggr_enable;
+       u8 padding;
+} __packed;
+
+#define ATH_HTC_RATE_MAX 30
+
+#define WLAN_RC_DS_FLAG  0x01
+#define WLAN_RC_40_FLAG  0x02
+#define WLAN_RC_SGI_FLAG 0x04
+#define WLAN_RC_HT_FLAG  0x08
+
+struct ath9k_htc_rateset {
+       u8 rs_nrates;
+       u8 rs_rates[ATH_HTC_RATE_MAX];
+};
+
+struct ath9k_htc_rate {
+       struct ath9k_htc_rateset legacy_rates;
+       struct ath9k_htc_rateset ht_rates;
+} __packed;
+
+struct ath9k_htc_target_rate {
+       u8 sta_index;
+       u8 isnew;
+       __be32 capflags;
+       struct ath9k_htc_rate rates;
+};
+
+struct ath9k_htc_target_stats {
+       __be32 tx_shortretry;
+       __be32 tx_longretry;
+       __be32 tx_xretries;
+       __be32 ht_txunaggr_xretry;
+       __be32 ht_tx_xretries;
+} __packed;
+
+struct ath9k_htc_vif {
+       u8 index;
+};
+
+#define ATH9K_HTC_MAX_STA 8
+#define ATH9K_HTC_MAX_TID 8
+
+enum tid_aggr_state {
+       AGGR_STOP = 0,
+       AGGR_PROGRESS,
+       AGGR_START,
+       AGGR_OPERATIONAL
+};
+
+struct ath9k_htc_sta {
+       u8 index;
+       enum tid_aggr_state tid_state[ATH9K_HTC_MAX_TID];
+};
+
+struct ath9k_htc_aggr_work {
+       u16 tid;
+       u8 sta_addr[ETH_ALEN];
+       struct ieee80211_hw *hw;
+       struct ieee80211_vif *vif;
+       enum ieee80211_ampdu_mlme_action action;
+       struct mutex mutex;
+};
+
+#define ATH9K_HTC_RXBUF 256
+#define HTC_RX_FRAME_HEADER_SIZE 40
+
+struct ath9k_htc_rxbuf {
+       bool in_process;
+       struct sk_buff *skb;
+       struct ath_htc_rx_status rxstatus;
+       struct list_head list;
+};
+
+struct ath9k_htc_rx {
+       int last_rssi; /* FIXME: per-STA */
+       struct list_head rxbuf;
+       spinlock_t rxbuflock;
+};
+
+struct ath9k_htc_tx_ctl {
+       u8 type; /* ATH9K_HTC_* */
+};
+
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+
+#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
+#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
+
+struct ath_tx_stats {
+       u32 buf_queued;
+       u32 buf_completed;
+       u32 skb_queued;
+       u32 skb_completed;
+       u32 skb_dropped;
+};
+
+struct ath_rx_stats {
+       u32 skb_allocated;
+       u32 skb_completed;
+       u32 skb_dropped;
+};
+
+struct ath9k_debug {
+       struct dentry *debugfs_phy;
+       struct dentry *debugfs_tgt_stats;
+       struct dentry *debugfs_xmit;
+       struct dentry *debugfs_recv;
+       struct ath_tx_stats tx_stats;
+       struct ath_rx_stats rx_stats;
+       u32 txrate;
+};
+
+#else
+
+#define TX_STAT_INC(c) do { } while (0)
+#define RX_STAT_INC(c) do { } while (0)
+
+#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
+
+#define ATH_LED_PIN_DEF             1
+#define ATH_LED_PIN_9287            8
+#define ATH_LED_PIN_9271            15
+#define ATH_LED_ON_DURATION_IDLE    350        /* in msecs */
+#define ATH_LED_OFF_DURATION_IDLE   250        /* in msecs */
+
+enum ath_led_type {
+       ATH_LED_RADIO,
+       ATH_LED_ASSOC,
+       ATH_LED_TX,
+       ATH_LED_RX
+};
+
+struct ath_led {
+       struct ath9k_htc_priv *priv;
+       struct led_classdev led_cdev;
+       enum ath_led_type led_type;
+       struct delayed_work brightness_work;
+       char name[32];
+       bool registered;
+       int brightness;
+};
+
+struct htc_beacon_config {
+       u16 beacon_interval;
+       u16 listen_interval;
+       u16 dtim_period;
+       u16 bmiss_timeout;
+       u8 dtim_count;
+};
+
+#define OP_INVALID        BIT(0)
+#define OP_SCANNING       BIT(1)
+#define OP_FULL_RESET     BIT(2)
+#define OP_LED_ASSOCIATED BIT(3)
+#define OP_LED_ON         BIT(4)
+#define OP_PREAMBLE_SHORT BIT(5)
+#define OP_PROTECT_ENABLE BIT(6)
+#define OP_TXAGGR         BIT(7)
+#define OP_ASSOCIATED     BIT(8)
+#define OP_ENABLE_BEACON  BIT(9)
+#define OP_LED_DEINIT     BIT(10)
+#define OP_UNPLUGGED      BIT(11)
+
+struct ath9k_htc_priv {
+       struct device *dev;
+       struct ieee80211_hw *hw;
+       struct ath_hw *ah;
+       struct htc_target *htc;
+       struct wmi *wmi;
+
+       enum htc_endpoint_id wmi_cmd_ep;
+       enum htc_endpoint_id beacon_ep;
+       enum htc_endpoint_id cab_ep;
+       enum htc_endpoint_id uapsd_ep;
+       enum htc_endpoint_id mgmt_ep;
+       enum htc_endpoint_id data_be_ep;
+       enum htc_endpoint_id data_bk_ep;
+       enum htc_endpoint_id data_vi_ep;
+       enum htc_endpoint_id data_vo_ep;
+
+       u16 op_flags;
+       u16 curtxpow;
+       u16 txpowlimit;
+       u16 nvifs;
+       u16 nstations;
+       u16 seq_no;
+       u32 bmiss_cnt;
+
+       spinlock_t beacon_lock;
+
+       bool tx_queues_stop;
+       spinlock_t tx_lock;
+
+       struct ieee80211_vif *vif;
+       struct htc_beacon_config cur_beacon_conf;
+       unsigned int rxfilter;
+       struct tasklet_struct wmi_tasklet;
+       struct tasklet_struct rx_tasklet;
+       struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
+       struct ath9k_htc_rx rx;
+       struct tasklet_struct tx_tasklet;
+       struct sk_buff_head tx_queue;
+       struct ath9k_htc_aggr_work aggr_work;
+       struct delayed_work ath9k_aggr_work;
+       struct delayed_work ath9k_ani_work;
+       struct work_struct ps_work;
+
+       struct mutex htc_pm_lock;
+       unsigned long ps_usecount;
+       bool ps_enabled;
+       bool ps_idle;
+
+       struct ath_led radio_led;
+       struct ath_led assoc_led;
+       struct ath_led tx_led;
+       struct ath_led rx_led;
+       struct delayed_work ath9k_led_blink_work;
+       int led_on_duration;
+       int led_off_duration;
+       int led_on_cnt;
+       int led_off_cnt;
+       int hwq_map[ATH9K_WME_AC_VO+1];
+
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+       struct ath9k_debug debug;
+#endif
+       struct ath9k_htc_target_rate tgt_rate;
+
+       struct mutex mutex;
+};
+
+static inline void ath_read_cachesize(struct ath_common *common, int *csz)
+{
+       common->bus_ops->read_cachesize(common, csz);
+}
+
+void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
+                            struct ieee80211_vif *vif);
+void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
+
+void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
+                   enum htc_endpoint_id ep_id);
+void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
+                   bool txok);
+void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
+                       enum htc_endpoint_id ep_id, bool txok);
+
+void ath9k_htc_station_work(struct work_struct *work);
+void ath9k_htc_aggr_work(struct work_struct *work);
+void ath9k_ani_work(struct work_struct *work);;
+
+int ath9k_tx_init(struct ath9k_htc_priv *priv);
+void ath9k_tx_tasklet(unsigned long data);
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
+void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
+bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
+                        enum ath9k_tx_queue_subtype qtype);
+int get_hw_qnum(u16 queue, int *hwq_map);
+int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
+                      struct ath9k_tx_queue_info *qinfo);
+
+int ath9k_rx_init(struct ath9k_htc_priv *priv);
+void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
+void ath9k_host_rx_init(struct ath9k_htc_priv *priv);
+void ath9k_rx_tasklet(unsigned long data);
+u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv);
+
+void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv);
+void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv);
+void ath9k_ps_work(struct work_struct *work);
+
+void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
+void ath9k_init_leds(struct ath9k_htc_priv *priv);
+void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
+
+int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
+                          u16 devid);
+void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug);
+#ifdef CONFIG_PM
+int ath9k_htc_resume(struct htc_target *htc_handle);
+#endif
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+int ath9k_htc_debug_create_root(void);
+void ath9k_htc_debug_remove_root(void);
+int ath9k_htc_init_debug(struct ath_hw *ah);
+void ath9k_htc_exit_debug(struct ath_hw *ah);
+#else
+static inline int ath9k_htc_debug_create_root(void) { return 0; };
+static inline void ath9k_htc_debug_remove_root(void) {};
+static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; };
+static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {};
+#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
+
+#endif /* HTC_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
new file mode 100644 (file)
index 0000000..c10c7d0
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+#define FUDGE 2
+
+static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
+                                       struct htc_beacon_config *bss_conf)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_beacon_state bs;
+       enum ath9k_int imask = 0;
+       int dtimperiod, dtimcount, sleepduration;
+       int cfpperiod, cfpcount, bmiss_timeout;
+       u32 nexttbtt = 0, intval, tsftu;
+       __be32 htc_imask = 0;
+       u64 tsf;
+       int num_beacons, offset, dtim_dec_count, cfp_dec_count;
+       int ret;
+       u8 cmd_rsp;
+
+       memset(&bs, 0, sizeof(bs));
+
+       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
+
+       /*
+        * Setup dtim and cfp parameters according to
+        * last beacon we received (which may be none).
+        */
+       dtimperiod = bss_conf->dtim_period;
+       if (dtimperiod <= 0)            /* NB: 0 if not known */
+               dtimperiod = 1;
+       dtimcount = 1;
+       if (dtimcount >= dtimperiod)    /* NB: sanity check */
+               dtimcount = 0;
+       cfpperiod = 1;                  /* NB: no PCF support yet */
+       cfpcount = 0;
+
+       sleepduration = intval;
+       if (sleepduration <= 0)
+               sleepduration = intval;
+
+       /*
+        * Pull nexttbtt forward to reflect the current
+        * TSF and calculate dtim+cfp state for the result.
+        */
+       tsf = ath9k_hw_gettsf64(priv->ah);
+       tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
+
+       num_beacons = tsftu / intval + 1;
+       offset = tsftu % intval;
+       nexttbtt = tsftu - offset;
+       if (offset)
+               nexttbtt += intval;
+
+       /* DTIM Beacon every dtimperiod Beacon */
+       dtim_dec_count = num_beacons % dtimperiod;
+       /* CFP every cfpperiod DTIM Beacon */
+       cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
+       if (dtim_dec_count)
+               cfp_dec_count++;
+
+       dtimcount -= dtim_dec_count;
+       if (dtimcount < 0)
+               dtimcount += dtimperiod;
+
+       cfpcount -= cfp_dec_count;
+       if (cfpcount < 0)
+               cfpcount += cfpperiod;
+
+       bs.bs_intval = intval;
+       bs.bs_nexttbtt = nexttbtt;
+       bs.bs_dtimperiod = dtimperiod*intval;
+       bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
+       bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
+       bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
+       bs.bs_cfpmaxduration = 0;
+
+       /*
+        * Calculate the number of consecutive beacons to miss* before taking
+        * a BMISS interrupt. The configuration is specified in TU so we only
+        * need calculate based on the beacon interval.  Note that we clamp the
+        * result to at most 15 beacons.
+        */
+       if (sleepduration > intval) {
+               bs.bs_bmissthreshold = ATH_DEFAULT_BMISS_LIMIT / 2;
+       } else {
+               bs.bs_bmissthreshold = DIV_ROUND_UP(bmiss_timeout, intval);
+               if (bs.bs_bmissthreshold > 15)
+                       bs.bs_bmissthreshold = 15;
+               else if (bs.bs_bmissthreshold <= 0)
+                       bs.bs_bmissthreshold = 1;
+       }
+
+       /*
+        * Calculate sleep duration. The configuration is given in ms.
+        * We ensure a multiple of the beacon period is used. Also, if the sleep
+        * duration is greater than the DTIM period then it makes senses
+        * to make it a multiple of that.
+        *
+        * XXX fixed at 100ms
+        */
+
+       bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
+       if (bs.bs_sleepduration > bs.bs_dtimperiod)
+               bs.bs_sleepduration = bs.bs_dtimperiod;
+
+       /* TSF out of range threshold fixed at 1 second */
+       bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
+
+       ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
+       ath_print(common, ATH_DBG_BEACON,
+                 "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
+                 bs.bs_bmissthreshold, bs.bs_sleepduration,
+                 bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+
+       /* Set the computed STA beacon timers */
+
+       WMI_CMD(WMI_DISABLE_INTR_CMDID);
+       ath9k_hw_set_sta_beacon_timers(priv->ah, &bs);
+       imask |= ATH9K_INT_BMISS;
+       htc_imask = cpu_to_be32(imask);
+       WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
+}
+
+static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
+                                         struct htc_beacon_config *bss_conf)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       enum ath9k_int imask = 0;
+       u32 nexttbtt, intval;
+       __be32 htc_imask = 0;
+       int ret;
+       u8 cmd_rsp;
+
+       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       nexttbtt = intval;
+       intval |= ATH9K_BEACON_ENA;
+       if (priv->op_flags & OP_ENABLE_BEACON)
+               imask |= ATH9K_INT_SWBA;
+
+       ath_print(common, ATH_DBG_BEACON,
+                 "IBSS Beacon config, intval: %d, imask: 0x%x\n",
+                 bss_conf->beacon_interval, imask);
+
+       WMI_CMD(WMI_DISABLE_INTR_CMDID);
+       ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
+       priv->bmiss_cnt = 0;
+       htc_imask = cpu_to_be32(imask);
+       WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
+}
+
+void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
+                       enum htc_endpoint_id ep_id, bool txok)
+{
+       dev_kfree_skb_any(skb);
+}
+
+void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
+{
+       struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv;
+       struct tx_beacon_header beacon_hdr;
+       struct ath9k_htc_tx_ctl tx_ctl;
+       struct ieee80211_tx_info *info;
+       struct sk_buff *beacon;
+       u8 *tx_fhdr;
+
+       memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
+       memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
+
+       /* FIXME: Handle BMISS */
+       if (beacon_pending != 0) {
+               priv->bmiss_cnt++;
+               return;
+       }
+
+       spin_lock_bh(&priv->beacon_lock);
+
+       if (unlikely(priv->op_flags & OP_SCANNING)) {
+               spin_unlock_bh(&priv->beacon_lock);
+               return;
+       }
+
+       /* Get a new beacon */
+       beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+       if (!beacon) {
+               spin_unlock_bh(&priv->beacon_lock);
+               return;
+       }
+
+       info = IEEE80211_SKB_CB(beacon);
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               struct ieee80211_hdr *hdr =
+                       (struct ieee80211_hdr *) beacon->data;
+               priv->seq_no += 0x10;
+               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(priv->seq_no);
+       }
+
+       tx_ctl.type = ATH9K_HTC_NORMAL;
+       beacon_hdr.vif_index = avp->index;
+       tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
+       memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
+
+       htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
+
+       spin_unlock_bh(&priv->beacon_lock);
+}
+
+
+void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
+                            struct ieee80211_vif *vif)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+       cur_conf->beacon_interval = bss_conf->beacon_int;
+       if (cur_conf->beacon_interval == 0)
+               cur_conf->beacon_interval = 100;
+
+       cur_conf->dtim_period = bss_conf->dtim_period;
+       cur_conf->listen_interval = 1;
+       cur_conf->dtim_count = 1;
+       cur_conf->bmiss_timeout =
+               ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               ath9k_htc_beacon_config_sta(priv, cur_conf);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               ath9k_htc_beacon_config_adhoc(priv, cur_conf);
+               break;
+       default:
+               ath_print(common, ATH_DBG_CONFIG,
+                         "Unsupported beaconing mode\n");
+               return;
+       }
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
new file mode 100644 (file)
index 0000000..dc01507
--- /dev/null
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+MODULE_AUTHOR("Atheros Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Atheros driver 802.11n HTC based wireless devices");
+
+static unsigned int ath9k_debug = ATH_DBG_DEFAULT;
+module_param_named(debug, ath9k_debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debugging mask");
+
+int htc_modparam_nohwcrypt;
+module_param_named(nohwcrypt, htc_modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+
+#define CHAN2G(_freq, _idx)  { \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 20, \
+}
+
+static struct ieee80211_channel ath9k_2ghz_channels[] = {
+       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 */
+};
+
+/* 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), /* shortp : 0x1e */
+       RATE(55, 0x19, IEEE80211_RATE_SHORT_PREAMBLE), /* shortp: 0x1d */
+       RATE(110, 0x18, IEEE80211_RATE_SHORT_PREAMBLE), /* short: 0x1c */
+       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 int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
+{
+       int time_left;
+
+       if (atomic_read(&priv->htc->tgt_ready) > 0) {
+               atomic_dec(&priv->htc->tgt_ready);
+               return 0;
+       }
+
+       /* Firmware can take up to 50ms to get ready, to be safe use 1 second */
+       time_left = wait_for_completion_timeout(&priv->htc->target_wait, HZ);
+       if (!time_left) {
+               dev_err(priv->dev, "ath9k_htc: Target is unresponsive\n");
+               return -ETIMEDOUT;
+       }
+
+       atomic_dec(&priv->htc->tgt_ready);
+
+       return 0;
+}
+
+static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
+{
+       ath9k_htc_exit_debug(priv->ah);
+       ath9k_hw_deinit(priv->ah);
+       tasklet_kill(&priv->wmi_tasklet);
+       tasklet_kill(&priv->rx_tasklet);
+       tasklet_kill(&priv->tx_tasklet);
+       kfree(priv->ah);
+       priv->ah = NULL;
+}
+
+static void ath9k_deinit_device(struct ath9k_htc_priv *priv)
+{
+       struct ieee80211_hw *hw = priv->hw;
+
+       wiphy_rfkill_stop_polling(hw->wiphy);
+       ath9k_deinit_leds(priv);
+       ieee80211_unregister_hw(hw);
+       ath9k_rx_cleanup(priv);
+       ath9k_tx_cleanup(priv);
+       ath9k_deinit_priv(priv);
+}
+
+static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
+                                       u16 service_id,
+                                       void (*tx) (void *,
+                                                   struct sk_buff *,
+                                                   enum htc_endpoint_id,
+                                                   bool txok),
+                                       enum htc_endpoint_id *ep_id)
+{
+       struct htc_service_connreq req;
+
+       memset(&req, 0, sizeof(struct htc_service_connreq));
+
+       req.service_id = service_id;
+       req.ep_callbacks.priv = priv;
+       req.ep_callbacks.rx = ath9k_htc_rxep;
+       req.ep_callbacks.tx = tx;
+
+       return htc_connect_service(priv->htc, &req, ep_id);
+}
+
+static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
+{
+       int ret;
+
+       /* WMI CMD*/
+       ret = ath9k_wmi_connect(priv->htc, priv->wmi, &priv->wmi_cmd_ep);
+       if (ret)
+               goto err;
+
+       /* Beacon */
+       ret = ath9k_htc_connect_svc(priv, WMI_BEACON_SVC, ath9k_htc_beaconep,
+                                   &priv->beacon_ep);
+       if (ret)
+               goto err;
+
+       /* CAB */
+       ret = ath9k_htc_connect_svc(priv, WMI_CAB_SVC, ath9k_htc_txep,
+                                   &priv->cab_ep);
+       if (ret)
+               goto err;
+
+
+       /* UAPSD */
+       ret = ath9k_htc_connect_svc(priv, WMI_UAPSD_SVC, ath9k_htc_txep,
+                                   &priv->uapsd_ep);
+       if (ret)
+               goto err;
+
+       /* MGMT */
+       ret = ath9k_htc_connect_svc(priv, WMI_MGMT_SVC, ath9k_htc_txep,
+                                   &priv->mgmt_ep);
+       if (ret)
+               goto err;
+
+       /* DATA BE */
+       ret = ath9k_htc_connect_svc(priv, WMI_DATA_BE_SVC, ath9k_htc_txep,
+                                   &priv->data_be_ep);
+       if (ret)
+               goto err;
+
+       /* DATA BK */
+       ret = ath9k_htc_connect_svc(priv, WMI_DATA_BK_SVC, ath9k_htc_txep,
+                                   &priv->data_bk_ep);
+       if (ret)
+               goto err;
+
+       /* DATA VI */
+       ret = ath9k_htc_connect_svc(priv, WMI_DATA_VI_SVC, ath9k_htc_txep,
+                                   &priv->data_vi_ep);
+       if (ret)
+               goto err;
+
+       /* DATA VO */
+       ret = ath9k_htc_connect_svc(priv, WMI_DATA_VO_SVC, ath9k_htc_txep,
+                                   &priv->data_vo_ep);
+       if (ret)
+               goto err;
+
+       ret = htc_init(priv->htc);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       dev_err(priv->dev, "ath9k_htc: Unable to initialize HTC services\n");
+       return ret;
+}
+
+static int ath9k_reg_notifier(struct wiphy *wiphy,
+                             struct regulatory_request *request)
+{
+       struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       return ath_reg_notifier_apply(wiphy, request,
+                                     ath9k_hw_regulatory(priv->ah));
+}
+
+static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
+{
+       struct ath_hw *ah = (struct ath_hw *) hw_priv;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+       __be32 val, reg = cpu_to_be32(reg_offset);
+       int r;
+
+       r = ath9k_wmi_cmd(priv->wmi, WMI_REG_READ_CMDID,
+                         (u8 *) &reg, sizeof(reg),
+                         (u8 *) &val, sizeof(val),
+                         100);
+       if (unlikely(r)) {
+               ath_print(common, ATH_DBG_WMI,
+                         "REGISTER READ FAILED: (0x%04x, %d)\n",
+                          reg_offset, r);
+               return -EIO;
+       }
+
+       return be32_to_cpu(val);
+}
+
+static void ath9k_regwrite_single(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 ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+       __be32 buf[2] = {
+               cpu_to_be32(reg_offset),
+               cpu_to_be32(val),
+       };
+       int r;
+
+       r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+                         (u8 *) &buf, sizeof(buf),
+                         (u8 *) &val, sizeof(val),
+                         100);
+       if (unlikely(r)) {
+               ath_print(common, ATH_DBG_WMI,
+                         "REGISTER WRITE FAILED:(0x%04x, %d)\n",
+                         reg_offset, r);
+       }
+}
+
+static void ath9k_regwrite_buffer(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 ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+       u32 rsp_status;
+       int r;
+
+       mutex_lock(&priv->wmi->multi_write_mutex);
+
+       /* Store the register/value */
+       priv->wmi->multi_write[priv->wmi->multi_write_idx].reg =
+               cpu_to_be32(reg_offset);
+       priv->wmi->multi_write[priv->wmi->multi_write_idx].val =
+               cpu_to_be32(val);
+
+       priv->wmi->multi_write_idx++;
+
+       /* If the buffer is full, send it out. */
+       if (priv->wmi->multi_write_idx == MAX_CMD_NUMBER) {
+               r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+                         (u8 *) &priv->wmi->multi_write,
+                         sizeof(struct register_write) * priv->wmi->multi_write_idx,
+                         (u8 *) &rsp_status, sizeof(rsp_status),
+                         100);
+               if (unlikely(r)) {
+                       ath_print(common, ATH_DBG_WMI,
+                                 "REGISTER WRITE FAILED, multi len: %d\n",
+                                 priv->wmi->multi_write_idx);
+               }
+               priv->wmi->multi_write_idx = 0;
+       }
+
+       mutex_unlock(&priv->wmi->multi_write_mutex);
+}
+
+static void ath9k_regwrite(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 ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+       if (atomic_read(&priv->wmi->mwrite_cnt))
+               ath9k_regwrite_buffer(hw_priv, val, reg_offset);
+       else
+               ath9k_regwrite_single(hw_priv, val, reg_offset);
+}
+
+static void ath9k_enable_regwrite_buffer(void *hw_priv)
+{
+       struct ath_hw *ah = (struct ath_hw *) hw_priv;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+       atomic_inc(&priv->wmi->mwrite_cnt);
+}
+
+static void ath9k_disable_regwrite_buffer(void *hw_priv)
+{
+       struct ath_hw *ah = (struct ath_hw *) hw_priv;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+       atomic_dec(&priv->wmi->mwrite_cnt);
+}
+
+static void ath9k_regwrite_flush(void *hw_priv)
+{
+       struct ath_hw *ah = (struct ath_hw *) hw_priv;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+       u32 rsp_status;
+       int r;
+
+       mutex_lock(&priv->wmi->multi_write_mutex);
+
+       if (priv->wmi->multi_write_idx) {
+               r = ath9k_wmi_cmd(priv->wmi, WMI_REG_WRITE_CMDID,
+                         (u8 *) &priv->wmi->multi_write,
+                         sizeof(struct register_write) * priv->wmi->multi_write_idx,
+                         (u8 *) &rsp_status, sizeof(rsp_status),
+                         100);
+               if (unlikely(r)) {
+                       ath_print(common, ATH_DBG_WMI,
+                                 "REGISTER WRITE FAILED, multi len: %d\n",
+                                 priv->wmi->multi_write_idx);
+               }
+               priv->wmi->multi_write_idx = 0;
+       }
+
+       mutex_unlock(&priv->wmi->multi_write_mutex);
+}
+
+static const struct ath_ops ath9k_common_ops = {
+       .read = ath9k_regread,
+       .write = ath9k_regwrite,
+       .enable_write_buffer = ath9k_enable_regwrite_buffer,
+       .disable_write_buffer = ath9k_disable_regwrite_buffer,
+       .write_flush = ath9k_regwrite_flush,
+};
+
+static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
+{
+       *csz = L1_CACHE_BYTES >> 2;
+}
+
+static bool ath_usb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
+{
+       struct ath_hw *ah = (struct ath_hw *) common->ah;
+
+       (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+       if (!ath9k_hw_wait(ah,
+                          AR_EEPROM_STATUS_DATA,
+                          AR_EEPROM_STATUS_DATA_BUSY |
+                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
+                          AH_WAIT_TIMEOUT))
+               return false;
+
+       *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+                  AR_EEPROM_STATUS_DATA_VAL);
+
+       return true;
+}
+
+static const struct ath_bus_ops ath9k_usb_bus_ops = {
+       .ath_bus_type = ATH_USB,
+       .read_cachesize = ath_usb_read_cachesize,
+       .eeprom_read = ath_usb_eeprom_read,
+};
+
+static void setup_ht_cap(struct ath9k_htc_priv *priv,
+                        struct ieee80211_sta_ht_cap *ht_info)
+{
+       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;
+
+       memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+       ht_info->mcs.rx_mask[0] = 0xff;
+       ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
+}
+
+static int ath9k_init_queues(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
+               priv->hwq_map[i] = -1;
+
+       if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BE)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for BE traffic\n");
+               goto err;
+       }
+
+       if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BK)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for BK traffic\n");
+               goto err;
+       }
+       if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VI)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for VI traffic\n");
+               goto err;
+       }
+       if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_VO)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to setup xmit queue for VO traffic\n");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       return -EINVAL;
+}
+
+static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       int i = 0;
+
+       /* Get the hardware key cache size. */
+       common->keymax = priv->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(priv->ah, (u16) i);
+
+       if (ath9k_hw_getcapability(priv->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(priv->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(priv->ah, ATH9K_CAP_CIPHER,
+                                  ATH9K_CIPHER_TKIP, NULL)
+           && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_CIPHER,
+                                     ATH9K_CIPHER_MIC, NULL)
+           && ath9k_hw_getcapability(priv->ah, ATH9K_CAP_TKIP_SPLIT,
+                                     0, NULL))
+               common->splitmic = 1;
+
+       /* turn on mcast key search if possible */
+       if (!ath9k_hw_getcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL))
+               (void)ath9k_hw_setcapability(priv->ah, ATH9K_CAP_MCAST_KEYSRCH,
+                                            1, 1, NULL);
+}
+
+static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
+{
+       if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes)) {
+               priv->sbands[IEEE80211_BAND_2GHZ].channels =
+                       ath9k_2ghz_channels;
+               priv->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+               priv->sbands[IEEE80211_BAND_2GHZ].n_channels =
+                       ARRAY_SIZE(ath9k_2ghz_channels);
+               priv->sbands[IEEE80211_BAND_2GHZ].bitrates = ath9k_legacy_rates;
+               priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
+                       ARRAY_SIZE(ath9k_legacy_rates);
+       }
+}
+
+static void ath9k_init_misc(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+
+       common->tx_chainmask = priv->ah->caps.tx_chainmask;
+       common->rx_chainmask = priv->ah->caps.rx_chainmask;
+
+       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+               memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
+
+       priv->op_flags |= OP_TXAGGR;
+       priv->ah->opmode = NL80211_IFTYPE_STATION;
+}
+
+static int ath9k_init_priv(struct ath9k_htc_priv *priv, u16 devid)
+{
+       struct ath_hw *ah = NULL;
+       struct ath_common *common;
+       int ret = 0, csz = 0;
+
+       priv->op_flags |= OP_INVALID;
+
+       ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL);
+       if (!ah)
+               return -ENOMEM;
+
+       ah->hw_version.devid = devid;
+       ah->hw_version.subsysid = 0; /* FIXME */
+       priv->ah = ah;
+
+       common = ath9k_hw_common(ah);
+       common->ops = &ath9k_common_ops;
+       common->bus_ops = &ath9k_usb_bus_ops;
+       common->ah = ah;
+       common->hw = priv->hw;
+       common->priv = priv;
+       common->debug_mask = ath9k_debug;
+
+       spin_lock_init(&priv->wmi->wmi_lock);
+       spin_lock_init(&priv->beacon_lock);
+       spin_lock_init(&priv->tx_lock);
+       mutex_init(&priv->mutex);
+       mutex_init(&priv->aggr_work.mutex);
+       mutex_init(&priv->htc_pm_lock);
+       tasklet_init(&priv->wmi_tasklet, ath9k_wmi_tasklet,
+                    (unsigned long)priv);
+       tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
+                    (unsigned long)priv);
+       tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet, (unsigned long)priv);
+       INIT_DELAYED_WORK(&priv->ath9k_aggr_work, ath9k_htc_aggr_work);
+       INIT_DELAYED_WORK(&priv->ath9k_ani_work, ath9k_ani_work);
+       INIT_WORK(&priv->ps_work, ath9k_ps_work);
+
+       /*
+        * 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_htc_init_debug(ah);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to create debugfs files\n");
+               goto err_debug;
+       }
+
+       ret = ath9k_init_queues(priv);
+       if (ret)
+               goto err_queues;
+
+       ath9k_init_crypto(priv);
+       ath9k_init_channels_rates(priv);
+       ath9k_init_misc(priv);
+
+       return 0;
+
+err_queues:
+       ath9k_htc_exit_debug(ah);
+err_debug:
+       ath9k_hw_deinit(ah);
+err_hw:
+
+       kfree(ah);
+       priv->ah = NULL;
+
+       return ret;
+}
+
+static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
+                              struct ieee80211_hw *hw)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+               IEEE80211_HW_AMPDU_AGGREGATION |
+               IEEE80211_HW_SPECTRUM_MGMT |
+               IEEE80211_HW_HAS_RATE_CONTROL |
+               IEEE80211_HW_RX_INCLUDES_FCS |
+               IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_PS_NULLFUNC_STACK;
+
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
+       hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       hw->queues = 4;
+       hw->channel_change_time = 5000;
+       hw->max_listen_interval = 10;
+       hw->vif_data_size = sizeof(struct ath9k_htc_vif);
+       hw->sta_data_size = sizeof(struct ath9k_htc_sta);
+
+       /* tx_frame_hdr is larger than tx_mgmt_hdr anyway */
+       hw->extra_tx_headroom = sizeof(struct tx_frame_hdr) +
+               sizeof(struct htc_frame_hdr) + 4;
+
+       if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
+               hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->sbands[IEEE80211_BAND_2GHZ];
+
+       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+               if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
+                       setup_ht_cap(priv,
+                                    &priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+       }
+
+       SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
+}
+
+static int ath9k_init_device(struct ath9k_htc_priv *priv, u16 devid)
+{
+       struct ieee80211_hw *hw = priv->hw;
+       struct ath_common *common;
+       struct ath_hw *ah;
+       int error = 0;
+       struct ath_regulatory *reg;
+
+       /* Bring up device */
+       error = ath9k_init_priv(priv, devid);
+       if (error != 0)
+               goto err_init;
+
+       ah = priv->ah;
+       common = ath9k_hw_common(ah);
+       ath9k_set_hw_capab(priv, hw);
+
+       /* Initialize regulatory */
+       error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
+                             ath9k_reg_notifier);
+       if (error)
+               goto err_regd;
+
+       reg = &common->regulatory;
+
+       /* Setup TX */
+       error = ath9k_tx_init(priv);
+       if (error != 0)
+               goto err_tx;
+
+       /* Setup RX */
+       error = ath9k_rx_init(priv);
+       if (error != 0)
+               goto err_rx;
+
+       /* Register with mac80211 */
+       error = ieee80211_register_hw(hw);
+       if (error)
+               goto err_register;
+
+       /* Handle world regulatory */
+       if (!ath_is_world_regd(reg)) {
+               error = regulatory_hint(hw->wiphy, reg->alpha2);
+               if (error)
+                       goto err_world;
+       }
+
+       ath9k_init_leds(priv);
+       ath9k_start_rfkill_poll(priv);
+
+       return 0;
+
+err_world:
+       ieee80211_unregister_hw(hw);
+err_register:
+       ath9k_rx_cleanup(priv);
+err_rx:
+       ath9k_tx_cleanup(priv);
+err_tx:
+       /* Nothing */
+err_regd:
+       ath9k_deinit_priv(priv);
+err_init:
+       return error;
+}
+
+int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
+                          u16 devid)
+{
+       struct ieee80211_hw *hw;
+       struct ath9k_htc_priv *priv;
+       int ret;
+
+       hw = ieee80211_alloc_hw(sizeof(struct ath9k_htc_priv), &ath9k_htc_ops);
+       if (!hw)
+               return -ENOMEM;
+
+       priv = hw->priv;
+       priv->hw = hw;
+       priv->htc = htc_handle;
+       priv->dev = dev;
+       htc_handle->drv_priv = priv;
+       SET_IEEE80211_DEV(hw, priv->dev);
+
+       ret = ath9k_htc_wait_for_target(priv);
+       if (ret)
+               goto err_free;
+
+       priv->wmi = ath9k_init_wmi(priv);
+       if (!priv->wmi) {
+               ret = -EINVAL;
+               goto err_free;
+       }
+
+       ret = ath9k_init_htc_services(priv);
+       if (ret)
+               goto err_init;
+
+       /* The device may have been unplugged earlier. */
+       priv->op_flags &= ~OP_UNPLUGGED;
+
+       ret = ath9k_init_device(priv, devid);
+       if (ret)
+               goto err_init;
+
+       return 0;
+
+err_init:
+       ath9k_deinit_wmi(priv);
+err_free:
+       ieee80211_free_hw(hw);
+       return ret;
+}
+
+void ath9k_htc_disconnect_device(struct htc_target *htc_handle, bool hotunplug)
+{
+       if (htc_handle->drv_priv) {
+
+               /* Check if the device has been yanked out. */
+               if (hotunplug)
+                       htc_handle->drv_priv->op_flags |= OP_UNPLUGGED;
+
+               ath9k_deinit_device(htc_handle->drv_priv);
+               ath9k_deinit_wmi(htc_handle->drv_priv);
+               ieee80211_free_hw(htc_handle->drv_priv->hw);
+       }
+}
+
+#ifdef CONFIG_PM
+int ath9k_htc_resume(struct htc_target *htc_handle)
+{
+       int ret;
+
+       ret = ath9k_htc_wait_for_target(htc_handle->drv_priv);
+       if (ret)
+               return ret;
+
+       ret = ath9k_init_htc_services(htc_handle->drv_priv);
+       return ret;
+}
+#endif
+
+static int __init ath9k_htc_init(void)
+{
+       int error;
+
+       error = ath9k_htc_debug_create_root();
+       if (error < 0) {
+               printk(KERN_ERR
+                       "ath9k_htc: Unable to create debugfs root: %d\n",
+                       error);
+               goto err_dbg;
+       }
+
+       error = ath9k_hif_usb_init();
+       if (error < 0) {
+               printk(KERN_ERR
+                       "ath9k_htc: No USB devices found,"
+                       " driver not installed.\n");
+               error = -ENODEV;
+               goto err_usb;
+       }
+
+       return 0;
+
+err_usb:
+       ath9k_htc_debug_remove_root();
+err_dbg:
+       return error;
+}
+module_init(ath9k_htc_init);
+
+static void __exit ath9k_htc_exit(void)
+{
+       ath9k_hif_usb_exit();
+       ath9k_htc_debug_remove_root();
+       printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
+}
+module_exit(ath9k_htc_exit);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
new file mode 100644 (file)
index 0000000..9d371c1
--- /dev/null
@@ -0,0 +1,1775 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+static struct dentry *ath9k_debugfs_root;
+#endif
+
+/*************/
+/* Utilities */
+/*************/
+
+static void ath_update_txpow(struct ath9k_htc_priv *priv)
+{
+       struct ath_hw *ah = priv->ah;
+       u32 txpow;
+
+       if (priv->curtxpow != priv->txpowlimit) {
+               ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit);
+               /* read back in case value is clamped */
+               ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow);
+               priv->curtxpow = txpow;
+       }
+}
+
+/* HACK Alert: Use 11NG for 2.4, use 11NA for 5 */
+static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
+                                             struct ath9k_channel *ichan)
+{
+       enum htc_phymode mode;
+
+       mode = HTC_MODE_AUTO;
+
+       switch (ichan->chanmode) {
+       case CHANNEL_G:
+       case CHANNEL_G_HT20:
+       case CHANNEL_G_HT40PLUS:
+       case CHANNEL_G_HT40MINUS:
+               mode = HTC_MODE_11NG;
+               break;
+       case CHANNEL_A:
+       case CHANNEL_A_HT20:
+       case CHANNEL_A_HT40PLUS:
+       case CHANNEL_A_HT40MINUS:
+               mode = HTC_MODE_11NA;
+               break;
+       default:
+               break;
+       }
+
+       return mode;
+}
+
+static bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
+                              enum ath9k_power_mode mode)
+{
+       bool ret;
+
+       mutex_lock(&priv->htc_pm_lock);
+       ret = ath9k_hw_setpower(priv->ah, mode);
+       mutex_unlock(&priv->htc_pm_lock);
+
+       return ret;
+}
+
+void ath9k_htc_ps_wakeup(struct ath9k_htc_priv *priv)
+{
+       mutex_lock(&priv->htc_pm_lock);
+       if (++priv->ps_usecount != 1)
+               goto unlock;
+       ath9k_hw_setpower(priv->ah, ATH9K_PM_AWAKE);
+
+unlock:
+       mutex_unlock(&priv->htc_pm_lock);
+}
+
+void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv)
+{
+       mutex_lock(&priv->htc_pm_lock);
+       if (--priv->ps_usecount != 0)
+               goto unlock;
+
+       if (priv->ps_idle)
+               ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP);
+       else if (priv->ps_enabled)
+               ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP);
+
+unlock:
+       mutex_unlock(&priv->htc_pm_lock);
+}
+
+void ath9k_ps_work(struct work_struct *work)
+{
+       struct ath9k_htc_priv *priv =
+               container_of(work, struct ath9k_htc_priv,
+                            ps_work);
+       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+
+       /* The chip wakes up after receiving the first beacon
+          while network sleep is enabled. For the driver to
+          be in sync with the hw, set the chip to awake and
+          only then set it to sleep.
+        */
+       ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
+}
+
+static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
+                                struct ieee80211_hw *hw,
+                                struct ath9k_channel *hchan)
+{
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_conf *conf = &common->hw->conf;
+       bool fastcc = true;
+       struct ieee80211_channel *channel = hw->conf.channel;
+       enum htc_phymode mode;
+       __be16 htc_mode;
+       u8 cmd_rsp;
+       int ret;
+
+       if (priv->op_flags & OP_INVALID)
+               return -EIO;
+
+       if (priv->op_flags & OP_FULL_RESET)
+               fastcc = false;
+
+       /* Fiddle around with fastcc later on, for now just use full reset */
+       fastcc = false;
+       ath9k_htc_ps_wakeup(priv);
+       htc_stop(priv->htc);
+       WMI_CMD(WMI_DISABLE_INTR_CMDID);
+       WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+       WMI_CMD(WMI_STOP_RECV_CMDID);
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "(%u MHz) -> (%u MHz), HT: %d, HT40: %d\n",
+                 priv->ah->curchan->channel,
+                 channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf));
+
+       ret = ath9k_hw_reset(ah, hchan, fastcc);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to reset channel (%u Mhz) "
+                         "reset status %d\n", channel->center_freq, ret);
+               goto err;
+       }
+
+       ath_update_txpow(priv);
+
+       WMI_CMD(WMI_START_RECV_CMDID);
+       if (ret)
+               goto err;
+
+       ath9k_host_rx_init(priv);
+
+       mode = ath9k_htc_get_curmode(priv, hchan);
+       htc_mode = cpu_to_be16(mode);
+       WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
+       if (ret)
+               goto err;
+
+       WMI_CMD(WMI_ENABLE_INTR_CMDID);
+       if (ret)
+               goto err;
+
+       htc_start(priv->htc);
+
+       priv->op_flags &= ~OP_FULL_RESET;
+err:
+       ath9k_htc_ps_restore(priv);
+       return ret;
+}
+
+static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_vif hvif;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       if (priv->nvifs > 0)
+               return -ENOBUFS;
+
+       memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+       memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
+
+       hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
+       priv->ah->opmode = NL80211_IFTYPE_MONITOR;
+       hvif.index = priv->nvifs;
+
+       WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
+       if (ret)
+               return ret;
+
+       priv->nvifs++;
+       return 0;
+}
+
+static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_vif hvif;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+       memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
+       hvif.index = 0; /* Should do for now */
+       WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+       priv->nvifs--;
+
+       return ret;
+}
+
+static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_sta tsta;
+       struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *) vif->drv_priv;
+       struct ath9k_htc_sta *ista;
+       int ret;
+       u8 cmd_rsp;
+
+       if (priv->nstations >= ATH9K_HTC_MAX_STA)
+               return -ENOBUFS;
+
+       memset(&tsta, 0, sizeof(struct ath9k_htc_target_sta));
+
+       if (sta) {
+               ista = (struct ath9k_htc_sta *) sta->drv_priv;
+               memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
+               memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
+               tsta.associd = common->curaid;
+               tsta.is_vif_sta = 0;
+               tsta.valid = true;
+               ista->index = priv->nstations;
+       } else {
+               memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
+               tsta.is_vif_sta = 1;
+       }
+
+       tsta.sta_index = priv->nstations;
+       tsta.vif_index = avp->index;
+       tsta.maxampdu = 0xffff;
+       if (sta && sta->ht_cap.ht_supported)
+               tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
+
+       WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
+       if (ret) {
+               if (sta)
+                       ath_print(common, ATH_DBG_FATAL,
+                         "Unable to add station entry for: %pM\n", sta->addr);
+               return ret;
+       }
+
+       if (sta)
+               ath_print(common, ATH_DBG_CONFIG,
+                         "Added a station entry for: %pM (idx: %d)\n",
+                         sta->addr, tsta.sta_index);
+
+       priv->nstations++;
+       return 0;
+}
+
+static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
+                                   struct ieee80211_vif *vif,
+                                   struct ieee80211_sta *sta)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_sta *ista;
+       int ret;
+       u8 cmd_rsp, sta_idx;
+
+       if (sta) {
+               ista = (struct ath9k_htc_sta *) sta->drv_priv;
+               sta_idx = ista->index;
+       } else {
+               sta_idx = 0;
+       }
+
+       WMI_CMD_BUF(WMI_NODE_REMOVE_CMDID, &sta_idx);
+       if (ret) {
+               if (sta)
+                       ath_print(common, ATH_DBG_FATAL,
+                         "Unable to remove station entry for: %pM\n",
+                         sta->addr);
+               return ret;
+       }
+
+       if (sta)
+               ath_print(common, ATH_DBG_CONFIG,
+                         "Removed a station entry for: %pM (idx: %d)\n",
+                         sta->addr, sta_idx);
+
+       priv->nstations--;
+       return 0;
+}
+
+static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
+{
+       struct ath9k_htc_cap_target tcap;
+       int ret;
+       u8 cmd_rsp;
+
+       memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
+
+       /* FIXME: Values are hardcoded */
+       tcap.flags = 0x240c40;
+       tcap.flags_ext = 0x80601000;
+       tcap.ampdu_limit = 0xffff0000;
+       tcap.ampdu_subframes = 20;
+       tcap.tx_chainmask_legacy = 1;
+       tcap.protmode = 1;
+       tcap.tx_chainmask = 1;
+
+       WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
+
+       return ret;
+}
+
+static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_sta *sta)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
+       struct ieee80211_supported_band *sband;
+       struct ath9k_htc_target_rate trate;
+       u32 caps = 0;
+       u8 cmd_rsp;
+       int i, j, ret;
+
+       memset(&trate, 0, sizeof(trate));
+
+       /* Only 2GHz is supported */
+       sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+
+       for (i = 0, j = 0; i < sband->n_bitrates; i++) {
+               if (sta->supp_rates[sband->band] & BIT(i)) {
+                       priv->tgt_rate.rates.legacy_rates.rs_rates[j]
+                               = (sband->bitrates[i].bitrate * 2) / 10;
+                       j++;
+               }
+       }
+       priv->tgt_rate.rates.legacy_rates.rs_nrates = j;
+
+       if (sta->ht_cap.ht_supported) {
+               for (i = 0, j = 0; i < 77; i++) {
+                       if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
+                               priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i;
+                       if (j == ATH_HTC_RATE_MAX)
+                               break;
+               }
+               priv->tgt_rate.rates.ht_rates.rs_nrates = j;
+
+               caps = WLAN_RC_HT_FLAG;
+               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+                       caps |= WLAN_RC_40_FLAG;
+               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+                       caps |= WLAN_RC_SGI_FLAG;
+
+       }
+
+       priv->tgt_rate.sta_index = ista->index;
+       priv->tgt_rate.isnew = 1;
+       trate = priv->tgt_rate;
+       priv->tgt_rate.capflags = cpu_to_be32(caps);
+       trate.capflags = cpu_to_be32(caps);
+
+       WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to initialize Rate information on target\n");
+               return ret;
+       }
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps);
+       return 0;
+}
+
+static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ieee80211_conf *conf = &hw->conf;
+
+       if (!conf_is_ht(conf))
+               return false;
+
+       if (!(priv->op_flags & OP_ASSOCIATED) ||
+           (priv->op_flags & OP_SCANNING))
+               return false;
+
+       if (conf_is_ht40(conf)) {
+               if (priv->ah->curchan->chanmode &
+                       (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) {
+                       return false;
+               } else {
+                       *cw40 = true;
+                       return true;
+               }
+       } else {  /* ht20 */
+               if (priv->ah->curchan->chanmode & CHANNEL_HT20)
+                       return false;
+               else
+                       return true;
+       }
+}
+
+static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
+{
+       struct ath9k_htc_target_rate trate;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       int ret;
+       u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
+       u8 cmd_rsp;
+
+       memset(&trate, 0, sizeof(trate));
+
+       trate = priv->tgt_rate;
+
+       if (is_cw40)
+               caps |= WLAN_RC_40_FLAG;
+       else
+               caps &= ~WLAN_RC_40_FLAG;
+
+       priv->tgt_rate.capflags = cpu_to_be32(caps);
+       trate.capflags = cpu_to_be32(caps);
+
+       WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to update Rate information on target\n");
+               return;
+       }
+
+       ath_print(common, ATH_DBG_CONFIG, "Rate control updated with "
+                 "caps:0x%x on target\n", priv->tgt_rate.capflags);
+}
+
+static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
+                              struct ieee80211_vif *vif,
+                              u8 *sta_addr, u8 tid, bool oper)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_aggr aggr;
+       struct ieee80211_sta *sta = NULL;
+       struct ath9k_htc_sta *ista;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       if (tid >= ATH9K_HTC_MAX_TID)
+               return -EINVAL;
+
+       memset(&aggr, 0, sizeof(struct ath9k_htc_target_aggr));
+
+       rcu_read_lock();
+
+       /* Check if we are able to retrieve the station */
+       sta = ieee80211_find_sta(vif, sta_addr);
+       if (!sta) {
+               rcu_read_unlock();
+               return -EINVAL;
+       }
+
+       ista = (struct ath9k_htc_sta *) sta->drv_priv;
+
+       if (oper)
+               ista->tid_state[tid] = AGGR_START;
+       else
+               ista->tid_state[tid] = AGGR_STOP;
+
+       aggr.sta_index = ista->index;
+
+       rcu_read_unlock();
+
+       aggr.tidno = tid;
+       aggr.aggr_enable = oper;
+
+       WMI_CMD_BUF(WMI_TX_AGGR_ENABLE_CMDID, &aggr);
+       if (ret)
+               ath_print(common, ATH_DBG_CONFIG,
+                         "Unable to %s TX aggregation for (%pM, %d)\n",
+                         (oper) ? "start" : "stop", sta->addr, tid);
+       else
+               ath_print(common, ATH_DBG_CONFIG,
+                         "%s aggregation for (%pM, %d)\n",
+                         (oper) ? "Starting" : "Stopping", sta->addr, tid);
+
+       return ret;
+}
+
+void ath9k_htc_aggr_work(struct work_struct *work)
+{
+       int ret = 0;
+       struct ath9k_htc_priv *priv =
+               container_of(work, struct ath9k_htc_priv,
+                            ath9k_aggr_work.work);
+       struct ath9k_htc_aggr_work *wk = &priv->aggr_work;
+
+       mutex_lock(&wk->mutex);
+
+       switch (wk->action) {
+       case IEEE80211_AMPDU_TX_START:
+               ret = ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
+                                         wk->tid, true);
+               if (!ret)
+                       ieee80211_start_tx_ba_cb(wk->vif, wk->sta_addr,
+                                                wk->tid);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               ath9k_htc_aggr_oper(priv, wk->vif, wk->sta_addr,
+                                   wk->tid, false);
+               ieee80211_stop_tx_ba_cb(wk->vif, wk->sta_addr, wk->tid);
+               break;
+       default:
+               ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
+                         "Unknown AMPDU action\n");
+       }
+
+       mutex_unlock(&wk->mutex);
+}
+
+/*********/
+/* DEBUG */
+/*********/
+
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath9k_htc_priv *priv =
+               (struct ath9k_htc_priv *) file->private_data;
+       struct ath9k_htc_target_stats cmd_rsp;
+       char buf[512];
+       unsigned int len = 0;
+       int ret = 0;
+
+       memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+       WMI_CMD(WMI_TGT_STATS_CMDID);
+       if (ret)
+               return -EINVAL;
+
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%19s : %10u\n", "TX Short Retries",
+                       be32_to_cpu(cmd_rsp.tx_shortretry));
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%19s : %10u\n", "TX Long Retries",
+                       be32_to_cpu(cmd_rsp.tx_longretry));
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%19s : %10u\n", "TX Xretries",
+                       be32_to_cpu(cmd_rsp.tx_xretries));
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%19s : %10u\n", "TX Unaggr. Xretries",
+                       be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%19s : %10u\n", "TX Xretries (HT)",
+                       be32_to_cpu(cmd_rsp.ht_tx_xretries));
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%19s : %10u\n", "TX Rate", priv->debug.txrate);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_stats = {
+       .read = read_file_tgt_stats,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+       struct ath9k_htc_priv *priv =
+               (struct ath9k_htc_priv *) file->private_data;
+       char buf[512];
+       unsigned int len = 0;
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "Buffers queued",
+                       priv->debug.tx_stats.buf_queued);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "Buffers completed",
+                       priv->debug.tx_stats.buf_completed);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "SKBs queued",
+                       priv->debug.tx_stats.skb_queued);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "SKBs completed",
+                       priv->debug.tx_stats.skb_completed);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "SKBs dropped",
+                       priv->debug.tx_stats.skb_dropped);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_xmit = {
+       .read = read_file_xmit,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+static ssize_t read_file_recv(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+{
+       struct ath9k_htc_priv *priv =
+               (struct ath9k_htc_priv *) file->private_data;
+       char buf[512];
+       unsigned int len = 0;
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "SKBs allocated",
+                       priv->debug.rx_stats.skb_allocated);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "SKBs completed",
+                       priv->debug.rx_stats.skb_completed);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%20s : %10u\n", "SKBs Dropped",
+                       priv->debug.rx_stats.skb_dropped);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_recv = {
+       .read = read_file_recv,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+int ath9k_htc_init_debug(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+       if (!ath9k_debugfs_root)
+               return -ENOENT;
+
+       priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
+                                                    ath9k_debugfs_root);
+       if (!priv->debug.debugfs_phy)
+               goto err;
+
+       priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
+                                                   priv->debug.debugfs_phy,
+                                                   priv, &fops_tgt_stats);
+       if (!priv->debug.debugfs_tgt_stats)
+               goto err;
+
+
+       priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
+                                                      priv->debug.debugfs_phy,
+                                                      priv, &fops_xmit);
+       if (!priv->debug.debugfs_xmit)
+               goto err;
+
+       priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
+                                                      priv->debug.debugfs_phy,
+                                                      priv, &fops_recv);
+       if (!priv->debug.debugfs_recv)
+               goto err;
+
+       return 0;
+
+err:
+       ath9k_htc_exit_debug(ah);
+       return -ENOMEM;
+}
+
+void ath9k_htc_exit_debug(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+       debugfs_remove(priv->debug.debugfs_recv);
+       debugfs_remove(priv->debug.debugfs_xmit);
+       debugfs_remove(priv->debug.debugfs_tgt_stats);
+       debugfs_remove(priv->debug.debugfs_phy);
+}
+
+int ath9k_htc_debug_create_root(void)
+{
+       ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+       if (!ath9k_debugfs_root)
+               return -ENOENT;
+
+       return 0;
+}
+
+void ath9k_htc_debug_remove_root(void)
+{
+       debugfs_remove(ath9k_debugfs_root);
+       ath9k_debugfs_root = NULL;
+}
+
+#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
+
+/*******/
+/* ANI */
+/*******/
+
+static void ath_start_ani(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       unsigned long timestamp = jiffies_to_msecs(jiffies);
+
+       common->ani.longcal_timer = timestamp;
+       common->ani.shortcal_timer = timestamp;
+       common->ani.checkani_timer = timestamp;
+
+       ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
+                                    msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
+}
+
+void ath9k_ani_work(struct work_struct *work)
+{
+       struct ath9k_htc_priv *priv =
+               container_of(work, struct ath9k_htc_priv,
+                            ath9k_ani_work.work);
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       bool longcal = false;
+       bool shortcal = false;
+       bool aniflag = false;
+       unsigned int timestamp = jiffies_to_msecs(jiffies);
+       u32 cal_interval, short_cal_interval;
+
+       short_cal_interval = ATH_STA_SHORT_CALINTERVAL;
+
+       /* Only calibrate if awake */
+       if (ah->power_mode != ATH9K_PM_AWAKE)
+               goto set_timer;
+
+       /* Long calibration runs independently of short calibration. */
+       if ((timestamp - common->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
+               longcal = true;
+               ath_print(common, ATH_DBG_ANI, "longcal @%lu\n", jiffies);
+               common->ani.longcal_timer = timestamp;
+       }
+
+       /* Short calibration applies only while caldone is false */
+       if (!common->ani.caldone) {
+               if ((timestamp - common->ani.shortcal_timer) >=
+                   short_cal_interval) {
+                       shortcal = true;
+                       ath_print(common, ATH_DBG_ANI,
+                                 "shortcal @%lu\n", jiffies);
+                       common->ani.shortcal_timer = timestamp;
+                       common->ani.resetcal_timer = timestamp;
+               }
+       } else {
+               if ((timestamp - common->ani.resetcal_timer) >=
+                   ATH_RESTART_CALINTERVAL) {
+                       common->ani.caldone = ath9k_hw_reset_calvalid(ah);
+                       if (common->ani.caldone)
+                               common->ani.resetcal_timer = timestamp;
+               }
+       }
+
+       /* Verify whether we must check ANI */
+       if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
+               aniflag = true;
+               common->ani.checkani_timer = timestamp;
+       }
+
+       /* Skip all processing if there's nothing to do. */
+       if (longcal || shortcal || aniflag) {
+
+               ath9k_htc_ps_wakeup(priv);
+
+               /* Call ANI routine if necessary */
+               if (aniflag)
+                       ath9k_hw_ani_monitor(ah, ah->curchan);
+
+               /* Perform calibration if necessary */
+               if (longcal || shortcal) {
+                       common->ani.caldone =
+                               ath9k_hw_calibrate(ah, ah->curchan,
+                                                  common->rx_chainmask,
+                                                  longcal);
+
+                       if (longcal)
+                               common->ani.noise_floor =
+                                       ath9k_hw_getchan_noise(ah, ah->curchan);
+
+                       ath_print(common, ATH_DBG_ANI,
+                                 " calibrate chan %u/%x nf: %d\n",
+                                 ah->curchan->channel,
+                                 ah->curchan->channelFlags,
+                                 common->ani.noise_floor);
+               }
+
+               ath9k_htc_ps_restore(priv);
+       }
+
+set_timer:
+       /*
+       * Set timer interval based on previous results.
+       * The interval must be the shortest necessary to satisfy ANI,
+       * short calibration and long calibration.
+       */
+       cal_interval = ATH_LONG_CALINTERVAL;
+       if (priv->ah->config.enable_ani)
+               cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
+       if (!common->ani.caldone)
+               cal_interval = min(cal_interval, (u32)short_cal_interval);
+
+       ieee80211_queue_delayed_work(common->hw, &priv->ath9k_ani_work,
+                                    msecs_to_jiffies(cal_interval));
+}
+
+/*******/
+/* LED */
+/*******/
+
+static void ath9k_led_blink_work(struct work_struct *work)
+{
+       struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
+                                                  ath9k_led_blink_work.work);
+
+       if (!(priv->op_flags & OP_LED_ASSOCIATED))
+               return;
+
+       if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
+           (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
+               ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
+       else
+               ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
+                                 (priv->op_flags & OP_LED_ON) ? 1 : 0);
+
+       ieee80211_queue_delayed_work(priv->hw,
+                                    &priv->ath9k_led_blink_work,
+                                    (priv->op_flags & OP_LED_ON) ?
+                                    msecs_to_jiffies(priv->led_off_duration) :
+                                    msecs_to_jiffies(priv->led_on_duration));
+
+       priv->led_on_duration = priv->led_on_cnt ?
+               max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
+               ATH_LED_ON_DURATION_IDLE;
+       priv->led_off_duration = priv->led_off_cnt ?
+               max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
+               ATH_LED_OFF_DURATION_IDLE;
+       priv->led_on_cnt = priv->led_off_cnt = 0;
+
+       if (priv->op_flags & OP_LED_ON)
+               priv->op_flags &= ~OP_LED_ON;
+       else
+               priv->op_flags |= OP_LED_ON;
+}
+
+static void ath9k_led_brightness_work(struct work_struct *work)
+{
+       struct ath_led *led = container_of(work, struct ath_led,
+                                          brightness_work.work);
+       struct ath9k_htc_priv *priv = led->priv;
+
+       switch (led->brightness) {
+       case LED_OFF:
+               if (led->led_type == ATH_LED_ASSOC ||
+                   led->led_type == ATH_LED_RADIO) {
+                       ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
+                                         (led->led_type == ATH_LED_RADIO));
+                       priv->op_flags &= ~OP_LED_ASSOCIATED;
+                       if (led->led_type == ATH_LED_RADIO)
+                               priv->op_flags &= ~OP_LED_ON;
+               } else {
+                       priv->led_off_cnt++;
+               }
+               break;
+       case LED_FULL:
+               if (led->led_type == ATH_LED_ASSOC) {
+                       priv->op_flags |= OP_LED_ASSOCIATED;
+                       ieee80211_queue_delayed_work(priv->hw,
+                                            &priv->ath9k_led_blink_work, 0);
+               } else if (led->led_type == ATH_LED_RADIO) {
+                       ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
+                       priv->op_flags |= OP_LED_ON;
+               } else {
+                       priv->led_on_cnt++;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void ath9k_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 ath9k_htc_priv *priv = led->priv;
+
+       led->brightness = brightness;
+       if (!(priv->op_flags & OP_LED_DEINIT))
+               ieee80211_queue_delayed_work(priv->hw,
+                                            &led->brightness_work, 0);
+}
+
+static void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
+{
+       cancel_delayed_work_sync(&priv->radio_led.brightness_work);
+       cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
+       cancel_delayed_work_sync(&priv->tx_led.brightness_work);
+       cancel_delayed_work_sync(&priv->rx_led.brightness_work);
+}
+
+static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
+                             char *trigger)
+{
+       int ret;
+
+       led->priv = priv;
+       led->led_cdev.name = led->name;
+       led->led_cdev.default_trigger = trigger;
+       led->led_cdev.brightness_set = ath9k_led_brightness;
+
+       ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
+       if (ret)
+               ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
+                         "Failed to register led:%s", led->name);
+       else
+               led->registered = 1;
+
+       INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
+
+       return ret;
+}
+
+static void ath9k_unregister_led(struct ath_led *led)
+{
+       if (led->registered) {
+               led_classdev_unregister(&led->led_cdev);
+               led->registered = 0;
+       }
+}
+
+void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
+{
+       priv->op_flags |= OP_LED_DEINIT;
+       ath9k_unregister_led(&priv->assoc_led);
+       priv->op_flags &= ~OP_LED_ASSOCIATED;
+       ath9k_unregister_led(&priv->tx_led);
+       ath9k_unregister_led(&priv->rx_led);
+       ath9k_unregister_led(&priv->radio_led);
+}
+
+void ath9k_init_leds(struct ath9k_htc_priv *priv)
+{
+       char *trigger;
+       int ret;
+
+       if (AR_SREV_9287(priv->ah))
+               priv->ah->led_pin = ATH_LED_PIN_9287;
+       else if (AR_SREV_9271(priv->ah))
+               priv->ah->led_pin = ATH_LED_PIN_9271;
+       else
+               priv->ah->led_pin = ATH_LED_PIN_DEF;
+
+       /* Configure gpio 1 for output */
+       ath9k_hw_cfg_output(priv->ah, priv->ah->led_pin,
+                           AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+       /* LED off, active low */
+       ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
+
+       INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
+
+       trigger = ieee80211_get_radio_led_name(priv->hw);
+       snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
+               "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
+       ret = ath9k_register_led(priv, &priv->radio_led, trigger);
+       priv->radio_led.led_type = ATH_LED_RADIO;
+       if (ret)
+               goto fail;
+
+       trigger = ieee80211_get_assoc_led_name(priv->hw);
+       snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
+               "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
+       ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
+       priv->assoc_led.led_type = ATH_LED_ASSOC;
+       if (ret)
+               goto fail;
+
+       trigger = ieee80211_get_tx_led_name(priv->hw);
+       snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
+               "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
+       ret = ath9k_register_led(priv, &priv->tx_led, trigger);
+       priv->tx_led.led_type = ATH_LED_TX;
+       if (ret)
+               goto fail;
+
+       trigger = ieee80211_get_rx_led_name(priv->hw);
+       snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
+               "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
+       ret = ath9k_register_led(priv, &priv->rx_led, trigger);
+       priv->rx_led.led_type = ATH_LED_RX;
+       if (ret)
+               goto fail;
+
+       priv->op_flags &= ~OP_LED_DEINIT;
+
+       return;
+
+fail:
+       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+       ath9k_deinit_leds(priv);
+}
+
+/*******************/
+/*     Rfkill     */
+/*******************/
+
+static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv)
+{
+       return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) ==
+               priv->ah->rfkill_polarity;
+}
+
+static void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       bool blocked = !!ath_is_rfkill_set(priv);
+
+       wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+
+void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
+{
+       if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+               wiphy_rfkill_start_polling(priv->hw->wiphy);
+}
+
+/**********************/
+/* mac80211 Callbacks */
+/**********************/
+
+static int ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr;
+       struct ath9k_htc_priv *priv = hw->priv;
+       int padpos, padsize, ret;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+       /* Add the padding after the header if this is not already done */
+       padpos = ath9k_cmn_padpos(hdr->frame_control);
+       padsize = padpos & 3;
+       if (padsize && skb->len > padpos) {
+               if (skb_headroom(skb) < padsize)
+                       return -1;
+               skb_push(skb, padsize);
+               memmove(skb->data, skb->data + padsize, padpos);
+       }
+
+       ret = ath9k_htc_tx_start(priv, skb);
+       if (ret != 0) {
+               if (ret == -ENOMEM) {
+                       ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+                                 "Stopping TX queues\n");
+                       ieee80211_stop_queues(hw);
+                       spin_lock_bh(&priv->tx_lock);
+                       priv->tx_queues_stop = true;
+                       spin_unlock_bh(&priv->tx_lock);
+               } else {
+                       ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+                                 "Tx failed");
+               }
+               goto fail_tx;
+       }
+
+       return 0;
+
+fail_tx:
+       dev_kfree_skb_any(skb);
+       return 0;
+}
+
+static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_channel *curchan = hw->conf.channel;
+       struct ath9k_channel *init_channel;
+       int ret = 0;
+       enum htc_phymode mode;
+       __be16 htc_mode;
+       u8 cmd_rsp;
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "Starting driver with initial channel: %d MHz\n",
+                 curchan->center_freq);
+
+       /* setup initial channel */
+       init_channel = ath9k_cmn_get_curchannel(hw, ah);
+
+       /* Reset SERDES registers */
+       ath9k_hw_configpcipowersave(ah, 0, 0);
+
+       ath9k_hw_htc_resetinit(ah);
+       ret = ath9k_hw_reset(ah, init_channel, false);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to reset hardware; reset status %d "
+                         "(freq %u MHz)\n", ret, curchan->center_freq);
+               return ret;
+       }
+
+       ath_update_txpow(priv);
+
+       mode = ath9k_htc_get_curmode(priv, init_channel);
+       htc_mode = cpu_to_be16(mode);
+       WMI_CMD_BUF(WMI_SET_MODE_CMDID, &htc_mode);
+       WMI_CMD(WMI_ATH_INIT_CMDID);
+       WMI_CMD(WMI_START_RECV_CMDID);
+
+       ath9k_host_rx_init(priv);
+
+       priv->op_flags &= ~OP_INVALID;
+       htc_start(priv->htc);
+
+       spin_lock_bh(&priv->tx_lock);
+       priv->tx_queues_stop = false;
+       spin_unlock_bh(&priv->tx_lock);
+
+       if (led) {
+               /* Enable LED */
+               ath9k_hw_cfg_output(ah, ah->led_pin,
+                                   AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+               ath9k_hw_set_gpio(ah, ah->led_pin, 0);
+       }
+
+       ieee80211_wake_queues(hw);
+
+       return ret;
+}
+
+static int ath9k_htc_start(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       int ret = 0;
+
+       mutex_lock(&priv->mutex);
+       ret = ath9k_htc_radio_enable(hw, false);
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+
+static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       int ret = 0;
+       u8 cmd_rsp;
+
+       if (priv->op_flags & OP_INVALID) {
+               ath_print(common, ATH_DBG_ANY, "Device not present\n");
+               return;
+       }
+
+       if (led) {
+               /* Disable LED */
+               ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+               ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+       }
+
+       /* Cancel all the running timers/work .. */
+       cancel_work_sync(&priv->ps_work);
+       cancel_delayed_work_sync(&priv->ath9k_ani_work);
+       cancel_delayed_work_sync(&priv->ath9k_aggr_work);
+       cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+       ath9k_led_stop_brightness(priv);
+
+       ath9k_htc_ps_wakeup(priv);
+       htc_stop(priv->htc);
+       WMI_CMD(WMI_DISABLE_INTR_CMDID);
+       WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+       WMI_CMD(WMI_STOP_RECV_CMDID);
+       ath9k_hw_phy_disable(ah);
+       ath9k_hw_disable(ah);
+       ath9k_hw_configpcipowersave(ah, 1, 1);
+       ath9k_htc_ps_restore(priv);
+       ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+
+       skb_queue_purge(&priv->tx_queue);
+
+       /* Remove monitor interface here */
+       if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+               if (ath9k_htc_remove_monitor_interface(priv))
+                       ath_print(common, ATH_DBG_FATAL,
+                                 "Unable to remove monitor interface\n");
+               else
+                       ath_print(common, ATH_DBG_CONFIG,
+                                 "Monitor interface removed\n");
+       }
+
+       priv->op_flags |= OP_INVALID;
+
+       ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
+}
+
+static void ath9k_htc_stop(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       mutex_lock(&priv->mutex);
+       ath9k_htc_radio_disable(hw, false);
+       mutex_unlock(&priv->mutex);
+}
+
+
+static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_vif hvif;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       mutex_lock(&priv->mutex);
+
+       /* Only one interface for now */
+       if (priv->nvifs > 0) {
+               ret = -ENOBUFS;
+               goto out;
+       }
+
+       ath9k_htc_ps_wakeup(priv);
+       memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+       memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               hvif.opmode = cpu_to_be32(HTC_M_STA);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               hvif.opmode = cpu_to_be32(HTC_M_IBSS);
+               break;
+       default:
+               ath_print(common, ATH_DBG_FATAL,
+                       "Interface type %d not yet supported\n", vif->type);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "Attach a VIF of type: %d\n", vif->type);
+
+       priv->ah->opmode = vif->type;
+
+       /* Index starts from zero on the target */
+       avp->index = hvif.index = priv->nvifs;
+       hvif.rtsthreshold = cpu_to_be16(2304);
+       WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
+       if (ret)
+               goto out;
+
+       priv->nvifs++;
+
+       /*
+        * We need a node in target to tx mgmt frames
+        * before association.
+        */
+       ret = ath9k_htc_add_station(priv, vif, NULL);
+       if (ret)
+               goto out;
+
+       ret = ath9k_htc_update_cap_target(priv);
+       if (ret)
+               ath_print(common, ATH_DBG_CONFIG, "Failed to update"
+                         " capability in target \n");
+
+       priv->vif = vif;
+out:
+       ath9k_htc_ps_restore(priv);
+       mutex_unlock(&priv->mutex);
+       return ret;
+}
+
+static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
+       struct ath9k_htc_target_vif hvif;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
+
+       mutex_lock(&priv->mutex);
+
+       memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+       memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
+       hvif.index = avp->index;
+       WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+       priv->nvifs--;
+
+       ath9k_htc_remove_station(priv, vif, NULL);
+       priv->vif = NULL;
+
+       mutex_unlock(&priv->mutex);
+}
+
+static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ieee80211_conf *conf = &hw->conf;
+
+       mutex_lock(&priv->mutex);
+
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+               bool enable_radio = false;
+               bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+
+               if (!idle && priv->ps_idle)
+                       enable_radio = true;
+
+               priv->ps_idle = idle;
+
+               if (enable_radio) {
+                       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+                       ath9k_htc_radio_enable(hw, true);
+                       ath_print(common, ATH_DBG_CONFIG,
+                                 "not-idle: enabling radio\n");
+               }
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               struct ieee80211_channel *curchan = hw->conf.channel;
+               int pos = curchan->hw_value;
+               bool is_cw40 = false;
+
+               ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
+                         curchan->center_freq);
+
+               if (check_rc_update(hw, &is_cw40))
+                       ath9k_htc_rc_update(priv, is_cw40);
+
+               ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
+
+               if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
+                       ath_print(common, ATH_DBG_FATAL,
+                                 "Unable to set channel\n");
+                       mutex_unlock(&priv->mutex);
+                       return -EINVAL;
+               }
+
+       }
+       if (changed & IEEE80211_CONF_CHANGE_PS) {
+               if (conf->flags & IEEE80211_CONF_PS) {
+                       ath9k_htc_setpower(priv, ATH9K_PM_NETWORK_SLEEP);
+                       priv->ps_enabled = true;
+               } else {
+                       priv->ps_enabled = false;
+                       cancel_work_sync(&priv->ps_work);
+                       ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+               }
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       if (ath9k_htc_add_monitor_interface(priv))
+                               ath_print(common, ATH_DBG_FATAL,
+                                         "Failed to set monitor mode\n");
+                       else
+                               ath_print(common, ATH_DBG_CONFIG,
+                                         "HW opmode set to Monitor mode\n");
+               }
+       }
+
+       if (priv->ps_idle) {
+               ath_print(common, ATH_DBG_CONFIG,
+                         "idle: disabling radio\n");
+               ath9k_htc_radio_disable(hw, true);
+       }
+
+       mutex_unlock(&priv->mutex);
+
+       return 0;
+}
+
+#define SUPPORTED_FILTERS                      \
+       (FIF_PROMISC_IN_BSS |                   \
+       FIF_ALLMULTI |                          \
+       FIF_CONTROL |                           \
+       FIF_PSPOLL |                            \
+       FIF_OTHER_BSS |                         \
+       FIF_BCN_PRBRESP_PROMISC |               \
+       FIF_FCSFAIL)
+
+static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
+                                      unsigned int changed_flags,
+                                      unsigned int *total_flags,
+                                      u64 multicast)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       u32 rfilt;
+
+       mutex_lock(&priv->mutex);
+
+       ath9k_htc_ps_wakeup(priv);
+       changed_flags &= SUPPORTED_FILTERS;
+       *total_flags &= SUPPORTED_FILTERS;
+
+       priv->rxfilter = *total_flags;
+       rfilt = ath9k_htc_calcrxfilter(priv);
+       ath9k_hw_setrxfilter(priv->ah, rfilt);
+
+       ath_print(ath9k_hw_common(priv->ah), ATH_DBG_CONFIG,
+                 "Set HW RX filter: 0x%x\n", rfilt);
+
+       ath9k_htc_ps_restore(priv);
+       mutex_unlock(&priv->mutex);
+}
+
+static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                enum sta_notify_cmd cmd,
+                                struct ieee80211_sta *sta)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       int ret;
+
+       mutex_lock(&priv->mutex);
+
+       switch (cmd) {
+       case STA_NOTIFY_ADD:
+               ret = ath9k_htc_add_station(priv, vif, sta);
+               if (!ret)
+                       ath9k_htc_init_rate(priv, vif, sta);
+               break;
+       case STA_NOTIFY_REMOVE:
+               ath9k_htc_remove_station(priv, vif, sta);
+               break;
+       default:
+               break;
+       }
+
+       mutex_unlock(&priv->mutex);
+}
+
+static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
+                            const struct ieee80211_tx_queue_params *params)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_tx_queue_info qi;
+       int ret = 0, qnum;
+
+       if (queue >= WME_NUM_AC)
+               return 0;
+
+       mutex_lock(&priv->mutex);
+
+       memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+
+       qi.tqi_aifs = params->aifs;
+       qi.tqi_cwmin = params->cw_min;
+       qi.tqi_cwmax = params->cw_max;
+       qi.tqi_burstTime = params->txop;
+
+       qnum = get_hw_qnum(queue, priv->hwq_map);
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "Configure tx [queue/hwq] [%d/%d],  "
+                 "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n",
+                 queue, qnum, params->aifs, params->cw_min,
+                 params->cw_max, params->txop);
+
+       ret = ath_htc_txq_update(priv, qnum, &qi);
+       if (ret)
+               ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
+
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+
+static int ath9k_htc_set_key(struct ieee80211_hw *hw,
+                            enum set_key_cmd cmd,
+                            struct ieee80211_vif *vif,
+                            struct ieee80211_sta *sta,
+                            struct ieee80211_key_conf *key)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       int ret = 0;
+
+       if (htc_modparam_nohwcrypt)
+               return -ENOSPC;
+
+       mutex_lock(&priv->mutex);
+       ath_print(common, ATH_DBG_CONFIG, "Set HW Key\n");
+       ath9k_htc_ps_wakeup(priv);
+
+       switch (cmd) {
+       case SET_KEY:
+               ret = ath9k_cmn_key_config(common, vif, sta, key);
+               if (ret >= 0) {
+                       key->hw_key_idx = ret;
+                       /* push IV and Michael MIC generation to stack */
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       if (key->alg == ALG_TKIP)
+                               key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+                       if (priv->ah->sw_mgmt_crypto && key->alg == ALG_CCMP)
+                               key->flags |= IEEE80211_KEY_FLAG_SW_MGMT;
+                       ret = 0;
+               }
+               break;
+       case DISABLE_KEY:
+               ath9k_cmn_key_delete(common, key);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       ath9k_htc_ps_restore(priv);
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+
+static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_bss_conf *bss_conf,
+                                      u32 changed)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       mutex_lock(&priv->mutex);
+       ath9k_htc_ps_wakeup(priv);
+
+       if (changed & BSS_CHANGED_ASSOC) {
+               common->curaid = bss_conf->assoc ?
+                                bss_conf->aid : 0;
+               ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+                       bss_conf->assoc);
+
+               if (bss_conf->assoc) {
+                       priv->op_flags |= OP_ASSOCIATED;
+                       ath_start_ani(priv);
+               } else {
+                       priv->op_flags &= ~OP_ASSOCIATED;
+                       cancel_work_sync(&priv->ps_work);
+                       cancel_delayed_work_sync(&priv->ath9k_ani_work);
+               }
+       }
+
+       if (changed & BSS_CHANGED_BSSID) {
+               /* Set BSSID */
+               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+               ath9k_hw_write_associd(ah);
+
+               ath_print(common, ATH_DBG_CONFIG,
+                         "BSSID: %pM aid: 0x%x\n",
+                         common->curbssid, common->curaid);
+       }
+
+       if ((changed & BSS_CHANGED_BEACON_INT) ||
+           (changed & BSS_CHANGED_BEACON) ||
+           ((changed & BSS_CHANGED_BEACON_ENABLED) &&
+           bss_conf->enable_beacon)) {
+               priv->op_flags |= OP_ENABLE_BEACON;
+               ath9k_htc_beacon_config(priv, vif);
+       }
+
+       if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
+           !bss_conf->enable_beacon) {
+               priv->op_flags &= ~OP_ENABLE_BEACON;
+               ath9k_htc_beacon_config(priv, vif);
+       }
+
+       if (changed & BSS_CHANGED_ERP_PREAMBLE) {
+               ath_print(common, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n",
+                         bss_conf->use_short_preamble);
+               if (bss_conf->use_short_preamble)
+                       priv->op_flags |= OP_PREAMBLE_SHORT;
+               else
+                       priv->op_flags &= ~OP_PREAMBLE_SHORT;
+       }
+
+       if (changed & BSS_CHANGED_ERP_CTS_PROT) {
+               ath_print(common, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n",
+                         bss_conf->use_cts_prot);
+               if (bss_conf->use_cts_prot &&
+                   hw->conf.channel->band != IEEE80211_BAND_5GHZ)
+                       priv->op_flags |= OP_PROTECT_ENABLE;
+               else
+                       priv->op_flags &= ~OP_PROTECT_ENABLE;
+       }
+
+       if (changed & BSS_CHANGED_ERP_SLOT) {
+               if (bss_conf->use_short_slot)
+                       ah->slottime = 9;
+               else
+                       ah->slottime = 20;
+
+               ath9k_hw_init_global_settings(ah);
+       }
+
+       ath9k_htc_ps_restore(priv);
+       mutex_unlock(&priv->mutex);
+}
+
+static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       u64 tsf;
+
+       mutex_lock(&priv->mutex);
+       tsf = ath9k_hw_gettsf64(priv->ah);
+       mutex_unlock(&priv->mutex);
+
+       return tsf;
+}
+
+static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       mutex_lock(&priv->mutex);
+       ath9k_hw_settsf64(priv->ah, tsf);
+       mutex_unlock(&priv->mutex);
+}
+
+static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       ath9k_htc_ps_wakeup(priv);
+       mutex_lock(&priv->mutex);
+       ath9k_hw_reset_tsf(priv->ah);
+       mutex_unlock(&priv->mutex);
+       ath9k_htc_ps_restore(priv);
+}
+
+static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 enum ieee80211_ampdu_mlme_action action,
+                                 struct ieee80211_sta *sta,
+                                 u16 tid, u16 *ssn)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+       struct ath9k_htc_aggr_work *work = &priv->aggr_work;
+       struct ath9k_htc_sta *ista;
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               break;
+       case IEEE80211_AMPDU_TX_START:
+       case IEEE80211_AMPDU_TX_STOP:
+               if (!(priv->op_flags & OP_TXAGGR))
+                       return -ENOTSUPP;
+               memcpy(work->sta_addr, sta->addr, ETH_ALEN);
+               work->hw = hw;
+               work->vif = vif;
+               work->action = action;
+               work->tid = tid;
+               ieee80211_queue_delayed_work(hw, &priv->ath9k_aggr_work, 0);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               ista = (struct ath9k_htc_sta *) sta->drv_priv;
+               ista->tid_state[tid] = AGGR_OPERATIONAL;
+               break;
+       default:
+               ath_print(ath9k_hw_common(priv->ah), ATH_DBG_FATAL,
+                         "Unknown AMPDU action\n");
+       }
+
+       return 0;
+}
+
+static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       mutex_lock(&priv->mutex);
+       spin_lock_bh(&priv->beacon_lock);
+       priv->op_flags |= OP_SCANNING;
+       spin_unlock_bh(&priv->beacon_lock);
+       cancel_work_sync(&priv->ps_work);
+       cancel_delayed_work_sync(&priv->ath9k_ani_work);
+       mutex_unlock(&priv->mutex);
+}
+
+static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       ath9k_htc_ps_wakeup(priv);
+       mutex_lock(&priv->mutex);
+       spin_lock_bh(&priv->beacon_lock);
+       priv->op_flags &= ~OP_SCANNING;
+       spin_unlock_bh(&priv->beacon_lock);
+       priv->op_flags |= OP_FULL_RESET;
+       if (priv->op_flags & OP_ASSOCIATED)
+               ath9k_htc_beacon_config(priv, priv->vif);
+       ath_start_ani(priv);
+       mutex_unlock(&priv->mutex);
+       ath9k_htc_ps_restore(priv);
+}
+
+static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       return 0;
+}
+
+static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
+                                        u8 coverage_class)
+{
+       struct ath9k_htc_priv *priv = hw->priv;
+
+       mutex_lock(&priv->mutex);
+       priv->ah->coverage_class = coverage_class;
+       ath9k_hw_init_global_settings(priv->ah);
+       mutex_unlock(&priv->mutex);
+}
+
+struct ieee80211_ops ath9k_htc_ops = {
+       .tx                 = ath9k_htc_tx,
+       .start              = ath9k_htc_start,
+       .stop               = ath9k_htc_stop,
+       .add_interface      = ath9k_htc_add_interface,
+       .remove_interface   = ath9k_htc_remove_interface,
+       .config             = ath9k_htc_config,
+       .configure_filter   = ath9k_htc_configure_filter,
+       .sta_notify         = ath9k_htc_sta_notify,
+       .conf_tx            = ath9k_htc_conf_tx,
+       .bss_info_changed   = ath9k_htc_bss_info_changed,
+       .set_key            = ath9k_htc_set_key,
+       .get_tsf            = ath9k_htc_get_tsf,
+       .set_tsf            = ath9k_htc_set_tsf,
+       .reset_tsf          = ath9k_htc_reset_tsf,
+       .ampdu_action       = ath9k_htc_ampdu_action,
+       .sw_scan_start      = ath9k_htc_sw_scan_start,
+       .sw_scan_complete   = ath9k_htc_sw_scan_complete,
+       .set_rts_threshold  = ath9k_htc_set_rts_threshold,
+       .rfkill_poll        = ath9k_htc_rfkill_poll_state,
+       .set_coverage_class = ath9k_htc_set_coverage_class,
+};
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
new file mode 100644 (file)
index 0000000..2571b44
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+/******/
+/* TX */
+/******/
+
+int get_hw_qnum(u16 queue, int *hwq_map)
+{
+       switch (queue) {
+       case 0:
+               return hwq_map[ATH9K_WME_AC_VO];
+       case 1:
+               return hwq_map[ATH9K_WME_AC_VI];
+       case 2:
+               return hwq_map[ATH9K_WME_AC_BE];
+       case 3:
+               return hwq_map[ATH9K_WME_AC_BK];
+       default:
+               return hwq_map[ATH9K_WME_AC_BE];
+       }
+}
+
+int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
+                      struct ath9k_tx_queue_info *qinfo)
+{
+       struct ath_hw *ah = priv->ah;
+       int error = 0;
+       struct ath9k_tx_queue_info qi;
+
+       ath9k_hw_get_txq_props(ah, qnum, &qi);
+
+       qi.tqi_aifs = qinfo->tqi_aifs;
+       qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */
+       qi.tqi_cwmax = qinfo->tqi_cwmax;
+       qi.tqi_burstTime = qinfo->tqi_burstTime;
+       qi.tqi_readyTime = qinfo->tqi_readyTime;
+
+       if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
+               ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+                         "Unable to update hardware queue %u!\n", qnum);
+               error = -EIO;
+       } else {
+               ath9k_hw_resettxqueue(ah, qnum);
+       }
+
+       return error;
+}
+
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = tx_info->control.sta;
+       struct ath9k_htc_sta *ista;
+       struct ath9k_htc_vif *avp;
+       struct ath9k_htc_tx_ctl tx_ctl;
+       enum htc_endpoint_id epid;
+       u16 qnum, hw_qnum;
+       __le16 fc;
+       u8 *tx_fhdr;
+       u8 sta_idx;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = hdr->frame_control;
+
+       avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv;
+       if (sta) {
+               ista = (struct ath9k_htc_sta *) sta->drv_priv;
+               sta_idx = ista->index;
+       } else {
+               sta_idx = 0;
+       }
+
+       memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
+
+       if (ieee80211_is_data(fc)) {
+               struct tx_frame_hdr tx_hdr;
+               u8 *qc;
+
+               memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
+
+               tx_hdr.node_idx = sta_idx;
+               tx_hdr.vif_idx = avp->index;
+
+               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       tx_ctl.type = ATH9K_HTC_AMPDU;
+                       tx_hdr.data_type = ATH9K_HTC_AMPDU;
+               } else {
+                       tx_ctl.type = ATH9K_HTC_NORMAL;
+                       tx_hdr.data_type = ATH9K_HTC_NORMAL;
+               }
+
+               if (ieee80211_is_data(fc)) {
+                       qc = ieee80211_get_qos_ctl(hdr);
+                       tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+               }
+
+               /* Check for RTS protection */
+               if (priv->hw->wiphy->rts_threshold != (u32) -1)
+                       if (skb->len > priv->hw->wiphy->rts_threshold)
+                               tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS;
+
+               /* CTS-to-self */
+               if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) &&
+                   (priv->op_flags & OP_PROTECT_ENABLE))
+                       tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY;
+
+               tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+               if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+                       tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+               else
+                       tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+               tx_fhdr = skb_push(skb, sizeof(tx_hdr));
+               memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
+
+               qnum = skb_get_queue_mapping(skb);
+               hw_qnum = get_hw_qnum(qnum, priv->hwq_map);
+
+               switch (hw_qnum) {
+               case 0:
+                       epid = priv->data_be_ep;
+                       break;
+               case 2:
+                       epid = priv->data_vi_ep;
+                       break;
+               case 3:
+                       epid = priv->data_vo_ep;
+                       break;
+               case 1:
+               default:
+                       epid = priv->data_bk_ep;
+                       break;
+               }
+       } else {
+               struct tx_mgmt_hdr mgmt_hdr;
+
+               memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
+
+               tx_ctl.type = ATH9K_HTC_NORMAL;
+
+               mgmt_hdr.node_idx = sta_idx;
+               mgmt_hdr.vif_idx = avp->index;
+               mgmt_hdr.tidno = 0;
+               mgmt_hdr.flags = 0;
+
+               mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+               if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+                       mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+               else
+                       mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+               tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
+               memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
+               epid = priv->mgmt_ep;
+       }
+
+       return htc_send(priv->htc, skb, epid, &tx_ctl);
+}
+
+void ath9k_tx_tasklet(unsigned long data)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+       struct ieee80211_sta *sta;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *tx_info;
+       struct sk_buff *skb = NULL;
+       __le16 fc;
+
+       while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) {
+
+               hdr = (struct ieee80211_hdr *) skb->data;
+               fc = hdr->frame_control;
+               tx_info = IEEE80211_SKB_CB(skb);
+
+               memset(&tx_info->status, 0, sizeof(tx_info->status));
+
+               rcu_read_lock();
+
+               sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+               if (!sta) {
+                       rcu_read_unlock();
+                       ieee80211_tx_status(priv->hw, skb);
+                       continue;
+               }
+
+               /* Check if we need to start aggregation */
+
+               if (sta && conf_is_ht(&priv->hw->conf) &&
+                   (priv->op_flags & OP_TXAGGR)
+                   && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+                       if (ieee80211_is_data_qos(fc)) {
+                               u8 *qc, tid;
+                               struct ath9k_htc_sta *ista;
+
+                               qc = ieee80211_get_qos_ctl(hdr);
+                               tid = qc[0] & 0xf;
+                               ista = (struct ath9k_htc_sta *)sta->drv_priv;
+
+                               if ((tid < ATH9K_HTC_MAX_TID) &&
+                                   ista->tid_state[tid] == AGGR_STOP) {
+                                       ieee80211_start_tx_ba_session(sta, tid);
+                                       ista->tid_state[tid] = AGGR_PROGRESS;
+                               }
+                       }
+               }
+
+               rcu_read_unlock();
+
+               /* Send status to mac80211 */
+               ieee80211_tx_status(priv->hw, skb);
+       }
+
+       /* Wake TX queues if needed */
+       spin_lock_bh(&priv->tx_lock);
+       if (priv->tx_queues_stop) {
+               priv->tx_queues_stop = false;
+               spin_unlock_bh(&priv->tx_lock);
+               ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
+                         "Waking up TX queues\n");
+               ieee80211_wake_queues(priv->hw);
+               return;
+       }
+       spin_unlock_bh(&priv->tx_lock);
+}
+
+void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
+                   enum htc_endpoint_id ep_id, bool txok)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ieee80211_tx_info *tx_info;
+
+       if (!skb)
+               return;
+
+       if (ep_id == priv->mgmt_ep) {
+               skb_pull(skb, sizeof(struct tx_mgmt_hdr));
+       } else if ((ep_id == priv->data_bk_ep) ||
+                  (ep_id == priv->data_be_ep) ||
+                  (ep_id == priv->data_vi_ep) ||
+                  (ep_id == priv->data_vo_ep)) {
+               skb_pull(skb, sizeof(struct tx_frame_hdr));
+       } else {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unsupported TX EPID: %d\n", ep_id);
+               dev_kfree_skb_any(skb);
+               return;
+       }
+
+       tx_info = IEEE80211_SKB_CB(skb);
+
+       if (txok)
+               tx_info->flags |= IEEE80211_TX_STAT_ACK;
+
+       skb_queue_tail(&priv->tx_queue, skb);
+       tasklet_schedule(&priv->tx_tasklet);
+}
+
+int ath9k_tx_init(struct ath9k_htc_priv *priv)
+{
+       skb_queue_head_init(&priv->tx_queue);
+       return 0;
+}
+
+void ath9k_tx_cleanup(struct ath9k_htc_priv *priv)
+{
+
+}
+
+bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
+                        enum ath9k_tx_queue_subtype subtype)
+{
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_tx_queue_info qi;
+       int qnum;
+
+       memset(&qi, 0, sizeof(qi));
+
+       qi.tqi_subtype = subtype;
+       qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
+       qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
+       qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
+       qi.tqi_physCompBuf = 0;
+       qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE;
+
+       qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
+       if (qnum == -1)
+               return false;
+
+       if (qnum >= ARRAY_SIZE(priv->hwq_map)) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "qnum %u out of range, max %u!\n",
+                         qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map));
+               ath9k_hw_releasetxqueue(ah, qnum);
+               return false;
+       }
+
+       priv->hwq_map[subtype] = qnum;
+       return true;
+}
+
+/******/
+/* RX */
+/******/
+
+/*
+ * Calculate the RX filter to be set in the HW.
+ */
+u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
+{
+#define        RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR)
+
+       struct ath_hw *ah = priv->ah;
+       u32 rfilt;
+
+       rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE)
+               | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST
+               | ATH9K_RX_FILTER_MCAST;
+
+       /* If not a STA, enable processing of Probe Requests */
+       if (ah->opmode != NL80211_IFTYPE_STATION)
+               rfilt |= ATH9K_RX_FILTER_PROBEREQ;
+
+       /*
+        * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
+        * mode interface or when in monitor mode. AP mode does not need this
+        * since it receives all in-BSS frames anyway.
+        */
+       if (((ah->opmode != NL80211_IFTYPE_AP) &&
+            (priv->rxfilter & FIF_PROMISC_IN_BSS)) ||
+           (ah->opmode == NL80211_IFTYPE_MONITOR))
+               rfilt |= ATH9K_RX_FILTER_PROM;
+
+       if (priv->rxfilter & FIF_CONTROL)
+               rfilt |= ATH9K_RX_FILTER_CONTROL;
+
+       if ((ah->opmode == NL80211_IFTYPE_STATION) &&
+           !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
+               rfilt |= ATH9K_RX_FILTER_MYBEACON;
+       else
+               rfilt |= ATH9K_RX_FILTER_BEACON;
+
+       if (conf_is_ht(&priv->hw->conf))
+               rfilt |= ATH9K_RX_FILTER_COMP_BAR;
+
+       return rfilt;
+
+#undef RX_FILTER_PRESERVE
+}
+
+/*
+ * Recv initialization for opmode change.
+ */
+static void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv)
+{
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       u32 rfilt, mfilt[2];
+
+       /* configure rx filter */
+       rfilt = ath9k_htc_calcrxfilter(priv);
+       ath9k_hw_setrxfilter(ah, rfilt);
+
+       /* configure bssid mask */
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+               ath_hw_setbssidmask(common);
+
+       /* configure operational mode */
+       ath9k_hw_setopmode(ah);
+
+       /* Handle any link-level address change. */
+       ath9k_hw_setmac(ah, common->macaddr);
+
+       /* calculate and install multicast filter */
+       mfilt[0] = mfilt[1] = ~0;
+       ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
+}
+
+void ath9k_host_rx_init(struct ath9k_htc_priv *priv)
+{
+       ath9k_hw_rxena(priv->ah);
+       ath9k_htc_opmode_init(priv);
+       ath9k_hw_startpcureceive(priv->ah);
+       priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER;
+}
+
+static void ath9k_process_rate(struct ieee80211_hw *hw,
+                              struct ieee80211_rx_status *rxs,
+                              u8 rx_rate, u8 rs_flags)
+{
+       struct ieee80211_supported_band *sband;
+       enum ieee80211_band band;
+       unsigned int i = 0;
+
+       if (rx_rate & 0x80) {
+               /* HT rate */
+               rxs->flag |= RX_FLAG_HT;
+               if (rs_flags & ATH9K_RX_2040)
+                       rxs->flag |= RX_FLAG_40MHZ;
+               if (rs_flags & ATH9K_RX_GI)
+                       rxs->flag |= RX_FLAG_SHORT_GI;
+               rxs->rate_idx = rx_rate & 0x7f;
+               return;
+       }
+
+       band = hw->conf.channel->band;
+       sband = hw->wiphy->bands[band];
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               if (sband->bitrates[i].hw_value == rx_rate) {
+                       rxs->rate_idx = i;
+                       return;
+               }
+               if (sband->bitrates[i].hw_value_short == rx_rate) {
+                       rxs->rate_idx = i;
+                       rxs->flag |= RX_FLAG_SHORTPRE;
+                       return;
+               }
+       }
+
+}
+
+static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
+                            struct ath9k_htc_rxbuf *rxbuf,
+                            struct ieee80211_rx_status *rx_status)
+
+{
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_hw *hw = priv->hw;
+       struct sk_buff *skb = rxbuf->skb;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath_htc_rx_status *rxstatus;
+       int hdrlen, padpos, padsize;
+       int last_rssi = ATH_RSSI_DUMMY_MARKER;
+       __le16 fc;
+
+       if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Corrupted RX frame, dropping\n");
+               goto rx_next;
+       }
+
+       rxstatus = (struct ath_htc_rx_status *)skb->data;
+
+       if (be16_to_cpu(rxstatus->rs_datalen) -
+           (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Corrupted RX data len, dropping "
+                         "(dlen: %d, skblen: %d)\n",
+                         rxstatus->rs_datalen, skb->len);
+               goto rx_next;
+       }
+
+       /* Get the RX status information */
+       memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
+       skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
+
+       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = hdr->frame_control;
+       hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+       padpos = ath9k_cmn_padpos(fc);
+
+       padsize = padpos & 3;
+       if (padsize && skb->len >= padpos+padsize+FCS_LEN) {
+               memmove(skb->data + padsize, skb->data, padpos);
+               skb_pull(skb, padsize);
+       }
+
+       memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+       if (rxbuf->rxstatus.rs_status != 0) {
+               if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC)
+                       rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+               if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY)
+                       goto rx_next;
+
+               if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) {
+                       /* FIXME */
+               } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) {
+                       if (ieee80211_is_ctl(fc))
+                               /*
+                                * Sometimes, we get invalid
+                                * MIC failures on valid control frames.
+                                * Remove these mic errors.
+                                */
+                               rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC;
+                       else
+                               rx_status->flag |= RX_FLAG_MMIC_ERROR;
+               }
+
+               /*
+                * Reject error frames with the exception of
+                * decryption and MIC failures. For monitor mode,
+                * we also ignore the CRC error.
+                */
+               if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) {
+                       if (rxbuf->rxstatus.rs_status &
+                           ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+                             ATH9K_RXERR_CRC))
+                               goto rx_next;
+               } else {
+                       if (rxbuf->rxstatus.rs_status &
+                           ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+                               goto rx_next;
+                       }
+               }
+       }
+
+       if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) {
+               u8 keyix;
+               keyix = rxbuf->rxstatus.rs_keyix;
+               if (keyix != ATH9K_RXKEYIX_INVALID) {
+                       rx_status->flag |= RX_FLAG_DECRYPTED;
+               } else if (ieee80211_has_protected(fc) &&
+                          skb->len >= hdrlen + 4) {
+                       keyix = skb->data[hdrlen + 3] >> 6;
+                       if (test_bit(keyix, common->keymap))
+                               rx_status->flag |= RX_FLAG_DECRYPTED;
+               }
+       }
+
+       ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate,
+                          rxbuf->rxstatus.rs_flags);
+
+       if (priv->op_flags & OP_ASSOCIATED) {
+               if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD &&
+                   !rxbuf->rxstatus.rs_moreaggr)
+                       ATH_RSSI_LPF(priv->rx.last_rssi,
+                                    rxbuf->rxstatus.rs_rssi);
+
+               last_rssi = priv->rx.last_rssi;
+
+               if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+                       rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi,
+                                                            ATH_RSSI_EP_MULTIPLIER);
+
+               if (rxbuf->rxstatus.rs_rssi < 0)
+                       rxbuf->rxstatus.rs_rssi = 0;
+
+               if (ieee80211_is_beacon(fc))
+                       priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi;
+       }
+
+       rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp);
+       rx_status->band = hw->conf.channel->band;
+       rx_status->freq = hw->conf.channel->center_freq;
+       rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
+       rx_status->antenna = rxbuf->rxstatus.rs_antenna;
+       rx_status->flag |= RX_FLAG_TSFT;
+
+       return true;
+
+rx_next:
+       return false;
+}
+
+/*
+ * FIXME: Handle FLUSH later on.
+ */
+void ath9k_rx_tasklet(unsigned long data)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+       struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
+       struct ieee80211_rx_status rx_status;
+       struct sk_buff *skb;
+       unsigned long flags;
+       struct ieee80211_hdr *hdr;
+
+       do {
+               spin_lock_irqsave(&priv->rx.rxbuflock, flags);
+               list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
+                       if (tmp_buf->in_process) {
+                               rxbuf = tmp_buf;
+                               break;
+                       }
+               }
+
+               if (rxbuf == NULL) {
+                       spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
+                       break;
+               }
+
+               if (!rxbuf->skb)
+                       goto requeue;
+
+               if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) {
+                       dev_kfree_skb_any(rxbuf->skb);
+                       goto requeue;
+               }
+
+               memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status,
+                      sizeof(struct ieee80211_rx_status));
+               skb = rxbuf->skb;
+               hdr = (struct ieee80211_hdr *) skb->data;
+
+               if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled)
+                               ieee80211_queue_work(priv->hw, &priv->ps_work);
+
+               spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
+
+               ieee80211_rx(priv->hw, skb);
+
+               spin_lock_irqsave(&priv->rx.rxbuflock, flags);
+requeue:
+               rxbuf->in_process = false;
+               rxbuf->skb = NULL;
+               list_move_tail(&rxbuf->list, &priv->rx.rxbuf);
+               rxbuf = NULL;
+               spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);
+       } while (1);
+
+}
+
+void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
+                   enum htc_endpoint_id ep_id)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv;
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
+
+       spin_lock(&priv->rx.rxbuflock);
+       list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
+               if (!tmp_buf->in_process) {
+                       rxbuf = tmp_buf;
+                       break;
+               }
+       }
+       spin_unlock(&priv->rx.rxbuflock);
+
+       if (rxbuf == NULL) {
+               ath_print(common, ATH_DBG_ANY,
+                         "No free RX buffer\n");
+               goto err;
+       }
+
+       spin_lock(&priv->rx.rxbuflock);
+       rxbuf->skb = skb;
+       rxbuf->in_process = true;
+       spin_unlock(&priv->rx.rxbuflock);
+
+       tasklet_schedule(&priv->rx_tasklet);
+       return;
+err:
+       dev_kfree_skb_any(skb);
+}
+
+/* FIXME: Locking for cleanup/init */
+
+void ath9k_rx_cleanup(struct ath9k_htc_priv *priv)
+{
+       struct ath9k_htc_rxbuf *rxbuf, *tbuf;
+
+       list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) {
+               list_del(&rxbuf->list);
+               if (rxbuf->skb)
+                       dev_kfree_skb_any(rxbuf->skb);
+               kfree(rxbuf);
+       }
+}
+
+int ath9k_rx_init(struct ath9k_htc_priv *priv)
+{
+       struct ath_hw *ah = priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_htc_rxbuf *rxbuf;
+       int i = 0;
+
+       INIT_LIST_HEAD(&priv->rx.rxbuf);
+       spin_lock_init(&priv->rx.rxbuflock);
+
+       for (i = 0; i < ATH9K_HTC_RXBUF; i++) {
+               rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL);
+               if (rxbuf == NULL) {
+                       ath_print(common, ATH_DBG_FATAL,
+                                 "Unable to allocate RX buffers\n");
+                       goto err;
+               }
+               list_add_tail(&rxbuf->list, &priv->rx.rxbuf);
+       }
+
+       return 0;
+
+err:
+       ath9k_rx_cleanup(priv);
+       return -ENOMEM;
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
new file mode 100644 (file)
index 0000000..064397f
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
+                         u16 len, u8 flags, u8 epid,
+                         struct ath9k_htc_tx_ctl *tx_ctl)
+{
+       struct htc_frame_hdr *hdr;
+       struct htc_endpoint *endpoint = &target->endpoint[epid];
+       int status;
+
+       hdr = (struct htc_frame_hdr *)
+               skb_push(skb, sizeof(struct htc_frame_hdr));
+       hdr->endpoint_id = epid;
+       hdr->flags = flags;
+       hdr->payload_len = cpu_to_be16(len);
+
+       status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb,
+                                  tx_ctl);
+       return status;
+}
+
+static struct htc_endpoint *get_next_avail_ep(struct htc_endpoint *endpoint)
+{
+       enum htc_endpoint_id avail_epid;
+
+       for (avail_epid = (ENDPOINT_MAX - 1); avail_epid > ENDPOINT0; avail_epid--)
+               if (endpoint[avail_epid].service_id == 0)
+                       return &endpoint[avail_epid];
+       return NULL;
+}
+
+static u8 service_to_ulpipe(u16 service_id)
+{
+       switch (service_id) {
+       case WMI_CONTROL_SVC:
+               return 4;
+       case WMI_BEACON_SVC:
+       case WMI_CAB_SVC:
+       case WMI_UAPSD_SVC:
+       case WMI_MGMT_SVC:
+       case WMI_DATA_VO_SVC:
+       case WMI_DATA_VI_SVC:
+       case WMI_DATA_BE_SVC:
+       case WMI_DATA_BK_SVC:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static u8 service_to_dlpipe(u16 service_id)
+{
+       switch (service_id) {
+       case WMI_CONTROL_SVC:
+               return 3;
+       case WMI_BEACON_SVC:
+       case WMI_CAB_SVC:
+       case WMI_UAPSD_SVC:
+       case WMI_MGMT_SVC:
+       case WMI_DATA_VO_SVC:
+       case WMI_DATA_VI_SVC:
+       case WMI_DATA_BE_SVC:
+       case WMI_DATA_BK_SVC:
+               return 2;
+       default:
+               return 0;
+       }
+}
+
+static void htc_process_target_rdy(struct htc_target *target,
+                                  void *buf)
+{
+       struct htc_endpoint *endpoint;
+       struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
+
+       target->credits = be16_to_cpu(htc_ready_msg->credits);
+       target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
+
+       endpoint = &target->endpoint[ENDPOINT0];
+       endpoint->service_id = HTC_CTRL_RSVD_SVC;
+       endpoint->max_msglen = HTC_MAX_CONTROL_MESSAGE_LENGTH;
+       atomic_inc(&target->tgt_ready);
+       complete(&target->target_wait);
+}
+
+static void htc_process_conn_rsp(struct htc_target *target,
+                                struct htc_frame_hdr *htc_hdr)
+{
+       struct htc_conn_svc_rspmsg *svc_rspmsg;
+       struct htc_endpoint *endpoint, *tmp_endpoint = NULL;
+       u16 service_id;
+       u16 max_msglen;
+       enum htc_endpoint_id epid, tepid;
+
+       svc_rspmsg = (struct htc_conn_svc_rspmsg *)
+               ((void *) htc_hdr + sizeof(struct htc_frame_hdr));
+
+       if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) {
+               epid = svc_rspmsg->endpoint_id;
+               service_id = be16_to_cpu(svc_rspmsg->service_id);
+               max_msglen = be16_to_cpu(svc_rspmsg->max_msg_len);
+               endpoint = &target->endpoint[epid];
+
+               for (tepid = (ENDPOINT_MAX - 1); tepid > ENDPOINT0; tepid--) {
+                       tmp_endpoint = &target->endpoint[tepid];
+                       if (tmp_endpoint->service_id == service_id) {
+                               tmp_endpoint->service_id = 0;
+                               break;
+                       }
+               }
+
+               if (tepid == ENDPOINT0)
+                       return;
+
+               endpoint->service_id = service_id;
+               endpoint->max_txqdepth = tmp_endpoint->max_txqdepth;
+               endpoint->ep_callbacks = tmp_endpoint->ep_callbacks;
+               endpoint->ul_pipeid = tmp_endpoint->ul_pipeid;
+               endpoint->dl_pipeid = tmp_endpoint->dl_pipeid;
+               endpoint->max_msglen = max_msglen;
+               target->conn_rsp_epid = epid;
+               complete(&target->cmd_wait);
+       } else {
+               target->conn_rsp_epid = ENDPOINT_UNUSED;
+       }
+}
+
+static int htc_config_pipe_credits(struct htc_target *target)
+{
+       struct sk_buff *skb;
+       struct htc_config_pipe_msg *cp_msg;
+       int ret, time_left;
+
+       skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
+       if (!skb) {
+               dev_err(target->dev, "failed to allocate send buffer\n");
+               return -ENOMEM;
+       }
+       skb_reserve(skb, sizeof(struct htc_frame_hdr));
+
+       cp_msg = (struct htc_config_pipe_msg *)
+               skb_put(skb, sizeof(struct htc_config_pipe_msg));
+
+       cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
+       cp_msg->pipe_id = USB_WLAN_TX_PIPE;
+       cp_msg->credits = 28;
+
+       target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
+
+       ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+       if (ret)
+               goto err;
+
+       time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
+       if (!time_left) {
+               dev_err(target->dev, "HTC credit config timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+err:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+static int htc_setup_complete(struct htc_target *target)
+{
+       struct sk_buff *skb;
+       struct htc_comp_msg *comp_msg;
+       int ret = 0, time_left;
+
+       skb = alloc_skb(50 + sizeof(struct htc_frame_hdr), GFP_ATOMIC);
+       if (!skb) {
+               dev_err(target->dev, "failed to allocate send buffer\n");
+               return -ENOMEM;
+       }
+       skb_reserve(skb, sizeof(struct htc_frame_hdr));
+
+       comp_msg = (struct htc_comp_msg *)
+               skb_put(skb, sizeof(struct htc_comp_msg));
+       comp_msg->msg_id = cpu_to_be16(HTC_MSG_SETUP_COMPLETE_ID);
+
+       target->htc_flags |= HTC_OP_START_WAIT;
+
+       ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+       if (ret)
+               goto err;
+
+       time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
+       if (!time_left) {
+               dev_err(target->dev, "HTC start timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+
+err:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+/* HTC APIs */
+
+int htc_init(struct htc_target *target)
+{
+       int ret;
+
+       ret = htc_config_pipe_credits(target);
+       if (ret)
+               return ret;
+
+       return htc_setup_complete(target);
+}
+
+int htc_connect_service(struct htc_target *target,
+                    struct htc_service_connreq *service_connreq,
+                    enum htc_endpoint_id *conn_rsp_epid)
+{
+       struct sk_buff *skb;
+       struct htc_endpoint *endpoint;
+       struct htc_conn_svc_msg *conn_msg;
+       int ret, time_left;
+
+       /* Find an available endpoint */
+       endpoint = get_next_avail_ep(target->endpoint);
+       if (!endpoint) {
+               dev_err(target->dev, "Endpoint is not available for"
+                       "service %d\n", service_connreq->service_id);
+               return -EINVAL;
+       }
+
+       endpoint->service_id = service_connreq->service_id;
+       endpoint->max_txqdepth = service_connreq->max_send_qdepth;
+       endpoint->ul_pipeid = service_to_ulpipe(service_connreq->service_id);
+       endpoint->dl_pipeid = service_to_dlpipe(service_connreq->service_id);
+       endpoint->ep_callbacks = service_connreq->ep_callbacks;
+
+       skb = alloc_skb(sizeof(struct htc_conn_svc_msg) +
+                           sizeof(struct htc_frame_hdr), GFP_ATOMIC);
+       if (!skb) {
+               dev_err(target->dev, "Failed to allocate buf to send"
+                       "service connect req\n");
+               return -ENOMEM;
+       }
+
+       skb_reserve(skb, sizeof(struct htc_frame_hdr));
+
+       conn_msg = (struct htc_conn_svc_msg *)
+                       skb_put(skb, sizeof(struct htc_conn_svc_msg));
+       conn_msg->service_id = cpu_to_be16(service_connreq->service_id);
+       conn_msg->msg_id = cpu_to_be16(HTC_MSG_CONNECT_SERVICE_ID);
+       conn_msg->con_flags = cpu_to_be16(service_connreq->con_flags);
+       conn_msg->dl_pipeid = endpoint->dl_pipeid;
+       conn_msg->ul_pipeid = endpoint->ul_pipeid;
+
+       ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+       if (ret)
+               goto err;
+
+       time_left = wait_for_completion_timeout(&target->cmd_wait, HZ);
+       if (!time_left) {
+               dev_err(target->dev, "Service connection timeout for: %d\n",
+                       service_connreq->service_id);
+               return -ETIMEDOUT;
+       }
+
+       *conn_rsp_epid = target->conn_rsp_epid;
+       return 0;
+err:
+       kfree_skb(skb);
+       return ret;
+}
+
+int htc_send(struct htc_target *target, struct sk_buff *skb,
+            enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl)
+{
+       return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl);
+}
+
+void htc_stop(struct htc_target *target)
+{
+       enum htc_endpoint_id epid;
+       struct htc_endpoint *endpoint;
+
+       for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
+               endpoint = &target->endpoint[epid];
+               if (endpoint->service_id != 0)
+                       target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
+       }
+}
+
+void htc_start(struct htc_target *target)
+{
+       enum htc_endpoint_id epid;
+       struct htc_endpoint *endpoint;
+
+       for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
+               endpoint = &target->endpoint[epid];
+               if (endpoint->service_id != 0)
+                       target->hif->start(target->hif_dev,
+                                          endpoint->ul_pipeid);
+       }
+}
+
+void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
+                              struct sk_buff *skb, bool txok)
+{
+       struct htc_endpoint *endpoint;
+       struct htc_frame_hdr *htc_hdr = NULL;
+
+       if (htc_handle->htc_flags & HTC_OP_CONFIG_PIPE_CREDITS) {
+               complete(&htc_handle->cmd_wait);
+               htc_handle->htc_flags &= ~HTC_OP_CONFIG_PIPE_CREDITS;
+               goto ret;
+       }
+
+       if (htc_handle->htc_flags & HTC_OP_START_WAIT) {
+               complete(&htc_handle->cmd_wait);
+               htc_handle->htc_flags &= ~HTC_OP_START_WAIT;
+               goto ret;
+       }
+
+       if (skb) {
+               htc_hdr = (struct htc_frame_hdr *) skb->data;
+               endpoint = &htc_handle->endpoint[htc_hdr->endpoint_id];
+               skb_pull(skb, sizeof(struct htc_frame_hdr));
+
+               if (endpoint->ep_callbacks.tx) {
+                       endpoint->ep_callbacks.tx(endpoint->ep_callbacks.priv,
+                                                 skb, htc_hdr->endpoint_id,
+                                                 txok);
+               }
+       }
+
+       return;
+ret:
+       /* HTC-generated packets are freed here. */
+       if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0)
+               dev_kfree_skb_any(skb);
+       else
+               kfree_skb(skb);
+}
+
+/*
+ * HTC Messages are handled directly here and the obtained SKB
+ * is freed.
+ *
+ * Sevice messages (Data, WMI) passed to the corresponding
+ * endpoint RX handlers, which have to free the SKB.
+ */
+void ath9k_htc_rx_msg(struct htc_target *htc_handle,
+                     struct sk_buff *skb, u32 len, u8 pipe_id)
+{
+       struct htc_frame_hdr *htc_hdr;
+       enum htc_endpoint_id epid;
+       struct htc_endpoint *endpoint;
+       __be16 *msg_id;
+
+       if (!htc_handle || !skb)
+               return;
+
+       htc_hdr = (struct htc_frame_hdr *) skb->data;
+       epid = htc_hdr->endpoint_id;
+
+       if (epid >= ENDPOINT_MAX) {
+               if (pipe_id != USB_REG_IN_PIPE)
+                       dev_kfree_skb_any(skb);
+               else
+                       kfree_skb(skb);
+               return;
+       }
+
+       if (epid == ENDPOINT0) {
+
+               /* Handle trailer */
+               if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) {
+                       if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000)
+                               /* Move past the Watchdog pattern */
+                               htc_hdr = (struct htc_frame_hdr *)(skb->data + 4);
+               }
+
+               /* Get the message ID */
+               msg_id = (__be16 *) ((void *) htc_hdr +
+                                    sizeof(struct htc_frame_hdr));
+
+               /* Now process HTC messages */
+               switch (be16_to_cpu(*msg_id)) {
+               case HTC_MSG_READY_ID:
+                       htc_process_target_rdy(htc_handle, htc_hdr);
+                       break;
+               case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID:
+                       htc_process_conn_rsp(htc_handle, htc_hdr);
+                       break;
+               default:
+                       break;
+               }
+
+               kfree_skb(skb);
+
+       } else {
+               if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER)
+                       skb_trim(skb, len - htc_hdr->control[0]);
+
+               skb_pull(skb, sizeof(struct htc_frame_hdr));
+
+               endpoint = &htc_handle->endpoint[epid];
+               if (endpoint->ep_callbacks.rx)
+                       endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv,
+                                                 skb, epid);
+       }
+}
+
+struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
+                                     struct ath9k_htc_hif *hif,
+                                     struct device *dev)
+{
+       struct htc_endpoint *endpoint;
+       struct htc_target *target;
+
+       target = kzalloc(sizeof(struct htc_target), GFP_KERNEL);
+       if (!target) {
+               printk(KERN_ERR "Unable to allocate memory for"
+                       "target device\n");
+               return NULL;
+       }
+
+       init_completion(&target->target_wait);
+       init_completion(&target->cmd_wait);
+
+       target->hif = hif;
+       target->hif_dev = hif_handle;
+       target->dev = dev;
+
+       /* Assign control endpoint pipe IDs */
+       endpoint = &target->endpoint[ENDPOINT0];
+       endpoint->ul_pipeid = hif->control_ul_pipe;
+       endpoint->dl_pipeid = hif->control_dl_pipe;
+
+       atomic_set(&target->tgt_ready, 0);
+
+       return target;
+}
+
+void ath9k_htc_hw_free(struct htc_target *htc)
+{
+       kfree(htc);
+}
+
+int ath9k_htc_hw_init(struct htc_target *target,
+                     struct device *dev, u16 devid)
+{
+       if (ath9k_htc_probe_device(target, dev, devid)) {
+               printk(KERN_ERR "Failed to initialize the device\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug)
+{
+       if (target)
+               ath9k_htc_disconnect_device(target, hot_unplug);
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
new file mode 100644 (file)
index 0000000..faba679
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef HTC_HST_H
+#define HTC_HST_H
+
+struct ath9k_htc_priv;
+struct htc_target;
+struct ath9k_htc_tx_ctl;
+
+enum ath9k_hif_transports {
+       ATH9K_HIF_USB,
+};
+
+struct ath9k_htc_hif {
+       struct list_head list;
+       const enum ath9k_hif_transports transport;
+       const char *name;
+
+       u8 control_dl_pipe;
+       u8 control_ul_pipe;
+
+       void (*start) (void *hif_handle, u8 pipe);
+       void (*stop) (void *hif_handle, u8 pipe);
+       int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf,
+                    struct ath9k_htc_tx_ctl *tx_ctl);
+};
+
+enum htc_endpoint_id {
+       ENDPOINT_UNUSED = -1,
+       ENDPOINT0 = 0,
+       ENDPOINT1 = 1,
+       ENDPOINT2 = 2,
+       ENDPOINT3 = 3,
+       ENDPOINT4 = 4,
+       ENDPOINT5 = 5,
+       ENDPOINT6 = 6,
+       ENDPOINT7 = 7,
+       ENDPOINT8 = 8,
+       ENDPOINT_MAX = 22
+};
+
+/* Htc frame hdr flags */
+#define HTC_FLAGS_RECV_TRAILER (1 << 1)
+
+struct htc_frame_hdr {
+       u8 endpoint_id;
+       u8 flags;
+       __be16 payload_len;
+       u8 control[4];
+} __packed;
+
+struct htc_ready_msg {
+       __be16 message_id;
+       __be16 credits;
+       __be16 credit_size;
+       u8 max_endpoints;
+       u8 pad;
+} __packed;
+
+struct htc_config_pipe_msg {
+       __be16 message_id;
+       u8 pipe_id;
+       u8 credits;
+} __packed;
+
+struct htc_packet {
+       void *pktcontext;
+       u8 *buf;
+       u8 *buf_payload;
+       u32 buflen;
+       u32 payload_len;
+
+       int endpoint;
+       int status;
+
+       void *context;
+       u32 reserved;
+};
+
+struct htc_ep_callbacks {
+       void *priv;
+       void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok);
+       void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id);
+};
+
+#define HTC_TX_QUEUE_SIZE 256
+
+struct htc_txq {
+       struct sk_buff *buf[HTC_TX_QUEUE_SIZE];
+       u32 txqdepth;
+       u16 txbuf_cnt;
+       u16 txq_head;
+       u16 txq_tail;
+};
+
+struct htc_endpoint {
+       u16 service_id;
+
+       struct htc_ep_callbacks ep_callbacks;
+       struct htc_txq htc_txq;
+       u32 max_txqdepth;
+       int max_msglen;
+
+       u8 ul_pipeid;
+       u8 dl_pipeid;
+};
+
+#define HTC_MAX_CONTROL_MESSAGE_LENGTH 255
+#define HTC_CONTROL_BUFFER_SIZE        \
+       (HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr))
+
+struct htc_control_buf {
+       struct htc_packet htc_pkt;
+       u8 buf[HTC_CONTROL_BUFFER_SIZE];
+};
+
+#define HTC_OP_START_WAIT           BIT(0)
+#define HTC_OP_CONFIG_PIPE_CREDITS  BIT(1)
+
+struct htc_target {
+       void *hif_dev;
+       struct ath9k_htc_priv *drv_priv;
+       struct device *dev;
+       struct ath9k_htc_hif *hif;
+       struct htc_endpoint endpoint[ENDPOINT_MAX];
+       struct completion target_wait;
+       struct completion cmd_wait;
+       struct list_head list;
+       enum htc_endpoint_id conn_rsp_epid;
+       u16 credits;
+       u16 credit_size;
+       u8 htc_flags;
+       atomic_t tgt_ready;
+};
+
+enum htc_msg_id {
+       HTC_MSG_READY_ID = 1,
+       HTC_MSG_CONNECT_SERVICE_ID,
+       HTC_MSG_CONNECT_SERVICE_RESPONSE_ID,
+       HTC_MSG_SETUP_COMPLETE_ID,
+       HTC_MSG_CONFIG_PIPE_ID,
+       HTC_MSG_CONFIG_PIPE_RESPONSE_ID,
+};
+
+struct htc_service_connreq {
+       u16 service_id;
+       u16 con_flags;
+       u32 max_send_qdepth;
+       struct htc_ep_callbacks ep_callbacks;
+};
+
+/* Current service IDs */
+
+enum htc_service_group_ids{
+       RSVD_SERVICE_GROUP = 0,
+       WMI_SERVICE_GROUP = 1,
+
+       HTC_SERVICE_GROUP_LAST = 255
+};
+
+#define MAKE_SERVICE_ID(group, index)          \
+       (int)(((int)group << 8) | (int)(index))
+
+/* NOTE: service ID of 0x0000 is reserved and should never be used */
+#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1)
+#define HTC_LOOPBACK_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 2)
+
+#define WMI_CONTROL_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0)
+#define WMI_BEACON_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1)
+#define WMI_CAB_SVC      MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2)
+#define WMI_UAPSD_SVC    MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3)
+#define WMI_MGMT_SVC     MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4)
+#define WMI_DATA_VO_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 5)
+#define WMI_DATA_VI_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 6)
+#define WMI_DATA_BE_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 7)
+#define WMI_DATA_BK_SVC   MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 8)
+
+struct htc_conn_svc_msg {
+       __be16 msg_id;
+       __be16 service_id;
+       __be16 con_flags;
+       u8 dl_pipeid;
+       u8 ul_pipeid;
+       u8 svc_meta_len;
+       u8 pad;
+} __packed;
+
+/* connect response status codes */
+#define HTC_SERVICE_SUCCESS      0
+#define HTC_SERVICE_NOT_FOUND    1
+#define HTC_SERVICE_FAILED       2
+#define HTC_SERVICE_NO_RESOURCES 3
+#define HTC_SERVICE_NO_MORE_EP   4
+
+struct htc_conn_svc_rspmsg {
+       __be16 msg_id;
+       __be16 service_id;
+       u8 status;
+       u8 endpoint_id;
+       __be16 max_msg_len;
+       u8 svc_meta_len;
+       u8 pad;
+} __packed;
+
+struct htc_comp_msg {
+       __be16 msg_id;
+} __packed;
+
+int htc_init(struct htc_target *target);
+int htc_connect_service(struct htc_target *target,
+                         struct htc_service_connreq *service_connreq,
+                         enum htc_endpoint_id *conn_rsp_eid);
+int htc_send(struct htc_target *target, struct sk_buff *skb,
+            enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl);
+void htc_stop(struct htc_target *target);
+void htc_start(struct htc_target *target);
+
+void ath9k_htc_rx_msg(struct htc_target *htc_handle,
+                     struct sk_buff *skb, u32 len, u8 pipe_id);
+void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
+                              struct sk_buff *skb, bool txok);
+
+struct htc_target *ath9k_htc_hw_alloc(void *hif_handle,
+                                     struct ath9k_htc_hif *hif,
+                                     struct device *dev);
+void ath9k_htc_hw_free(struct htc_target *htc);
+int ath9k_htc_hw_init(struct htc_target *target,
+                     struct device *dev, u16 devid);
+void ath9k_htc_hw_deinit(struct htc_target *target, bool hot_unplug);
+
+#endif /* HTC_HST_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
new file mode 100644 (file)
index 0000000..624422a
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef ATH9K_HW_OPS_H
+#define ATH9K_HW_OPS_H
+
+#include "hw.h"
+
+/* Hardware core and driver accessible callbacks */
+
+static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah,
+                                              int restore,
+                                              int power_off)
+{
+       ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off);
+}
+
+static inline void ath9k_hw_rxena(struct ath_hw *ah)
+{
+       ath9k_hw_ops(ah)->rx_enable(ah);
+}
+
+static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds,
+                                         u32 link)
+{
+       ath9k_hw_ops(ah)->set_desc_link(ds, link);
+}
+
+static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds,
+                                         u32 **link)
+{
+       ath9k_hw_ops(ah)->get_desc_link(ds, link);
+}
+static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
+                                     struct ath9k_channel *chan,
+                                     u8 rxchainmask,
+                                     bool longcal)
+{
+       return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
+}
+
+static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
+{
+       return ath9k_hw_ops(ah)->get_isr(ah, masked);
+}
+
+static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen,
+                                 bool is_firstseg, bool is_lastseg,
+                                 const void *ds0, dma_addr_t buf_addr,
+                                 unsigned int qcu)
+{
+       ath9k_hw_ops(ah)->fill_txdesc(ah, ds, seglen, is_firstseg, is_lastseg,
+                                     ds0, buf_addr, qcu);
+}
+
+static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds,
+                                     struct ath_tx_status *ts)
+{
+       return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts);
+}
+
+static inline void ath9k_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
+                                         u32 pktLen, enum ath9k_pkt_type type,
+                                         u32 txPower, u32 keyIx,
+                                         enum ath9k_key_type keyType,
+                                         u32 flags)
+{
+       ath9k_hw_ops(ah)->set11n_txdesc(ah, ds, pktLen, type, txPower, keyIx,
+                                     keyType, flags);
+}
+
+static inline void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
+                                       void *lastds,
+                                       u32 durUpdateEn, u32 rtsctsRate,
+                                       u32 rtsctsDuration,
+                                       struct ath9k_11n_rate_series series[],
+                                       u32 nseries, u32 flags)
+{
+       ath9k_hw_ops(ah)->set11n_ratescenario(ah, ds, lastds, durUpdateEn,
+                                           rtsctsRate, rtsctsDuration, series,
+                                           nseries, flags);
+}
+
+static inline void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, void *ds,
+                                       u32 aggrLen)
+{
+       ath9k_hw_ops(ah)->set11n_aggr_first(ah, ds, aggrLen);
+}
+
+static inline void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds,
+                                              u32 numDelims)
+{
+       ath9k_hw_ops(ah)->set11n_aggr_middle(ah, ds, numDelims);
+}
+
+static inline void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, void *ds)
+{
+       ath9k_hw_ops(ah)->set11n_aggr_last(ah, ds);
+}
+
+static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
+{
+       ath9k_hw_ops(ah)->clr11n_aggr(ah, ds);
+}
+
+static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
+                                                u32 burstDuration)
+{
+       ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
+}
+
+static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
+                                                  u32 vmf)
+{
+       ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
+}
+
+/* Private hardware call ops */
+
+/* PHY ops */
+
+static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah,
+                                      struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->rf_set_freq(ah, chan);
+}
+
+static inline void ath9k_hw_spur_mitigate_freq(struct ath_hw *ah,
+                                              struct ath9k_channel *chan)
+{
+       ath9k_hw_private_ops(ah)->spur_mitigate_freq(ah, chan);
+}
+
+static inline int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->rf_alloc_ext_banks)
+               return 0;
+
+       return ath9k_hw_private_ops(ah)->rf_alloc_ext_banks(ah);
+}
+
+static inline void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->rf_free_ext_banks)
+               return;
+
+       ath9k_hw_private_ops(ah)->rf_free_ext_banks(ah);
+}
+
+static inline bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
+                                       struct ath9k_channel *chan,
+                                       u16 modesIndex)
+{
+       if (!ath9k_hw_private_ops(ah)->set_rf_regs)
+               return true;
+
+       return ath9k_hw_private_ops(ah)->set_rf_regs(ah, chan, modesIndex);
+}
+
+static inline void ath9k_hw_init_bb(struct ath_hw *ah,
+                                   struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->init_bb(ah, chan);
+}
+
+static inline void ath9k_hw_set_channel_regs(struct ath_hw *ah,
+                                            struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->set_channel_regs(ah, chan);
+}
+
+static inline int ath9k_hw_process_ini(struct ath_hw *ah,
+                                       struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->process_ini(ah, chan);
+}
+
+static inline void ath9k_olc_init(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->olc_init)
+               return;
+
+       return ath9k_hw_private_ops(ah)->olc_init(ah);
+}
+
+static inline void ath9k_hw_set_rfmode(struct ath_hw *ah,
+                                      struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->set_rfmode(ah, chan);
+}
+
+static inline void ath9k_hw_mark_phy_inactive(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->mark_phy_inactive(ah);
+}
+
+static inline void ath9k_hw_set_delta_slope(struct ath_hw *ah,
+                                           struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->set_delta_slope(ah, chan);
+}
+
+static inline bool ath9k_hw_rfbus_req(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->rfbus_req(ah);
+}
+
+static inline void ath9k_hw_rfbus_done(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->rfbus_done(ah);
+}
+
+static inline void ath9k_enable_rfkill(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->enable_rfkill(ah);
+}
+
+static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->restore_chainmask)
+               return;
+
+       return ath9k_hw_private_ops(ah)->restore_chainmask(ah);
+}
+
+static inline void ath9k_hw_set_diversity(struct ath_hw *ah, bool value)
+{
+       return ath9k_hw_private_ops(ah)->set_diversity(ah, value);
+}
+
+static inline bool ath9k_hw_ani_control(struct ath_hw *ah,
+                                       enum ath9k_ani_cmd cmd, int param)
+{
+       return ath9k_hw_private_ops(ah)->ani_control(ah, cmd, param);
+}
+
+static inline void ath9k_hw_do_getnf(struct ath_hw *ah,
+                                    int16_t nfarray[NUM_NF_READINGS])
+{
+       ath9k_hw_private_ops(ah)->do_getnf(ah, nfarray);
+}
+
+static inline void ath9k_hw_loadnf(struct ath_hw *ah,
+                                  struct ath9k_channel *chan)
+{
+       ath9k_hw_private_ops(ah)->loadnf(ah, chan);
+}
+
+static inline bool ath9k_hw_init_cal(struct ath_hw *ah,
+                                    struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->init_cal(ah, chan);
+}
+
+static inline void ath9k_hw_setup_calibration(struct ath_hw *ah,
+                                             struct ath9k_cal_list *currCal)
+{
+       ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal);
+}
+
+static inline bool ath9k_hw_iscal_supported(struct ath_hw *ah,
+                                           enum ath9k_cal_types calType)
+{
+       return ath9k_hw_private_ops(ah)->iscal_supported(ah, calType);
+}
+
+#endif /* ATH9K_HW_OPS_H */
index 78b571129c92a57e8cf921f7f02040aa0f47b959..c33f17dbe6f17e978191e76ac43bffbbc0978ffe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2010 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
 #include <asm/unaligned.h>
 
 #include "hw.h"
+#include "hw-ops.h"
 #include "rc.h"
-#include "initvals.h"
+#include "ar9003_mac.h"
 
 #define ATH9K_CLOCK_RATE_CCK           22
 #define ATH9K_CLOCK_RATE_5GHZ_OFDM     40
 #define ATH9K_CLOCK_RATE_2GHZ_OFDM     44
+#define ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM 44
 
 static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type);
-static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan);
-static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
-                             struct ar5416_eeprom_def *pEepData,
-                             u32 reg, u32 value);
 
 MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
@@ -49,6 +47,39 @@ static void __exit ath9k_exit(void)
 }
 module_exit(ath9k_exit);
 
+/* Private hardware callbacks */
+
+static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->init_cal_settings(ah);
+}
+
+static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->init_mode_regs(ah);
+}
+
+static bool ath9k_hw_macversion_supported(struct ath_hw *ah)
+{
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+
+       return priv_ops->macversion_supported(ah->hw_version.macVersion);
+}
+
+static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
+                                       struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan);
+}
+
+static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs)
+               return;
+
+       ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
+}
+
 /********************/
 /* Helper Functions */
 /********************/
@@ -61,7 +92,11 @@ static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs)
                return usecs *ATH9K_CLOCK_RATE_CCK;
        if (conf->channel->band == IEEE80211_BAND_2GHZ)
                return usecs *ATH9K_CLOCK_RATE_2GHZ_OFDM;
-       return usecs *ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
+               return usecs * ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+       else
+               return usecs * ATH9K_CLOCK_RATE_5GHZ_OFDM;
 }
 
 static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
@@ -236,21 +271,6 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
        }
 }
 
-static int ath9k_hw_get_radiorev(struct ath_hw *ah)
-{
-       u32 val;
-       int i;
-
-       REG_WRITE(ah, AR_PHY(0x36), 0x00007058);
-
-       for (i = 0; i < 8; i++)
-               REG_WRITE(ah, AR_PHY(0x20), 0x00010000);
-       val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff;
-       val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4);
-
-       return ath9k_hw_reverse_bits(val, 8);
-}
-
 /************************************/
 /* HW Attach, Detach, Init Routines */
 /************************************/
@@ -260,6 +280,8 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
        if (AR_SREV_9100(ah))
                return;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
        REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
        REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029);
@@ -271,20 +293,30 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah)
        REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007);
 
        REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
+/* This should work for all families including legacy */
 static bool ath9k_hw_chip_test(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) };
+       u32 regAddr[2] = { AR_STA_ID0 };
        u32 regHold[2];
        u32 patternData[4] = { 0x55555555,
                               0xaaaaaaaa,
                               0x66666666,
                               0x99999999 };
-       int i, j;
+       int i, j, loop_max;
+
+       if (!AR_SREV_9300_20_OR_LATER(ah)) {
+               loop_max = 2;
+               regAddr[1] = AR_PHY_BASE + (8 << 2);
+       } else
+               loop_max = 1;
 
-       for (i = 0; i < 2; i++) {
+       for (i = 0; i < loop_max; i++) {
                u32 addr = regAddr[i];
                u32 wrData, rdData;
 
@@ -339,7 +371,13 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        ah->config.ofdm_trig_high = 500;
        ah->config.cck_trig_high = 200;
        ah->config.cck_trig_low = 100;
-       ah->config.enable_ani = 1;
+
+       /*
+        * For now ANI is disabled for AR9003, it is still
+        * being tested.
+        */
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               ah->config.enable_ani = 1;
 
        for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
                ah->config.spurchans[i][0] = AR_NO_SPUR;
@@ -353,6 +391,12 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
 
        ah->config.rx_intr_mitigation = true;
 
+       /*
+        * Tx IQ Calibration (ah->config.tx_iq_calibration) is only
+        * used by AR9003, but it is showing reliability issues.
+        * It will take a while to fix so this is currently disabled.
+        */
+
        /*
         * We need this for PCI devices only (Cardbus, PCI, miniPCI)
         * _and_ if on non-uniprocessor systems (Multiprocessor/HT).
@@ -372,7 +416,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
        if (num_possible_cpus() > 1)
                ah->config.serialize_regmode = SER_REG_MODE_AUTO;
 }
-EXPORT_SYMBOL(ath9k_hw_init);
 
 static void ath9k_hw_init_defaults(struct ath_hw *ah)
 {
@@ -386,8 +429,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->hw_version.subvendorid = 0;
 
        ah->ah_flags = 0;
-       if (ah->hw_version.devid == AR5416_AR9100_DEVID)
-               ah->hw_version.macVersion = AR_SREV_VERSION_9100;
        if (!AR_SREV_9100(ah))
                ah->ah_flags = AH_USE_EEPROM;
 
@@ -400,44 +441,17 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->power_mode = ATH9K_PM_UNDEFINED;
 }
 
-static int ath9k_hw_rf_claim(struct ath_hw *ah)
-{
-       u32 val;
-
-       REG_WRITE(ah, AR_PHY(0), 0x00000007);
-
-       val = ath9k_hw_get_radiorev(ah);
-       switch (val & AR_RADIO_SREV_MAJOR) {
-       case 0:
-               val = AR_RAD5133_SREV_MAJOR;
-               break;
-       case AR_RAD5133_SREV_MAJOR:
-       case AR_RAD5122_SREV_MAJOR:
-       case AR_RAD2133_SREV_MAJOR:
-       case AR_RAD2122_SREV_MAJOR:
-               break;
-       default:
-               ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
-                         "Radio Chip Rev 0x%02X not supported\n",
-                         val & AR_RADIO_SREV_MAJOR);
-               return -EOPNOTSUPP;
-       }
-
-       ah->hw_version.analog5GhzRev = val;
-
-       return 0;
-}
-
 static int ath9k_hw_init_macaddr(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        u32 sum;
        int i;
        u16 eeval;
+       u32 EEP_MAC[] = { EEP_MAC_LSW, EEP_MAC_MID, EEP_MAC_MSW };
 
        sum = 0;
        for (i = 0; i < 3; i++) {
-               eeval = ah->eep_ops->get_eeprom(ah, AR_EEPROM_MAC(i));
+               eeval = ah->eep_ops->get_eeprom(ah, EEP_MAC[i]);
                sum += eeval;
                common->macaddr[2 * i] = eeval >> 8;
                common->macaddr[2 * i + 1] = eeval & 0xff;
@@ -448,64 +462,20 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah)
        return 0;
 }
 
-static void ath9k_hw_init_rxgain_ini(struct ath_hw *ah)
-{
-       u32 rxgain_type;
-
-       if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) {
-               rxgain_type = ah->eep_ops->get_eeprom(ah, EEP_RXGAIN_TYPE);
-
-               if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
-                       INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9280Modes_backoff_13db_rxgain_9280_2,
-                       ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6);
-               else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
-                       INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9280Modes_backoff_23db_rxgain_9280_2,
-                       ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6);
-               else
-                       INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9280Modes_original_rxgain_9280_2,
-                       ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
-       } else {
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-                       ar9280Modes_original_rxgain_9280_2,
-                       ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6);
-       }
-}
-
-static void ath9k_hw_init_txgain_ini(struct ath_hw *ah)
-{
-       u32 txgain_type;
-
-       if (ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) {
-               txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
-
-               if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER)
-                       INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9280Modes_high_power_tx_gain_9280_2,
-                       ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6);
-               else
-                       INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9280Modes_original_tx_gain_9280_2,
-                       ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
-       } else {
-               INIT_INI_ARRAY(&ah->iniModesTxGain,
-               ar9280Modes_original_tx_gain_9280_2,
-               ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6);
-       }
-}
-
 static int ath9k_hw_post_init(struct ath_hw *ah)
 {
        int ecode;
 
-       if (!ath9k_hw_chip_test(ah))
-               return -ENODEV;
+       if (!AR_SREV_9271(ah)) {
+               if (!ath9k_hw_chip_test(ah))
+                       return -ENODEV;
+       }
 
-       ecode = ath9k_hw_rf_claim(ah);
-       if (ecode != 0)
-               return ecode;
+       if (!AR_SREV_9300_20_OR_LATER(ah)) {
+               ecode = ar9002_hw_rf_claim(ah);
+               if (ecode != 0)
+                       return ecode;
+       }
 
        ecode = ath9k_hw_eeprom_init(ah);
        if (ecode != 0)
@@ -516,14 +486,12 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
                  ah->eep_ops->get_eeprom_ver(ah),
                  ah->eep_ops->get_eeprom_rev(ah));
 
-        if (!AR_SREV_9280_10_OR_LATER(ah)) {
-               ecode = ath9k_hw_rf_alloc_ext_banks(ah);
-               if (ecode) {
-                       ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
-                                 "Failed allocating banks for "
-                                 "external radio\n");
-                       return ecode;
-               }
+       ecode = ath9k_hw_rf_alloc_ext_banks(ah);
+       if (ecode) {
+               ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+                         "Failed allocating banks for "
+                         "external radio\n");
+               return ecode;
        }
 
        if (!AR_SREV_9100(ah)) {
@@ -534,321 +502,22 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
        return 0;
 }
 
-static bool ath9k_hw_devid_supported(u16 devid)
+static void ath9k_hw_attach_ops(struct ath_hw *ah)
 {
-       switch (devid) {
-       case AR5416_DEVID_PCI:
-       case AR5416_DEVID_PCIE:
-       case AR5416_AR9100_DEVID:
-       case AR9160_DEVID_PCI:
-       case AR9280_DEVID_PCI:
-       case AR9280_DEVID_PCIE:
-       case AR9285_DEVID_PCIE:
-       case AR5416_DEVID_AR9287_PCI:
-       case AR5416_DEVID_AR9287_PCIE:
-       case AR9271_USB:
-       case AR2427_DEVID_PCIE:
-               return true;
-       default:
-               break;
-       }
-       return false;
-}
-
-static bool ath9k_hw_macversion_supported(u32 macversion)
-{
-       switch (macversion) {
-       case AR_SREV_VERSION_5416_PCI:
-       case AR_SREV_VERSION_5416_PCIE:
-       case AR_SREV_VERSION_9160:
-       case AR_SREV_VERSION_9100:
-       case AR_SREV_VERSION_9280:
-       case AR_SREV_VERSION_9285:
-       case AR_SREV_VERSION_9287:
-       case AR_SREV_VERSION_9271:
-               return true;
-       default:
-               break;
-       }
-       return false;
-}
-
-static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
-{
-       if (AR_SREV_9160_10_OR_LATER(ah)) {
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       ah->iq_caldata.calData = &iq_cal_single_sample;
-                       ah->adcgain_caldata.calData =
-                               &adc_gain_cal_single_sample;
-                       ah->adcdc_caldata.calData =
-                               &adc_dc_cal_single_sample;
-                       ah->adcdc_calinitdata.calData =
-                               &adc_init_dc_cal;
-               } else {
-                       ah->iq_caldata.calData = &iq_cal_multi_sample;
-                       ah->adcgain_caldata.calData =
-                               &adc_gain_cal_multi_sample;
-                       ah->adcdc_caldata.calData =
-                               &adc_dc_cal_multi_sample;
-                       ah->adcdc_calinitdata.calData =
-                               &adc_init_dc_cal;
-               }
-               ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
-       }
-}
-
-static void ath9k_hw_init_mode_regs(struct ath_hw *ah)
-{
-       if (AR_SREV_9271(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271,
-                              ARRAY_SIZE(ar9271Modes_9271), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271,
-                              ARRAY_SIZE(ar9271Common_9271), 2);
-               INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only,
-                              ar9271Modes_9271_1_0_only,
-                              ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6);
-               return;
-       }
-
-       if (AR_SREV_9287_11_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1,
-                               ARRAY_SIZE(ar9287Modes_9287_1_1), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1,
-                               ARRAY_SIZE(ar9287Common_9287_1_1), 2);
-               if (ah->config.pcie_clock_req)
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9287PciePhy_clkreq_off_L1_9287_1_1,
-                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_1), 2);
-               else
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9287PciePhy_clkreq_always_on_L1_9287_1_1,
-                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_1),
-                                       2);
-       } else if (AR_SREV_9287_10_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_0,
-                               ARRAY_SIZE(ar9287Modes_9287_1_0), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_0,
-                               ARRAY_SIZE(ar9287Common_9287_1_0), 2);
-
-               if (ah->config.pcie_clock_req)
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9287PciePhy_clkreq_off_L1_9287_1_0,
-                       ARRAY_SIZE(ar9287PciePhy_clkreq_off_L1_9287_1_0), 2);
-               else
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9287PciePhy_clkreq_always_on_L1_9287_1_0,
-                       ARRAY_SIZE(ar9287PciePhy_clkreq_always_on_L1_9287_1_0),
-                                 2);
-       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
-
-
-               INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
-                              ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
-                              ARRAY_SIZE(ar9285Common_9285_1_2), 2);
-
-               if (ah->config.pcie_clock_req) {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9285PciePhy_clkreq_off_L1_9285_1_2,
-                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9285PciePhy_clkreq_always_on_L1_9285_1_2,
-                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
-                                 2);
-               }
-       } else if (AR_SREV_9285_10_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
-                              ARRAY_SIZE(ar9285Modes_9285), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285,
-                              ARRAY_SIZE(ar9285Common_9285), 2);
-
-               if (ah->config.pcie_clock_req) {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9285PciePhy_clkreq_off_L1_9285,
-                       ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                       ar9285PciePhy_clkreq_always_on_L1_9285,
-                       ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2);
-               }
-       } else if (AR_SREV_9280_20_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2,
-                              ARRAY_SIZE(ar9280Modes_9280_2), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2,
-                              ARRAY_SIZE(ar9280Common_9280_2), 2);
-
-               if (ah->config.pcie_clock_req) {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9280PciePhy_clkreq_off_L1_9280,
-                              ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniPcieSerdes,
-                              ar9280PciePhy_clkreq_always_on_L1_9280,
-                              ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
-               }
-               INIT_INI_ARRAY(&ah->iniModesAdditional,
-                              ar9280Modes_fast_clock_9280_2,
-                              ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
-       } else if (AR_SREV_9280_10_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280,
-                              ARRAY_SIZE(ar9280Modes_9280), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280,
-                              ARRAY_SIZE(ar9280Common_9280), 2);
-       } else if (AR_SREV_9160_10_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160,
-                              ARRAY_SIZE(ar5416Modes_9160), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160,
-                              ARRAY_SIZE(ar5416Common_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160,
-                              ARRAY_SIZE(ar5416Bank0_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9160,
-                              ARRAY_SIZE(ar5416BB_RfGain_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9160,
-                              ARRAY_SIZE(ar5416Bank1_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9160,
-                              ARRAY_SIZE(ar5416Bank2_9160), 2);
-               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9160,
-                              ARRAY_SIZE(ar5416Bank3_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9160,
-                              ARRAY_SIZE(ar5416Bank6_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9160,
-                              ARRAY_SIZE(ar5416Bank6TPC_9160), 3);
-               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9160,
-                              ARRAY_SIZE(ar5416Bank7_9160), 2);
-               if (AR_SREV_9160_11(ah)) {
-                       INIT_INI_ARRAY(&ah->iniAddac,
-                                      ar5416Addac_91601_1,
-                                      ARRAY_SIZE(ar5416Addac_91601_1), 2);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160,
-                                      ARRAY_SIZE(ar5416Addac_9160), 2);
-               }
-       } else if (AR_SREV_9100_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100,
-                              ARRAY_SIZE(ar5416Modes_9100), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100,
-                              ARRAY_SIZE(ar5416Common_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100,
-                              ARRAY_SIZE(ar5416Bank0_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain_9100,
-                              ARRAY_SIZE(ar5416BB_RfGain_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1_9100,
-                              ARRAY_SIZE(ar5416Bank1_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2_9100,
-                              ARRAY_SIZE(ar5416Bank2_9100), 2);
-               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3_9100,
-                              ARRAY_SIZE(ar5416Bank3_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100,
-                              ARRAY_SIZE(ar5416Bank6_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100,
-                              ARRAY_SIZE(ar5416Bank6TPC_9100), 3);
-               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7_9100,
-                              ARRAY_SIZE(ar5416Bank7_9100), 2);
-               INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100,
-                              ARRAY_SIZE(ar5416Addac_9100), 2);
-       } else {
-               INIT_INI_ARRAY(&ah->iniModes, ar5416Modes,
-                              ARRAY_SIZE(ar5416Modes), 6);
-               INIT_INI_ARRAY(&ah->iniCommon, ar5416Common,
-                              ARRAY_SIZE(ar5416Common), 2);
-               INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0,
-                              ARRAY_SIZE(ar5416Bank0), 2);
-               INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain,
-                              ARRAY_SIZE(ar5416BB_RfGain), 3);
-               INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1,
-                              ARRAY_SIZE(ar5416Bank1), 2);
-               INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2,
-                              ARRAY_SIZE(ar5416Bank2), 2);
-               INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3,
-                              ARRAY_SIZE(ar5416Bank3), 3);
-               INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6,
-                              ARRAY_SIZE(ar5416Bank6), 3);
-               INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC,
-                              ARRAY_SIZE(ar5416Bank6TPC), 3);
-               INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7,
-                              ARRAY_SIZE(ar5416Bank7), 2);
-               INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac,
-                              ARRAY_SIZE(ar5416Addac), 2);
-       }
-}
-
-static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
-{
-       if (AR_SREV_9287_11_OR_LATER(ah))
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-               ar9287Modes_rx_gain_9287_1_1,
-               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6);
-       else if (AR_SREV_9287_10(ah))
-               INIT_INI_ARRAY(&ah->iniModesRxGain,
-               ar9287Modes_rx_gain_9287_1_0,
-               ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_0), 6);
-       else if (AR_SREV_9280_20(ah))
-               ath9k_hw_init_rxgain_ini(ah);
-
-       if (AR_SREV_9287_11_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniModesTxGain,
-               ar9287Modes_tx_gain_9287_1_1,
-               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6);
-       } else if (AR_SREV_9287_10(ah)) {
-               INIT_INI_ARRAY(&ah->iniModesTxGain,
-               ar9287Modes_tx_gain_9287_1_0,
-               ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_0), 6);
-       } else if (AR_SREV_9280_20(ah)) {
-               ath9k_hw_init_txgain_ini(ah);
-       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
-               u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
-
-               /* txgain table */
-               if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
-                       INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9285Modes_high_power_tx_gain_9285_1_2,
-                       ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6);
-               } else {
-                       INIT_INI_ARRAY(&ah->iniModesTxGain,
-                       ar9285Modes_original_tx_gain_9285_1_2,
-                       ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6);
-               }
-
-       }
-}
-
-static void ath9k_hw_init_eeprom_fix(struct ath_hw *ah)
-{
-       u32 i, j;
-
-       if (ah->hw_version.devid == AR9280_DEVID_PCI) {
-
-               /* EEPROM Fixup */
-               for (i = 0; i < ah->iniModes.ia_rows; i++) {
-                       u32 reg = INI_RA(&ah->iniModes, i, 0);
-
-                       for (j = 1; j < ah->iniModes.ia_columns; j++) {
-                               u32 val = INI_RA(&ah->iniModes, i, j);
-
-                               INI_RA(&ah->iniModes, i, j) =
-                                       ath9k_hw_ini_fixup(ah,
-                                                          &ah->eeprom.def,
-                                                          reg, val);
-                       }
-               }
-       }
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               ar9003_hw_attach_ops(ah);
+       else
+               ar9002_hw_attach_ops(ah);
 }
 
-int ath9k_hw_init(struct ath_hw *ah)
+/* Called for all hardware families */
+static int __ath9k_hw_init(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
        int r = 0;
 
-       if (!ath9k_hw_devid_supported(ah->hw_version.devid)) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unsupported device ID: 0x%0x\n",
-                         ah->hw_version.devid);
-               return -EOPNOTSUPP;
-       }
-
-       ath9k_hw_init_defaults(ah);
-       ath9k_hw_init_config(ah);
+       if (ah->hw_version.devid == AR5416_AR9100_DEVID)
+               ah->hw_version.macVersion = AR_SREV_VERSION_9100;
 
        if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) {
                ath_print(common, ATH_DBG_FATAL,
@@ -856,6 +525,11 @@ int ath9k_hw_init(struct ath_hw *ah)
                return -EIO;
        }
 
+       ath9k_hw_init_defaults(ah);
+       ath9k_hw_init_config(ah);
+
+       ath9k_hw_attach_ops(ah);
+
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
                ath_print(common, ATH_DBG_FATAL, "Couldn't wakeup chip\n");
                return -EIO;
@@ -880,7 +554,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        else
                ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
 
-       if (!ath9k_hw_macversion_supported(ah->hw_version.macVersion)) {
+       if (!ath9k_hw_macversion_supported(ah)) {
                ath_print(common, ATH_DBG_FATAL,
                          "Mac Chip Rev 0x%02x.%x is not supported by "
                          "this driver\n", ah->hw_version.macVersion,
@@ -888,45 +562,45 @@ int ath9k_hw_init(struct ath_hw *ah)
                return -EOPNOTSUPP;
        }
 
-       if (AR_SREV_9100(ah)) {
-               ah->iq_caldata.calData = &iq_cal_multi_sample;
-               ah->supp_cals = IQ_MISMATCH_CAL;
-               ah->is_pciexpress = false;
-       }
-
-       if (AR_SREV_9271(ah))
+       if (AR_SREV_9271(ah) || AR_SREV_9100(ah))
                ah->is_pciexpress = false;
 
        ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
-
        ath9k_hw_init_cal_settings(ah);
 
        ah->ani_function = ATH9K_ANI_ALL;
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
+       if (AR_SREV_9280_10_OR_LATER(ah) && !AR_SREV_9300_20_OR_LATER(ah))
                ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
-               ah->ath9k_hw_rf_set_freq = &ath9k_hw_ar9280_set_channel;
-               ah->ath9k_hw_spur_mitigate_freq = &ath9k_hw_9280_spur_mitigate;
-       } else {
-               ah->ath9k_hw_rf_set_freq = &ath9k_hw_set_channel;
-               ah->ath9k_hw_spur_mitigate_freq = &ath9k_hw_spur_mitigate;
-       }
 
        ath9k_hw_init_mode_regs(ah);
 
+       /*
+        * Configire PCIE after Ini init. SERDES values now come from ini file
+        * This enables PCIe low power mode.
+        */
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               u32 regval;
+               unsigned int i;
+
+               /* Set Bits 16 and 17 in the AR_WA register. */
+               regval = REG_READ(ah, AR_WA);
+               regval |= 0x00030000;
+               REG_WRITE(ah, AR_WA, regval);
+
+               for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) {
+                       REG_WRITE(ah,
+                                 INI_RA(&ah->iniPcieSerdesLowPower, i, 0),
+                                 INI_RA(&ah->iniPcieSerdesLowPower, i, 1));
+               }
+       }
+
        if (ah->is_pciexpress)
                ath9k_hw_configpcipowersave(ah, 0, 0);
        else
                ath9k_hw_disablepcie(ah);
 
-       /* Support for Japan ch.14 (2484) spread */
-       if (AR_SREV_9287_11_OR_LATER(ah)) {
-               INIT_INI_ARRAY(&ah->iniCckfirNormal,
-                      ar9287Common_normal_cck_fir_coeff_92871_1,
-                      ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_92871_1), 2);
-               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
-                      ar9287Common_japan_2484_cck_fir_coeff_92871_1,
-                      ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_92871_1), 2);
-       }
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               ar9002_hw_cck_chan14_spread(ah);
 
        r = ath9k_hw_post_init(ah);
        if (r)
@@ -937,8 +611,6 @@ int ath9k_hw_init(struct ath_hw *ah)
        if (r)
                return r;
 
-       ath9k_hw_init_eeprom_fix(ah);
-
        r = ath9k_hw_init_macaddr(ah);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
@@ -951,6 +623,9 @@ int ath9k_hw_init(struct ath_hw *ah)
        else
                ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               ar9003_hw_set_nf_limits(ah);
+
        ath9k_init_nfcal_hist_buffer(ah);
 
        common->state = ATH_HW_INITIALIZED;
@@ -958,24 +633,50 @@ int ath9k_hw_init(struct ath_hw *ah)
        return 0;
 }
 
-static void ath9k_hw_init_bb(struct ath_hw *ah,
-                            struct ath9k_channel *chan)
+int ath9k_hw_init(struct ath_hw *ah)
 {
-       u32 synthDelay;
+       int ret;
+       struct ath_common *common = ath9k_hw_common(ah);
 
-       synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-       if (IS_CHAN_B(chan))
-               synthDelay = (4 * synthDelay) / 22;
-       else
-               synthDelay /= 10;
+       /* These are all the AR5008/AR9001/AR9002 hardware family of chipsets */
+       switch (ah->hw_version.devid) {
+       case AR5416_DEVID_PCI:
+       case AR5416_DEVID_PCIE:
+       case AR5416_AR9100_DEVID:
+       case AR9160_DEVID_PCI:
+       case AR9280_DEVID_PCI:
+       case AR9280_DEVID_PCIE:
+       case AR9285_DEVID_PCIE:
+       case AR9287_DEVID_PCI:
+       case AR9287_DEVID_PCIE:
+       case AR2427_DEVID_PCIE:
+       case AR9300_DEVID_PCIE:
+               break;
+       default:
+               if (common->bus_ops->ath_bus_type == ATH_USB)
+                       break;
+               ath_print(common, ATH_DBG_FATAL,
+                         "Hardware device ID 0x%04x not supported\n",
+                         ah->hw_version.devid);
+               return -EOPNOTSUPP;
+       }
 
-       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+       ret = __ath9k_hw_init(ah);
+       if (ret) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to initialize hardware; "
+                         "initialization status: %d\n", ret);
+               return ret;
+       }
 
-       udelay(synthDelay + BASE_ACTIVATE_DELAY);
+       return 0;
 }
+EXPORT_SYMBOL(ath9k_hw_init);
 
 static void ath9k_hw_init_qos(struct ath_hw *ah)
 {
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa);
        REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210);
 
@@ -989,105 +690,22 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
        REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF);
        REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF);
        REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF);
-}
-
-static void ath9k_hw_change_target_baud(struct ath_hw *ah, u32 freq, u32 baud)
-{
-       u32 lcr;
-       u32 baud_divider = freq * 1000 * 1000 / 16 / baud;
 
-       lcr = REG_READ(ah , 0x5100c);
-       lcr |= 0x80;
-
-       REG_WRITE(ah, 0x5100c, lcr);
-       REG_WRITE(ah, 0x51004, (baud_divider >> 8));
-       REG_WRITE(ah, 0x51000, (baud_divider & 0xff));
-
-       lcr &= ~0x80;
-       REG_WRITE(ah, 0x5100c, lcr);
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 static void ath9k_hw_init_pll(struct ath_hw *ah,
                              struct ath9k_channel *chan)
 {
-       u32 pll;
-
-       if (AR_SREV_9100(ah)) {
-               if (chan && IS_CHAN_5GHZ(chan))
-                       pll = 0x1450;
-               else
-                       pll = 0x1458;
-       } else {
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
-                       if (chan && IS_CHAN_HALF_RATE(chan))
-                               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
-                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
-                               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
-
-                       if (chan && IS_CHAN_5GHZ(chan)) {
-                               pll |= SM(0x28, AR_RTC_9160_PLL_DIV);
-
+       u32 pll = ath9k_hw_compute_pll_control(ah, chan);
 
-                               if (AR_SREV_9280_20(ah)) {
-                                       if (((chan->channel % 20) == 0)
-                                           || ((chan->channel % 10) == 0))
-                                               pll = 0x2850;
-                                       else
-                                               pll = 0x142c;
-                               }
-                       } else {
-                               pll |= SM(0x2c, AR_RTC_9160_PLL_DIV);
-                       }
-
-               } else if (AR_SREV_9160_10_OR_LATER(ah)) {
-
-                       pll = SM(0x5, AR_RTC_9160_PLL_REFDIV);
-
-                       if (chan && IS_CHAN_HALF_RATE(chan))
-                               pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL);
-                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
-                               pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL);
-
-                       if (chan && IS_CHAN_5GHZ(chan))
-                               pll |= SM(0x50, AR_RTC_9160_PLL_DIV);
-                       else
-                               pll |= SM(0x58, AR_RTC_9160_PLL_DIV);
-               } else {
-                       pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2;
-
-                       if (chan && IS_CHAN_HALF_RATE(chan))
-                               pll |= SM(0x1, AR_RTC_PLL_CLKSEL);
-                       else if (chan && IS_CHAN_QUARTER_RATE(chan))
-                               pll |= SM(0x2, AR_RTC_PLL_CLKSEL);
-
-                       if (chan && IS_CHAN_5GHZ(chan))
-                               pll |= SM(0xa, AR_RTC_PLL_DIV);
-                       else
-                               pll |= SM(0xb, AR_RTC_PLL_DIV);
-               }
-       }
        REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
 
        /* Switch the core clock for ar9271 to 117Mhz */
        if (AR_SREV_9271(ah)) {
-               if ((pll == 0x142c) || (pll == 0x2850) ) {
-                       udelay(500);
-                       /* set CLKOBS to output AHB clock */
-                       REG_WRITE(ah, 0x7020, 0xe);
-                       /*
-                        * 0x304: 117Mhz, ahb_ratio: 1x1
-                        * 0x306: 40Mhz, ahb_ratio: 1x1
-                        */
-                       REG_WRITE(ah, 0x50040, 0x304);
-                       /*
-                        * makes adjustments for the baud dividor to keep the
-                        * targetted baud rate based on the used core clock.
-                        */
-                       ath9k_hw_change_target_baud(ah, AR9271_CORE_CLOCK,
-                                                   AR9271_TARGET_BAUD_RATE);
-               }
+               udelay(500);
+               REG_WRITE(ah, 0x50040, 0x304);
        }
 
        udelay(RTC_PLL_SETTLE_DELAY);
@@ -1095,70 +713,58 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
        REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
 }
 
-static void ath9k_hw_init_chain_masks(struct ath_hw *ah)
-{
-       int rx_chainmask, tx_chainmask;
-
-       rx_chainmask = ah->rxchainmask;
-       tx_chainmask = ah->txchainmask;
-
-       switch (rx_chainmask) {
-       case 0x5:
-               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
-                           AR_PHY_SWAP_ALT_CHAIN);
-       case 0x3:
-               if (ah->hw_version.macVersion == AR_SREV_REVISION_5416_10) {
-                       REG_WRITE(ah, AR_PHY_RX_CHAINMASK, 0x7);
-                       REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, 0x7);
-                       break;
-               }
-       case 0x1:
-       case 0x2:
-       case 0x7:
-               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
-               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
-               break;
-       default:
-               break;
-       }
-
-       REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask);
-       if (tx_chainmask == 0x5) {
-               REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
-                           AR_PHY_SWAP_ALT_CHAIN);
-       }
-       if (AR_SREV_9100(ah))
-               REG_WRITE(ah, AR_PHY_ANALOG_SWAP,
-                         REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001);
-}
-
 static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
                                          enum nl80211_iftype opmode)
 {
-       ah->mask_reg = AR_IMR_TXERR |
+       u32 imr_reg = AR_IMR_TXERR |
                AR_IMR_TXURN |
                AR_IMR_RXERR |
                AR_IMR_RXORN |
                AR_IMR_BCNMISC;
 
-       if (ah->config.rx_intr_mitigation)
-               ah->mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
-       else
-               ah->mask_reg |= AR_IMR_RXOK;
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               imr_reg |= AR_IMR_RXOK_HP;
+               if (ah->config.rx_intr_mitigation)
+                       imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+               else
+                       imr_reg |= AR_IMR_RXOK_LP;
 
-       ah->mask_reg |= AR_IMR_TXOK;
+       } else {
+               if (ah->config.rx_intr_mitigation)
+                       imr_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR;
+               else
+                       imr_reg |= AR_IMR_RXOK;
+       }
+
+       if (ah->config.tx_intr_mitigation)
+               imr_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR;
+       else
+               imr_reg |= AR_IMR_TXOK;
 
        if (opmode == NL80211_IFTYPE_AP)
-               ah->mask_reg |= AR_IMR_MIB;
+               imr_reg |= AR_IMR_MIB;
+
+       ENABLE_REGWRITE_BUFFER(ah);
 
-       REG_WRITE(ah, AR_IMR, ah->mask_reg);
-       REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT);
+       REG_WRITE(ah, AR_IMR, imr_reg);
+       ah->imrs2_reg |= AR_IMR_S2_GTT;
+       REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
 
        if (!AR_SREV_9100(ah)) {
                REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
                REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
                REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
        }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               REG_WRITE(ah, AR_INTR_PRIO_ASYNC_ENABLE, 0);
+               REG_WRITE(ah, AR_INTR_PRIO_ASYNC_MASK, 0);
+               REG_WRITE(ah, AR_INTR_PRIO_SYNC_ENABLE, 0);
+               REG_WRITE(ah, AR_INTR_PRIO_SYNC_MASK, 0);
+       }
 }
 
 static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us)
@@ -1241,19 +847,13 @@ void ath9k_hw_deinit(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
 
-       if (common->state <= ATH_HW_INITIALIZED)
+       if (common->state < ATH_HW_INITIALIZED)
                goto free_hw;
 
-       if (!AR_SREV_9100(ah))
-               ath9k_hw_ani_disable(ah);
-
        ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
 
 free_hw:
-       if (!AR_SREV_9280_10_OR_LATER(ah))
-               ath9k_hw_rf_free_ext_banks(ah);
-       kfree(ah);
-       ah = NULL;
+       ath9k_hw_rf_free_ext_banks(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_deinit);
 
@@ -1261,136 +861,7 @@ EXPORT_SYMBOL(ath9k_hw_deinit);
 /* INI */
 /*******/
 
-static void ath9k_hw_override_ini(struct ath_hw *ah,
-                                 struct ath9k_channel *chan)
-{
-       u32 val;
-
-       if (AR_SREV_9271(ah)) {
-               /*
-                * Enable spectral scan to solution for issues with stuck
-                * beacons on AR9271 1.0. The beacon stuck issue is not seeon on
-                * AR9271 1.1
-                */
-               if (AR_SREV_9271_10(ah)) {
-                       val = REG_READ(ah, AR_PHY_SPECTRAL_SCAN) |
-                             AR_PHY_SPECTRAL_SCAN_ENABLE;
-                       REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
-               }
-               else if (AR_SREV_9271_11(ah))
-                       /*
-                        * change AR_PHY_RF_CTL3 setting to fix MAC issue
-                        * present on AR9271 1.1
-                        */
-                       REG_WRITE(ah, AR_PHY_RF_CTL3, 0x3a020001);
-               return;
-       }
-
-       /*
-        * Set the RX_ABORT and RX_DIS and clear if off only after
-        * RXE is set for MAC. This prevents frames with corrupted
-        * descriptor status.
-        */
-       REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
-
-       if (AR_SREV_9280_10_OR_LATER(ah)) {
-               val = REG_READ(ah, AR_PCU_MISC_MODE2) &
-                              (~AR_PCU_MISC_MODE2_HWWAR1);
-
-               if (AR_SREV_9287_10_OR_LATER(ah))
-                       val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
-
-               REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
-       }
-
-       if (!AR_SREV_5416_20_OR_LATER(ah) ||
-           AR_SREV_9280_10_OR_LATER(ah))
-               return;
-       /*
-        * Disable BB clock gating
-        * Necessary to avoid issues on AR5416 2.0
-        */
-       REG_WRITE(ah, 0x9800 + (651 << 2), 0x11);
-
-       /*
-        * Disable RIFS search on some chips to avoid baseband
-        * hang issues.
-        */
-       if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
-               val = REG_READ(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS);
-               val &= ~AR_PHY_RIFS_INIT_DELAY;
-               REG_WRITE(ah, AR_PHY_HEAVY_CLIP_FACTOR_RIFS, val);
-       }
-}
-
-static u32 ath9k_hw_def_ini_fixup(struct ath_hw *ah,
-                             struct ar5416_eeprom_def *pEepData,
-                             u32 reg, u32 value)
-{
-       struct base_eep_header *pBase = &(pEepData->baseEepHeader);
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       switch (ah->hw_version.devid) {
-       case AR9280_DEVID_PCI:
-               if (reg == 0x7894) {
-                       ath_print(common, ATH_DBG_EEPROM,
-                               "ini VAL: %x  EEPROM: %x\n", value,
-                               (pBase->version & 0xff));
-
-                       if ((pBase->version & 0xff) > 0x0a) {
-                               ath_print(common, ATH_DBG_EEPROM,
-                                         "PWDCLKIND: %d\n",
-                                         pBase->pwdclkind);
-                               value &= ~AR_AN_TOP2_PWDCLKIND;
-                               value |= AR_AN_TOP2_PWDCLKIND &
-                                       (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S);
-                       } else {
-                               ath_print(common, ATH_DBG_EEPROM,
-                                         "PWDCLKIND Earlier Rev\n");
-                       }
-
-                       ath_print(common, ATH_DBG_EEPROM,
-                                 "final ini VAL: %x\n", value);
-               }
-               break;
-       }
-
-       return value;
-}
-
-static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
-                             struct ar5416_eeprom_def *pEepData,
-                             u32 reg, u32 value)
-{
-       if (ah->eep_map == EEP_MAP_4KBITS)
-               return value;
-       else
-               return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
-}
-
-static void ath9k_olc_init(struct ath_hw *ah)
-{
-       u32 i;
-
-       if (OLC_FOR_AR9287_10_LATER) {
-               REG_SET_BIT(ah, AR_PHY_TX_PWRCTRL9,
-                               AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL);
-               ath9k_hw_analog_shift_rmw(ah, AR9287_AN_TXPC0,
-                               AR9287_AN_TXPC0_TXPCMODE,
-                               AR9287_AN_TXPC0_TXPCMODE_S,
-                               AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE);
-               udelay(100);
-       } else {
-               for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
-                       ah->originalGain[i] =
-                               MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
-                                               AR_PHY_TX_GAIN);
-               ah->PDADCdelta = 0;
-       }
-}
-
-static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
-                             struct ath9k_channel *chan)
+u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)
 {
        u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band);
 
@@ -1404,173 +875,24 @@ static u32 ath9k_regd_get_ctl(struct ath_regulatory *reg,
        return ctl;
 }
 
-static int ath9k_hw_process_ini(struct ath_hw *ah,
-                               struct ath9k_channel *chan)
-{
-       struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
-       int i, regWrites = 0;
-       struct ieee80211_channel *channel = chan->chan;
-       u32 modesIndex, freqIndex;
-
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-               modesIndex = 1;
-               freqIndex = 1;
-               break;
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               modesIndex = 2;
-               freqIndex = 1;
-               break;
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_B:
-               modesIndex = 4;
-               freqIndex = 2;
-               break;
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               modesIndex = 3;
-               freqIndex = 2;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       REG_WRITE(ah, AR_PHY(0), 0x00000007);
-       REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
-       ah->eep_ops->set_addac(ah, chan);
-
-       if (AR_SREV_5416_22_OR_LATER(ah)) {
-               REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
-       } else {
-               struct ar5416IniArray temp;
-               u32 addacSize =
-                       sizeof(u32) * ah->iniAddac.ia_rows *
-                       ah->iniAddac.ia_columns;
-
-               memcpy(ah->addac5416_21,
-                      ah->iniAddac.ia_array, addacSize);
-
-               (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0;
-
-               temp.ia_array = ah->addac5416_21;
-               temp.ia_columns = ah->iniAddac.ia_columns;
-               temp.ia_rows = ah->iniAddac.ia_rows;
-               REG_WRITE_ARRAY(&temp, 1, regWrites);
-       }
-
-       REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC);
-
-       for (i = 0; i < ah->iniModes.ia_rows; i++) {
-               u32 reg = INI_RA(&ah->iniModes, i, 0);
-               u32 val = INI_RA(&ah->iniModes, i, modesIndex);
-
-               REG_WRITE(ah, reg, val);
-
-               if (reg >= 0x7800 && reg < 0x78a0
-                   && ah->config.analog_shiftreg) {
-                       udelay(100);
-               }
-
-               DO_DELAY(regWrites);
-       }
-
-       if (AR_SREV_9280(ah) || AR_SREV_9287_10_OR_LATER(ah))
-               REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
-
-       if (AR_SREV_9280(ah) || AR_SREV_9285_12_OR_LATER(ah) ||
-           AR_SREV_9287_10_OR_LATER(ah))
-               REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
-
-       for (i = 0; i < ah->iniCommon.ia_rows; i++) {
-               u32 reg = INI_RA(&ah->iniCommon, i, 0);
-               u32 val = INI_RA(&ah->iniCommon, i, 1);
-
-               REG_WRITE(ah, reg, val);
-
-               if (reg >= 0x7800 && reg < 0x78a0
-                   && ah->config.analog_shiftreg) {
-                       udelay(100);
-               }
-
-               DO_DELAY(regWrites);
-       }
-
-       ath9k_hw_write_regs(ah, freqIndex, regWrites);
-
-       if (AR_SREV_9271_10(ah))
-               REG_WRITE_ARRAY(&ah->iniModes_9271_1_0_only,
-                               modesIndex, regWrites);
-
-       if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) {
-               REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex,
-                               regWrites);
-       }
-
-       ath9k_hw_override_ini(ah, chan);
-       ath9k_hw_set_regs(ah, chan);
-       ath9k_hw_init_chain_masks(ah);
-
-       if (OLC_FOR_AR9280_20_LATER)
-               ath9k_olc_init(ah);
-
-       ah->eep_ops->set_txpower(ah, chan,
-                                ath9k_regd_get_ctl(regulatory, chan),
-                                channel->max_antenna_gain * 2,
-                                channel->max_power * 2,
-                                min((u32) MAX_RATE_POWER,
-                                (u32) regulatory->power_limit));
-
-       if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
-               ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
-                         "ar5416SetRfRegs failed\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
 /****************************************/
 /* Reset and Channel Switching Routines */
 /****************************************/
 
-static void ath9k_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       u32 rfMode = 0;
-
-       if (chan == NULL)
-               return;
-
-       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
-               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
-
-       if (!AR_SREV_9280_10_OR_LATER(ah))
-               rfMode |= (IS_CHAN_5GHZ(chan)) ?
-                       AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ;
-
-       if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan))
-               rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
-
-       REG_WRITE(ah, AR_PHY_MODE, rfMode);
-}
-
-static void ath9k_hw_mark_phy_inactive(struct ath_hw *ah)
-{
-       REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
-}
-
 static inline void ath9k_hw_set_dma(struct ath_hw *ah)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
        u32 regval;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        /*
         * set AHB_MODE not to do cacheline prefetches
        */
-       regval = REG_READ(ah, AR_AHB_MODE);
-       REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+       if (!AR_SREV_9300_20_OR_LATER(ah)) {
+               regval = REG_READ(ah, AR_AHB_MODE);
+               REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
+       }
 
        /*
         * let mac dma reads be in 128 byte chunks
@@ -1578,12 +900,18 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
        regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
        REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        /*
         * Restore TX Trigger Level to its pre-reset value.
         * The initial value depends on whether aggregation is enabled, and is
         * adjusted whenever underruns are detected.
         */
-       REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->tx_trig_level);
+
+       ENABLE_REGWRITE_BUFFER(ah);
 
        /*
         * let mac dma writes be in 128 byte chunks
@@ -1596,6 +924,14 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
         */
        REG_WRITE(ah, AR_RXFIFO_CFG, 0x200);
 
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1);
+               REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1);
+
+               ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
+                       ah->caps.rx_status_len);
+       }
+
        /*
         * reduce the number of usable entries in PCU TXBUF to avoid
         * wrap around issues.
@@ -1611,6 +947,12 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
                REG_WRITE(ah, AR_PCU_TXBUF_CTRL,
                          AR_PCU_TXBUF_CTRL_USABLE_SIZE);
        }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               ath9k_hw_reset_txstatus_ring(ah);
 }
 
 static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
@@ -1638,10 +980,8 @@ static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
        }
 }
 
-static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah,
-                                                u32 coef_scaled,
-                                                u32 *coef_mantissa,
-                                                u32 *coef_exponent)
+void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
+                                  u32 *coef_mantissa, u32 *coef_exponent)
 {
        u32 coef_exp, coef_man;
 
@@ -1657,40 +997,6 @@ static inline void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah,
        *coef_exponent = coef_exp - 16;
 }
 
-static void ath9k_hw_set_delta_slope(struct ath_hw *ah,
-                                    struct ath9k_channel *chan)
-{
-       u32 coef_scaled, ds_coef_exp, ds_coef_man;
-       u32 clockMhzScaled = 0x64000000;
-       struct chan_centers centers;
-
-       if (IS_CHAN_HALF_RATE(chan))
-               clockMhzScaled = clockMhzScaled >> 1;
-       else if (IS_CHAN_QUARTER_RATE(chan))
-               clockMhzScaled = clockMhzScaled >> 2;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       coef_scaled = clockMhzScaled / centers.synth_center;
-
-       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
-                                     &ds_coef_exp);
-
-       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
-                     AR_PHY_TIMING3_DSC_MAN, ds_coef_man);
-       REG_RMW_FIELD(ah, AR_PHY_TIMING3,
-                     AR_PHY_TIMING3_DSC_EXP, ds_coef_exp);
-
-       coef_scaled = (9 * coef_scaled) / 10;
-
-       ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man,
-                                     &ds_coef_exp);
-
-       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
-                     AR_PHY_HALFGI_DSC_MAN, ds_coef_man);
-       REG_RMW_FIELD(ah, AR_PHY_HALFGI,
-                     AR_PHY_HALFGI_DSC_EXP, ds_coef_exp);
-}
-
 static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 {
        u32 rst_flags;
@@ -1704,6 +1010,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                (void)REG_READ(ah, AR_RTC_DERIVED_CLK);
        }
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1715,11 +1023,16 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
                if (tmpReg &
                    (AR_INTR_SYNC_LOCAL_TIMEOUT |
                     AR_INTR_SYNC_RADM_CPL_TIMEOUT)) {
+                       u32 val;
                        REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
-                       REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
-               } else {
+
+                       val = AR_RC_HOSTIF;
+                       if (!AR_SREV_9300_20_OR_LATER(ah))
+                               val |= AR_RC_AHB;
+                       REG_WRITE(ah, AR_RC, val);
+
+               } else if (!AR_SREV_9300_20_OR_LATER(ah))
                        REG_WRITE(ah, AR_RC, AR_RC_AHB);
-               }
 
                rst_flags = AR_RTC_RC_MAC_WARM;
                if (type == ATH9K_RESET_COLD)
@@ -1727,6 +1040,10 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        }
 
        REG_WRITE(ah, AR_RTC_RC, rst_flags);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        udelay(50);
 
        REG_WRITE(ah, AR_RTC_RC, 0);
@@ -1747,16 +1064,23 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
 
 static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
 {
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
-       if (!AR_SREV_9100(ah))
+       if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
                REG_WRITE(ah, AR_RC, AR_RC_AHB);
 
        REG_WRITE(ah, AR_RTC_RESET, 0);
-       udelay(2);
 
-       if (!AR_SREV_9100(ah))
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               udelay(2);
+
+       if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
                REG_WRITE(ah, AR_RC, 0);
 
        REG_WRITE(ah, AR_RTC_RESET, 1);
@@ -1792,34 +1116,6 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
        }
 }
 
-static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       u32 phymode;
-       u32 enableDacFifo = 0;
-
-       if (AR_SREV_9285_10_OR_LATER(ah))
-               enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) &
-                                        AR_PHY_FC_ENABLE_DAC_FIFO);
-
-       phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40
-               | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo;
-
-       if (IS_CHAN_HT40(chan)) {
-               phymode |= AR_PHY_FC_DYN2040_EN;
-
-               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-                   (chan->chanmode == CHANNEL_G_HT40PLUS))
-                       phymode |= AR_PHY_FC_DYN2040_PRI_CH;
-
-       }
-       REG_WRITE(ah, AR_PHY_TURBO, phymode);
-
-       ath9k_hw_set11nmac2040(ah);
-
-       REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
-       REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S);
-}
-
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
                                struct ath9k_channel *chan)
 {
@@ -1845,7 +1141,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
        struct ath_common *common = ath9k_hw_common(ah);
        struct ieee80211_channel *channel = chan->chan;
-       u32 synthDelay, qnum;
+       u32 qnum;
        int r;
 
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
@@ -1857,17 +1153,15 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
                }
        }
 
-       REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
-       if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
-                          AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
+       if (!ath9k_hw_rfbus_req(ah)) {
                ath_print(common, ATH_DBG_FATAL,
                          "Could not kill baseband RX\n");
                return false;
        }
 
-       ath9k_hw_set_regs(ah, chan);
+       ath9k_hw_set_channel_regs(ah, chan);
 
-       r = ah->ath9k_hw_rf_set_freq(ah, chan);
+       r = ath9k_hw_rf_set_freq(ah, chan);
        if (r) {
                ath_print(common, ATH_DBG_FATAL,
                          "Failed to set channel\n");
@@ -1881,20 +1175,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
                             min((u32) MAX_RATE_POWER,
                             (u32) regulatory->power_limit));
 
-       synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
-       if (IS_CHAN_B(chan))
-               synthDelay = (4 * synthDelay) / 22;
-       else
-               synthDelay /= 10;
-
-       udelay(synthDelay + BASE_ACTIVATE_DELAY);
-
-       REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
+       ath9k_hw_rfbus_done(ah);
 
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
 
-       ah->ath9k_hw_spur_mitigate_freq(ah, chan);
+       ath9k_hw_spur_mitigate_freq(ah, chan);
 
        if (!chan->oneTimeCalsDone)
                chan->oneTimeCalsDone = true;
@@ -1902,17 +1188,33 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        return true;
 }
 
-static void ath9k_enable_rfkill(struct ath_hw *ah)
+bool ath9k_hw_check_alive(struct ath_hw *ah)
 {
-       REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-                   AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+       int count = 50;
+       u32 reg;
+
+       if (AR_SREV_9285_10_OR_LATER(ah))
+               return true;
 
-       REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-                   AR_GPIO_INPUT_MUX2_RFSILENT);
+       do {
+               reg = REG_READ(ah, AR_OBS_BUS_1);
 
-       ath9k_hw_cfg_gpio_input(ah, ah->rfkill_gpio);
-       REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+               if ((reg & 0x7E7FFFEF) == 0x00702400)
+                       continue;
+
+               switch (reg & 0x7E000B00) {
+               case 0x1E000000:
+               case 0x52000B00:
+               case 0x18000B00:
+                       continue;
+               default:
+                       return true;
+               }
+       } while (count-- > 0);
+
+       return false;
 }
+EXPORT_SYMBOL(ath9k_hw_check_alive);
 
 int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                    bool bChannelChange)
@@ -1923,11 +1225,18 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        u32 saveDefAntenna;
        u32 macStaId1;
        u64 tsf = 0;
-       int i, rx_chainmask, r;
+       int i, r;
 
        ah->txchainmask = common->tx_chainmask;
        ah->rxchainmask = common->rx_chainmask;
 
+       if (!ah->chip_fullsleep) {
+               ath9k_hw_abortpcurecv(ah);
+               if (!ath9k_hw_stopdmarecv(ah))
+                       ath_print(common, ATH_DBG_XMIT,
+                               "Failed to stop receive dma\n");
+       }
+
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
                return -EIO;
 
@@ -1940,8 +1249,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
            (chan->channel != ah->curchan->channel) &&
            ((chan->channelFlags & CHANNEL_ALL) ==
             (ah->curchan->channelFlags & CHANNEL_ALL)) &&
-            !(AR_SREV_9280(ah) || IS_CHAN_A_5MHZ_SPACED(chan) ||
-            IS_CHAN_A_5MHZ_SPACED(ah->curchan))) {
+           !AR_SREV_9280(ah)) {
 
                if (ath9k_hw_channel_change(ah, chan)) {
                        ath9k_hw_loadnf(ah, ah->curchan);
@@ -1966,6 +1274,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_mark_phy_inactive(ah);
 
+       /* Only required on the first reset */
        if (AR_SREV_9271(ah) && ah->htc_reset_init) {
                REG_WRITE(ah,
                          AR9271_RESET_POWER_DOWN_CONTROL,
@@ -1978,6 +1287,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                return -EINVAL;
        }
 
+       /* Only required on the first reset */
        if (AR_SREV_9271(ah) && ah->htc_reset_init) {
                ah->htc_reset_init = false;
                REG_WRITE(ah,
@@ -1993,16 +1303,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (AR_SREV_9280_10_OR_LATER(ah))
                REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
 
-       if (AR_SREV_9287_12_OR_LATER(ah)) {
-               /* Enable ASYNC FIFO */
-               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
-                               AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
-               REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
-               REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
-                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
-               REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
-                               AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
-       }
        r = ath9k_hw_process_ini(ah, chan);
        if (r)
                return r;
@@ -2027,9 +1327,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
 
-       ah->ath9k_hw_spur_mitigate_freq(ah, chan);
+       ath9k_hw_spur_mitigate_freq(ah, chan);
        ah->eep_ops->set_board_values(ah, chan);
 
+       ath9k_hw_set_operating_mode(ah, ah->opmode);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr));
        REG_WRITE(ah, AR_STA_ID1, get_unaligned_le16(common->macaddr + 4)
                  | macStaId1
@@ -2037,25 +1341,27 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                  | (ah->config.
                     ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
                  | ah->sta_id1_defaults);
-       ath9k_hw_set_operating_mode(ah, ah->opmode);
-
        ath_hw_setbssidmask(common);
-
        REG_WRITE(ah, AR_DEF_ANTENNA, saveDefAntenna);
-
        ath9k_hw_write_associd(ah);
-
        REG_WRITE(ah, AR_ISR, ~0);
-
        REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
-       r = ah->ath9k_hw_rf_set_freq(ah, chan);
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
+       r = ath9k_hw_rf_set_freq(ah, chan);
        if (r)
                return r;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        for (i = 0; i < AR_NUM_DCU; i++)
                REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        ah->intr_txqs = 0;
        for (i = 0; i < ah->caps.total_queues; i++)
                ath9k_hw_resettxqueue(ah, i);
@@ -2068,25 +1374,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_init_global_settings(ah);
 
-       if (AR_SREV_9287_12_OR_LATER(ah)) {
-               REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
-                         AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
-               REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
-                         AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
-               REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
-                         AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
-
-               REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
-               REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
-
-               REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
-                           AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
-               REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
-                             AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
-       }
-       if (AR_SREV_9287_12_OR_LATER(ah)) {
-               REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
-                               AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+       if (!AR_SREV_9300_20_OR_LATER(ah)) {
+               ar9002_hw_enable_async_fifo(ah);
+               ar9002_hw_enable_wep_aggregation(ah);
        }
 
        REG_WRITE(ah, AR_STA_ID1,
@@ -2101,19 +1391,24 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, 2000);
        }
 
+       if (ah->config.tx_intr_mitigation) {
+               REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, 300);
+               REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, 750);
+       }
+
        ath9k_hw_init_bb(ah, chan);
 
        if (!ath9k_hw_init_cal(ah, chan))
                return -EIO;
 
-       rx_chainmask = ah->rxchainmask;
-       if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
-               REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask);
-               REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask);
-       }
+       ENABLE_REGWRITE_BUFFER(ah);
 
+       ath9k_hw_restore_chainmask(ah);
        REG_WRITE(ah, AR_CFG_LED, saveLedState | AR_CFG_SCLK_32KHZ);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        /*
         * For big endian systems turn on swapping for descriptors
         */
@@ -2143,6 +1438,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
 
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               ath9k_hw_loadnf(ah, curchan);
+               ath9k_hw_start_nfcal(ah);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_reset);
@@ -2429,21 +1729,35 @@ EXPORT_SYMBOL(ath9k_hw_keyisvalid);
 /* Power Management (Chipset) */
 /******************************/
 
+/*
+ * Notify Power Mgt is disabled in self-generated frames.
+ * If requested, force chip to sleep.
+ */
 static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip)
 {
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
        if (setChip) {
+               /*
+                * Clear the RTC force wake bit to allow the
+                * mac to go to sleep.
+                */
                REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
                            AR_RTC_FORCE_WAKE_EN);
-               if (!AR_SREV_9100(ah))
+               if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
                        REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);
 
-               if(!AR_SREV_5416(ah))
+               /* Shutdown chip. Active low */
+               if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah))
                        REG_CLR_BIT(ah, (AR_RTC_RESET),
                                    AR_RTC_RESET_EN);
        }
 }
 
+/*
+ * Notify Power Management is enabled in self-generating
+ * frames. If request, set power mode of chip to
+ * auto/normal.  Duration in units of 128us (1/8 TU).
+ */
 static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
 {
        REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
@@ -2451,9 +1765,14 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip)
                struct ath9k_hw_capabilities *pCap = &ah->caps;
 
                if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+                       /* Set WakeOnInterrupt bit; clear ForceWake bit */
                        REG_WRITE(ah, AR_RTC_FORCE_WAKE,
                                  AR_RTC_FORCE_WAKE_ON_INT);
                } else {
+                       /*
+                        * Clear the RTC force wake bit to allow the
+                        * mac to go to sleep.
+                        */
                        REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE,
                                    AR_RTC_FORCE_WAKE_EN);
                }
@@ -2472,7 +1791,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
                                           ATH9K_RESET_POWER_ON) != true) {
                                return false;
                        }
-                       ath9k_hw_init_pll(ah, NULL);
+                       if (!AR_SREV_9300_20_OR_LATER(ah))
+                               ath9k_hw_init_pll(ah, NULL);
                }
                if (AR_SREV_9100(ah))
                        REG_SET_BIT(ah, AR_RTC_RESET,
@@ -2542,424 +1862,6 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
 }
 EXPORT_SYMBOL(ath9k_hw_setpower);
 
-/*
- * Helper for ASPM support.
- *
- * Disable PLL when in L0s as well as receiver clock when in L1.
- * This power saving option must be enabled through the SerDes.
- *
- * Programming the SerDes must go through the same 288 bit serial shift
- * register as the other analog registers.  Hence the 9 writes.
- */
-void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off)
-{
-       u8 i;
-       u32 val;
-
-       if (ah->is_pciexpress != true)
-               return;
-
-       /* Do not touch SerDes registers */
-       if (ah->config.pcie_powersave_enable == 2)
-               return;
-
-       /* Nothing to do on restore for 11N */
-       if (!restore) {
-               if (AR_SREV_9280_20_OR_LATER(ah)) {
-                       /*
-                        * AR9280 2.0 or later chips use SerDes values from the
-                        * initvals.h initialized depending on chipset during
-                        * ath9k_hw_init()
-                        */
-                       for (i = 0; i < ah->iniPcieSerdes.ia_rows; i++) {
-                               REG_WRITE(ah, INI_RA(&ah->iniPcieSerdes, i, 0),
-                                         INI_RA(&ah->iniPcieSerdes, i, 1));
-                       }
-               } else if (AR_SREV_9280(ah) &&
-                          (ah->hw_version.macRev == AR_SREV_REVISION_9280_10)) {
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-
-                       /* RX shut off when elecidle is asserted */
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560);
-
-                       /* Shut off CLKREQ active in L1 */
-                       if (ah->config.pcie_clock_req)
-                               REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc);
-                       else
-                               REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd);
-
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007);
-
-                       /* Load the new settings */
-                       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-
-               } else {
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924);
-
-                       /* RX shut off when elecidle is asserted */
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579);
-
-                       /*
-                        * Ignore ah->ah_config.pcie_clock_req setting for
-                        * pre-AR9280 11n
-                        */
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff);
-
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554);
-                       REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007);
-
-                       /* Load the new settings */
-                       REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000);
-               }
-
-               udelay(1000);
-
-               /* set bit 19 to allow forcing of pcie core into L1 state */
-               REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
-
-               /* Several PCIe massages to ensure proper behaviour */
-               if (ah->config.pcie_waen) {
-                       val = ah->config.pcie_waen;
-                       if (!power_off)
-                               val &= (~AR_WA_D3_L1_DISABLE);
-               } else {
-                       if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
-                           AR_SREV_9287(ah)) {
-                               val = AR9285_WA_DEFAULT;
-                               if (!power_off)
-                                       val &= (~AR_WA_D3_L1_DISABLE);
-                       } else if (AR_SREV_9280(ah)) {
-                               /*
-                                * On AR9280 chips bit 22 of 0x4004 needs to be
-                                * set otherwise card may disappear.
-                                */
-                               val = AR9280_WA_DEFAULT;
-                               if (!power_off)
-                                       val &= (~AR_WA_D3_L1_DISABLE);
-                       } else
-                               val = AR_WA_DEFAULT;
-               }
-
-               REG_WRITE(ah, AR_WA, val);
-       }
-
-       if (power_off) {
-               /*
-                * Set PCIe workaround bits
-                * bit 14 in WA register (disable L1) should only
-                * be set when device enters D3 and be cleared
-                * when device comes back to D0.
-                */
-               if (ah->config.pcie_waen) {
-                       if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
-                               REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
-               } else {
-                       if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
-                             AR_SREV_9287(ah)) &&
-                            (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
-                           (AR_SREV_9280(ah) &&
-                            (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
-                               REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
-                       }
-               }
-       }
-}
-EXPORT_SYMBOL(ath9k_hw_configpcipowersave);
-
-/**********************/
-/* Interrupt Handling */
-/**********************/
-
-bool ath9k_hw_intrpend(struct ath_hw *ah)
-{
-       u32 host_isr;
-
-       if (AR_SREV_9100(ah))
-               return true;
-
-       host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
-       if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
-               return true;
-
-       host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
-       if ((host_isr & AR_INTR_SYNC_DEFAULT)
-           && (host_isr != AR_INTR_SPURIOUS))
-               return true;
-
-       return false;
-}
-EXPORT_SYMBOL(ath9k_hw_intrpend);
-
-bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
-{
-       u32 isr = 0;
-       u32 mask2 = 0;
-       struct ath9k_hw_capabilities *pCap = &ah->caps;
-       u32 sync_cause = 0;
-       bool fatal_int = false;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       if (!AR_SREV_9100(ah)) {
-               if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) {
-                       if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M)
-                           == AR_RTC_STATUS_ON) {
-                               isr = REG_READ(ah, AR_ISR);
-                       }
-               }
-
-               sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) &
-                       AR_INTR_SYNC_DEFAULT;
-
-               *masked = 0;
-
-               if (!isr && !sync_cause)
-                       return false;
-       } else {
-               *masked = 0;
-               isr = REG_READ(ah, AR_ISR);
-       }
-
-       if (isr) {
-               if (isr & AR_ISR_BCNMISC) {
-                       u32 isr2;
-                       isr2 = REG_READ(ah, AR_ISR_S2);
-                       if (isr2 & AR_ISR_S2_TIM)
-                               mask2 |= ATH9K_INT_TIM;
-                       if (isr2 & AR_ISR_S2_DTIM)
-                               mask2 |= ATH9K_INT_DTIM;
-                       if (isr2 & AR_ISR_S2_DTIMSYNC)
-                               mask2 |= ATH9K_INT_DTIMSYNC;
-                       if (isr2 & (AR_ISR_S2_CABEND))
-                               mask2 |= ATH9K_INT_CABEND;
-                       if (isr2 & AR_ISR_S2_GTT)
-                               mask2 |= ATH9K_INT_GTT;
-                       if (isr2 & AR_ISR_S2_CST)
-                               mask2 |= ATH9K_INT_CST;
-                       if (isr2 & AR_ISR_S2_TSFOOR)
-                               mask2 |= ATH9K_INT_TSFOOR;
-               }
-
-               isr = REG_READ(ah, AR_ISR_RAC);
-               if (isr == 0xffffffff) {
-                       *masked = 0;
-                       return false;
-               }
-
-               *masked = isr & ATH9K_INT_COMMON;
-
-               if (ah->config.rx_intr_mitigation) {
-                       if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM))
-                               *masked |= ATH9K_INT_RX;
-               }
-
-               if (isr & (AR_ISR_RXOK | AR_ISR_RXERR))
-                       *masked |= ATH9K_INT_RX;
-               if (isr &
-                   (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR |
-                    AR_ISR_TXEOL)) {
-                       u32 s0_s, s1_s;
-
-                       *masked |= ATH9K_INT_TX;
-
-                       s0_s = REG_READ(ah, AR_ISR_S0_S);
-                       ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
-                       ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
-
-                       s1_s = REG_READ(ah, AR_ISR_S1_S);
-                       ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
-                       ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
-               }
-
-               if (isr & AR_ISR_RXORN) {
-                       ath_print(common, ATH_DBG_INTERRUPT,
-                                 "receive FIFO overrun interrupt\n");
-               }
-
-               if (!AR_SREV_9100(ah)) {
-                       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-                               u32 isr5 = REG_READ(ah, AR_ISR_S5_S);
-                               if (isr5 & AR_ISR_S5_TIM_TIMER)
-                                       *masked |= ATH9K_INT_TIM_TIMER;
-                       }
-               }
-
-               *masked |= mask2;
-       }
-
-       if (AR_SREV_9100(ah))
-               return true;
-
-       if (isr & AR_ISR_GENTMR) {
-               u32 s5_s;
-
-               s5_s = REG_READ(ah, AR_ISR_S5_S);
-               if (isr & AR_ISR_GENTMR) {
-                       ah->intr_gen_timer_trigger =
-                               MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
-
-                       ah->intr_gen_timer_thresh =
-                               MS(s5_s, AR_ISR_S5_GENTIMER_THRESH);
-
-                       if (ah->intr_gen_timer_trigger)
-                               *masked |= ATH9K_INT_GENTIMER;
-
-               }
-       }
-
-       if (sync_cause) {
-               fatal_int =
-                       (sync_cause &
-                        (AR_INTR_SYNC_HOST1_FATAL | AR_INTR_SYNC_HOST1_PERR))
-                       ? true : false;
-
-               if (fatal_int) {
-                       if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) {
-                               ath_print(common, ATH_DBG_ANY,
-                                         "received PCI FATAL interrupt\n");
-                       }
-                       if (sync_cause & AR_INTR_SYNC_HOST1_PERR) {
-                               ath_print(common, ATH_DBG_ANY,
-                                         "received PCI PERR interrupt\n");
-                       }
-                       *masked |= ATH9K_INT_FATAL;
-               }
-               if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) {
-                       ath_print(common, ATH_DBG_INTERRUPT,
-                                 "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n");
-                       REG_WRITE(ah, AR_RC, AR_RC_HOSTIF);
-                       REG_WRITE(ah, AR_RC, 0);
-                       *masked |= ATH9K_INT_FATAL;
-               }
-               if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) {
-                       ath_print(common, ATH_DBG_INTERRUPT,
-                                 "AR_INTR_SYNC_LOCAL_TIMEOUT\n");
-               }
-
-               REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause);
-               (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR);
-       }
-
-       return true;
-}
-EXPORT_SYMBOL(ath9k_hw_getisr);
-
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
-{
-       u32 omask = ah->mask_reg;
-       u32 mask, mask2;
-       struct ath9k_hw_capabilities *pCap = &ah->caps;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
-
-       if (omask & ATH9K_INT_GLOBAL) {
-               ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
-               REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
-               (void) REG_READ(ah, AR_IER);
-               if (!AR_SREV_9100(ah)) {
-                       REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
-                       (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
-
-                       REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
-                       (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
-               }
-       }
-
-       mask = ints & ATH9K_INT_COMMON;
-       mask2 = 0;
-
-       if (ints & ATH9K_INT_TX) {
-               if (ah->txok_interrupt_mask)
-                       mask |= AR_IMR_TXOK;
-               if (ah->txdesc_interrupt_mask)
-                       mask |= AR_IMR_TXDESC;
-               if (ah->txerr_interrupt_mask)
-                       mask |= AR_IMR_TXERR;
-               if (ah->txeol_interrupt_mask)
-                       mask |= AR_IMR_TXEOL;
-       }
-       if (ints & ATH9K_INT_RX) {
-               mask |= AR_IMR_RXERR;
-               if (ah->config.rx_intr_mitigation)
-                       mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
-               else
-                       mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
-               if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
-                       mask |= AR_IMR_GENTMR;
-       }
-
-       if (ints & (ATH9K_INT_BMISC)) {
-               mask |= AR_IMR_BCNMISC;
-               if (ints & ATH9K_INT_TIM)
-                       mask2 |= AR_IMR_S2_TIM;
-               if (ints & ATH9K_INT_DTIM)
-                       mask2 |= AR_IMR_S2_DTIM;
-               if (ints & ATH9K_INT_DTIMSYNC)
-                       mask2 |= AR_IMR_S2_DTIMSYNC;
-               if (ints & ATH9K_INT_CABEND)
-                       mask2 |= AR_IMR_S2_CABEND;
-               if (ints & ATH9K_INT_TSFOOR)
-                       mask2 |= AR_IMR_S2_TSFOOR;
-       }
-
-       if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
-               mask |= AR_IMR_BCNMISC;
-               if (ints & ATH9K_INT_GTT)
-                       mask2 |= AR_IMR_S2_GTT;
-               if (ints & ATH9K_INT_CST)
-                       mask2 |= AR_IMR_S2_CST;
-       }
-
-       ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
-       REG_WRITE(ah, AR_IMR, mask);
-       mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM |
-                                          AR_IMR_S2_DTIM |
-                                          AR_IMR_S2_DTIMSYNC |
-                                          AR_IMR_S2_CABEND |
-                                          AR_IMR_S2_CABTO |
-                                          AR_IMR_S2_TSFOOR |
-                                          AR_IMR_S2_GTT | AR_IMR_S2_CST);
-       REG_WRITE(ah, AR_IMR_S2, mask | mask2);
-       ah->mask_reg = ints;
-
-       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-               if (ints & ATH9K_INT_TIM_TIMER)
-                       REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
-               else
-                       REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
-       }
-
-       if (ints & ATH9K_INT_GLOBAL) {
-               ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
-               REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
-               if (!AR_SREV_9100(ah)) {
-                       REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
-                                 AR_INTR_MAC_IRQ);
-                       REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
-
-
-                       REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
-                                 AR_INTR_SYNC_DEFAULT);
-                       REG_WRITE(ah, AR_INTR_SYNC_MASK,
-                                 AR_INTR_SYNC_DEFAULT);
-               }
-               ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
-                         REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
-       }
-
-       return omask;
-}
-EXPORT_SYMBOL(ath9k_hw_set_interrupts);
-
 /*******************/
 /* Beacon Handling */
 /*******************/
@@ -2970,6 +1872,8 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
 
        ah->beacon_interval = beacon_period;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        switch (ah->opmode) {
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_MONITOR:
@@ -3013,6 +1917,9 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
        REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
        REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        beacon_period &= ~ATH9K_BEACON_ENA;
        if (beacon_period & ATH9K_BEACON_RESET_TSF) {
                ath9k_hw_reset_tsf(ah);
@@ -3029,6 +1936,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        struct ath9k_hw_capabilities *pCap = &ah->caps;
        struct ath_common *common = ath9k_hw_common(ah);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
 
        REG_WRITE(ah, AR_BEACON_PERIOD,
@@ -3036,6 +1945,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
                  TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        REG_RMW_FIELD(ah, AR_RSSI_THR,
                      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
 
@@ -3058,6 +1970,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        ath_print(common, ATH_DBG_BEACON, "beacon period %d\n", beaconintval);
        ath_print(common, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_NEXT_DTIM,
                  TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP));
        REG_WRITE(ah, AR_NEXT_TIM, TU_TO_USEC(nextTbtt - SLEEP_SLOP));
@@ -3077,6 +1991,9 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval));
        REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod));
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        REG_SET_BIT(ah, AR_TIMER_MODE,
                    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
                    AR_DTIM_TIMER_EN);
@@ -3219,7 +2136,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        else
                pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
 
-       if (AR_SREV_9285_10_OR_LATER(ah))
+       if (AR_SREV_9271(ah))
+               pCap->num_gpio_pins = AR9271_NUM_GPIO;
+       else if (AR_SREV_9285_10_OR_LATER(ah))
                pCap->num_gpio_pins = AR9285_NUM_GPIO;
        else if (AR_SREV_9280_10_OR_LATER(ah))
                pCap->num_gpio_pins = AR928X_NUM_GPIO;
@@ -3246,8 +2165,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
        }
 #endif
-
-       pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
+       if (AR_SREV_9271(ah))
+               pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
+       else
+               pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
 
        if (AR_SREV_9280(ah) || AR_SREV_9285(ah))
                pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS;
@@ -3291,6 +2212,26 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
        }
 
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_LDPC |
+                                ATH9K_HW_CAP_FASTCLOCK;
+               pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
+               pCap->rx_lp_qdepth = ATH9K_HW_RX_LP_QDEPTH;
+               pCap->rx_status_len = sizeof(struct ar9003_rxs);
+               pCap->tx_desc_len = sizeof(struct ar9003_txc);
+               pCap->txs_len = sizeof(struct ar9003_txs);
+       } else {
+               pCap->tx_desc_len = sizeof(struct ath_desc);
+               if (AR_SREV_9280_20(ah) &&
+                   ((ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV) <=
+                     AR5416_EEP_MINOR_VER_16) ||
+                    ah->eep_ops->get_eeprom(ah, EEP_FSTCLK_5G)))
+                       pCap->hw_caps |= ATH9K_HW_CAP_FASTCLOCK;
+       }
+
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
+
        return 0;
 }
 
@@ -3323,10 +2264,6 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
        case ATH9K_CAP_TKIP_SPLIT:
                return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ?
                        false : true;
-       case ATH9K_CAP_DIVERSITY:
-               return (REG_READ(ah, AR_PHY_CCK_DETECT) &
-                       AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
-                       true : false;
        case ATH9K_CAP_MCAST_KEYSRCH:
                switch (capability) {
                case 0:
@@ -3369,8 +2306,6 @@ EXPORT_SYMBOL(ath9k_hw_getcapability);
 bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                            u32 capability, u32 setting, int *status)
 {
-       u32 v;
-
        switch (type) {
        case ATH9K_CAP_TKIP_MIC:
                if (setting)
@@ -3380,14 +2315,6 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                        ah->sta_id1_defaults &=
                                ~AR_STA_ID1_CRPT_MIC_ENABLE;
                return true;
-       case ATH9K_CAP_DIVERSITY:
-               v = REG_READ(ah, AR_PHY_CCK_DETECT);
-               if (setting)
-                       v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-               else
-                       v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-               REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-               return true;
        case ATH9K_CAP_MCAST_KEYSRCH:
                if (setting)
                        ah->sta_id1_defaults |= AR_STA_ID1_MCAST_KSRCH;
@@ -3455,7 +2382,11 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
        if (gpio >= ah->caps.num_gpio_pins)
                return 0xffffffff;
 
-       if (AR_SREV_9287_10_OR_LATER(ah))
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               return MS_REG_READ(AR9300, gpio) != 0;
+       else if (AR_SREV_9271(ah))
+               return MS_REG_READ(AR9271, gpio) != 0;
+       else if (AR_SREV_9287_10_OR_LATER(ah))
                return MS_REG_READ(AR9287, gpio) != 0;
        else if (AR_SREV_9285_10_OR_LATER(ah))
                return MS_REG_READ(AR9285, gpio) != 0;
@@ -3484,6 +2415,9 @@ EXPORT_SYMBOL(ath9k_hw_cfg_output);
 
 void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)
 {
+       if (AR_SREV_9271(ah))
+               val = ~val;
+
        REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio),
                AR_GPIO_BIT(gpio));
 }
@@ -3523,6 +2457,8 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
 {
        u32 phybits;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_RX_FILTER, bits);
 
        phybits = 0;
@@ -3538,6 +2474,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
        else
                REG_WRITE(ah, AR_RXCFG,
                          REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 EXPORT_SYMBOL(ath9k_hw_setrxfilter);
 
@@ -3610,14 +2549,25 @@ void ath9k_hw_write_associd(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_write_associd);
 
+#define ATH9K_MAX_TSF_READ 10
+
 u64 ath9k_hw_gettsf64(struct ath_hw *ah)
 {
-       u64 tsf;
+       u32 tsf_lower, tsf_upper1, tsf_upper2;
+       int i;
+
+       tsf_upper1 = REG_READ(ah, AR_TSF_U32);
+       for (i = 0; i < ATH9K_MAX_TSF_READ; i++) {
+               tsf_lower = REG_READ(ah, AR_TSF_L32);
+               tsf_upper2 = REG_READ(ah, AR_TSF_U32);
+               if (tsf_upper2 == tsf_upper1)
+                       break;
+               tsf_upper1 = tsf_upper2;
+       }
 
-       tsf = REG_READ(ah, AR_TSF_U32);
-       tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32);
+       WARN_ON( i == ATH9K_MAX_TSF_READ );
 
-       return tsf;
+       return (((u64)tsf_upper1 << 32) | tsf_lower);
 }
 EXPORT_SYMBOL(ath9k_hw_gettsf64);
 
@@ -3868,6 +2818,16 @@ void ath_gen_timer_isr(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath_gen_timer_isr);
 
+/********/
+/* HTC  */
+/********/
+
+void ath9k_hw_htc_resetinit(struct ath_hw *ah)
+{
+       ah->htc_reset_init = true;
+}
+EXPORT_SYMBOL(ath9k_hw_htc_resetinit);
+
 static struct {
        u32 version;
        const char * name;
@@ -3882,6 +2842,7 @@ static struct {
        { AR_SREV_VERSION_9285,         "9285" },
        { AR_SREV_VERSION_9287,         "9287" },
        { AR_SREV_VERSION_9271,         "9271" },
+       { AR_SREV_VERSION_9300,         "9300" },
 };
 
 /* For devices with external radios */
index dbbf7ca5f97d8a5b7ca60f6e3d193a7435f08d7d..77245dff599358e5070c92293df0dc97d2f1bd1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2010 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
 #define AR9280_DEVID_PCIE      0x002a
 #define AR9285_DEVID_PCIE      0x002b
 #define AR2427_DEVID_PCIE      0x002c
+#define AR9287_DEVID_PCI       0x002d
+#define AR9287_DEVID_PCIE      0x002e
+#define AR9300_DEVID_PCIE      0x0030
 
 #define AR5416_AR9100_DEVID    0x000b
 
-#define AR9271_USB             0x9271
-
 #define        AR_SUBVENDOR_ID_NOG     0x0e11
 #define AR_SUBVENDOR_ID_NEW_A  0x7065
 #define AR5416_MAGIC           0x19641014
 
-#define AR5416_DEVID_AR9287_PCI  0x002D
-#define AR5416_DEVID_AR9287_PCIE 0x002E
-
 #define AR9280_COEX2WIRE_SUBSYSID      0x309b
 #define AT9285_COEX3WIRE_SA_SUBSYSID   0x30aa
 #define AT9285_COEX3WIRE_DA_SUBSYSID   0x30ab
 #define REG_READ(_ah, _reg) \
        ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
 
+#define ENABLE_REGWRITE_BUFFER(_ah)                                    \
+       do {                                                            \
+               if (AR_SREV_9271(_ah))                                  \
+                       ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
+       } while (0)
+
+#define DISABLE_REGWRITE_BUFFER(_ah)                                   \
+       do {                                                            \
+               if (AR_SREV_9271(_ah))                                  \
+                       ath9k_hw_common(_ah)->ops->disable_write_buffer((_ah)); \
+       } while (0)
+
+#define REGWRITE_BUFFER_FLUSH(_ah)                                     \
+       do {                                                            \
+               if (AR_SREV_9271(_ah))                                  \
+                       ath9k_hw_common(_ah)->ops->write_flush((_ah));  \
+       } while (0)
+
 #define SM(_v, _f)  (((_v) << _f##_S) & _f)
 #define MS(_v, _f)  (((_v) & _f) >> _f##_S)
 #define REG_RMW(_a, _r, _set, _clr)    \
@@ -77,6 +93,8 @@
 #define REG_RMW_FIELD(_a, _r, _f, _v) \
        REG_WRITE(_a, _r, \
        (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
+#define REG_READ_FIELD(_a, _r, _f) \
+       (((REG_READ(_a, _r) & _f) >> _f##_S))
 #define REG_SET_BIT(_a, _r, _f) \
        REG_WRITE(_a, _r, REG_READ(_a, _r) | _f)
 #define REG_CLR_BIT(_a, _r, _f) \
 
 #define TU_TO_USEC(_tu)             ((_tu) << 10)
 
+#define ATH9K_HW_RX_HP_QDEPTH  16
+#define ATH9K_HW_RX_LP_QDEPTH  128
+
+enum ath_ini_subsys {
+       ATH_INI_PRE = 0,
+       ATH_INI_CORE,
+       ATH_INI_POST,
+       ATH_INI_NUM_SPLIT,
+};
+
 enum wireless_mode {
        ATH9K_MODE_11A = 0,
        ATH9K_MODE_11G,
@@ -167,13 +195,16 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_ENHANCEDPM                 = BIT(14),
        ATH9K_HW_CAP_AUTOSLEEP                  = BIT(15),
        ATH9K_HW_CAP_4KB_SPLITTRANS             = BIT(16),
+       ATH9K_HW_CAP_EDMA                       = BIT(17),
+       ATH9K_HW_CAP_RAC_SUPPORTED              = BIT(18),
+       ATH9K_HW_CAP_LDPC                       = BIT(19),
+       ATH9K_HW_CAP_FASTCLOCK                  = BIT(20),
 };
 
 enum ath9k_capability_type {
        ATH9K_CAP_CIPHER = 0,
        ATH9K_CAP_TKIP_MIC,
        ATH9K_CAP_TKIP_SPLIT,
-       ATH9K_CAP_DIVERSITY,
        ATH9K_CAP_TXPOW,
        ATH9K_CAP_MCAST_KEYSRCH,
        ATH9K_CAP_DS
@@ -194,6 +225,11 @@ struct ath9k_hw_capabilities {
        u8 num_gpio_pins;
        u8 num_antcfg_2ghz;
        u8 num_antcfg_5ghz;
+       u8 rx_hp_qdepth;
+       u8 rx_lp_qdepth;
+       u8 rx_status_len;
+       u8 tx_desc_len;
+       u8 txs_len;
 };
 
 struct ath9k_ops_config {
@@ -214,6 +250,7 @@ struct ath9k_ops_config {
        u32 enable_ani;
        int serialize_regmode;
        bool rx_intr_mitigation;
+       bool tx_intr_mitigation;
 #define SPUR_DISABLE           0
 #define SPUR_ENABLE_IOCTL      1
 #define SPUR_ENABLE_EEPROM     2
@@ -225,6 +262,7 @@ struct ath9k_ops_config {
 #define AR_BASE_FREQ_5GHZ      4900
 #define AR_SPUR_FEEQ_BOUND_HT40 19
 #define AR_SPUR_FEEQ_BOUND_HT20 10
+       bool tx_iq_calibration; /* Only available for >= AR9003 */
        int spurmode;
        u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
        u8 max_txtrig_level;
@@ -233,6 +271,8 @@ struct ath9k_ops_config {
 enum ath9k_int {
        ATH9K_INT_RX = 0x00000001,
        ATH9K_INT_RXDESC = 0x00000002,
+       ATH9K_INT_RXHP = 0x00000001,
+       ATH9K_INT_RXLP = 0x00000002,
        ATH9K_INT_RXNOFRM = 0x00000008,
        ATH9K_INT_RXEOL = 0x00000010,
        ATH9K_INT_RXORN = 0x00000020,
@@ -329,10 +369,9 @@ struct ath9k_channel {
 #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
 #define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
 #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
-#define IS_CHAN_A_5MHZ_SPACED(_c)                      \
+#define IS_CHAN_A_FAST_CLOCK(_ah, _c)                  \
        ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&  \
-        (((_c)->channel % 20) != 0) &&                 \
-        (((_c)->channel % 10) != 0))
+        ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK))
 
 /* These macros check chanmode and not channelFlags */
 #define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
@@ -365,6 +404,12 @@ enum ser_reg_mode {
        SER_REG_MODE_AUTO = 2,
 };
 
+enum ath9k_rx_qtype {
+       ATH9K_RX_QUEUE_HP,
+       ATH9K_RX_QUEUE_LP,
+       ATH9K_RX_QUEUE_MAX,
+};
+
 struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
@@ -442,6 +487,124 @@ struct ath_gen_timer_table {
        } timer_mask;
 };
 
+/**
+ * struct ath_hw_private_ops - callbacks used internally by hardware code
+ *
+ * This structure contains private callbacks designed to only be used internally
+ * by the hardware core.
+ *
+ * @init_cal_settings: setup types of calibrations supported
+ * @init_cal: starts actual calibration
+ *
+ * @init_mode_regs: Initializes mode registers
+ * @init_mode_gain_regs: Initialize TX/RX gain registers
+ * @macversion_supported: If this specific mac revision is supported
+ *
+ * @rf_set_freq: change frequency
+ * @spur_mitigate_freq: spur mitigation
+ * @rf_alloc_ext_banks:
+ * @rf_free_ext_banks:
+ * @set_rf_regs:
+ * @compute_pll_control: compute the PLL control value to use for
+ *     AR_RTC_PLL_CONTROL for a given channel
+ * @setup_calibration: set up calibration
+ * @iscal_supported: used to query if a type of calibration is supported
+ * @loadnf: load noise floor read from each chain on the CCA registers
+ */
+struct ath_hw_private_ops {
+       /* Calibration ops */
+       void (*init_cal_settings)(struct ath_hw *ah);
+       bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
+
+       void (*init_mode_regs)(struct ath_hw *ah);
+       void (*init_mode_gain_regs)(struct ath_hw *ah);
+       bool (*macversion_supported)(u32 macversion);
+       void (*setup_calibration)(struct ath_hw *ah,
+                                 struct ath9k_cal_list *currCal);
+       bool (*iscal_supported)(struct ath_hw *ah,
+                               enum ath9k_cal_types calType);
+
+       /* PHY ops */
+       int (*rf_set_freq)(struct ath_hw *ah,
+                          struct ath9k_channel *chan);
+       void (*spur_mitigate_freq)(struct ath_hw *ah,
+                                  struct ath9k_channel *chan);
+       int (*rf_alloc_ext_banks)(struct ath_hw *ah);
+       void (*rf_free_ext_banks)(struct ath_hw *ah);
+       bool (*set_rf_regs)(struct ath_hw *ah,
+                           struct ath9k_channel *chan,
+                           u16 modesIndex);
+       void (*set_channel_regs)(struct ath_hw *ah, struct ath9k_channel *chan);
+       void (*init_bb)(struct ath_hw *ah,
+                       struct ath9k_channel *chan);
+       int (*process_ini)(struct ath_hw *ah, struct ath9k_channel *chan);
+       void (*olc_init)(struct ath_hw *ah);
+       void (*set_rfmode)(struct ath_hw *ah, struct ath9k_channel *chan);
+       void (*mark_phy_inactive)(struct ath_hw *ah);
+       void (*set_delta_slope)(struct ath_hw *ah, struct ath9k_channel *chan);
+       bool (*rfbus_req)(struct ath_hw *ah);
+       void (*rfbus_done)(struct ath_hw *ah);
+       void (*enable_rfkill)(struct ath_hw *ah);
+       void (*restore_chainmask)(struct ath_hw *ah);
+       void (*set_diversity)(struct ath_hw *ah, bool value);
+       u32 (*compute_pll_control)(struct ath_hw *ah,
+                                  struct ath9k_channel *chan);
+       bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
+                           int param);
+       void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]);
+       void (*loadnf)(struct ath_hw *ah, struct ath9k_channel *chan);
+};
+
+/**
+ * struct ath_hw_ops - callbacks used by hardware code and driver code
+ *
+ * This structure contains callbacks designed to to be used internally by
+ * hardware code and also by the lower level driver.
+ *
+ * @config_pci_powersave:
+ * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
+ */
+struct ath_hw_ops {
+       void (*config_pci_powersave)(struct ath_hw *ah,
+                                    int restore,
+                                    int power_off);
+       void (*rx_enable)(struct ath_hw *ah);
+       void (*set_desc_link)(void *ds, u32 link);
+       void (*get_desc_link)(void *ds, u32 **link);
+       bool (*calibrate)(struct ath_hw *ah,
+                         struct ath9k_channel *chan,
+                         u8 rxchainmask,
+                         bool longcal);
+       bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked);
+       void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen,
+                           bool is_firstseg, bool is_is_lastseg,
+                           const void *ds0, dma_addr_t buf_addr,
+                           unsigned int qcu);
+       int (*proc_txdesc)(struct ath_hw *ah, void *ds,
+                          struct ath_tx_status *ts);
+       void (*set11n_txdesc)(struct ath_hw *ah, void *ds,
+                             u32 pktLen, enum ath9k_pkt_type type,
+                             u32 txPower, u32 keyIx,
+                             enum ath9k_key_type keyType,
+                             u32 flags);
+       void (*set11n_ratescenario)(struct ath_hw *ah, void *ds,
+                               void *lastds,
+                               u32 durUpdateEn, u32 rtsctsRate,
+                               u32 rtsctsDuration,
+                               struct ath9k_11n_rate_series series[],
+                               u32 nseries, u32 flags);
+       void (*set11n_aggr_first)(struct ath_hw *ah, void *ds,
+                                 u32 aggrLen);
+       void (*set11n_aggr_middle)(struct ath_hw *ah, void *ds,
+                                  u32 numDelims);
+       void (*set11n_aggr_last)(struct ath_hw *ah, void *ds);
+       void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
+       void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
+                                    u32 burstDuration);
+       void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
+                                      u32 vmf);
+};
+
 struct ath_hw {
        struct ieee80211_hw *hw;
        struct ath_common common;
@@ -455,13 +618,18 @@ struct ath_hw {
                struct ar5416_eeprom_def def;
                struct ar5416_eeprom_4k map4k;
                struct ar9287_eeprom map9287;
+               struct ar9300_eeprom ar9300_eep;
        } eeprom;
        const struct eeprom_ops *eep_ops;
-       enum ath9k_eep_map eep_map;
 
        bool sw_mgmt_crypto;
        bool is_pciexpress;
+       bool need_an_top2_fixup;
        u16 tx_trig_level;
+       s16 nf_2g_max;
+       s16 nf_2g_min;
+       s16 nf_5g_max;
+       s16 nf_5g_min;
        u16 rfsilent;
        u32 rfkill_gpio;
        u32 rfkill_polarity;
@@ -478,7 +646,8 @@ struct ath_hw {
        struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
 
        int16_t curchan_rad_index;
-       u32 mask_reg;
+       enum ath9k_int imask;
+       u32 imrs2_reg;
        u32 txok_interrupt_mask;
        u32 txerr_interrupt_mask;
        u32 txdesc_interrupt_mask;
@@ -493,6 +662,7 @@ struct ath_hw {
        struct ath9k_cal_list adcgain_caldata;
        struct ath9k_cal_list adcdc_calinitdata;
        struct ath9k_cal_list adcdc_caldata;
+       struct ath9k_cal_list tempCompCalData;
        struct ath9k_cal_list *cal_list;
        struct ath9k_cal_list *cal_list_last;
        struct ath9k_cal_list *cal_list_curr;
@@ -533,12 +703,10 @@ struct ath_hw {
                DONT_USE_32KHZ,
        } enable_32kHz_clock;
 
-       /* Callback for radio frequency change */
-       int (*ath9k_hw_rf_set_freq)(struct ath_hw *ah, struct ath9k_channel *chan);
-
-       /* Callback for baseband spur frequency */
-       void (*ath9k_hw_spur_mitigate_freq)(struct ath_hw *ah,
-                                           struct ath9k_channel *chan);
+       /* Private to hardware code */
+       struct ath_hw_private_ops private_ops;
+       /* Accessed by the lower level driver */
+       struct ath_hw_ops ops;
 
        /* Used to program the radio on non single-chip devices */
        u32 *analogBank0Data;
@@ -551,6 +719,7 @@ struct ath_hw {
        u32 *addac5416_21;
        u32 *bank6Temp;
 
+       u8 txpower_limit;
        int16_t txpower_indexoffset;
        int coverage_class;
        u32 beacon_interval;
@@ -592,16 +761,34 @@ struct ath_hw {
        struct ar5416IniArray iniBank7;
        struct ar5416IniArray iniAddac;
        struct ar5416IniArray iniPcieSerdes;
+       struct ar5416IniArray iniPcieSerdesLowPower;
        struct ar5416IniArray iniModesAdditional;
        struct ar5416IniArray iniModesRxGain;
        struct ar5416IniArray iniModesTxGain;
        struct ar5416IniArray iniModes_9271_1_0_only;
        struct ar5416IniArray iniCckfirNormal;
        struct ar5416IniArray iniCckfirJapan2484;
+       struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271;
+       struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271;
+       struct ar5416IniArray iniModes_9271_ANI_reg;
+       struct ar5416IniArray iniModes_high_power_tx_gain_9271;
+       struct ar5416IniArray iniModes_normal_power_tx_gain_9271;
+
+       struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT];
+       struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT];
+       struct ar5416IniArray iniRadio[ATH_INI_NUM_SPLIT];
+       struct ar5416IniArray iniSOC[ATH_INI_NUM_SPLIT];
 
        u32 intr_gen_timer_trigger;
        u32 intr_gen_timer_thresh;
        struct ath_gen_timer_table hw_gen_timers;
+
+       struct ar9003_txs *ts_ring;
+       void *ts_start;
+       u32 ts_paddr_start;
+       u32 ts_paddr_end;
+       u16 ts_tail;
+       u8 ts_size;
 };
 
 static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -614,6 +801,16 @@ static inline struct ath_regulatory *ath9k_hw_regulatory(struct ath_hw *ah)
        return &(ath9k_hw_common(ah)->regulatory);
 }
 
+static inline struct ath_hw_private_ops *ath9k_hw_private_ops(struct ath_hw *ah)
+{
+       return &ah->private_ops;
+}
+
+static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah)
+{
+       return &ah->ops;
+}
+
 /* Initialization, Detach, Reset */
 const char *ath9k_hw_probe(u16 vendorid, u16 devid);
 void ath9k_hw_deinit(struct ath_hw *ah);
@@ -625,6 +822,7 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                            u32 capability, u32 *result);
 bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                            u32 capability, u32 setting, int *status);
+u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan);
 
 /* Key Cache Management */
 bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
@@ -673,16 +871,10 @@ 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,
                                    const struct ath9k_beacon_state *bs);
+bool ath9k_hw_check_alive(struct ath_hw *ah);
 
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
 
-void ath9k_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off);
-
-/* Interrupt Handling */
-bool ath9k_hw_intrpend(struct ath_hw *ah);
-bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked);
-enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
-
 /* Generic hw timer primitives */
 struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
                                          void (*trigger)(void *),
@@ -701,6 +893,39 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah);
 
 void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len);
 
+/* HTC */
+void ath9k_hw_htc_resetinit(struct ath_hw *ah);
+
+/* PHY */
+void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
+                                  u32 *coef_mantissa, u32 *coef_exponent);
+
+/*
+ * Code Specific to AR5008, AR9001 or AR9002,
+ * we stuff these here to avoid callbacks for AR9003.
+ */
+void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
+int ar9002_hw_rf_claim(struct ath_hw *ah);
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
+void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
+
+/*
+ * Code specifric to AR9003, we stuff these here to avoid callbacks
+ * for older families
+ */
+void ar9003_hw_set_nf_limits(struct ath_hw *ah);
+
+/* Hardware family op attach helpers */
+void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
+void ar9002_hw_attach_phy_ops(struct ath_hw *ah);
+void ar9003_hw_attach_phy_ops(struct ath_hw *ah);
+
+void ar9002_hw_attach_calib_ops(struct ath_hw *ah);
+void ar9003_hw_attach_calib_ops(struct ath_hw *ah);
+
+void ar9002_hw_attach_ops(struct ath_hw *ah);
+void ar9003_hw_attach_ops(struct ath_hw *ah);
+
 #define ATH_PCIE_CAP_LINK_CTRL 0x70
 #define ATH_PCIE_CAP_LINK_L0S  1
 #define ATH_PCIE_CAP_LINK_L1   2
index 3d4d897add6d9bc07f250dcee458633e4ae7355f..d457cb3bd7720af182d929599f38e5d46fcac2d8 100644 (file)
@@ -175,6 +175,18 @@ static const struct ath_ops ath9k_common_ops = {
        .write = ath9k_iowrite32,
 };
 
+static int count_streams(unsigned int chainmask, int max)
+{
+       int streams = 0;
+
+       do {
+               if (++streams == max)
+                       break;
+       } while ((chainmask = chainmask & (chainmask - 1)));
+
+       return streams;
+}
+
 /**************************/
 /*     Initialization     */
 /**************************/
@@ -182,8 +194,10 @@ static const struct ath_ops ath9k_common_ops = {
 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);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        u8 tx_streams, rx_streams;
+       int i, max_streams;
 
        ht_info->ht_supported = true;
        ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -191,28 +205,40 @@ static void setup_ht_cap(struct ath_softc *sc,
                       IEEE80211_HT_CAP_SGI_40 |
                       IEEE80211_HT_CAP_DSSSCCK40;
 
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
+               ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+
        ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
        ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
 
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               max_streams = 3;
+       else
+               max_streams = 2;
+
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               if (max_streams >= 2)
+                       ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+               ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+       }
+
        /* 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;
+       tx_streams = count_streams(common->tx_chainmask, max_streams);
+       rx_streams = count_streams(common->rx_chainmask, max_streams);
+
+       ath_print(common, ATH_DBG_CONFIG,
+                 "TX streams %d, RX streams: %d\n",
+                 tx_streams, rx_streams);
 
        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;
+       for (i = 0; i < rx_streams; i++)
+               ht_info->mcs.rx_mask[i] = 0xff;
 
        ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
 }
@@ -235,31 +261,37 @@ static int ath9k_reg_notifier(struct wiphy *wiphy,
 */
 int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                      struct list_head *head, const char *name,
-                     int nbuf, int ndesc)
+                     int nbuf, int ndesc, bool is_tx)
 {
 #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;
+       u8 *ds;
        struct ath_buf *bf;
-       int i, bsize, error;
+       int i, bsize, error, desc_len;
 
        ath_print(common, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
                  name, nbuf, ndesc);
 
        INIT_LIST_HEAD(head);
+
+       if (is_tx)
+               desc_len = sc->sc_ah->caps.tx_desc_len;
+       else
+               desc_len = sizeof(struct ath_desc);
+
        /* ath_desc must be a multiple of DWORDs */
-       if ((sizeof(struct ath_desc) % 4) != 0) {
+       if ((desc_len % 4) != 0) {
                ath_print(common, ATH_DBG_FATAL,
                          "ath_desc not DWORD aligned\n");
-               BUG_ON((sizeof(struct ath_desc) % 4) != 0);
+               BUG_ON((desc_len % 4) != 0);
                error = -ENOMEM;
                goto fail;
        }
 
-       dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc;
+       dd->dd_desc_len = desc_len * nbuf * ndesc;
 
        /*
         * Need additional DMA memory because we can't use
@@ -272,11 +304,11 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                u32 dma_len;
 
                while (ndesc_skipped) {
-                       dma_len = ndesc_skipped * sizeof(struct ath_desc);
+                       dma_len = ndesc_skipped * desc_len;
                        dd->dd_desc_len += dma_len;
 
                        ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len);
-               };
+               }
        }
 
        /* allocate descriptors */
@@ -286,7 +318,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                error = -ENOMEM;
                goto fail;
        }
-       ds = dd->dd_desc;
+       ds = (u8 *) 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);
@@ -300,7 +332,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
        }
        dd->dd_bufptr = bf;
 
-       for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
+       for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
                bf->bf_desc = ds;
                bf->bf_daddr = DS2PHYS(dd, ds);
 
@@ -316,7 +348,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                                       ((caddr_t) dd->dd_desc +
                                        dd->dd_desc_len));
 
-                               ds += ndesc;
+                               ds += (desc_len * ndesc);
                                bf->bf_desc = ds;
                                bf->bf_daddr = DS2PHYS(dd, ds);
                        }
@@ -514,7 +546,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
        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);
+       ath9k_hw_set_diversity(sc->sc_ah, true);
        sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
@@ -568,13 +600,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
        ath_read_cachesize(common, &csz);
        common->cachelsz = csz << 2; /* convert to bytes */
 
+       /* Initializes the hardware for all supported chipsets */
        ret = ath9k_hw_init(ah);
-       if (ret) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to initialize hardware; "
-                         "initialization status: %d\n", ret);
+       if (ret)
                goto err_hw;
-       }
 
        ret = ath9k_init_debug(ah);
        if (ret) {
@@ -760,6 +789,9 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
 
        tasklet_kill(&sc->intr_tq);
        tasklet_kill(&sc->bcon_tasklet);
+
+       kfree(sc->sc_ah);
+       sc->sc_ah = NULL;
 }
 
 void ath9k_deinit_device(struct ath_softc *sc)
index efc420cd42bf91322f23cf711e638b3f7e8906c2..0e425cb4bbb1b9b8fb189d17792c9758babb1bd1 100644 (file)
@@ -25,14 +25,21 @@ static void ath9k_hw_set_txq_interrupts(struct ath_hw *ah,
                  ah->txdesc_interrupt_mask, ah->txeol_interrupt_mask,
                  ah->txurn_interrupt_mask);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_IMR_S0,
                  SM(ah->txok_interrupt_mask, AR_IMR_S0_QCU_TXOK)
                  | SM(ah->txdesc_interrupt_mask, AR_IMR_S0_QCU_TXDESC));
        REG_WRITE(ah, AR_IMR_S1,
                  SM(ah->txerr_interrupt_mask, AR_IMR_S1_QCU_TXERR)
                  | SM(ah->txeol_interrupt_mask, AR_IMR_S1_QCU_TXEOL));
-       REG_RMW_FIELD(ah, AR_IMR_S2,
-                     AR_IMR_S2_QCU_TXURN, ah->txurn_interrupt_mask);
+
+       ah->imrs2_reg &= ~AR_IMR_S2_QCU_TXURN;
+       ah->imrs2_reg |= (ah->txurn_interrupt_mask & AR_IMR_S2_QCU_TXURN);
+       REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q)
@@ -55,6 +62,18 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q)
 }
 EXPORT_SYMBOL(ath9k_hw_txstart);
 
+void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds)
+{
+       struct ar5416_desc *ads = AR5416DESC(ds);
+
+       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
+       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
+       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
+       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
+       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
+}
+EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
+
 u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q)
 {
        u32 npend;
@@ -103,7 +122,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel)
        if (ah->tx_trig_level >= ah->config.max_txtrig_level)
                return false;
 
-       omask = ath9k_hw_set_interrupts(ah, ah->mask_reg & ~ATH9K_INT_GLOBAL);
+       omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL);
 
        txcfg = REG_READ(ah, AR_TXCFG);
        curLevel = MS(txcfg, AR_FTRIG);
@@ -205,280 +224,6 @@ bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q)
 }
 EXPORT_SYMBOL(ath9k_hw_stoptxdma);
 
-void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
-                        u32 segLen, bool firstSeg,
-                        bool lastSeg, const struct ath_desc *ds0)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       if (firstSeg) {
-               ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore);
-       } else if (lastSeg) {
-               ads->ds_ctl0 = 0;
-               ads->ds_ctl1 = segLen;
-               ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2;
-               ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3;
-       } else {
-               ads->ds_ctl0 = 0;
-               ads->ds_ctl1 = segLen | AR_TxMore;
-               ads->ds_ctl2 = 0;
-               ads->ds_ctl3 = 0;
-       }
-       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
-       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
-       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
-       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
-       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-}
-EXPORT_SYMBOL(ath9k_hw_filltxdesc);
-
-void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       ads->ds_txstatus0 = ads->ds_txstatus1 = 0;
-       ads->ds_txstatus2 = ads->ds_txstatus3 = 0;
-       ads->ds_txstatus4 = ads->ds_txstatus5 = 0;
-       ads->ds_txstatus6 = ads->ds_txstatus7 = 0;
-       ads->ds_txstatus8 = ads->ds_txstatus9 = 0;
-}
-EXPORT_SYMBOL(ath9k_hw_cleartxdesc);
-
-int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       if ((ads->ds_txstatus9 & AR_TxDone) == 0)
-               return -EINPROGRESS;
-
-       ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum);
-       ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp;
-       ds->ds_txstat.ts_status = 0;
-       ds->ds_txstat.ts_flags = 0;
-
-       if (ads->ds_txstatus1 & AR_FrmXmitOK)
-               ds->ds_txstat.ts_status |= ATH9K_TX_ACKED;
-       if (ads->ds_txstatus1 & AR_ExcessiveRetries)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY;
-       if (ads->ds_txstatus1 & AR_Filtered)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT;
-       if (ads->ds_txstatus1 & AR_FIFOUnderrun) {
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO;
-               ath9k_hw_updatetxtriglevel(ah, true);
-       }
-       if (ads->ds_txstatus9 & AR_TxOpExceeded)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP;
-       if (ads->ds_txstatus1 & AR_TxTimerExpired)
-               ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED;
-
-       if (ads->ds_txstatus1 & AR_DescCfgErr)
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR;
-       if (ads->ds_txstatus1 & AR_TxDataUnderrun) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN;
-               ath9k_hw_updatetxtriglevel(ah, true);
-       }
-       if (ads->ds_txstatus1 & AR_TxDelimUnderrun) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN;
-               ath9k_hw_updatetxtriglevel(ah, true);
-       }
-       if (ads->ds_txstatus0 & AR_TxBaStatus) {
-               ds->ds_txstat.ts_flags |= ATH9K_TX_BA;
-               ds->ds_txstat.ba_low = ads->AR_BaBitmapLow;
-               ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh;
-       }
-
-       ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx);
-       switch (ds->ds_txstat.ts_rateindex) {
-       case 0:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0);
-               break;
-       case 1:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1);
-               break;
-       case 2:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2);
-               break;
-       case 3:
-               ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3);
-               break;
-       }
-
-       ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined);
-       ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00);
-       ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01);
-       ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02);
-       ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10);
-       ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11);
-       ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12);
-       ds->ds_txstat.evm0 = ads->AR_TxEVM0;
-       ds->ds_txstat.evm1 = ads->AR_TxEVM1;
-       ds->ds_txstat.evm2 = ads->AR_TxEVM2;
-       ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
-       ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
-       ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
-       ds->ds_txstat.ts_antenna = 0;
-
-       return 0;
-}
-EXPORT_SYMBOL(ath9k_hw_txprocdesc);
-
-void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
-                           u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
-                           u32 keyIx, enum ath9k_key_type keyType, u32 flags)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       txPower += ah->txpower_indexoffset;
-       if (txPower > 63)
-               txPower = 63;
-
-       ads->ds_ctl0 = (pktLen & AR_FrameLen)
-               | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
-               | SM(txPower, AR_XmitPower)
-               | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
-               | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
-               | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
-               | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
-
-       ads->ds_ctl1 =
-               (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0)
-               | SM(type, AR_FrameType)
-               | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0)
-               | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0)
-               | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0);
-
-       ads->ds_ctl6 = SM(keyType, AR_EncrType);
-
-       if (AR_SREV_9285(ah)) {
-               ads->ds_ctl8 = 0;
-               ads->ds_ctl9 = 0;
-               ads->ds_ctl10 = 0;
-               ads->ds_ctl11 = 0;
-       }
-}
-EXPORT_SYMBOL(ath9k_hw_set11n_txdesc);
-
-void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
-                                 struct ath_desc *lastds,
-                                 u32 durUpdateEn, u32 rtsctsRate,
-                                 u32 rtsctsDuration,
-                                 struct ath9k_11n_rate_series series[],
-                                 u32 nseries, u32 flags)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-       struct ar5416_desc *last_ads = AR5416DESC(lastds);
-       u32 ds_ctl0;
-
-       if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) {
-               ds_ctl0 = ads->ds_ctl0;
-
-               if (flags & ATH9K_TXDESC_RTSENA) {
-                       ds_ctl0 &= ~AR_CTSEnable;
-                       ds_ctl0 |= AR_RTSEnable;
-               } else {
-                       ds_ctl0 &= ~AR_RTSEnable;
-                       ds_ctl0 |= AR_CTSEnable;
-               }
-
-               ads->ds_ctl0 = ds_ctl0;
-       } else {
-               ads->ds_ctl0 =
-                       (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
-       }
-
-       ads->ds_ctl2 = set11nTries(series, 0)
-               | set11nTries(series, 1)
-               | set11nTries(series, 2)
-               | set11nTries(series, 3)
-               | (durUpdateEn ? AR_DurUpdateEna : 0)
-               | SM(0, AR_BurstDur);
-
-       ads->ds_ctl3 = set11nRate(series, 0)
-               | set11nRate(series, 1)
-               | set11nRate(series, 2)
-               | set11nRate(series, 3);
-
-       ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
-               | set11nPktDurRTSCTS(series, 1);
-
-       ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
-               | set11nPktDurRTSCTS(series, 3);
-
-       ads->ds_ctl7 = set11nRateFlags(series, 0)
-               | set11nRateFlags(series, 1)
-               | set11nRateFlags(series, 2)
-               | set11nRateFlags(series, 3)
-               | SM(rtsctsRate, AR_RTSCTSRate);
-       last_ads->ds_ctl2 = ads->ds_ctl2;
-       last_ads->ds_ctl3 = ads->ds_ctl3;
-}
-EXPORT_SYMBOL(ath9k_hw_set11n_ratescenario);
-
-void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
-                               u32 aggrLen)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-       ads->ds_ctl6 &= ~AR_AggrLen;
-       ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen);
-}
-EXPORT_SYMBOL(ath9k_hw_set11n_aggr_first);
-
-void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
-                                u32 numDelims)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-       unsigned int ctl6;
-
-       ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr);
-
-       ctl6 = ads->ds_ctl6;
-       ctl6 &= ~AR_PadDelim;
-       ctl6 |= SM(numDelims, AR_PadDelim);
-       ads->ds_ctl6 = ctl6;
-}
-EXPORT_SYMBOL(ath9k_hw_set11n_aggr_middle);
-
-void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       ads->ds_ctl1 |= AR_IsAggr;
-       ads->ds_ctl1 &= ~AR_MoreAggr;
-       ads->ds_ctl6 &= ~AR_PadDelim;
-}
-EXPORT_SYMBOL(ath9k_hw_set11n_aggr_last);
-
-void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
-}
-EXPORT_SYMBOL(ath9k_hw_clr11n_aggr);
-
-void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
-                                  u32 burstDuration)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       ads->ds_ctl2 &= ~AR_BurstDur;
-       ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
-}
-EXPORT_SYMBOL(ath9k_hw_set11n_burstduration);
-
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
-                                    u32 vmf)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-
-       if (vmf)
-               ads->ds_ctl0 |= AR_VirtMoreFrag;
-       else
-               ads->ds_ctl0 &= ~AR_VirtMoreFrag;
-}
-
 void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs)
 {
        *txqs &= ah->intr_txqs;
@@ -730,6 +475,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
        } else
                cwMin = qi->tqi_cwmin;
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_DLCL_IFS(q),
                  SM(cwMin, AR_D_LCL_IFS_CWMIN) |
                  SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) |
@@ -744,6 +491,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
        REG_WRITE(ah, AR_DMISC(q),
                  AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+
        if (qi->tqi_cbrPeriod) {
                REG_WRITE(ah, AR_QCBRCFG(q),
                          SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
@@ -759,6 +508,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                          AR_Q_RDYTIMECFG_EN);
        }
 
+       REGWRITE_BUFFER_FLUSH(ah);
+
        REG_WRITE(ah, AR_DCHNTIME(q),
                  SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) |
                  (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
@@ -776,6 +527,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                          REG_READ(ah, AR_DMISC(q)) |
                          AR_D_MISC_POST_FR_BKOFF_DIS);
        }
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
                REG_WRITE(ah, AR_DMISC(q),
                          REG_READ(ah, AR_DMISC(q)) |
@@ -783,6 +538,8 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
        }
        switch (qi->tqi_type) {
        case ATH9K_TX_QUEUE_BEACON:
+               ENABLE_REGWRITE_BUFFER(ah);
+
                REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
                          | AR_Q_MISC_FSP_DBA_GATED
                          | AR_Q_MISC_BEACON_USE
@@ -793,8 +550,20 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                             AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
                          | AR_D_MISC_BEACON_USE
                          | AR_D_MISC_POST_FR_BKOFF_DIS);
+
+               REGWRITE_BUFFER_FLUSH(ah);
+               DISABLE_REGWRITE_BUFFER(ah);
+
+               /* cwmin and cwmax should be 0 for beacon queue */
+               if (AR_SREV_9300_20_OR_LATER(ah)) {
+                       REG_WRITE(ah, AR_DLCL_IFS(q), SM(0, AR_D_LCL_IFS_CWMIN)
+                                 | SM(0, AR_D_LCL_IFS_CWMAX)
+                                 | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS));
+               }
                break;
        case ATH9K_TX_QUEUE_CAB:
+               ENABLE_REGWRITE_BUFFER(ah);
+
                REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
                          | AR_Q_MISC_FSP_DBA_GATED
                          | AR_Q_MISC_CBR_INCR_DIS1
@@ -808,6 +577,10 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
                          | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
                             AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
+
+               REGWRITE_BUFFER_FLUSH(ah);
+               DISABLE_REGWRITE_BUFFER(ah);
+
                break;
        case ATH9K_TX_QUEUE_PSPOLL:
                REG_WRITE(ah, AR_QMISC(q),
@@ -829,6 +602,9 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
                          AR_D_MISC_POST_FR_BKOFF_DIS);
        }
 
+       if (AR_SREV_9300_20_OR_LATER(ah))
+               REG_WRITE(ah, AR_Q_DESC_CRCCHK, AR_Q_DESC_CRCCHK_EN);
+
        if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE)
                ah->txok_interrupt_mask |= 1 << q;
        else
@@ -856,7 +632,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 EXPORT_SYMBOL(ath9k_hw_resettxqueue);
 
 int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
-                       u32 pa, struct ath_desc *nds, u64 tsf)
+                       struct ath_rx_status *rs, u64 tsf)
 {
        struct ar5416_desc ads;
        struct ar5416_desc *adsp = AR5416DESC(ds);
@@ -867,92 +643,76 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
 
        ads.u.rx = adsp->u.rx;
 
-       ds->ds_rxstat.rs_status = 0;
-       ds->ds_rxstat.rs_flags = 0;
+       rs->rs_status = 0;
+       rs->rs_flags = 0;
 
-       ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
-       ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
+       rs->rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
+       rs->rs_tstamp = ads.AR_RcvTimestamp;
 
        if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
-               ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
-               ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
+               rs->rs_rssi = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
+               rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
        } else {
-               ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
-               ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+               rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt00);
-               ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt01);
-               ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+               rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
                                                AR_RxRSSIAnt02);
-               ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt10);
-               ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt11);
-               ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+               rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
                                                AR_RxRSSIAnt12);
        }
        if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
-               ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
+               rs->rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
        else
-               ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID;
+               rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
 
-       ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads));
-       ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
+       rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
+       rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
 
-       ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
-       ds->ds_rxstat.rs_moreaggr =
+       rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
+       rs->rs_moreaggr =
                (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0;
-       ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
-       ds->ds_rxstat.rs_flags =
+       rs->rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna);
+       rs->rs_flags =
                (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0;
-       ds->ds_rxstat.rs_flags |=
+       rs->rs_flags |=
                (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0;
 
        if (ads.ds_rxstatus8 & AR_PreDelimCRCErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
+               rs->rs_flags |= ATH9K_RX_DELIM_CRC_PRE;
        if (ads.ds_rxstatus8 & AR_PostDelimCRCErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST;
+               rs->rs_flags |= ATH9K_RX_DELIM_CRC_POST;
        if (ads.ds_rxstatus8 & AR_DecryptBusyErr)
-               ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY;
+               rs->rs_flags |= ATH9K_RX_DECRYPT_BUSY;
 
        if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) {
                if (ads.ds_rxstatus8 & AR_CRCErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC;
+                       rs->rs_status |= ATH9K_RXERR_CRC;
                else if (ads.ds_rxstatus8 & AR_PHYErr) {
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY;
+                       rs->rs_status |= ATH9K_RXERR_PHY;
                        phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode);
-                       ds->ds_rxstat.rs_phyerr = phyerr;
+                       rs->rs_phyerr = phyerr;
                } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT;
+                       rs->rs_status |= ATH9K_RXERR_DECRYPT;
                else if (ads.ds_rxstatus8 & AR_MichaelErr)
-                       ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC;
+                       rs->rs_status |= ATH9K_RXERR_MIC;
        }
 
        return 0;
 }
 EXPORT_SYMBOL(ath9k_hw_rxprocdesc);
 
-void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
-                         u32 size, u32 flags)
-{
-       struct ar5416_desc *ads = AR5416DESC(ds);
-       struct ath9k_hw_capabilities *pCap = &ah->caps;
-
-       ads->ds_ctl1 = size & AR_BufLen;
-       if (flags & ATH9K_RXDESC_INTREQ)
-               ads->ds_ctl1 |= AR_RxIntrReq;
-
-       ads->ds_rxstatus8 &= ~AR_RxDone;
-       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
-               memset(&(ads->u), 0, sizeof(ads->u));
-}
-EXPORT_SYMBOL(ath9k_hw_setuprxdesc);
-
 /*
  * This can stop or re-enables RX.
  *
@@ -996,12 +756,6 @@ void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp)
 }
 EXPORT_SYMBOL(ath9k_hw_putrxbuf);
 
-void ath9k_hw_rxena(struct ath_hw *ah)
-{
-       REG_WRITE(ah, AR_CR, AR_CR_RXE);
-}
-EXPORT_SYMBOL(ath9k_hw_rxena);
-
 void ath9k_hw_startpcureceive(struct ath_hw *ah)
 {
        ath9k_enable_mib_counters(ah);
@@ -1020,6 +774,14 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
 
+void ath9k_hw_abortpcurecv(struct ath_hw *ah)
+{
+       REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
+
+       ath9k_hw_disable_mib_counters(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_abortpcurecv);
+
 bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
 {
 #define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
@@ -1065,3 +827,142 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah)
        return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
 }
 EXPORT_SYMBOL(ath9k_hw_beaconq_setup);
+
+bool ath9k_hw_intrpend(struct ath_hw *ah)
+{
+       u32 host_isr;
+
+       if (AR_SREV_9100(ah))
+               return true;
+
+       host_isr = REG_READ(ah, AR_INTR_ASYNC_CAUSE);
+       if ((host_isr & AR_INTR_MAC_IRQ) && (host_isr != AR_INTR_SPURIOUS))
+               return true;
+
+       host_isr = REG_READ(ah, AR_INTR_SYNC_CAUSE);
+       if ((host_isr & AR_INTR_SYNC_DEFAULT)
+           && (host_isr != AR_INTR_SPURIOUS))
+               return true;
+
+       return false;
+}
+EXPORT_SYMBOL(ath9k_hw_intrpend);
+
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
+                                             enum ath9k_int ints)
+{
+       enum ath9k_int omask = ah->imask;
+       u32 mask, mask2;
+       struct ath9k_hw_capabilities *pCap = &ah->caps;
+       struct ath_common *common = ath9k_hw_common(ah);
+
+       ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints);
+
+       if (omask & ATH9K_INT_GLOBAL) {
+               ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n");
+               REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
+               (void) REG_READ(ah, AR_IER);
+               if (!AR_SREV_9100(ah)) {
+                       REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0);
+                       (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE);
+
+                       REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0);
+                       (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
+               }
+       }
+
+       /* TODO: global int Ref count */
+       mask = ints & ATH9K_INT_COMMON;
+       mask2 = 0;
+
+       if (ints & ATH9K_INT_TX) {
+               if (ah->config.tx_intr_mitigation)
+                       mask |= AR_IMR_TXMINTR | AR_IMR_TXINTM;
+               else {
+                       if (ah->txok_interrupt_mask)
+                               mask |= AR_IMR_TXOK;
+                       if (ah->txdesc_interrupt_mask)
+                               mask |= AR_IMR_TXDESC;
+               }
+               if (ah->txerr_interrupt_mask)
+                       mask |= AR_IMR_TXERR;
+               if (ah->txeol_interrupt_mask)
+                       mask |= AR_IMR_TXEOL;
+       }
+       if (ints & ATH9K_INT_RX) {
+               if (AR_SREV_9300_20_OR_LATER(ah)) {
+                       mask |= AR_IMR_RXERR | AR_IMR_RXOK_HP;
+                       if (ah->config.rx_intr_mitigation) {
+                               mask &= ~AR_IMR_RXOK_LP;
+                               mask |=  AR_IMR_RXMINTR | AR_IMR_RXINTM;
+                       } else {
+                               mask |= AR_IMR_RXOK_LP;
+                       }
+               } else {
+                       if (ah->config.rx_intr_mitigation)
+                               mask |= AR_IMR_RXMINTR | AR_IMR_RXINTM;
+                       else
+                               mask |= AR_IMR_RXOK | AR_IMR_RXDESC;
+               }
+               if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+                       mask |= AR_IMR_GENTMR;
+       }
+
+       if (ints & (ATH9K_INT_BMISC)) {
+               mask |= AR_IMR_BCNMISC;
+               if (ints & ATH9K_INT_TIM)
+                       mask2 |= AR_IMR_S2_TIM;
+               if (ints & ATH9K_INT_DTIM)
+                       mask2 |= AR_IMR_S2_DTIM;
+               if (ints & ATH9K_INT_DTIMSYNC)
+                       mask2 |= AR_IMR_S2_DTIMSYNC;
+               if (ints & ATH9K_INT_CABEND)
+                       mask2 |= AR_IMR_S2_CABEND;
+               if (ints & ATH9K_INT_TSFOOR)
+                       mask2 |= AR_IMR_S2_TSFOOR;
+       }
+
+       if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
+               mask |= AR_IMR_BCNMISC;
+               if (ints & ATH9K_INT_GTT)
+                       mask2 |= AR_IMR_S2_GTT;
+               if (ints & ATH9K_INT_CST)
+                       mask2 |= AR_IMR_S2_CST;
+       }
+
+       ath_print(common, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask);
+       REG_WRITE(ah, AR_IMR, mask);
+       ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
+                          AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
+                          AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST);
+       ah->imrs2_reg |= mask2;
+       REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
+
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+               if (ints & ATH9K_INT_TIM_TIMER)
+                       REG_SET_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+               else
+                       REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER);
+       }
+
+       if (ints & ATH9K_INT_GLOBAL) {
+               ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n");
+               REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
+               if (!AR_SREV_9100(ah)) {
+                       REG_WRITE(ah, AR_INTR_ASYNC_ENABLE,
+                                 AR_INTR_MAC_IRQ);
+                       REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
+
+
+                       REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
+                                 AR_INTR_SYNC_DEFAULT);
+                       REG_WRITE(ah, AR_INTR_SYNC_MASK,
+                                 AR_INTR_SYNC_DEFAULT);
+               }
+               ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
+                         REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
+       }
+
+       return omask;
+}
+EXPORT_SYMBOL(ath9k_hw_set_interrupts);
index 29851e6376a9606a095cc6c2d88ab7078e6b5af6..00f3e0c7528a185e31abe85a2ce520e7524e2a12 100644 (file)
@@ -37,6 +37,8 @@
          AR_2040_##_index : 0)                                         \
         |((_series)[_index].RateFlags & ATH9K_RATESERIES_HALFGI ?      \
           AR_GI##_index : 0)                                           \
+        |((_series)[_index].RateFlags & ATH9K_RATESERIES_STBC ?        \
+          AR_STBC##_index : 0)                                         \
         |SM((_series)[_index].ChSel, AR_ChainSel##_index))
 
 #define CCK_SIFS_TIME        10
@@ -86,7 +88,6 @@
 #define ATH9K_TX_DESC_CFG_ERR      0x04
 #define ATH9K_TX_DATA_UNDERRUN     0x08
 #define ATH9K_TX_DELIM_UNDERRUN    0x10
-#define ATH9K_TX_SW_ABORTED        0x40
 #define ATH9K_TX_SW_FILTERED       0x80
 
 /* 64 bytes */
@@ -117,7 +118,10 @@ struct ath_tx_status {
        int8_t ts_rssi_ext0;
        int8_t ts_rssi_ext1;
        int8_t ts_rssi_ext2;
-       u8 pad[3];
+       u8 qid;
+       u16 desc_id;
+       u8 tid;
+       u8 pad[2];
        u32 ba_low;
        u32 ba_high;
        u32 evm0;
@@ -148,6 +152,34 @@ struct ath_rx_status {
        u32 evm0;
        u32 evm1;
        u32 evm2;
+       u32 evm3;
+       u32 evm4;
+};
+
+struct ath_htc_rx_status {
+       __be64 rs_tstamp;
+       __be16 rs_datalen;
+       u8 rs_status;
+       u8 rs_phyerr;
+       int8_t rs_rssi;
+       int8_t rs_rssi_ctl0;
+       int8_t rs_rssi_ctl1;
+       int8_t rs_rssi_ctl2;
+       int8_t rs_rssi_ext0;
+       int8_t rs_rssi_ext1;
+       int8_t rs_rssi_ext2;
+       u8 rs_keyix;
+       u8 rs_rate;
+       u8 rs_antenna;
+       u8 rs_more;
+       u8 rs_isaggr;
+       u8 rs_moreaggr;
+       u8 rs_num_delims;
+       u8 rs_flags;
+       u8 rs_dummy;
+       __be32 evm0;
+       __be32 evm1;
+       __be32 evm2;
 };
 
 #define ATH9K_RXERR_CRC           0x01
@@ -207,18 +239,9 @@ struct ath_desc {
        u32 ds_ctl0;
        u32 ds_ctl1;
        u32 ds_hw[20];
-       union {
-               struct ath_tx_status tx;
-               struct ath_rx_status rx;
-               void *stats;
-       } ds_us;
        void *ds_vdata;
 } __packed;
 
-#define        ds_txstat       ds_us.tx
-#define        ds_rxstat       ds_us.rx
-#define ds_stat                ds_us.stats
-
 #define ATH9K_TXDESC_CLRDMASK          0x0001
 #define ATH9K_TXDESC_NOACK             0x0002
 #define ATH9K_TXDESC_RTSENA            0x0004
@@ -242,7 +265,8 @@ struct ath_desc {
 #define ATH9K_TXDESC_EXT_AND_CTL       0x0080
 #define ATH9K_TXDESC_VMF               0x0100
 #define ATH9K_TXDESC_FRAG_IS_ON        0x0200
-#define ATH9K_TXDESC_CAB               0x0400
+#define ATH9K_TXDESC_LOWRXCHAIN                0x0400
+#define ATH9K_TXDESC_LDPC              0x00010000
 
 #define ATH9K_RXDESC_INTREQ            0x0020
 
@@ -336,7 +360,6 @@ struct ar5416_desc {
 #define AR_DestIdxValid     0x40000000
 #define AR_CTSEnable        0x80000000
 
-#define AR_BufLen           0x00000fff
 #define AR_TxMore           0x00001000
 #define AR_DestIdx          0x000fe000
 #define AR_DestIdx_S        13
@@ -393,6 +416,7 @@ struct ar5416_desc {
 #define AR_EncrType         0x0c000000
 #define AR_EncrType_S       26
 #define AR_TxCtlRsvd61      0xf0000000
+#define AR_LDPC             0x80000000
 
 #define AR_2040_0           0x00000001
 #define AR_GI0              0x00000002
@@ -412,7 +436,10 @@ struct ar5416_desc {
 #define AR_ChainSel3_S      17
 #define AR_RTSCTSRate       0x0ff00000
 #define AR_RTSCTSRate_S     20
-#define AR_TxCtlRsvd70      0xf0000000
+#define AR_STBC0            0x10000000
+#define AR_STBC1            0x20000000
+#define AR_STBC2            0x40000000
+#define AR_STBC3            0x80000000
 
 #define AR_TxRSSIAnt00      0x000000ff
 #define AR_TxRSSIAnt00_S    0
@@ -476,7 +503,6 @@ struct ar5416_desc {
 
 #define AR_RxCTLRsvd00  0xffffffff
 
-#define AR_BufLen       0x00000fff
 #define AR_RxCtlRsvd00  0x00001000
 #define AR_RxIntrReq    0x00002000
 #define AR_RxCtlRsvd01  0xffffc000
@@ -626,6 +652,7 @@ enum ath9k_rx_filter {
 #define ATH9K_RATESERIES_RTS_CTS  0x0001
 #define ATH9K_RATESERIES_2040     0x0002
 #define ATH9K_RATESERIES_HALFGI   0x0004
+#define ATH9K_RATESERIES_STBC     0x0008
 
 struct ath9k_11n_rate_series {
        u32 Tries;
@@ -669,33 +696,10 @@ struct ath9k_channel;
 u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q);
 void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp);
 void ath9k_hw_txstart(struct ath_hw *ah, u32 q);
+void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds);
 u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q);
 bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel);
 bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q);
-void ath9k_hw_filltxdesc(struct ath_hw *ah, struct ath_desc *ds,
-                        u32 segLen, bool firstSeg,
-                        bool lastSeg, const struct ath_desc *ds0);
-void ath9k_hw_cleartxdesc(struct ath_hw *ah, struct ath_desc *ds);
-int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_txdesc(struct ath_hw *ah, struct ath_desc *ds,
-                           u32 pktLen, enum ath9k_pkt_type type, u32 txPower,
-                           u32 keyIx, enum ath9k_key_type keyType, u32 flags);
-void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, struct ath_desc *ds,
-                                 struct ath_desc *lastds,
-                                 u32 durUpdateEn, u32 rtsctsRate,
-                                 u32 rtsctsDuration,
-                                 struct ath9k_11n_rate_series series[],
-                                 u32 nseries, u32 flags);
-void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, struct ath_desc *ds,
-                               u32 aggrLen);
-void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, struct ath_desc *ds,
-                                u32 numDelims);
-void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, struct ath_desc *ds);
-void ath9k_hw_clr11n_aggr(struct ath_hw *ah, struct ath_desc *ds);
-void ath9k_hw_set11n_burstduration(struct ath_hw *ah, struct ath_desc *ds,
-                                  u32 burstDuration);
-void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, struct ath_desc *ds,
-                                    u32 vmf);
 void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs);
 bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
                            const struct ath9k_tx_queue_info *qinfo);
@@ -706,15 +710,22 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
 bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q);
 bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q);
 int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
-                       u32 pa, struct ath_desc *nds, u64 tsf);
+                       struct ath_rx_status *rs, u64 tsf);
 void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
                          u32 size, u32 flags);
 bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
 void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
-void ath9k_hw_rxena(struct ath_hw *ah);
 void ath9k_hw_startpcureceive(struct ath_hw *ah);
 void ath9k_hw_stoppcurecv(struct ath_hw *ah);
+void ath9k_hw_abortpcurecv(struct ath_hw *ah);
 bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
 int ath9k_hw_beaconq_setup(struct ath_hw *ah);
 
+/* Interrupt Handling */
+bool ath9k_hw_intrpend(struct ath_hw *ah);
+enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah,
+                                      enum ath9k_int ints);
+
+void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
+
 #endif /* MAC_H */
index 115e1aeedb592128c615026ed8bc677276fbd91e..893b552981a07494413288064dd9601be1e3373e 100644 (file)
@@ -225,7 +225,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 
        ath_cache_conf_rate(sc, &hw->conf);
        ath_update_txpow(sc);
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
  ps_restore:
        ath9k_ps_restore(sc);
@@ -401,23 +401,41 @@ void ath9k_tasklet(unsigned long data)
        struct ath_common *common = ath9k_hw_common(ah);
 
        u32 status = sc->intrstatus;
+       u32 rxmask;
 
        ath9k_ps_wakeup(sc);
 
-       if (status & ATH9K_INT_FATAL) {
+       if ((status & ATH9K_INT_FATAL) ||
+           !ath9k_hw_check_alive(ah)) {
                ath_reset(sc, false);
                ath9k_ps_restore(sc);
                return;
        }
 
-       if (status & (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) {
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
+                         ATH9K_INT_RXORN);
+       else
+               rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+
+       if (status & rxmask) {
                spin_lock_bh(&sc->rx.rxflushlock);
-               ath_rx_tasklet(sc, 0);
+
+               /* Check for high priority Rx first */
+               if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+                   (status & ATH9K_INT_RXHP))
+                       ath_rx_tasklet(sc, 0, true);
+
+               ath_rx_tasklet(sc, 0, false);
                spin_unlock_bh(&sc->rx.rxflushlock);
        }
 
-       if (status & ATH9K_INT_TX)
-               ath_tx_tasklet(sc);
+       if (status & ATH9K_INT_TX) {
+               if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+                       ath_tx_edma_tasklet(sc);
+               else
+                       ath_tx_tasklet(sc);
+       }
 
        if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                /*
@@ -434,7 +452,7 @@ void ath9k_tasklet(unsigned long data)
                        ath_gen_timer_isr(sc->sc_ah);
 
        /* re-enable hardware interrupt */
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
        ath9k_ps_restore(sc);
 }
 
@@ -445,6 +463,8 @@ irqreturn_t ath_isr(int irq, void *dev)
                ATH9K_INT_RXORN |               \
                ATH9K_INT_RXEOL |               \
                ATH9K_INT_RX |                  \
+               ATH9K_INT_RXLP |                \
+               ATH9K_INT_RXHP |                \
                ATH9K_INT_TX |                  \
                ATH9K_INT_BMISS |               \
                ATH9K_INT_CST |                 \
@@ -477,7 +497,7 @@ irqreturn_t ath_isr(int irq, void *dev)
         * value to insure we only process bits we requested.
         */
        ath9k_hw_getisr(ah, &status);   /* NB: clears ISR too */
-       status &= sc->imask;    /* discard unasked-for bits */
+       status &= ah->imask;    /* discard unasked-for bits */
 
        /*
         * If there are no status bits set, then this interrupt was not
@@ -496,7 +516,8 @@ irqreturn_t ath_isr(int irq, void *dev)
         * If a FATAL or RXORN interrupt is received, we have to reset the
         * chip immediately.
         */
-       if (status & (ATH9K_INT_FATAL | ATH9K_INT_RXORN))
+       if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) &&
+           !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
                goto chip_reset;
 
        if (status & ATH9K_INT_SWBA)
@@ -505,6 +526,13 @@ irqreturn_t ath_isr(int irq, void *dev)
        if (status & ATH9K_INT_TXURN)
                ath9k_hw_updatetxtriglevel(ah, true);
 
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               if (status & ATH9K_INT_RXEOL) {
+                       ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN);
+                       ath9k_hw_set_interrupts(ah, ah->imask);
+               }
+       }
+
        if (status & ATH9K_INT_MIB) {
                /*
                 * Disable interrupts until we service the MIB
@@ -518,7 +546,7 @@ irqreturn_t ath_isr(int irq, void *dev)
                 * the interrupt.
                 */
                ath9k_hw_procmibevent(ah);
-               ath9k_hw_set_interrupts(ah, sc->imask);
+               ath9k_hw_set_interrupts(ah, ah->imask);
        }
 
        if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
@@ -536,7 +564,7 @@ chip_reset:
 
        if (sched) {
                /* turn off every interrupt except SWBA */
-               ath9k_hw_set_interrupts(ah, (sc->imask & ATH9K_INT_SWBA));
+               ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA));
                tasklet_schedule(&sc->intr_tq);
        }
 
@@ -724,6 +752,7 @@ static int ath_key_config(struct ath_common *common,
        struct ath_hw *ah = common->ah;
        struct ath9k_keyval hk;
        const u8 *mac = NULL;
+       u8 gmac[ETH_ALEN];
        int ret = 0;
        int idx;
 
@@ -747,9 +776,30 @@ static int ath_key_config(struct ath_common *common,
        memcpy(hk.kv_val, key->key, key->keylen);
 
        if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-               /* For now, use the default keys for broadcast keys. This may
-                * need to change with virtual interfaces. */
-               idx = key->keyidx;
+
+               if (key->ap_addr) {
+                       /*
+                        * Group keys on hardware that supports multicast frame
+                        * key search use a mac that is the sender's address with
+                        * the high bit set instead of the app-specified address.
+                        */
+                       memcpy(gmac, key->ap_addr, ETH_ALEN);
+                       gmac[0] |= 0x80;
+                       mac = gmac;
+
+                       if (key->alg == ALG_TKIP)
+                               idx = ath_reserve_key_cache_slot_tkip(common);
+                       else
+                               idx = ath_reserve_key_cache_slot(common);
+                       if (idx < 0)
+                               mac = NULL; /* no free key cache entries */
+               }
+
+               if (!mac) {
+                       /* For now, use the default keys for broadcast keys. This may
+                        * need to change with virtual interfaces. */
+                       idx = key->keyidx;
+               }
        } else if (key->keyidx) {
                if (WARN_ON(!sta))
                        return -EOPNOTSUPP;
@@ -887,7 +937,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
                ath_beacon_config(sc, NULL);    /* restart beacons */
 
        /* Re-Enable  interrupts */
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* Enable LED */
        ath9k_hw_cfg_output(ah, ah->led_pin,
@@ -977,7 +1027,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        if (sc->sc_flags & SC_OP_BEACONS)
                ath_beacon_config(sc, NULL);    /* restart beacons */
 
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        if (retry_tx) {
                int i;
@@ -1162,23 +1212,28 @@ static int ath9k_start(struct ieee80211_hw *hw)
        }
 
        /* Setup our intr mask. */
-       sc->imask = ATH9K_INT_RX | ATH9K_INT_TX
-               | ATH9K_INT_RXEOL | ATH9K_INT_RXORN
-               | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL;
+       ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL |
+                   ATH9K_INT_RXORN | ATH9K_INT_FATAL |
+                   ATH9K_INT_GLOBAL;
+
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               ah->imask |= ATH9K_INT_RXHP | ATH9K_INT_RXLP;
+       else
+               ah->imask |= ATH9K_INT_RX;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_GTT)
-               sc->imask |= ATH9K_INT_GTT;
+               ah->imask |= ATH9K_INT_GTT;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
-               sc->imask |= ATH9K_INT_CST;
+               ah->imask |= ATH9K_INT_CST;
 
        ath_cache_conf_rate(sc, &hw->conf);
 
        sc->sc_flags &= ~SC_OP_INVALID;
 
        /* Disable BMISS interrupt when we're not associated */
-       sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
-       ath9k_hw_set_interrupts(ah, sc->imask);
+       ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        ieee80211_wake_queues(hw);
 
@@ -1372,14 +1427,15 @@ static int ath9k_add_interface(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);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
        enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
        int ret = 0;
 
        mutex_lock(&sc->mutex);
 
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
            sc->nvifs > 0) {
                ret = -ENOBUFS;
                goto out;
@@ -1414,19 +1470,19 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
 
        sc->nvifs++;
 
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
                ath9k_set_bssid_mask(hw);
 
        if (sc->nvifs > 1)
                goto out; /* skip global settings for secondary vif */
 
        if (ic_opmode == NL80211_IFTYPE_AP) {
-               ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+               ath9k_hw_set_tsfadjust(ah, 1);
                sc->sc_flags |= SC_OP_TSF_RESET;
        }
 
        /* Set the device opmode */
-       sc->sc_ah->opmode = ic_opmode;
+       ah->opmode = ic_opmode;
 
        /*
         * Enable MIB interrupts when there are hardware phy counters.
@@ -1435,11 +1491,12 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        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;
+               if (ah->config.enable_ani)
+                       ah->imask |= ATH9K_INT_MIB;
+               ah->imask |= ATH9K_INT_TSFOOR;
        }
 
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        if (vif->type == NL80211_IFTYPE_AP    ||
            vif->type == NL80211_IFTYPE_ADHOC ||
@@ -1495,15 +1552,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
 void ath9k_enable_ps(struct ath_softc *sc)
 {
+       struct ath_hw *ah = sc->sc_ah;
+
        sc->ps_enabled = true;
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
-               if ((sc->imask & ATH9K_INT_TIM_TIMER) == 0) {
-                       sc->imask |= ATH9K_INT_TIM_TIMER;
-                       ath9k_hw_set_interrupts(sc->sc_ah,
-                                       sc->imask);
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
+               if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) {
+                       ah->imask |= ATH9K_INT_TIM_TIMER;
+                       ath9k_hw_set_interrupts(ah, ah->imask);
                }
        }
-       ath9k_hw_setrxabort(sc->sc_ah, 1);
+       ath9k_hw_setrxabort(ah, 1);
 }
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1579,10 +1637,10 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                                                  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;
+                               if (ah->imask & ATH9K_INT_TIM_TIMER) {
+                                       ah->imask &= ~ATH9K_INT_TIM_TIMER;
                                        ath9k_hw_set_interrupts(sc->sc_ah,
-                                                       sc->imask);
+                                                       ah->imask);
                                }
                        }
                }
@@ -1986,6 +2044,25 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
        return ret;
 }
 
+static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
+                            struct survey_info *survey)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_conf *conf = &hw->conf;
+
+        if (idx != 0)
+               return -ENOENT;
+
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = common->ani.noise_floor;
+
+       return 0;
+}
+
 static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
 {
        struct ath_wiphy *aphy = hw->priv;
@@ -2057,6 +2134,7 @@ struct ieee80211_ops ath9k_ops = {
        .set_tsf            = ath9k_set_tsf,
        .reset_tsf          = ath9k_reset_tsf,
        .ampdu_action       = ath9k_ampdu_action,
+       .get_survey         = ath9k_get_survey,
        .sw_scan_start      = ath9k_sw_scan_start,
        .sw_scan_complete   = ath9k_sw_scan_complete,
        .rfkill_poll        = ath9k_rfkill_poll_state,
index 9441c6718a3098a760c0c0d1a13819b3fe8524aa..257b10ba6f57e2b4c7e99872ef046709ba7c668f 100644 (file)
@@ -28,6 +28,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */
        { PCI_VDEVICE(ATHEROS, 0x002D) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */
+       { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E  AR9300 */
        { 0 }
 };
 
@@ -88,6 +89,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common)
 }
 
 static const struct ath_bus_ops ath_pci_bus_ops = {
+       .ath_bus_type = ATH_PCI,
        .read_cachesize = ath_pci_read_cachesize,
        .eeprom_read = ath_pci_eeprom_read,
        .bt_coex_prep = ath_pci_bt_coex_prep,
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
deleted file mode 100644 (file)
index 2547b3c..0000000
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * DOC: Programming Atheros 802.11n analog front end radios
- *
- * AR5416 MAC based PCI devices and AR518 MAC based PCI-Express
- * devices have either an external AR2133 analog front end radio for single
- * band 2.4 GHz communication or an AR5133 analog front end radio for dual
- * band 2.4 GHz / 5 GHz communication.
- *
- * All devices after the AR5416 and AR5418 family starting with the AR9280
- * have their analog front radios, MAC/BB and host PCIe/USB interface embedded
- * into a single-chip and require less programming.
- *
- * The following single-chips exist with a respective embedded radio:
- *
- * AR9280 - 11n dual-band 2x2 MIMO for PCIe
- * AR9281 - 11n single-band 1x2 MIMO for PCIe
- * AR9285 - 11n single-band 1x1 for PCIe
- * AR9287 - 11n single-band 2x2 MIMO for PCIe
- *
- * AR9220 - 11n dual-band 2x2 MIMO for PCI
- * AR9223 - 11n single-band 2x2 MIMO for PCI
- *
- * AR9287 - 11n single-band 1x1 MIMO for USB
- */
-
-#include <linux/slab.h>
-
-#include "hw.h"
-
-/**
- * ath9k_hw_write_regs - ??
- *
- * @ah: atheros hardware structure
- * @freqIndex:
- * @regWrites:
- *
- * Used for both the chipsets with an external AR2133/AR5133 radios and
- * single-chip devices.
- */
-void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites)
-{
-       REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites);
-}
-
-/**
- * ath9k_hw_ar9280_set_channel - set channel on single-chip device
- * @ah: atheros hardware structure
- * @chan:
- *
- * This is the function to change channel on single-chip devices, that is
- * all devices after ar9280.
- *
- * This function takes the channel value in MHz and sets
- * hardware channel value. Assumes writes have been enabled to analog bus.
- *
- * Actual Expression,
- *
- * For 2GHz channel,
- * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17)
- * (freq_ref = 40MHz)
- *
- * For 5GHz channel,
- * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10)
- * (freq_ref = 40MHz/(24>>amodeRefSel))
- */
-int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       u16 bMode, fracMode, aModeRefSel = 0;
-       u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
-       struct chan_centers centers;
-       u32 refDivA = 24;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       freq = centers.synth_center;
-
-       reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
-       reg32 &= 0xc0000000;
-
-       if (freq < 4800) { /* 2 GHz, fractional mode */
-               u32 txctl;
-               int regWrites = 0;
-
-               bMode = 1;
-               fracMode = 1;
-               aModeRefSel = 0;
-               channelSel = (freq * 0x10000) / 15;
-
-               if (AR_SREV_9287_11_OR_LATER(ah)) {
-                       if (freq == 2484) {
-                               /* Enable channel spreading for channel 14 */
-                               REG_WRITE_ARRAY(&ah->iniCckfirJapan2484,
-                                               1, regWrites);
-                       } else {
-                               REG_WRITE_ARRAY(&ah->iniCckfirNormal,
-                                               1, regWrites);
-                       }
-               } else {
-                       txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
-                       if (freq == 2484) {
-                               /* Enable channel spreading for channel 14 */
-                               REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
-                                         txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
-                       } else {
-                               REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
-                                         txctl &~ AR_PHY_CCK_TX_CTRL_JAPAN);
-                       }
-               }
-       } else {
-               bMode = 0;
-               fracMode = 0;
-
-               switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
-               case 0:
-                       if ((freq % 20) == 0) {
-                               aModeRefSel = 3;
-                       } else if ((freq % 10) == 0) {
-                               aModeRefSel = 2;
-                       }
-                       if (aModeRefSel)
-                               break;
-               case 1:
-               default:
-                       aModeRefSel = 0;
-                       /*
-                        * Enable 2G (fractional) mode for channels
-                        * which are 5MHz spaced.
-                        */
-                       fracMode = 1;
-                       refDivA = 1;
-                       channelSel = (freq * 0x8000) / 15;
-
-                       /* RefDivA setting */
-                       REG_RMW_FIELD(ah, AR_AN_SYNTH9,
-                                     AR_AN_SYNTH9_REFDIVA, refDivA);
-
-               }
-
-               if (!fracMode) {
-                       ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
-                       channelSel = ndiv & 0x1ff;
-                       channelFrac = (ndiv & 0xfffffe00) * 2;
-                       channelSel = (channelSel << 17) | channelFrac;
-               }
-       }
-
-       reg32 = reg32 |
-           (bMode << 29) |
-           (fracMode << 28) | (aModeRefSel << 26) | (channelSel);
-
-       REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
-
-       ah->curchan = chan;
-       ah->curchan_rad_index = -1;
-
-       return 0;
-}
-
-/**
- * ath9k_hw_9280_spur_mitigate - convert baseband spur frequency
- * @ah: atheros hardware structure
- * @chan:
- *
- * For single-chip solutions. Converts to baseband spur frequency given the
- * input channel frequency and compute register settings below.
- */
-void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       int bb_spur = AR_NO_SPUR;
-       int freq;
-       int bin, cur_bin;
-       int bb_spur_off, spur_subchannel_sd;
-       int spur_freq_sd;
-       int spur_delta_phase;
-       int denominator;
-       int upper, lower, cur_vit_mask;
-       int tmp, newVal;
-       int i;
-       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
-                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
-       };
-       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
-                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
-       };
-       int inc[4] = { 0, 100, 0, 0 };
-       struct chan_centers centers;
-
-       int8_t mask_m[123];
-       int8_t mask_p[123];
-       int8_t mask_amt;
-       int tmp_mask;
-       int cur_bb_spur;
-       bool is2GHz = IS_CHAN_2GHZ(chan);
-
-       memset(&mask_m, 0, sizeof(int8_t) * 123);
-       memset(&mask_p, 0, sizeof(int8_t) * 123);
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       freq = centers.synth_center;
-
-       ah->config.spurmode = SPUR_ENABLE_EEPROM;
-       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-               cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
-
-               if (is2GHz)
-                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ;
-               else
-                       cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ;
-
-               if (AR_NO_SPUR == cur_bb_spur)
-                       break;
-               cur_bb_spur = cur_bb_spur - freq;
-
-               if (IS_CHAN_HT40(chan)) {
-                       if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) &&
-                           (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) {
-                               bb_spur = cur_bb_spur;
-                               break;
-                       }
-               } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) &&
-                          (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) {
-                       bb_spur = cur_bb_spur;
-                       break;
-               }
-       }
-
-       if (AR_NO_SPUR == bb_spur) {
-               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
-                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
-               return;
-       } else {
-               REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK,
-                           AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
-       }
-
-       bin = bb_spur * 320;
-
-       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
-
-       newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
-                       AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
-                       AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
-                       AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
-       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal);
-
-       newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
-                 AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
-                 AR_PHY_SPUR_REG_MASK_RATE_SELECT |
-                 AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
-                 SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
-       REG_WRITE(ah, AR_PHY_SPUR_REG, newVal);
-
-       if (IS_CHAN_HT40(chan)) {
-               if (bb_spur < 0) {
-                       spur_subchannel_sd = 1;
-                       bb_spur_off = bb_spur + 10;
-               } else {
-                       spur_subchannel_sd = 0;
-                       bb_spur_off = bb_spur - 10;
-               }
-       } else {
-               spur_subchannel_sd = 0;
-               bb_spur_off = bb_spur;
-       }
-
-       if (IS_CHAN_HT40(chan))
-               spur_delta_phase =
-                       ((bb_spur * 262144) /
-                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-       else
-               spur_delta_phase =
-                       ((bb_spur * 524288) /
-                        10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-
-       denominator = IS_CHAN_2GHZ(chan) ? 44 : 40;
-       spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff;
-
-       newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
-                 SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
-                 SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
-       REG_WRITE(ah, AR_PHY_TIMING11, newVal);
-
-       newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S;
-       REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal);
-
-       cur_bin = -6000;
-       upper = bin + 100;
-       lower = bin - 100;
-
-       for (i = 0; i < 4; i++) {
-               int pilot_mask = 0;
-               int chan_mask = 0;
-               int bp = 0;
-               for (bp = 0; bp < 30; bp++) {
-                       if ((cur_bin > lower) && (cur_bin < upper)) {
-                               pilot_mask = pilot_mask | 0x1 << bp;
-                               chan_mask = chan_mask | 0x1 << bp;
-                       }
-                       cur_bin += 100;
-               }
-               cur_bin += inc[i];
-               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
-               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
-       }
-
-       cur_vit_mask = 6100;
-       upper = bin + 120;
-       lower = bin - 120;
-
-       for (i = 0; i < 123; i++) {
-               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
-                       /* workaround for gcc bug #37014 */
-                       volatile int tmp_v = abs(cur_vit_mask - bin);
-
-                       if (tmp_v < 75)
-                               mask_amt = 1;
-                       else
-                               mask_amt = 0;
-                       if (cur_vit_mask < 0)
-                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
-                       else
-                               mask_p[cur_vit_mask / 100] = mask_amt;
-               }
-               cur_vit_mask -= 100;
-       }
-
-       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
-               | (mask_m[48] << 26) | (mask_m[49] << 24)
-               | (mask_m[50] << 22) | (mask_m[51] << 20)
-               | (mask_m[52] << 18) | (mask_m[53] << 16)
-               | (mask_m[54] << 14) | (mask_m[55] << 12)
-               | (mask_m[56] << 10) | (mask_m[57] << 8)
-               | (mask_m[58] << 6) | (mask_m[59] << 4)
-               | (mask_m[60] << 2) | (mask_m[61] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
-
-       tmp_mask = (mask_m[31] << 28)
-               | (mask_m[32] << 26) | (mask_m[33] << 24)
-               | (mask_m[34] << 22) | (mask_m[35] << 20)
-               | (mask_m[36] << 18) | (mask_m[37] << 16)
-               | (mask_m[48] << 14) | (mask_m[39] << 12)
-               | (mask_m[40] << 10) | (mask_m[41] << 8)
-               | (mask_m[42] << 6) | (mask_m[43] << 4)
-               | (mask_m[44] << 2) | (mask_m[45] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
-
-       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
-               | (mask_m[18] << 26) | (mask_m[18] << 24)
-               | (mask_m[20] << 22) | (mask_m[20] << 20)
-               | (mask_m[22] << 18) | (mask_m[22] << 16)
-               | (mask_m[24] << 14) | (mask_m[24] << 12)
-               | (mask_m[25] << 10) | (mask_m[26] << 8)
-               | (mask_m[27] << 6) | (mask_m[28] << 4)
-               | (mask_m[29] << 2) | (mask_m[30] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
-
-       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
-               | (mask_m[2] << 26) | (mask_m[3] << 24)
-               | (mask_m[4] << 22) | (mask_m[5] << 20)
-               | (mask_m[6] << 18) | (mask_m[7] << 16)
-               | (mask_m[8] << 14) | (mask_m[9] << 12)
-               | (mask_m[10] << 10) | (mask_m[11] << 8)
-               | (mask_m[12] << 6) | (mask_m[13] << 4)
-               | (mask_m[14] << 2) | (mask_m[15] << 0);
-       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
-
-       tmp_mask = (mask_p[15] << 28)
-               | (mask_p[14] << 26) | (mask_p[13] << 24)
-               | (mask_p[12] << 22) | (mask_p[11] << 20)
-               | (mask_p[10] << 18) | (mask_p[9] << 16)
-               | (mask_p[8] << 14) | (mask_p[7] << 12)
-               | (mask_p[6] << 10) | (mask_p[5] << 8)
-               | (mask_p[4] << 6) | (mask_p[3] << 4)
-               | (mask_p[2] << 2) | (mask_p[1] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
-
-       tmp_mask = (mask_p[30] << 28)
-               | (mask_p[29] << 26) | (mask_p[28] << 24)
-               | (mask_p[27] << 22) | (mask_p[26] << 20)
-               | (mask_p[25] << 18) | (mask_p[24] << 16)
-               | (mask_p[23] << 14) | (mask_p[22] << 12)
-               | (mask_p[21] << 10) | (mask_p[20] << 8)
-               | (mask_p[19] << 6) | (mask_p[18] << 4)
-               | (mask_p[17] << 2) | (mask_p[16] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
-
-       tmp_mask = (mask_p[45] << 28)
-               | (mask_p[44] << 26) | (mask_p[43] << 24)
-               | (mask_p[42] << 22) | (mask_p[41] << 20)
-               | (mask_p[40] << 18) | (mask_p[39] << 16)
-               | (mask_p[38] << 14) | (mask_p[37] << 12)
-               | (mask_p[36] << 10) | (mask_p[35] << 8)
-               | (mask_p[34] << 6) | (mask_p[33] << 4)
-               | (mask_p[32] << 2) | (mask_p[31] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
-
-       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
-               | (mask_p[59] << 26) | (mask_p[58] << 24)
-               | (mask_p[57] << 22) | (mask_p[56] << 20)
-               | (mask_p[55] << 18) | (mask_p[54] << 16)
-               | (mask_p[53] << 14) | (mask_p[52] << 12)
-               | (mask_p[51] << 10) | (mask_p[50] << 8)
-               | (mask_p[49] << 6) | (mask_p[48] << 4)
-               | (mask_p[47] << 2) | (mask_p[46] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
-}
-
-/* All code below is for non single-chip solutions */
-
-/**
- * ath9k_phy_modify_rx_buffer() - perform analog swizzling of parameters
- * @rfbuf:
- * @reg32:
- * @numBits:
- * @firstBit:
- * @column:
- *
- * Performs analog "swizzling" of parameters into their location.
- * Used on external AR2133/AR5133 radios.
- */
-static void ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32,
-                                      u32 numBits, u32 firstBit,
-                                      u32 column)
-{
-       u32 tmp32, mask, arrayEntry, lastBit;
-       int32_t bitPosition, bitsLeft;
-
-       tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
-       arrayEntry = (firstBit - 1) / 8;
-       bitPosition = (firstBit - 1) % 8;
-       bitsLeft = numBits;
-       while (bitsLeft > 0) {
-               lastBit = (bitPosition + bitsLeft > 8) ?
-                   8 : bitPosition + bitsLeft;
-               mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
-                   (column * 8);
-               rfBuf[arrayEntry] &= ~mask;
-               rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
-                                     (column * 8)) & mask;
-               bitsLeft -= 8 - bitPosition;
-               tmp32 = tmp32 >> (8 - bitPosition);
-               bitPosition = 0;
-               arrayEntry++;
-       }
-}
-
-/*
- * Fix on 2.4 GHz band for orientation sensitivity issue by increasing
- * rf_pwd_icsyndiv.
- *
- * Theoretical Rules:
- *   if 2 GHz band
- *      if forceBiasAuto
- *         if synth_freq < 2412
- *            bias = 0
- *         else if 2412 <= synth_freq <= 2422
- *            bias = 1
- *         else // synth_freq > 2422
- *            bias = 2
- *      else if forceBias > 0
- *         bias = forceBias & 7
- *      else
- *         no change, use value from ini file
- *   else
- *      no change, invalid band
- *
- *  1st Mod:
- *    2422 also uses value of 2
- *    <approved>
- *
- *  2nd Mod:
- *    Less than 2412 uses value of 0, 2412 and above uses value of 2
- */
-static void ath9k_hw_force_bias(struct ath_hw *ah, u16 synth_freq)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 tmp_reg;
-       int reg_writes = 0;
-       u32 new_bias = 0;
-
-       if (!AR_SREV_5416(ah) || synth_freq >= 3000) {
-               return;
-       }
-
-       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
-
-       if (synth_freq < 2412)
-               new_bias = 0;
-       else if (synth_freq < 2422)
-               new_bias = 1;
-       else
-               new_bias = 2;
-
-       /* pre-reverse this field */
-       tmp_reg = ath9k_hw_reverse_bits(new_bias, 3);
-
-       ath_print(common, ATH_DBG_CONFIG,
-                 "Force rf_pwd_icsyndiv to %1d on %4d\n",
-                 new_bias, synth_freq);
-
-       /* swizzle rf_pwd_icsyndiv */
-       ath9k_phy_modify_rx_buffer(ah->analogBank6Data, tmp_reg, 3, 181, 3);
-
-       /* write Bank 6 with new params */
-       REG_WRITE_RF_ARRAY(&ah->iniBank6, ah->analogBank6Data, reg_writes);
-}
-
-/**
- * ath9k_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios
- * @ah: atheros hardware stucture
- * @chan:
- *
- * For the external AR2133/AR5133 radios, takes the MHz channel value and set
- * the channel value. Assumes writes enabled to analog bus and bank6 register
- * cache in ah->analogBank6Data.
- */
-int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       u32 channelSel = 0;
-       u32 bModeSynth = 0;
-       u32 aModeRefSel = 0;
-       u32 reg32 = 0;
-       u16 freq;
-       struct chan_centers centers;
-
-       ath9k_hw_get_channel_centers(ah, chan, &centers);
-       freq = centers.synth_center;
-
-       if (freq < 4800) {
-               u32 txctl;
-
-               if (((freq - 2192) % 5) == 0) {
-                       channelSel = ((freq - 672) * 2 - 3040) / 10;
-                       bModeSynth = 0;
-               } else if (((freq - 2224) % 5) == 0) {
-                       channelSel = ((freq - 704) * 2 - 3040) / 10;
-                       bModeSynth = 1;
-               } else {
-                       ath_print(common, ATH_DBG_FATAL,
-                                 "Invalid channel %u MHz\n", freq);
-                       return -EINVAL;
-               }
-
-               channelSel = (channelSel << 2) & 0xff;
-               channelSel = ath9k_hw_reverse_bits(channelSel, 8);
-
-               txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
-               if (freq == 2484) {
-
-                       REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
-                                 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
-               } else {
-                       REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
-                                 txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
-               }
-
-       } else if ((freq % 20) == 0 && freq >= 5120) {
-               channelSel =
-                   ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
-               aModeRefSel = ath9k_hw_reverse_bits(1, 2);
-       } else if ((freq % 10) == 0) {
-               channelSel =
-                   ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
-               if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
-                       aModeRefSel = ath9k_hw_reverse_bits(2, 2);
-               else
-                       aModeRefSel = ath9k_hw_reverse_bits(1, 2);
-       } else if ((freq % 5) == 0) {
-               channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
-               aModeRefSel = ath9k_hw_reverse_bits(1, 2);
-       } else {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Invalid channel %u MHz\n", freq);
-               return -EINVAL;
-       }
-
-       ath9k_hw_force_bias(ah, freq);
-
-       reg32 =
-           (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
-           (1 << 5) | 0x1;
-
-       REG_WRITE(ah, AR_PHY(0x37), reg32);
-
-       ah->curchan = chan;
-       ah->curchan_rad_index = -1;
-
-       return 0;
-}
-
-/**
- * ath9k_hw_spur_mitigate - convert baseband spur frequency for external radios
- * @ah: atheros hardware structure
- * @chan:
- *
- * For non single-chip solutions. Converts to baseband spur frequency given the
- * input channel frequency and compute register settings below.
- */
-void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan)
-{
-       int bb_spur = AR_NO_SPUR;
-       int bin, cur_bin;
-       int spur_freq_sd;
-       int spur_delta_phase;
-       int denominator;
-       int upper, lower, cur_vit_mask;
-       int tmp, new;
-       int i;
-       int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8,
-                         AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60
-       };
-       int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10,
-                        AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60
-       };
-       int inc[4] = { 0, 100, 0, 0 };
-
-       int8_t mask_m[123];
-       int8_t mask_p[123];
-       int8_t mask_amt;
-       int tmp_mask;
-       int cur_bb_spur;
-       bool is2GHz = IS_CHAN_2GHZ(chan);
-
-       memset(&mask_m, 0, sizeof(int8_t) * 123);
-       memset(&mask_p, 0, sizeof(int8_t) * 123);
-
-       for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
-               cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz);
-               if (AR_NO_SPUR == cur_bb_spur)
-                       break;
-               cur_bb_spur = cur_bb_spur - (chan->channel * 10);
-               if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) {
-                       bb_spur = cur_bb_spur;
-                       break;
-               }
-       }
-
-       if (AR_NO_SPUR == bb_spur)
-               return;
-
-       bin = bb_spur * 32;
-
-       tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0));
-       new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
-                    AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
-                    AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
-                    AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
-
-       REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new);
-
-       new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL |
-              AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
-              AR_PHY_SPUR_REG_MASK_RATE_SELECT |
-              AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
-              SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH));
-       REG_WRITE(ah, AR_PHY_SPUR_REG, new);
-
-       spur_delta_phase = ((bb_spur * 524288) / 100) &
-               AR_PHY_TIMING11_SPUR_DELTA_PHASE;
-
-       denominator = IS_CHAN_2GHZ(chan) ? 440 : 400;
-       spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff;
-
-       new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC |
-              SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) |
-              SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE));
-       REG_WRITE(ah, AR_PHY_TIMING11, new);
-
-       cur_bin = -6000;
-       upper = bin + 100;
-       lower = bin - 100;
-
-       for (i = 0; i < 4; i++) {
-               int pilot_mask = 0;
-               int chan_mask = 0;
-               int bp = 0;
-               for (bp = 0; bp < 30; bp++) {
-                       if ((cur_bin > lower) && (cur_bin < upper)) {
-                               pilot_mask = pilot_mask | 0x1 << bp;
-                               chan_mask = chan_mask | 0x1 << bp;
-                       }
-                       cur_bin += 100;
-               }
-               cur_bin += inc[i];
-               REG_WRITE(ah, pilot_mask_reg[i], pilot_mask);
-               REG_WRITE(ah, chan_mask_reg[i], chan_mask);
-       }
-
-       cur_vit_mask = 6100;
-       upper = bin + 120;
-       lower = bin - 120;
-
-       for (i = 0; i < 123; i++) {
-               if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) {
-
-                       /* workaround for gcc bug #37014 */
-                       volatile int tmp_v = abs(cur_vit_mask - bin);
-
-                       if (tmp_v < 75)
-                               mask_amt = 1;
-                       else
-                               mask_amt = 0;
-                       if (cur_vit_mask < 0)
-                               mask_m[abs(cur_vit_mask / 100)] = mask_amt;
-                       else
-                               mask_p[cur_vit_mask / 100] = mask_amt;
-               }
-               cur_vit_mask -= 100;
-       }
-
-       tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28)
-               | (mask_m[48] << 26) | (mask_m[49] << 24)
-               | (mask_m[50] << 22) | (mask_m[51] << 20)
-               | (mask_m[52] << 18) | (mask_m[53] << 16)
-               | (mask_m[54] << 14) | (mask_m[55] << 12)
-               | (mask_m[56] << 10) | (mask_m[57] << 8)
-               | (mask_m[58] << 6) | (mask_m[59] << 4)
-               | (mask_m[60] << 2) | (mask_m[61] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask);
-
-       tmp_mask = (mask_m[31] << 28)
-               | (mask_m[32] << 26) | (mask_m[33] << 24)
-               | (mask_m[34] << 22) | (mask_m[35] << 20)
-               | (mask_m[36] << 18) | (mask_m[37] << 16)
-               | (mask_m[48] << 14) | (mask_m[39] << 12)
-               | (mask_m[40] << 10) | (mask_m[41] << 8)
-               | (mask_m[42] << 6) | (mask_m[43] << 4)
-               | (mask_m[44] << 2) | (mask_m[45] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask);
-
-       tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28)
-               | (mask_m[18] << 26) | (mask_m[18] << 24)
-               | (mask_m[20] << 22) | (mask_m[20] << 20)
-               | (mask_m[22] << 18) | (mask_m[22] << 16)
-               | (mask_m[24] << 14) | (mask_m[24] << 12)
-               | (mask_m[25] << 10) | (mask_m[26] << 8)
-               | (mask_m[27] << 6) | (mask_m[28] << 4)
-               | (mask_m[29] << 2) | (mask_m[30] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask);
-
-       tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28)
-               | (mask_m[2] << 26) | (mask_m[3] << 24)
-               | (mask_m[4] << 22) | (mask_m[5] << 20)
-               | (mask_m[6] << 18) | (mask_m[7] << 16)
-               | (mask_m[8] << 14) | (mask_m[9] << 12)
-               | (mask_m[10] << 10) | (mask_m[11] << 8)
-               | (mask_m[12] << 6) | (mask_m[13] << 4)
-               | (mask_m[14] << 2) | (mask_m[15] << 0);
-       REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask);
-
-       tmp_mask = (mask_p[15] << 28)
-               | (mask_p[14] << 26) | (mask_p[13] << 24)
-               | (mask_p[12] << 22) | (mask_p[11] << 20)
-               | (mask_p[10] << 18) | (mask_p[9] << 16)
-               | (mask_p[8] << 14) | (mask_p[7] << 12)
-               | (mask_p[6] << 10) | (mask_p[5] << 8)
-               | (mask_p[4] << 6) | (mask_p[3] << 4)
-               | (mask_p[2] << 2) | (mask_p[1] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask);
-
-       tmp_mask = (mask_p[30] << 28)
-               | (mask_p[29] << 26) | (mask_p[28] << 24)
-               | (mask_p[27] << 22) | (mask_p[26] << 20)
-               | (mask_p[25] << 18) | (mask_p[24] << 16)
-               | (mask_p[23] << 14) | (mask_p[22] << 12)
-               | (mask_p[21] << 10) | (mask_p[20] << 8)
-               | (mask_p[19] << 6) | (mask_p[18] << 4)
-               | (mask_p[17] << 2) | (mask_p[16] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask);
-
-       tmp_mask = (mask_p[45] << 28)
-               | (mask_p[44] << 26) | (mask_p[43] << 24)
-               | (mask_p[42] << 22) | (mask_p[41] << 20)
-               | (mask_p[40] << 18) | (mask_p[39] << 16)
-               | (mask_p[38] << 14) | (mask_p[37] << 12)
-               | (mask_p[36] << 10) | (mask_p[35] << 8)
-               | (mask_p[34] << 6) | (mask_p[33] << 4)
-               | (mask_p[32] << 2) | (mask_p[31] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask);
-
-       tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28)
-               | (mask_p[59] << 26) | (mask_p[58] << 24)
-               | (mask_p[57] << 22) | (mask_p[56] << 20)
-               | (mask_p[55] << 18) | (mask_p[54] << 16)
-               | (mask_p[53] << 14) | (mask_p[52] << 12)
-               | (mask_p[51] << 10) | (mask_p[50] << 8)
-               | (mask_p[49] << 6) | (mask_p[48] << 4)
-               | (mask_p[47] << 2) | (mask_p[46] << 0);
-       REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask);
-       REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask);
-}
-
-/**
- * ath9k_hw_rf_alloc_ext_banks - allocates banks for external radio programming
- * @ah: atheros hardware structure
- *
- * Only required for older devices with external AR2133/AR5133 radios.
- */
-int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah)
-{
-#define ATH_ALLOC_BANK(bank, size) do { \
-               bank = kzalloc((sizeof(u32) * size), GFP_KERNEL); \
-               if (!bank) { \
-                       ath_print(common, ATH_DBG_FATAL, \
-                                 "Cannot allocate RF banks\n"); \
-                       return -ENOMEM; \
-               } \
-       } while (0);
-
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
-
-       ATH_ALLOC_BANK(ah->analogBank0Data, ah->iniBank0.ia_rows);
-       ATH_ALLOC_BANK(ah->analogBank1Data, ah->iniBank1.ia_rows);
-       ATH_ALLOC_BANK(ah->analogBank2Data, ah->iniBank2.ia_rows);
-       ATH_ALLOC_BANK(ah->analogBank3Data, ah->iniBank3.ia_rows);
-       ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows);
-       ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows);
-       ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows);
-       ATH_ALLOC_BANK(ah->addac5416_21,
-                      ah->iniAddac.ia_rows * ah->iniAddac.ia_columns);
-       ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows);
-
-       return 0;
-#undef ATH_ALLOC_BANK
-}
-
-
-/**
- * ath9k_hw_rf_free_ext_banks - Free memory for analog bank scratch buffers
- * @ah: atheros hardware struture
- * For the external AR2133/AR5133 radios banks.
- */
-void
-ath9k_hw_rf_free_ext_banks(struct ath_hw *ah)
-{
-#define ATH_FREE_BANK(bank) do { \
-               kfree(bank); \
-               bank = NULL; \
-       } while (0);
-
-       BUG_ON(AR_SREV_9280_10_OR_LATER(ah));
-
-       ATH_FREE_BANK(ah->analogBank0Data);
-       ATH_FREE_BANK(ah->analogBank1Data);
-       ATH_FREE_BANK(ah->analogBank2Data);
-       ATH_FREE_BANK(ah->analogBank3Data);
-       ATH_FREE_BANK(ah->analogBank6Data);
-       ATH_FREE_BANK(ah->analogBank6TPCData);
-       ATH_FREE_BANK(ah->analogBank7Data);
-       ATH_FREE_BANK(ah->addac5416_21);
-       ATH_FREE_BANK(ah->bank6Temp);
-
-#undef ATH_FREE_BANK
-}
-
-/* *
- * ath9k_hw_set_rf_regs - programs rf registers based on EEPROM
- * @ah: atheros hardware structure
- * @chan:
- * @modesIndex:
- *
- * Used for the external AR2133/AR5133 radios.
- *
- * Reads the EEPROM header info from the device structure and programs
- * all rf registers. This routine requires access to the analog
- * rf device. This is not required for single-chip devices.
- */
-bool ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan,
-                         u16 modesIndex)
-{
-       u32 eepMinorRev;
-       u32 ob5GHz = 0, db5GHz = 0;
-       u32 ob2GHz = 0, db2GHz = 0;
-       int regWrites = 0;
-
-       /*
-        * Software does not need to program bank data
-        * for single chip devices, that is AR9280 or anything
-        * after that.
-        */
-       if (AR_SREV_9280_10_OR_LATER(ah))
-               return true;
-
-       /* Setup rf parameters */
-       eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
-
-       /* Setup Bank 0 Write */
-       RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
-
-       /* Setup Bank 1 Write */
-       RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
-
-       /* Setup Bank 2 Write */
-       RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
-
-       /* Setup Bank 6 Write */
-       RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3,
-                     modesIndex);
-       {
-               int i;
-               for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) {
-                       ah->analogBank6Data[i] =
-                           INI_RA(&ah->iniBank6TPC, i, modesIndex);
-               }
-       }
-
-       /* Only the 5 or 2 GHz OB/DB need to be set for a mode */
-       if (eepMinorRev >= 2) {
-               if (IS_CHAN_2GHZ(chan)) {
-                       ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2);
-                       db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2);
-                       ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
-                                                  ob2GHz, 3, 197, 0);
-                       ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
-                                                  db2GHz, 3, 194, 0);
-               } else {
-                       ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5);
-                       db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5);
-                       ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
-                                                  ob5GHz, 3, 203, 0);
-                       ath9k_phy_modify_rx_buffer(ah->analogBank6Data,
-                                                  db5GHz, 3, 200, 0);
-               }
-       }
-
-       /* Setup Bank 7 Setup */
-       RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
-
-       /* Write Analog registers */
-       REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
-                          regWrites);
-       REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data,
-                          regWrites);
-       REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data,
-                          regWrites);
-       REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data,
-                          regWrites);
-       REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data,
-                          regWrites);
-       REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data,
-                          regWrites);
-
-       return true;
-}
index 0999a495fd46add32fa1b9d0c95c1ec55c2e39e8..e724c2c1ae2a320eb5e17e7c4d419a346c5b1bdf 100644 (file)
 #ifndef PHY_H
 #define PHY_H
 
-/* Common between single chip and non single-chip solutions */
-void ath9k_hw_write_regs(struct ath_hw *ah, u32 freqIndex, int regWrites);
-
-/* Single chip radio settings */
-int ath9k_hw_ar9280_set_channel(struct ath_hw *ah, struct ath9k_channel *chan);
-void ath9k_hw_9280_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
-
-/* Routines below are for non single-chip solutions */
-int ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan);
-void ath9k_hw_spur_mitigate(struct ath_hw *ah, struct ath9k_channel *chan);
-
-int ath9k_hw_rf_alloc_ext_banks(struct ath_hw *ah);
-void ath9k_hw_rf_free_ext_banks(struct ath_hw *ah);
-
-bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
-                         struct ath9k_channel *chan,
-                         u16 modesIndex);
+#define CHANSEL_DIV            15
+#define CHANSEL_2G(_freq)      (((_freq) * 0x10000) / CHANSEL_DIV)
+#define CHANSEL_5G(_freq)      (((_freq) * 0x8000) / CHANSEL_DIV)
 
 #define AR_PHY_BASE     0x9800
 #define AR_PHY(_n)      (AR_PHY_BASE + ((_n)<<2))
 
-#define AR_PHY_TEST             0x9800
-#define PHY_AGC_CLR             0x10000000
-#define RFSILENT_BB             0x00002000
-
-#define AR_PHY_TURBO                0x9804
-#define AR_PHY_FC_TURBO_MODE        0x00000001
-#define AR_PHY_FC_TURBO_SHORT       0x00000002
-#define AR_PHY_FC_DYN2040_EN        0x00000004
-#define AR_PHY_FC_DYN2040_PRI_ONLY  0x00000008
-#define AR_PHY_FC_DYN2040_PRI_CH    0x00000010
-/* For 25 MHz channel spacing -- not used but supported by hw */
-#define AR_PHY_FC_DYN2040_EXT_CH    0x00000020
-#define AR_PHY_FC_HT_EN             0x00000040
-#define AR_PHY_FC_SHORT_GI_40       0x00000080
-#define AR_PHY_FC_WALSH             0x00000100
-#define AR_PHY_FC_SINGLE_HT_LTF1    0x00000200
-#define AR_PHY_FC_ENABLE_DAC_FIFO   0x00000800
-
-#define AR_PHY_TEST2               0x9808
-
-#define AR_PHY_TIMING2           0x9810
-#define AR_PHY_TIMING3           0x9814
-#define AR_PHY_TIMING3_DSC_MAN   0xFFFE0000
-#define AR_PHY_TIMING3_DSC_MAN_S 17
-#define AR_PHY_TIMING3_DSC_EXP   0x0001E000
-#define AR_PHY_TIMING3_DSC_EXP_S 13
-
-#define AR_PHY_CHIP_ID            0x9818
-#define AR_PHY_CHIP_ID_REV_0      0x80
-#define AR_PHY_CHIP_ID_REV_1      0x81
-#define AR_PHY_CHIP_ID_9160_REV_0 0xb0
-
-#define AR_PHY_ACTIVE       0x981C
-#define AR_PHY_ACTIVE_EN    0x00000001
-#define AR_PHY_ACTIVE_DIS   0x00000000
-
-#define AR_PHY_RF_CTL2             0x9824
-#define AR_PHY_TX_END_DATA_START   0x000000FF
-#define AR_PHY_TX_END_DATA_START_S 0
-#define AR_PHY_TX_END_PA_ON        0x0000FF00
-#define AR_PHY_TX_END_PA_ON_S      8
-
-#define AR_PHY_RF_CTL3                  0x9828
-#define AR_PHY_TX_END_TO_A2_RX_ON       0x00FF0000
-#define AR_PHY_TX_END_TO_A2_RX_ON_S     16
-
-#define AR_PHY_ADC_CTL                  0x982C
-#define AR_PHY_ADC_CTL_OFF_INBUFGAIN    0x00000003
-#define AR_PHY_ADC_CTL_OFF_INBUFGAIN_S  0
-#define AR_PHY_ADC_CTL_OFF_PWDDAC       0x00002000
-#define AR_PHY_ADC_CTL_OFF_PWDBANDGAP   0x00004000
-#define AR_PHY_ADC_CTL_OFF_PWDADC       0x00008000
-#define AR_PHY_ADC_CTL_ON_INBUFGAIN     0x00030000
-#define AR_PHY_ADC_CTL_ON_INBUFGAIN_S   16
-
-#define AR_PHY_ADC_SERIAL_CTL       0x9830
-#define AR_PHY_SEL_INTERNAL_ADDAC   0x00000000
-#define AR_PHY_SEL_EXTERNAL_RADIO   0x00000001
-
-#define AR_PHY_RF_CTL4                    0x9834
-#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF    0xFF000000
-#define AR_PHY_RF_CTL4_TX_END_XPAB_OFF_S  24
-#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF    0x00FF0000
-#define AR_PHY_RF_CTL4_TX_END_XPAA_OFF_S  16
-#define AR_PHY_RF_CTL4_FRAME_XPAB_ON      0x0000FF00
-#define AR_PHY_RF_CTL4_FRAME_XPAB_ON_S    8
-#define AR_PHY_RF_CTL4_FRAME_XPAA_ON      0x000000FF
-#define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S    0
-
-#define AR_PHY_TSTDAC_CONST               0x983c
-
-#define AR_PHY_SETTLING          0x9844
-#define AR_PHY_SETTLING_SWITCH   0x00003F80
-#define AR_PHY_SETTLING_SWITCH_S 7
-
-#define AR_PHY_RXGAIN                   0x9848
-#define AR_PHY_RXGAIN_TXRX_ATTEN        0x0003F000
-#define AR_PHY_RXGAIN_TXRX_ATTEN_S      12
-#define AR_PHY_RXGAIN_TXRX_RF_MAX       0x007C0000
-#define AR_PHY_RXGAIN_TXRX_RF_MAX_S     18
-#define AR9280_PHY_RXGAIN_TXRX_ATTEN    0x00003F80
-#define AR9280_PHY_RXGAIN_TXRX_ATTEN_S  7
-#define AR9280_PHY_RXGAIN_TXRX_MARGIN   0x001FC000
-#define AR9280_PHY_RXGAIN_TXRX_MARGIN_S 14
-
-#define AR_PHY_DESIRED_SZ           0x9850
-#define AR_PHY_DESIRED_SZ_ADC       0x000000FF
-#define AR_PHY_DESIRED_SZ_ADC_S     0
-#define AR_PHY_DESIRED_SZ_PGA       0x0000FF00
-#define AR_PHY_DESIRED_SZ_PGA_S     8
-#define AR_PHY_DESIRED_SZ_TOT_DES   0x0FF00000
-#define AR_PHY_DESIRED_SZ_TOT_DES_S 20
-
-#define AR_PHY_FIND_SIG           0x9858
-#define AR_PHY_FIND_SIG_FIRSTEP   0x0003F000
-#define AR_PHY_FIND_SIG_FIRSTEP_S 12
-#define AR_PHY_FIND_SIG_FIRPWR    0x03FC0000
-#define AR_PHY_FIND_SIG_FIRPWR_S  18
-
-#define AR_PHY_AGC_CTL1                  0x985C
-#define AR_PHY_AGC_CTL1_COARSE_LOW       0x00007F80
-#define AR_PHY_AGC_CTL1_COARSE_LOW_S     7
-#define AR_PHY_AGC_CTL1_COARSE_HIGH      0x003F8000
-#define AR_PHY_AGC_CTL1_COARSE_HIGH_S    15
-
-#define AR_PHY_AGC_CONTROL               0x9860
-#define AR_PHY_AGC_CONTROL_CAL           0x00000001
-#define AR_PHY_AGC_CONTROL_NF            0x00000002
-#define AR_PHY_AGC_CONTROL_ENABLE_NF     0x00008000
-#define AR_PHY_AGC_CONTROL_FLTR_CAL      0x00010000
-#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF  0x00020000
-
-#define AR_PHY_CCA                  0x9864
-#define AR_PHY_MINCCA_PWR           0x0FF80000
-#define AR_PHY_MINCCA_PWR_S         19
-#define AR_PHY_CCA_THRESH62         0x0007F000
-#define AR_PHY_CCA_THRESH62_S       12
-#define AR9280_PHY_MINCCA_PWR       0x1FF00000
-#define AR9280_PHY_MINCCA_PWR_S     20
-#define AR9280_PHY_CCA_THRESH62     0x000FF000
-#define AR9280_PHY_CCA_THRESH62_S   12
-
-#define AR_PHY_SFCORR_LOW                    0x986C
-#define AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW  0x00000001
-#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW    0x00003F00
-#define AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW_S  8
-#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW      0x001FC000
-#define AR_PHY_SFCORR_LOW_M1_THRESH_LOW_S    14
-#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW      0x0FE00000
-#define AR_PHY_SFCORR_LOW_M2_THRESH_LOW_S    21
-
-#define AR_PHY_SFCORR                0x9868
-#define AR_PHY_SFCORR_M2COUNT_THR    0x0000001F
-#define AR_PHY_SFCORR_M2COUNT_THR_S  0
-#define AR_PHY_SFCORR_M1_THRESH      0x00FE0000
-#define AR_PHY_SFCORR_M1_THRESH_S    17
-#define AR_PHY_SFCORR_M2_THRESH      0x7F000000
-#define AR_PHY_SFCORR_M2_THRESH_S    24
-
-#define AR_PHY_SLEEP_CTR_CONTROL    0x9870
-#define AR_PHY_SLEEP_CTR_LIMIT      0x9874
-#define AR_PHY_SYNTH_CONTROL        0x9874
-#define AR_PHY_SLEEP_SCAL           0x9878
-
-#define AR_PHY_PLL_CTL          0x987c
-#define AR_PHY_PLL_CTL_40       0xaa
-#define AR_PHY_PLL_CTL_40_5413  0x04
-#define AR_PHY_PLL_CTL_44       0xab
-#define AR_PHY_PLL_CTL_44_2133  0xeb
-#define AR_PHY_PLL_CTL_40_2133  0xea
-
-#define AR_PHY_SPECTRAL_SCAN                   0x9910  /* AR9280 spectral scan configuration register */
-#define        AR_PHY_SPECTRAL_SCAN_ENABLE             0x1
-#define AR_PHY_SPECTRAL_SCAN_ENA               0x00000001  /* Enable spectral scan, reg 68, bit 0 */
-#define AR_PHY_SPECTRAL_SCAN_ENA_S             0  /* Enable spectral scan, reg 68, bit 0 */
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE            0x00000002  /* Activate spectral scan reg 68, bit 1*/
-#define AR_PHY_SPECTRAL_SCAN_ACTIVE_S          1  /* Activate spectral scan reg 68, bit 1*/
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD                0x000000F0  /* Interval for FFT reports, reg 68, bits 4-7*/
-#define AR_PHY_SPECTRAL_SCAN_FFT_PERIOD_S      4
-#define AR_PHY_SPECTRAL_SCAN_PERIOD            0x0000FF00  /* Interval for FFT reports, reg 68, bits 8-15*/
-#define AR_PHY_SPECTRAL_SCAN_PERIOD_S          8
-#define AR_PHY_SPECTRAL_SCAN_COUNT             0x00FF0000  /* Number of reports, reg 68, bits 16-23*/
-#define AR_PHY_SPECTRAL_SCAN_COUNT_S           16
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT      0x01000000  /* Short repeat, reg 68, bit 24*/
-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S    24  /* Short repeat, reg 68, bit 24*/
-
-#define AR_PHY_RX_DELAY           0x9914
-#define AR_PHY_SEARCH_START_DELAY 0x9918
-#define AR_PHY_RX_DELAY_DELAY     0x00003FFF
-
-#define AR_PHY_TIMING_CTRL4(_i)     (0x9920 + ((_i) << 12))
-#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF 0x01F
-#define AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF_S   0
-#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF 0x7E0
-#define AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF_S   5
-#define AR_PHY_TIMING_CTRL4_IQCORR_ENABLE   0x800
-#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX 0xF000
-#define AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX_S   12
-#define AR_PHY_TIMING_CTRL4_DO_CAL    0x10000
-
-#define AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI   0x80000000
-#define        AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER  0x40000000
-#define        AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK    0x20000000
-#define        AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK   0x10000000
-
-#define AR_PHY_TIMING5               0x9924
-#define AR_PHY_TIMING5_CYCPWR_THR1   0x000000FE
-#define AR_PHY_TIMING5_CYCPWR_THR1_S 1
-
-#define AR_PHY_POWER_TX_RATE1               0x9934
-#define AR_PHY_POWER_TX_RATE2               0x9938
-#define AR_PHY_POWER_TX_RATE_MAX            0x993c
-#define AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE 0x00000040
-
-#define AR_PHY_FRAME_CTL            0x9944
-#define AR_PHY_FRAME_CTL_TX_CLIP    0x00000038
-#define AR_PHY_FRAME_CTL_TX_CLIP_S  3
-
-#define AR_PHY_TXPWRADJ                   0x994C
-#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA    0x00000FC0
-#define AR_PHY_TXPWRADJ_CCK_GAIN_DELTA_S  6
-#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX   0x00FC0000
-#define AR_PHY_TXPWRADJ_CCK_PCDAC_INDEX_S 18
-
-#define AR_PHY_RADAR_EXT      0x9940
-#define AR_PHY_RADAR_EXT_ENA  0x00004000
-
-#define AR_PHY_RADAR_0          0x9954
-#define AR_PHY_RADAR_0_ENA      0x00000001
-#define AR_PHY_RADAR_0_FFT_ENA  0x80000000
-#define AR_PHY_RADAR_0_INBAND   0x0000003e
-#define AR_PHY_RADAR_0_INBAND_S 1
-#define AR_PHY_RADAR_0_PRSSI    0x00000FC0
-#define AR_PHY_RADAR_0_PRSSI_S  6
-#define AR_PHY_RADAR_0_HEIGHT   0x0003F000
-#define AR_PHY_RADAR_0_HEIGHT_S 12
-#define AR_PHY_RADAR_0_RRSSI    0x00FC0000
-#define AR_PHY_RADAR_0_RRSSI_S  18
-#define AR_PHY_RADAR_0_FIRPWR   0x7F000000
-#define AR_PHY_RADAR_0_FIRPWR_S 24
-
-#define AR_PHY_RADAR_1                  0x9958
-#define AR_PHY_RADAR_1_RELPWR_ENA       0x00800000
-#define AR_PHY_RADAR_1_USE_FIR128       0x00400000
-#define AR_PHY_RADAR_1_RELPWR_THRESH    0x003F0000
-#define AR_PHY_RADAR_1_RELPWR_THRESH_S  16
-#define AR_PHY_RADAR_1_BLOCK_CHECK      0x00008000
-#define AR_PHY_RADAR_1_MAX_RRSSI        0x00004000
-#define AR_PHY_RADAR_1_RELSTEP_CHECK    0x00002000
-#define AR_PHY_RADAR_1_RELSTEP_THRESH   0x00001F00
-#define AR_PHY_RADAR_1_RELSTEP_THRESH_S 8
-#define AR_PHY_RADAR_1_MAXLEN           0x000000FF
-#define AR_PHY_RADAR_1_MAXLEN_S         0
-
-#define AR_PHY_SWITCH_CHAIN_0     0x9960
-#define AR_PHY_SWITCH_COM         0x9964
-
-#define AR_PHY_SIGMA_DELTA            0x996C
-#define AR_PHY_SIGMA_DELTA_ADC_SEL    0x00000003
-#define AR_PHY_SIGMA_DELTA_ADC_SEL_S  0
-#define AR_PHY_SIGMA_DELTA_FILT2      0x000000F8
-#define AR_PHY_SIGMA_DELTA_FILT2_S    3
-#define AR_PHY_SIGMA_DELTA_FILT1      0x00001F00
-#define AR_PHY_SIGMA_DELTA_FILT1_S    8
-#define AR_PHY_SIGMA_DELTA_ADC_CLIP   0x01FFE000
-#define AR_PHY_SIGMA_DELTA_ADC_CLIP_S 13
-
-#define AR_PHY_RESTART          0x9970
-#define AR_PHY_RESTART_DIV_GC   0x001C0000
-#define AR_PHY_RESTART_DIV_GC_S 18
-
-#define AR_PHY_RFBUS_REQ        0x997C
-#define AR_PHY_RFBUS_REQ_EN     0x00000001
-
-#define        AR_PHY_TIMING7                  0x9980
-#define        AR_PHY_TIMING8                  0x9984
-#define        AR_PHY_TIMING8_PILOT_MASK_2     0x000FFFFF
-#define        AR_PHY_TIMING8_PILOT_MASK_2_S   0
-
-#define        AR_PHY_BIN_MASK2_1      0x9988
-#define        AR_PHY_BIN_MASK2_2      0x998c
-#define        AR_PHY_BIN_MASK2_3      0x9990
-#define        AR_PHY_BIN_MASK2_4      0x9994
-
-#define        AR_PHY_BIN_MASK_1       0x9900
-#define        AR_PHY_BIN_MASK_2       0x9904
-#define        AR_PHY_BIN_MASK_3       0x9908
-
-#define        AR_PHY_MASK_CTL         0x990c
-
-#define        AR_PHY_BIN_MASK2_4_MASK_4       0x00003FFF
-#define        AR_PHY_BIN_MASK2_4_MASK_4_S     0
-
-#define        AR_PHY_TIMING9                  0x9998
-#define        AR_PHY_TIMING10                 0x999c
-#define        AR_PHY_TIMING10_PILOT_MASK_2    0x000FFFFF
-#define        AR_PHY_TIMING10_PILOT_MASK_2_S  0
-
-#define        AR_PHY_TIMING11                         0x99a0
-#define        AR_PHY_TIMING11_SPUR_DELTA_PHASE        0x000FFFFF
-#define        AR_PHY_TIMING11_SPUR_DELTA_PHASE_S      0
-#define        AR_PHY_TIMING11_SPUR_FREQ_SD            0x3FF00000
-#define        AR_PHY_TIMING11_SPUR_FREQ_SD_S          20
-#define AR_PHY_TIMING11_USE_SPUR_IN_AGC                0x40000000
-#define AR_PHY_TIMING11_USE_SPUR_IN_SELFCOR    0x80000000
-
-#define AR_PHY_RX_CHAINMASK     0x99a4
-#define AR_PHY_NEW_ADC_DC_GAIN_CORR(_i) (0x99b4 + ((_i) << 12))
-#define AR_PHY_NEW_ADC_GAIN_CORR_ENABLE 0x40000000
-#define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
-
-#define AR_PHY_MULTICHAIN_GAIN_CTL          0x99ac
-#define AR_PHY_9285_ANT_DIV_CTL_ALL         0x7f000000
-#define AR_PHY_9285_ANT_DIV_CTL             0x01000000
-#define AR_PHY_9285_ANT_DIV_CTL_S           24
-#define AR_PHY_9285_ANT_DIV_ALT_LNACONF     0x06000000
-#define AR_PHY_9285_ANT_DIV_ALT_LNACONF_S   25
-#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF    0x18000000
-#define AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S  27
-#define AR_PHY_9285_ANT_DIV_ALT_GAINTB      0x20000000
-#define AR_PHY_9285_ANT_DIV_ALT_GAINTB_S    29
-#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB     0x40000000
-#define AR_PHY_9285_ANT_DIV_MAIN_GAINTB_S   30
-#define AR_PHY_9285_ANT_DIV_LNA1            2
-#define AR_PHY_9285_ANT_DIV_LNA2            1
-#define AR_PHY_9285_ANT_DIV_LNA1_PLUS_LNA2  3
-#define AR_PHY_9285_ANT_DIV_LNA1_MINUS_LNA2 0
-#define AR_PHY_9285_ANT_DIV_GAINTB_0        0
-#define AR_PHY_9285_ANT_DIV_GAINTB_1        1
+#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX   0x0007E000
+#define AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX_S 13
+#define AR_PHY_TX_GAIN_CLC       0x0000001E
+#define AR_PHY_TX_GAIN_CLC_S     1
+#define AR_PHY_TX_GAIN           0x0007F000
+#define AR_PHY_TX_GAIN_S         12
 
-#define AR_PHY_EXT_CCA0             0x99b8
-#define AR_PHY_EXT_CCA0_THRESH62    0x000000FF
-#define AR_PHY_EXT_CCA0_THRESH62_S  0
-
-#define AR_PHY_EXT_CCA                  0x99bc
-#define AR_PHY_EXT_CCA_CYCPWR_THR1      0x0000FE00
-#define AR_PHY_EXT_CCA_CYCPWR_THR1_S    9
-#define AR_PHY_EXT_CCA_THRESH62         0x007F0000
-#define AR_PHY_EXT_CCA_THRESH62_S       16
-#define AR_PHY_EXT_MINCCA_PWR           0xFF800000
-#define AR_PHY_EXT_MINCCA_PWR_S         23
-#define AR9280_PHY_EXT_MINCCA_PWR       0x01FF0000
-#define AR9280_PHY_EXT_MINCCA_PWR_S     16
-
-#define AR_PHY_SFCORR_EXT                 0x99c0
-#define AR_PHY_SFCORR_EXT_M1_THRESH       0x0000007F
-#define AR_PHY_SFCORR_EXT_M1_THRESH_S     0
-#define AR_PHY_SFCORR_EXT_M2_THRESH       0x00003F80
-#define AR_PHY_SFCORR_EXT_M2_THRESH_S     7
-#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW   0x001FC000
-#define AR_PHY_SFCORR_EXT_M1_THRESH_LOW_S 14
-#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW   0x0FE00000
-#define AR_PHY_SFCORR_EXT_M2_THRESH_LOW_S 21
-#define AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S   28
-
-#define AR_PHY_HALFGI           0x99D0
-#define AR_PHY_HALFGI_DSC_MAN   0x0007FFF0
-#define AR_PHY_HALFGI_DSC_MAN_S 4
-#define AR_PHY_HALFGI_DSC_EXP   0x0000000F
-#define AR_PHY_HALFGI_DSC_EXP_S 0
-
-#define AR_PHY_CHAN_INFO_MEMORY               0x99DC
-#define AR_PHY_CHAN_INFO_MEMORY_CAPTURE_MASK  0x0001
-
-#define AR_PHY_HEAVY_CLIP_ENABLE         0x99E0
-
-#define AR_PHY_HEAVY_CLIP_FACTOR_RIFS    0x99EC
-#define AR_PHY_RIFS_INIT_DELAY         0x03ff0000
-
-#define AR_PHY_M_SLEEP      0x99f0
-#define AR_PHY_REFCLKDLY    0x99f4
-#define AR_PHY_REFCLKPD     0x99f8
-
-#define AR_PHY_CALMODE      0x99f0
-
-#define AR_PHY_CALMODE_IQ           0x00000000
-#define AR_PHY_CALMODE_ADC_GAIN     0x00000001
-#define AR_PHY_CALMODE_ADC_DC_PER   0x00000002
-#define AR_PHY_CALMODE_ADC_DC_INIT  0x00000003
-
-#define AR_PHY_CAL_MEAS_0(_i)     (0x9c10 + ((_i) << 12))
-#define AR_PHY_CAL_MEAS_1(_i)     (0x9c14 + ((_i) << 12))
-#define AR_PHY_CAL_MEAS_2(_i)     (0x9c18 + ((_i) << 12))
-#define AR_PHY_CAL_MEAS_3(_i)     (0x9c1c + ((_i) << 12))
-
-#define AR_PHY_CURRENT_RSSI 0x9c1c
-#define AR9280_PHY_CURRENT_RSSI 0x9c3c
-
-#define AR_PHY_RFBUS_GRANT       0x9C20
-#define AR_PHY_RFBUS_GRANT_EN    0x00000001
-
-#define AR_PHY_CHAN_INFO_GAIN_DIFF             0x9CF4
-#define AR_PHY_CHAN_INFO_GAIN_DIFF_UPPER_LIMIT 320
-
-#define AR_PHY_CHAN_INFO_GAIN          0x9CFC
-
-#define AR_PHY_MODE         0xA200
-#define AR_PHY_MODE_ASYNCFIFO 0x80
-#define AR_PHY_MODE_AR2133  0x08
-#define AR_PHY_MODE_AR5111  0x00
-#define AR_PHY_MODE_AR5112  0x08
-#define AR_PHY_MODE_DYNAMIC 0x04
-#define AR_PHY_MODE_RF2GHZ  0x02
-#define AR_PHY_MODE_RF5GHZ  0x00
-#define AR_PHY_MODE_CCK     0x01
-#define AR_PHY_MODE_OFDM    0x00
-#define AR_PHY_MODE_DYN_CCK_DISABLE 0x100
-
-#define AR_PHY_CCK_TX_CTRL       0xA204
-#define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
-#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK         0x0000000C
-#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S       2
-
-#define AR_PHY_CCK_DETECT                           0xA208
-#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
-#define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK_S        0
-/* [12:6] settling time for antenna switch */
-#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME           0x00001FC0
-#define AR_PHY_CCK_DETECT_ANT_SWITCH_TIME_S         6
-#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV    0x2000
-#define AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV_S  13
-
-#define AR_PHY_GAIN_2GHZ                0xA20C
-#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN    0x00FC0000
-#define AR_PHY_GAIN_2GHZ_RXTX_MARGIN_S  18
-#define AR_PHY_GAIN_2GHZ_BSW_MARGIN     0x00003C00
-#define AR_PHY_GAIN_2GHZ_BSW_MARGIN_S   10
-#define AR_PHY_GAIN_2GHZ_BSW_ATTEN      0x0000001F
-#define AR_PHY_GAIN_2GHZ_BSW_ATTEN_S    0
-
-#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN     0x003E0000
-#define AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN_S   17
-#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN     0x0001F000
-#define AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN_S   12
-#define AR_PHY_GAIN_2GHZ_XATTEN2_DB         0x00000FC0
-#define AR_PHY_GAIN_2GHZ_XATTEN2_DB_S       6
-#define AR_PHY_GAIN_2GHZ_XATTEN1_DB         0x0000003F
-#define AR_PHY_GAIN_2GHZ_XATTEN1_DB_S       0
-
-#define AR_PHY_CCK_RXCTRL4  0xA21C
-#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT   0x01F80000
-#define AR_PHY_CCK_RXCTRL4_FREQ_EST_SHORT_S 19
-
-#define AR_PHY_DAG_CTRLCCK  0xA228
-#define AR_PHY_DAG_CTRLCCK_EN_RSSI_THR  0x00000200
-#define AR_PHY_DAG_CTRLCCK_RSSI_THR     0x0001FC00
-#define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
-
-#define AR_PHY_FORCE_CLKEN_CCK              0xA22C
-#define AR_PHY_FORCE_CLKEN_CCK_MRC_MUX      0x00000040
-
-#define AR_PHY_POWER_TX_RATE3   0xA234
-#define AR_PHY_POWER_TX_RATE4   0xA238
-
-#define AR_PHY_SCRM_SEQ_XR       0xA23C
-#define AR_PHY_HEADER_DETECT_XR  0xA240
-#define AR_PHY_CHIRP_DETECTED_XR 0xA244
-#define AR_PHY_BLUETOOTH         0xA254
-
-#define AR_PHY_TPCRG1   0xA258
-#define AR_PHY_TPCRG1_NUM_PD_GAIN   0x0000c000
-#define AR_PHY_TPCRG1_NUM_PD_GAIN_S 14
-
-#define AR_PHY_TPCRG1_PD_GAIN_1    0x00030000
-#define AR_PHY_TPCRG1_PD_GAIN_1_S  16
-#define AR_PHY_TPCRG1_PD_GAIN_2    0x000C0000
-#define AR_PHY_TPCRG1_PD_GAIN_2_S  18
-#define AR_PHY_TPCRG1_PD_GAIN_3    0x00300000
-#define AR_PHY_TPCRG1_PD_GAIN_3_S  20
-
-#define AR_PHY_TPCRG1_PD_CAL_ENABLE   0x00400000
-#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22
-
-#define AR_PHY_TX_PWRCTRL4       0xa264
-#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID     0x00000001
-#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S   0
-#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT       0x000001FE
-#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S     1
-
-#define AR_PHY_TX_PWRCTRL6_0     0xa270
-#define AR_PHY_TX_PWRCTRL6_1     0xb270
-#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE     0x03000000
-#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S   24
-
-#define AR_PHY_TX_PWRCTRL7       0xa274
-#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN     0x01F80000
-#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S   19
-
-#define AR_PHY_TX_PWRCTRL9       0xa27C
-#define AR_PHY_TX_DESIRED_SCALE_CCK        0x00007C00
-#define AR_PHY_TX_DESIRED_SCALE_CCK_S      10
-#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL  0x80000000
-#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL_S 31
-
-#define AR_PHY_TX_GAIN_TBL1      0xa300
-#define AR_PHY_TX_GAIN                     0x0007F000
-#define AR_PHY_TX_GAIN_S                   12
-
-#define AR_PHY_CH0_TX_PWRCTRL11  0xa398
-#define AR_PHY_CH1_TX_PWRCTRL11  0xb398
-#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP   0x0000FC00
-#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
-
-#define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
-#define AR_PHY_MASK2_M_31_45     0xa3a4
-#define AR_PHY_MASK2_M_16_30     0xa3a8
-#define AR_PHY_MASK2_M_00_15     0xa3ac
-#define AR_PHY_MASK2_P_15_01     0xa3b8
-#define AR_PHY_MASK2_P_30_16     0xa3bc
-#define AR_PHY_MASK2_P_45_31     0xa3c0
-#define AR_PHY_MASK2_P_61_45     0xa3c4
-#define AR_PHY_SPUR_REG          0x994c
-
-#define AR_PHY_SPUR_REG_MASK_RATE_CNTL       (0xFF << 18)
-#define AR_PHY_SPUR_REG_MASK_RATE_CNTL_S     18
-
-#define AR_PHY_SPUR_REG_ENABLE_MASK_PPM      0x20000
-#define AR_PHY_SPUR_REG_MASK_RATE_SELECT     (0xFF << 9)
-#define AR_PHY_SPUR_REG_MASK_RATE_SELECT_S   9
-#define AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI 0x100
-#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH     0x7F
-#define AR_PHY_SPUR_REG_SPUR_RSSI_THRESH_S   0
-
-#define AR_PHY_PILOT_MASK_01_30   0xa3b0
-#define AR_PHY_PILOT_MASK_31_60   0xa3b4
-
-#define AR_PHY_CHANNEL_MASK_01_30 0x99d4
-#define AR_PHY_CHANNEL_MASK_31_60 0x99d8
-
-#define AR_PHY_ANALOG_SWAP      0xa268
-#define AR_PHY_SWAP_ALT_CHAIN   0x00000040
-
-#define AR_PHY_TPCRG5   0xA26C
-#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP       0x0000000F
-#define AR_PHY_TPCRG5_PD_GAIN_OVERLAP_S     0
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1    0x000003F0
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1_S  4
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2    0x0000FC00
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2_S  10
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3    0x003F0000
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3_S  16
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4    0x0FC00000
-#define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S  22
-
-/* Carrier leak calibration control, do it after AGC calibration */
-#define AR_PHY_CL_CAL_CTL       0xA358
-#define AR_PHY_CL_CAL_ENABLE    0x00000002
-#define AR_PHY_PARALLEL_CAL_ENABLE    0x00000001
-
-#define AR_PHY_POWER_TX_RATE5   0xA38C
-#define AR_PHY_POWER_TX_RATE6   0xA390
-
-#define AR_PHY_CAL_CHAINMASK    0xA39C
-
-#define AR_PHY_POWER_TX_SUB     0xA3C8
-#define AR_PHY_POWER_TX_RATE7   0xA3CC
-#define AR_PHY_POWER_TX_RATE8   0xA3D0
-#define AR_PHY_POWER_TX_RATE9   0xA3D4
-
-#define AR_PHY_XPA_CFG         0xA3D8
-#define AR_PHY_FORCE_XPA_CFG   0x000000001
-#define AR_PHY_FORCE_XPA_CFG_S 0
-
-#define AR_PHY_CH1_CCA          0xa864
-#define AR_PHY_CH1_MINCCA_PWR   0x0FF80000
-#define AR_PHY_CH1_MINCCA_PWR_S 19
-#define AR9280_PHY_CH1_MINCCA_PWR   0x1FF00000
-#define AR9280_PHY_CH1_MINCCA_PWR_S 20
-
-#define AR_PHY_CH2_CCA          0xb864
-#define AR_PHY_CH2_MINCCA_PWR   0x0FF80000
-#define AR_PHY_CH2_MINCCA_PWR_S 19
-
-#define AR_PHY_CH1_EXT_CCA          0xa9bc
-#define AR_PHY_CH1_EXT_MINCCA_PWR   0xFF800000
-#define AR_PHY_CH1_EXT_MINCCA_PWR_S 23
-#define AR9280_PHY_CH1_EXT_MINCCA_PWR   0x01FF0000
-#define AR9280_PHY_CH1_EXT_MINCCA_PWR_S 16
-
-#define AR_PHY_CH2_EXT_CCA          0xb9bc
-#define AR_PHY_CH2_EXT_MINCCA_PWR   0xFF800000
-#define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
+#define AR_PHY_CLC_TBL1      0xa35c
+#define AR_PHY_CLC_I0        0x07ff0000
+#define AR_PHY_CLC_I0_S      16
+#define AR_PHY_CLC_Q0        0x0000ffd0
+#define AR_PHY_CLC_Q0_S      5
 
 #define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do {               \
                int r;                                                  \
@@ -615,6 +51,7 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
 #define ANTSWAP_AB 0x0001
 #define REDUCE_CHAIN_0 0x00000050
 #define REDUCE_CHAIN_1 0x00000051
+#define AR_PHY_CHIP_ID 0x9818
 
 #define RF_BANK_SETUP(_bank, _iniarray, _col) do {                     \
                int i;                                                  \
@@ -622,4 +59,7 @@ bool ath9k_hw_set_rf_regs(struct ath_hw *ah,
                        (_bank)[i] = INI_RA((_iniarray), i, _col);;     \
        } while (0)
 
+#define        AR_PHY_TIMING11_SPUR_FREQ_SD            0x3FF00000
+#define        AR_PHY_TIMING11_SPUR_FREQ_SD_S          20
+
 #endif
index 244e1c6291776dc9f5c0a931ef1cb7cdcbbfb14a..8519452c95f1b1024b3584a49a33af14a0501350 100644 (file)
@@ -691,6 +691,19 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        rate_table = sc->cur_rate_table;
        rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
 
+       /*
+        * If we're in HT mode and both us and our peer supports LDPC.
+        * We don't need to check our own device's capabilities as our own
+        * ht capabilities would have already been intersected with our peer's.
+        */
+       if (conf_is_ht(&sc->hw->conf) &&
+           (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
+               tx_info->flags |= IEEE80211_TX_CTL_LDPC;
+
+       if (conf_is_ht(&sc->hw->conf) &&
+           (sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC))
+               tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT);
+
        if (is_probe) {
                /* set one try for probe rates. For the
                 * probes don't enable rts */
@@ -1228,8 +1241,12 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                long_retry = rate->count - 1;
        }
 
-       if (!priv_sta || !ieee80211_is_data(fc) ||
-           !(tx_info->pad[0] & ATH_TX_INFO_UPDATE_RC))
+       if (!priv_sta || !ieee80211_is_data(fc))
+               return;
+
+       /* This packet was aggregated but doesn't carry status info */
+       if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
+           !(tx_info->flags & IEEE80211_TX_STAT_AMPDU))
                return;
 
        if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
index 4f6d6fd442f477f6d7d759539cec602459259b5d..3d8d40cdc99ee2f934cf13109a54a4b604ccf2a9 100644 (file)
@@ -110,8 +110,8 @@ struct ath_rate_table {
        int rate_cnt;
        int mcs_start;
        struct {
-               int valid;
-               int valid_single_stream;
+               u8 valid;
+               u8 valid_single_stream;
                u8 phy;
                u32 ratekbps;
                u32 user_ratekbps;
@@ -172,14 +172,13 @@ struct ath_rate_priv {
 
 #define ATH_TX_INFO_FRAME_TYPE_INTERNAL        (1 << 0)
 #define ATH_TX_INFO_FRAME_TYPE_PAUSE   (1 << 1)
-#define ATH_TX_INFO_UPDATE_RC          (1 << 2)
 #define ATH_TX_INFO_XRETRY             (1 << 3)
 #define ATH_TX_INFO_UNDERRUN           (1 << 4)
 
 enum ath9k_internal_frame_type {
-       ATH9K_NOT_INTERNAL,
-       ATH9K_INT_PAUSE,
-       ATH9K_INT_UNPAUSE
+       ATH9K_IFT_NOT_INTERNAL,
+       ATH9K_IFT_PAUSE,
+       ATH9K_IFT_UNPAUSE
 };
 
 int ath_rate_control_register(void);
index 1ca42e5148c81ba72935899a931125b1a60b2d1a..ba139132c85f9013fb062154f6fa37a5d3e73bef 100644 (file)
@@ -15,6 +15,9 @@
  */
 
 #include "ath9k.h"
+#include "ar9003_mac.h"
+
+#define SKB_CB_ATHBUF(__skb)   (*((struct ath_buf **)__skb->cb))
 
 static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
                                             struct ieee80211_hdr *hdr)
@@ -115,56 +118,244 @@ static void ath_opmode_init(struct ath_softc *sc)
        ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]);
 }
 
-int ath_rx_init(struct ath_softc *sc, int nbufs)
+static bool ath_rx_edma_buf_link(struct ath_softc *sc,
+                                enum ath9k_rx_qtype qtype)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_rx_edma *rx_edma;
        struct sk_buff *skb;
        struct ath_buf *bf;
-       int error = 0;
 
-       spin_lock_init(&sc->rx.rxflushlock);
-       sc->sc_flags &= ~SC_OP_RXFLUSH;
-       spin_lock_init(&sc->rx.rxbuflock);
+       rx_edma = &sc->rx.rx_edma[qtype];
+       if (skb_queue_len(&rx_edma->rx_fifo) >= rx_edma->rx_fifo_hwsize)
+               return false;
 
-       common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
-                                    min(common->cachelsz, (u16)64));
+       bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+       list_del_init(&bf->list);
 
-       ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
-                 common->cachelsz, common->rx_bufsize);
+       skb = bf->bf_mpdu;
+
+       ATH_RXBUF_RESET(bf);
+       memset(skb->data, 0, ah->caps.rx_status_len);
+       dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+                               ah->caps.rx_status_len, DMA_TO_DEVICE);
 
-       /* Initialize rx descriptors */
+       SKB_CB_ATHBUF(skb) = bf;
+       ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype);
+       skb_queue_tail(&rx_edma->rx_fifo, skb);
 
-       error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
-                                 "rx", nbufs, 1);
-       if (error != 0) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "failed to allocate rx descriptors: %d\n", error);
-               goto err;
+       return true;
+}
+
+static void ath_rx_addbuffer_edma(struct ath_softc *sc,
+                                 enum ath9k_rx_qtype qtype, int size)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       u32 nbuf = 0;
+
+       if (list_empty(&sc->rx.rxbuf)) {
+               ath_print(common, ATH_DBG_QUEUE, "No free rx buf available\n");
+               return;
        }
 
+       while (!list_empty(&sc->rx.rxbuf)) {
+               nbuf++;
+
+               if (!ath_rx_edma_buf_link(sc, qtype))
+                       break;
+
+               if (nbuf >= size)
+                       break;
+       }
+}
+
+static void ath_rx_remove_buffer(struct ath_softc *sc,
+                                enum ath9k_rx_qtype qtype)
+{
+       struct ath_buf *bf;
+       struct ath_rx_edma *rx_edma;
+       struct sk_buff *skb;
+
+       rx_edma = &sc->rx.rx_edma[qtype];
+
+       while ((skb = skb_dequeue(&rx_edma->rx_fifo)) != NULL) {
+               bf = SKB_CB_ATHBUF(skb);
+               BUG_ON(!bf);
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+       }
+}
+
+static void ath_rx_edma_cleanup(struct ath_softc *sc)
+{
+       struct ath_buf *bf;
+
+       ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
+       ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
+
        list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+               if (bf->bf_mpdu)
+                       dev_kfree_skb_any(bf->bf_mpdu);
+       }
+
+       INIT_LIST_HEAD(&sc->rx.rxbuf);
+
+       kfree(sc->rx.rx_bufptr);
+       sc->rx.rx_bufptr = NULL;
+}
+
+static void ath_rx_edma_init_queue(struct ath_rx_edma *rx_edma, int size)
+{
+       skb_queue_head_init(&rx_edma->rx_fifo);
+       skb_queue_head_init(&rx_edma->rx_buffers);
+       rx_edma->rx_fifo_hwsize = size;
+}
+
+static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct sk_buff *skb;
+       struct ath_buf *bf;
+       int error = 0, i;
+       u32 size;
+
+
+       common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN +
+                                    ah->caps.rx_status_len,
+                                    min(common->cachelsz, (u16)64));
+
+       ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
+                                   ah->caps.rx_status_len);
+
+       ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_LP],
+                              ah->caps.rx_lp_qdepth);
+       ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP],
+                              ah->caps.rx_hp_qdepth);
+
+       size = sizeof(struct ath_buf) * nbufs;
+       bf = kzalloc(size, GFP_KERNEL);
+       if (!bf)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&sc->rx.rxbuf);
+       sc->rx.rx_bufptr = bf;
+
+       for (i = 0; i < nbufs; i++, bf++) {
                skb = ath_rxbuf_alloc(common, common->rx_bufsize, GFP_KERNEL);
-               if (skb == NULL) {
+               if (!skb) {
                        error = -ENOMEM;
-                       goto err;
+                       goto rx_init_fail;
                }
 
+               memset(skb->data, 0, common->rx_bufsize);
                bf->bf_mpdu = skb;
+
                bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
                                                 common->rx_bufsize,
-                                                DMA_FROM_DEVICE);
+                                                DMA_BIDIRECTIONAL);
                if (unlikely(dma_mapping_error(sc->dev,
-                                              bf->bf_buf_addr))) {
-                       dev_kfree_skb_any(skb);
-                       bf->bf_mpdu = NULL;
+                                               bf->bf_buf_addr))) {
+                               dev_kfree_skb_any(skb);
+                               bf->bf_mpdu = NULL;
+                               ath_print(common, ATH_DBG_FATAL,
+                                       "dma_mapping_error() on RX init\n");
+                               error = -ENOMEM;
+                               goto rx_init_fail;
+               }
+
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+       }
+
+       return 0;
+
+rx_init_fail:
+       ath_rx_edma_cleanup(sc);
+       return error;
+}
+
+static void ath_edma_start_recv(struct ath_softc *sc)
+{
+       spin_lock_bh(&sc->rx.rxbuflock);
+
+       ath9k_hw_rxena(sc->sc_ah);
+
+       ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_HP,
+                             sc->rx.rx_edma[ATH9K_RX_QUEUE_HP].rx_fifo_hwsize);
+
+       ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP,
+                             sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize);
+
+       spin_unlock_bh(&sc->rx.rxbuflock);
+
+       ath_opmode_init(sc);
+
+       ath9k_hw_startpcureceive(sc->sc_ah);
+}
+
+static void ath_edma_stop_recv(struct ath_softc *sc)
+{
+       spin_lock_bh(&sc->rx.rxbuflock);
+       ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
+       ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
+       spin_unlock_bh(&sc->rx.rxbuflock);
+}
+
+int ath_rx_init(struct ath_softc *sc, int nbufs)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct sk_buff *skb;
+       struct ath_buf *bf;
+       int error = 0;
+
+       spin_lock_init(&sc->rx.rxflushlock);
+       sc->sc_flags &= ~SC_OP_RXFLUSH;
+       spin_lock_init(&sc->rx.rxbuflock);
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               return ath_rx_edma_init(sc, nbufs);
+       } else {
+               common->rx_bufsize = roundup(IEEE80211_MAX_MPDU_LEN,
+                               min(common->cachelsz, (u16)64));
+
+               ath_print(common, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n",
+                               common->cachelsz, common->rx_bufsize);
+
+               /* Initialize rx descriptors */
+
+               error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf,
+                               "rx", nbufs, 1, 0);
+               if (error != 0) {
                        ath_print(common, ATH_DBG_FATAL,
-                                 "dma_mapping_error() on RX init\n");
-                       error = -ENOMEM;
+                                 "failed to allocate rx descriptors: %d\n",
+                                 error);
                        goto err;
                }
-               bf->bf_dmacontext = bf->bf_buf_addr;
+
+               list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+                       skb = ath_rxbuf_alloc(common, common->rx_bufsize,
+                                             GFP_KERNEL);
+                       if (skb == NULL) {
+                               error = -ENOMEM;
+                               goto err;
+                       }
+
+                       bf->bf_mpdu = skb;
+                       bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+                                       common->rx_bufsize,
+                                       DMA_FROM_DEVICE);
+                       if (unlikely(dma_mapping_error(sc->dev,
+                                                       bf->bf_buf_addr))) {
+                               dev_kfree_skb_any(skb);
+                               bf->bf_mpdu = NULL;
+                               ath_print(common, ATH_DBG_FATAL,
+                                         "dma_mapping_error() on RX init\n");
+                               error = -ENOMEM;
+                               goto err;
+                       }
+                       bf->bf_dmacontext = bf->bf_buf_addr;
+               }
+               sc->rx.rxlink = NULL;
        }
-       sc->rx.rxlink = NULL;
 
 err:
        if (error)
@@ -180,17 +371,23 @@ void ath_rx_cleanup(struct ath_softc *sc)
        struct sk_buff *skb;
        struct ath_buf *bf;
 
-       list_for_each_entry(bf, &sc->rx.rxbuf, list) {
-               skb = bf->bf_mpdu;
-               if (skb) {
-                       dma_unmap_single(sc->dev, bf->bf_buf_addr,
-                                        common->rx_bufsize, DMA_FROM_DEVICE);
-                       dev_kfree_skb(skb);
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               ath_rx_edma_cleanup(sc);
+               return;
+       } else {
+               list_for_each_entry(bf, &sc->rx.rxbuf, list) {
+                       skb = bf->bf_mpdu;
+                       if (skb) {
+                               dma_unmap_single(sc->dev, bf->bf_buf_addr,
+                                               common->rx_bufsize,
+                                               DMA_FROM_DEVICE);
+                               dev_kfree_skb(skb);
+                       }
                }
-       }
 
-       if (sc->rx.rxdma.dd_desc_len != 0)
-               ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
+               if (sc->rx.rxdma.dd_desc_len != 0)
+                       ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf);
+       }
 }
 
 /*
@@ -273,6 +470,11 @@ int ath_startrecv(struct ath_softc *sc)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf, *tbf;
 
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               ath_edma_start_recv(sc);
+               return 0;
+       }
+
        spin_lock_bh(&sc->rx.rxbuflock);
        if (list_empty(&sc->rx.rxbuf))
                goto start_recv;
@@ -306,7 +508,11 @@ bool ath_stoprecv(struct ath_softc *sc)
        ath9k_hw_stoppcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
        stopped = ath9k_hw_stopdmarecv(ah);
-       sc->rx.rxlink = NULL;
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               ath_edma_stop_recv(sc);
+       else
+               sc->rx.rxlink = NULL;
 
        return stopped;
 }
@@ -315,7 +521,9 @@ void ath_flushrecv(struct ath_softc *sc)
 {
        spin_lock_bh(&sc->rx.rxflushlock);
        sc->sc_flags |= SC_OP_RXFLUSH;
-       ath_rx_tasklet(sc, 1);
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               ath_rx_tasklet(sc, 1, true);
+       ath_rx_tasklet(sc, 1, false);
        sc->sc_flags &= ~SC_OP_RXFLUSH;
        spin_unlock_bh(&sc->rx.rxflushlock);
 }
@@ -469,15 +677,148 @@ static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
                ieee80211_rx(hw, skb);
 }
 
-int ath_rx_tasklet(struct ath_softc *sc, int flush)
+static bool ath_edma_get_buffers(struct ath_softc *sc,
+                                enum ath9k_rx_qtype qtype)
 {
-#define PA2DESC(_sc, _pa)                                               \
-       ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc +         \
-                            ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr)))
+       struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype];
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct sk_buff *skb;
+       struct ath_buf *bf;
+       int ret;
+
+       skb = skb_peek(&rx_edma->rx_fifo);
+       if (!skb)
+               return false;
+
+       bf = SKB_CB_ATHBUF(skb);
+       BUG_ON(!bf);
+
+       dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+                               common->rx_bufsize, DMA_FROM_DEVICE);
+
+       ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
+       if (ret == -EINPROGRESS)
+               return false;
+
+       __skb_unlink(skb, &rx_edma->rx_fifo);
+       if (ret == -EINVAL) {
+               /* corrupt descriptor, skip this one and the following one */
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+               ath_rx_edma_buf_link(sc, qtype);
+               skb = skb_peek(&rx_edma->rx_fifo);
+               if (!skb)
+                       return true;
+
+               bf = SKB_CB_ATHBUF(skb);
+               BUG_ON(!bf);
+
+               __skb_unlink(skb, &rx_edma->rx_fifo);
+               list_add_tail(&bf->list, &sc->rx.rxbuf);
+               ath_rx_edma_buf_link(sc, qtype);
+               return true;
+       }
+       skb_queue_tail(&rx_edma->rx_buffers, skb);
+
+       return true;
+}
 
+static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc,
+                                               struct ath_rx_status *rs,
+                                               enum ath9k_rx_qtype qtype)
+{
+       struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype];
+       struct sk_buff *skb;
        struct ath_buf *bf;
+
+       while (ath_edma_get_buffers(sc, qtype));
+       skb = __skb_dequeue(&rx_edma->rx_buffers);
+       if (!skb)
+               return NULL;
+
+       bf = SKB_CB_ATHBUF(skb);
+       ath9k_hw_process_rxdesc_edma(sc->sc_ah, rs, skb->data);
+       return bf;
+}
+
+static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
+                                          struct ath_rx_status *rs)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_desc *ds;
-       struct ath_rx_status *rx_stats;
+       struct ath_buf *bf;
+       int ret;
+
+       if (list_empty(&sc->rx.rxbuf)) {
+               sc->rx.rxlink = NULL;
+               return NULL;
+       }
+
+       bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+       ds = bf->bf_desc;
+
+       /*
+        * Must provide the virtual address of the current
+        * descriptor, the physical address, and the virtual
+        * address of the next descriptor in the h/w chain.
+        * This allows the HAL to look ahead to see if the
+        * hardware is done with a descriptor by checking the
+        * done bit in the following descriptor and the address
+        * of the current descriptor the DMA engine is working
+        * on.  All this is necessary because of our use of
+        * a self-linked list to avoid rx overruns.
+        */
+       ret = ath9k_hw_rxprocdesc(ah, ds, rs, 0);
+       if (ret == -EINPROGRESS) {
+               struct ath_rx_status trs;
+               struct ath_buf *tbf;
+               struct ath_desc *tds;
+
+               memset(&trs, 0, sizeof(trs));
+               if (list_is_last(&bf->list, &sc->rx.rxbuf)) {
+                       sc->rx.rxlink = NULL;
+                       return NULL;
+               }
+
+               tbf = list_entry(bf->list.next, struct ath_buf, list);
+
+               /*
+                * On some hardware the descriptor status words could
+                * get corrupted, including the done bit. Because of
+                * this, check if the next descriptor's done bit is
+                * set or not.
+                *
+                * If the next descriptor's done bit is set, the current
+                * descriptor has been corrupted. Force s/w to discard
+                * this descriptor and continue...
+                */
+
+               tds = tbf->bf_desc;
+               ret = ath9k_hw_rxprocdesc(ah, tds, &trs, 0);
+               if (ret == -EINPROGRESS)
+                       return NULL;
+       }
+
+       if (!bf->bf_mpdu)
+               return bf;
+
+       /*
+        * Synchronize the DMA transfer with CPU before
+        * 1. accessing the frame
+        * 2. requeueing the same buffer to h/w
+        */
+       dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+                       common->rx_bufsize,
+                       DMA_FROM_DEVICE);
+
+       return bf;
+}
+
+
+int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
+{
+       struct ath_buf *bf;
        struct sk_buff *skb = NULL, *requeue_skb;
        struct ieee80211_rx_status *rxs;
        struct ath_hw *ah = sc->sc_ah;
@@ -491,7 +832,17 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
        struct ieee80211_hdr *hdr;
        int retval;
        bool decrypt_error = false;
+       struct ath_rx_status rs;
+       enum ath9k_rx_qtype qtype;
+       bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
+       int dma_type;
 
+       if (edma)
+               dma_type = DMA_FROM_DEVICE;
+       else
+               dma_type = DMA_BIDIRECTIONAL;
+
+       qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
        spin_lock_bh(&sc->rx.rxbuflock);
 
        do {
@@ -499,79 +850,25 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0))
                        break;
 
-               if (list_empty(&sc->rx.rxbuf)) {
-                       sc->rx.rxlink = NULL;
-                       break;
-               }
-
-               bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
-               ds = bf->bf_desc;
-
-               /*
-                * Must provide the virtual address of the current
-                * descriptor, the physical address, and the virtual
-                * address of the next descriptor in the h/w chain.
-                * This allows the HAL to look ahead to see if the
-                * hardware is done with a descriptor by checking the
-                * done bit in the following descriptor and the address
-                * of the current descriptor the DMA engine is working
-                * on.  All this is necessary because of our use of
-                * a self-linked list to avoid rx overruns.
-                */
-               retval = ath9k_hw_rxprocdesc(ah, ds,
-                                            bf->bf_daddr,
-                                            PA2DESC(sc, ds->ds_link),
-                                            0);
-               if (retval == -EINPROGRESS) {
-                       struct ath_buf *tbf;
-                       struct ath_desc *tds;
-
-                       if (list_is_last(&bf->list, &sc->rx.rxbuf)) {
-                               sc->rx.rxlink = NULL;
-                               break;
-                       }
+               memset(&rs, 0, sizeof(rs));
+               if (edma)
+                       bf = ath_edma_get_next_rx_buf(sc, &rs, qtype);
+               else
+                       bf = ath_get_next_rx_buf(sc, &rs);
 
-                       tbf = list_entry(bf->list.next, struct ath_buf, list);
-
-                       /*
-                        * On some hardware the descriptor status words could
-                        * get corrupted, including the done bit. Because of
-                        * this, check if the next descriptor's done bit is
-                        * set or not.
-                        *
-                        * If the next descriptor's done bit is set, the current
-                        * descriptor has been corrupted. Force s/w to discard
-                        * this descriptor and continue...
-                        */
-
-                       tds = tbf->bf_desc;
-                       retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr,
-                                            PA2DESC(sc, tds->ds_link), 0);
-                       if (retval == -EINPROGRESS) {
-                               break;
-                       }
-               }
+               if (!bf)
+                       break;
 
                skb = bf->bf_mpdu;
                if (!skb)
                        continue;
 
-               /*
-                * Synchronize the DMA transfer with CPU before
-                * 1. accessing the frame
-                * 2. requeueing the same buffer to h/w
-                */
-               dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
-                               common->rx_bufsize,
-                               DMA_FROM_DEVICE);
-
                hdr = (struct ieee80211_hdr *) skb->data;
                rxs =  IEEE80211_SKB_RXCB(skb);
 
                hw = ath_get_virt_hw(sc, hdr);
-               rx_stats = &ds->ds_rxstat;
 
-               ath_debug_stat_rx(sc, bf);
+               ath_debug_stat_rx(sc, &rs);
 
                /*
                 * If we're asked to flush receive queue, directly
@@ -580,7 +877,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                if (flush)
                        goto requeue;
 
-               retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, rx_stats,
+               retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs,
                                                     rxs, &decrypt_error);
                if (retval)
                        goto requeue;
@@ -599,18 +896,20 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                /* Unmap the frame */
                dma_unmap_single(sc->dev, bf->bf_buf_addr,
                                 common->rx_bufsize,
-                                DMA_FROM_DEVICE);
+                                dma_type);
 
-               skb_put(skb, rx_stats->rs_datalen);
+               skb_put(skb, rs.rs_datalen + ah->caps.rx_status_len);
+               if (ah->caps.rx_status_len)
+                       skb_pull(skb, ah->caps.rx_status_len);
 
-               ath9k_cmn_rx_skb_postprocess(common, skb, rx_stats,
+               ath9k_cmn_rx_skb_postprocess(common, skb, &rs,
                                             rxs, decrypt_error);
 
                /* We will now give hardware our shiny new allocated skb */
                bf->bf_mpdu = requeue_skb;
                bf->bf_buf_addr = dma_map_single(sc->dev, requeue_skb->data,
                                                 common->rx_bufsize,
-                                                DMA_FROM_DEVICE);
+                                                dma_type);
                if (unlikely(dma_mapping_error(sc->dev,
                          bf->bf_buf_addr))) {
                        dev_kfree_skb_any(requeue_skb);
@@ -626,9 +925,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                 * change the default rx antenna if rx diversity chooses the
                 * other antenna 3 times in a row.
                 */
-               if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
+               if (sc->rx.defant != rs.rs_antenna) {
                        if (++sc->rx.rxotherant >= 3)
-                               ath_setdefantenna(sc, rx_stats->rs_antenna);
+                               ath_setdefantenna(sc, rs.rs_antenna);
                } else {
                        sc->rx.rxotherant = 0;
                }
@@ -641,12 +940,16 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                ath_rx_send_to_mac80211(hw, sc, skb, rxs);
 
 requeue:
-               list_move_tail(&bf->list, &sc->rx.rxbuf);
-               ath_rx_buf_link(sc, bf);
+               if (edma) {
+                       list_add_tail(&bf->list, &sc->rx.rxbuf);
+                       ath_rx_edma_buf_link(sc, qtype);
+               } else {
+                       list_move_tail(&bf->list, &sc->rx.rxbuf);
+                       ath_rx_buf_link(sc, bf);
+               }
        } while (1);
 
        spin_unlock_bh(&sc->rx.rxbuflock);
 
        return 0;
-#undef PA2DESC
 }
index 72cfa8ebd9ae193677cc6c77c985ffab9b6c354a..d4371a43bdaac35a6073a55fccf319c3bbe46043 100644 (file)
@@ -20,7 +20,7 @@
 #include "../reg.h"
 
 #define AR_CR                0x0008
-#define AR_CR_RXE            0x00000004
+#define AR_CR_RXE            (AR_SREV_9300_20_OR_LATER(ah) ? 0x0000000c : 0x00000004)
 #define AR_CR_RXD            0x00000020
 #define AR_CR_SWI            0x00000040
 
 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH         0x00060000
 #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S       17
 
+#define AR_RXBP_THRESH       0x0018
+#define AR_RXBP_THRESH_HP    0x0000000f
+#define AR_RXBP_THRESH_HP_S  0
+#define AR_RXBP_THRESH_LP    0x00003f00
+#define AR_RXBP_THRESH_LP_S  8
+
 #define AR_MIRT              0x0020
 #define AR_MIRT_VAL          0x0000ffff
 #define AR_MIRT_VAL_S        16
 #define AR_MACMISC_MISC_OBS_BUS_MSB_S   15
 #define AR_MACMISC_MISC_OBS_BUS_1       1
 
+#define AR_DATABUF_SIZE                0x0060
+#define AR_DATABUF_SIZE_MASK   0x00000FFF
+
 #define AR_GTXTO    0x0064
 #define AR_GTXTO_TIMEOUT_COUNTER    0x0000FFFF
 #define AR_GTXTO_TIMEOUT_LIMIT      0xFFFF0000
 #define AR_CST_TIMEOUT_LIMIT      0xFFFF0000
 #define AR_CST_TIMEOUT_LIMIT_S    16
 
+#define AR_HP_RXDP 0x0074
+#define AR_LP_RXDP 0x0078
+
 #define AR_ISR               0x0080
 #define AR_ISR_RXOK          0x00000001
 #define AR_ISR_RXDESC        0x00000002
+#define AR_ISR_HP_RXOK      0x00000001
+#define AR_ISR_LP_RXOK      0x00000002
 #define AR_ISR_RXERR         0x00000004
 #define AR_ISR_RXNOPKT       0x00000008
 #define AR_ISR_RXEOL         0x00000010
 #define AR_ISR_S5_TIMER_THRESH      0x0007FE00
 #define AR_ISR_S5_TIM_TIMER         0x00000010
 #define AR_ISR_S5_DTIM_TIMER        0x00000020
-#define AR_ISR_S5_S                 0x00d8
 #define AR_IMR_S5                   0x00b8
 #define AR_IMR_S5_TIM_TIMER         0x00000010
 #define AR_IMR_S5_DTIM_TIMER        0x00000020
 #define AR_ISR_S5_GENTIMER_TRIG_S   0
 #define AR_ISR_S5_GENTIMER_THRESH   0xFF800000
 #define AR_ISR_S5_GENTIMER_THRESH_S 16
-#define AR_ISR_S5_S                 0x00d8
 #define AR_IMR_S5_GENTIMER_TRIG     0x0000FF80
 #define AR_IMR_S5_GENTIMER_TRIG_S   0
 #define AR_IMR_S5_GENTIMER_THRESH   0xFF800000
 #define AR_IMR               0x00a0
 #define AR_IMR_RXOK          0x00000001
 #define AR_IMR_RXDESC        0x00000002
+#define AR_IMR_RXOK_HP      0x00000001
+#define AR_IMR_RXOK_LP      0x00000002
 #define AR_IMR_RXERR         0x00000004
 #define AR_IMR_RXNOPKT       0x00000008
 #define AR_IMR_RXEOL         0x00000010
 #define AR_ISR_S1_QCU_TXEOL    0x03FF0000
 #define AR_ISR_S1_QCU_TXEOL_S  16
 
-#define AR_ISR_S2_S           0x00cc
-#define AR_ISR_S3_S           0x00d0
-#define AR_ISR_S4_S           0x00d4
-#define AR_ISR_S5_S           0x00d8
+#define AR_ISR_S2_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d0 : 0x00cc)
+#define AR_ISR_S3_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d4 : 0x00d0)
+#define AR_ISR_S4_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00d8 : 0x00d4)
+#define AR_ISR_S5_S           (AR_SREV_9300_20_OR_LATER(ah) ? 0x00dc : 0x00d8)
 #define AR_DMADBG_0           0x00e0
 #define AR_DMADBG_1           0x00e4
 #define AR_DMADBG_2           0x00e8
 #define AR_Q9_TXDP           0x0824
 #define AR_QTXDP(_i)    (AR_Q0_TXDP + ((_i)<<2))
 
+#define AR_Q_STATUS_RING_START 0x830
+#define AR_Q_STATUS_RING_END   0x834
+
 #define AR_Q_TXE             0x0840
 #define AR_Q_TXE_M           0x000003FF
 
 #define AR_Q_RDYTIMESHDN    0x0a40
 #define AR_Q_RDYTIMESHDN_M  0x000003FF
 
+/* MAC Descriptor CRC check */
+#define AR_Q_DESC_CRCCHK    0xa44
+/* Enable CRC check on the descriptor fetched from host */
+#define AR_Q_DESC_CRCCHK_EN 1
 
 #define AR_NUM_DCU      10
 #define AR_DCU_0        0x0001
 
 #define AR_WA                          0x4004
 #define AR_WA_D3_L1_DISABLE            (1 << 14)
-#define AR9285_WA_DEFAULT              0x004a05cb
+#define AR9285_WA_DEFAULT              0x004a050b
 #define AR9280_WA_DEFAULT              0x0040073b
 #define AR_WA_DEFAULT                  0x0000073f
 
 #define AR_SREV_VERSION_9271                   0x140
 #define AR_SREV_REVISION_9271_10               0
 #define AR_SREV_REVISION_9271_11               1
+#define AR_SREV_VERSION_9300                  0x1c0
+#define AR_SREV_REVISION_9300_20              2 /* 2.0 and 2.1 */
 
 #define AR_SREV_5416(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
 #define AR_SREV_9271_11(_ah) \
     (AR_SREV_9271(_ah) && \
      ((_ah)->hw_version.macRev == AR_SREV_REVISION_9271_11))
+#define AR_SREV_9300(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
+#define AR_SREV_9300_20(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9300_20))
+#define AR_SREV_9300_20_OR_LATER(_ah) \
+       (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \
+        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
+         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20)))
+
+#define AR_SREV_9285E_20(_ah) \
+    (AR_SREV_9285_12_OR_LATER(_ah) && \
+     ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1))
 
 #define AR_RADIO_SREV_MAJOR                   0xf0
 #define AR_RAD5133_SREV_MAJOR                 0xc0
@@ -940,6 +976,8 @@ enum {
 #define AR928X_NUM_GPIO                          10
 #define AR9285_NUM_GPIO                          12
 #define AR9287_NUM_GPIO                          11
+#define AR9271_NUM_GPIO                          16
+#define AR9300_NUM_GPIO                          17
 
 #define AR_GPIO_IN_OUT                           0x4048
 #define AR_GPIO_IN_VAL                           0x0FFFC000
@@ -950,19 +988,23 @@ enum {
 #define AR9285_GPIO_IN_VAL_S                     12
 #define AR9287_GPIO_IN_VAL                       0x003FF800
 #define AR9287_GPIO_IN_VAL_S                     11
+#define AR9271_GPIO_IN_VAL                       0xFFFF0000
+#define AR9271_GPIO_IN_VAL_S                     16
+#define AR9300_GPIO_IN_VAL                       0x0001FFFF
+#define AR9300_GPIO_IN_VAL_S                     0
 
-#define AR_GPIO_OE_OUT                           0x404c
+#define AR_GPIO_OE_OUT                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
 #define AR_GPIO_OE_OUT_DRV                       0x3
 #define AR_GPIO_OE_OUT_DRV_NO                    0x0
 #define AR_GPIO_OE_OUT_DRV_LOW                   0x1
 #define AR_GPIO_OE_OUT_DRV_HI                    0x2
 #define AR_GPIO_OE_OUT_DRV_ALL                   0x3
 
-#define AR_GPIO_INTR_POL                         0x4050
-#define AR_GPIO_INTR_POL_VAL                     0x00001FFF
+#define AR_GPIO_INTR_POL                         (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)
+#define AR_GPIO_INTR_POL_VAL                     0x0001FFFF
 #define AR_GPIO_INTR_POL_VAL_S                   0
 
-#define AR_GPIO_INPUT_EN_VAL                     0x4054
+#define AR_GPIO_INPUT_EN_VAL                     (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)
 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF     0x00000004
 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S       2
 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF    0x00000008
@@ -980,13 +1022,13 @@ enum {
 #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE        0x00010000
 #define AR_GPIO_JTAG_DISABLE                     0x00020000
 
-#define AR_GPIO_INPUT_MUX1                       0x4058
+#define AR_GPIO_INPUT_MUX1                       (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)
 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE             0x000f0000
 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S           16
 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY           0x00000f00
 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S         8
 
-#define AR_GPIO_INPUT_MUX2                       0x405c
+#define AR_GPIO_INPUT_MUX2                       (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)
 #define AR_GPIO_INPUT_MUX2_CLK25                 0x0000000f
 #define AR_GPIO_INPUT_MUX2_CLK25_S               0
 #define AR_GPIO_INPUT_MUX2_RFSILENT              0x000000f0
@@ -994,13 +1036,13 @@ enum {
 #define AR_GPIO_INPUT_MUX2_RTC_RESET             0x00000f00
 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S           8
 
-#define AR_GPIO_OUTPUT_MUX1                      0x4060
-#define AR_GPIO_OUTPUT_MUX2                      0x4064
-#define AR_GPIO_OUTPUT_MUX3                      0x4068
+#define AR_GPIO_OUTPUT_MUX1                      (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)
+#define AR_GPIO_OUTPUT_MUX2                      (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)
+#define AR_GPIO_OUTPUT_MUX3                      (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)
 
-#define AR_INPUT_STATE                           0x406c
+#define AR_INPUT_STATE                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)
 
-#define AR_EEPROM_STATUS_DATA                    0x407c
+#define AR_EEPROM_STATUS_DATA                    (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)
 #define AR_EEPROM_STATUS_DATA_VAL                0x0000ffff
 #define AR_EEPROM_STATUS_DATA_VAL_S              0
 #define AR_EEPROM_STATUS_DATA_BUSY               0x00010000
@@ -1008,13 +1050,24 @@ enum {
 #define AR_EEPROM_STATUS_DATA_PROT_ACCESS        0x00040000
 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS      0x00080000
 
-#define AR_OBS                  0x4080
+#define AR_OBS                  (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)
 
-#define AR_GPIO_PDPU                             0x4088
+#define AR_GPIO_PDPU                             (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088)
 
-#define AR_PCIE_MSI                              0x4094
+#define AR_PCIE_MSI                              (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)
 #define AR_PCIE_MSI_ENABLE                       0x00000001
 
+#define AR_INTR_PRIO_SYNC_ENABLE  0x40c4
+#define AR_INTR_PRIO_ASYNC_MASK   0x40c8
+#define AR_INTR_PRIO_SYNC_MASK    0x40cc
+#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4
+
+#define AR_RTC_9300_PLL_DIV          0x000003ff
+#define AR_RTC_9300_PLL_DIV_S        0
+#define AR_RTC_9300_PLL_REFDIV       0x00003C00
+#define AR_RTC_9300_PLL_REFDIV_S     10
+#define AR_RTC_9300_PLL_CLKSEL       0x0000C000
+#define AR_RTC_9300_PLL_CLKSEL_S     14
 
 #define AR_RTC_9160_PLL_DIV    0x000003ff
 #define AR_RTC_9160_PLL_DIV_S   0
@@ -1032,6 +1085,16 @@ enum {
 #define AR_RTC_RC_COLD_RESET    0x00000004
 #define AR_RTC_RC_WARM_RESET    0x00000008
 
+/* Crystal Control */
+#define AR_RTC_XTAL_CONTROL     0x7004
+
+/* Reg Control 0 */
+#define AR_RTC_REG_CONTROL0     0x7008
+
+/* Reg Control 1 */
+#define AR_RTC_REG_CONTROL1     0x700c
+#define AR_RTC_REG_CONTROL1_SWREG_PROGRAM       0x00000001
+
 #define AR_RTC_PLL_CONTROL \
        ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0014) : 0x7014)
 
@@ -1062,6 +1125,7 @@ enum {
 #define AR_RTC_SLEEP_CLK \
        ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0048) : 0x7048)
 #define AR_RTC_FORCE_DERIVED_CLK    0x2
+#define AR_RTC_FORCE_SWREG_PRD      0x00000004
 
 #define AR_RTC_FORCE_WAKE \
        ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x004c) : 0x704c)
@@ -1178,6 +1242,13 @@ enum {
 #define AR9285_AN_RF2G4_DB2_4    0x00003800
 #define AR9285_AN_RF2G4_DB2_4_S    11
 
+#define AR9285_RF2G5                   0x7830
+#define AR9285_RF2G5_IC50TX            0xfffff8ff
+#define AR9285_RF2G5_IC50TX_SET                0x00000400
+#define AR9285_RF2G5_IC50TX_XE_SET     0x00000500
+#define AR9285_RF2G5_IC50TX_CLEAR      0x00000700
+#define AR9285_RF2G5_IC50TX_CLEAR_S    8
+
 /* AR9271 : 0x7828, 0x782c different setting from AR9285 */
 #define AR9271_AN_RF2G3_OB_cck         0x001C0000
 #define AR9271_AN_RF2G3_OB_cck_S       18
@@ -1519,7 +1590,7 @@ enum {
 #define AR_TSFOOR_THRESHOLD       0x813c
 #define AR_TSFOOR_THRESHOLD_VAL   0x0000FFFF
 
-#define AR_PHY_ERR_EIFS_MASK   8144
+#define AR_PHY_ERR_EIFS_MASK   0x8144
 
 #define AR_PHY_ERR_3           0x8168
 #define AR_PHY_ERR_3_COUNT     0x00FFFFFF
@@ -1585,24 +1656,26 @@ enum {
 #define AR_FIRST_NDP_TIMER                  7
 #define AR_NDP2_PERIOD                      0x81a0
 #define AR_NDP2_TIMER_MODE                  0x81c0
-#define AR_NEXT_TBTT_TIMER                  0x8200
-#define AR_NEXT_DMA_BEACON_ALERT            0x8204
-#define AR_NEXT_SWBA                        0x8208
-#define AR_NEXT_CFP                         0x8208
-#define AR_NEXT_HCF                         0x820C
-#define AR_NEXT_TIM                         0x8210
-#define AR_NEXT_DTIM                        0x8214
-#define AR_NEXT_QUIET_TIMER                 0x8218
-#define AR_NEXT_NDP_TIMER                   0x821C
-
-#define AR_BEACON_PERIOD                    0x8220
-#define AR_DMA_BEACON_PERIOD                0x8224
-#define AR_SWBA_PERIOD                      0x8228
-#define AR_HCF_PERIOD                       0x822C
-#define AR_TIM_PERIOD                       0x8230
-#define AR_DTIM_PERIOD                      0x8234
-#define AR_QUIET_PERIOD                     0x8238
-#define AR_NDP_PERIOD                       0x823C
+
+#define AR_GEN_TIMERS(_i)                   (0x8200 + ((_i) << 2))
+#define AR_NEXT_TBTT_TIMER                  AR_GEN_TIMERS(0)
+#define AR_NEXT_DMA_BEACON_ALERT            AR_GEN_TIMERS(1)
+#define AR_NEXT_SWBA                        AR_GEN_TIMERS(2)
+#define AR_NEXT_CFP                         AR_GEN_TIMERS(2)
+#define AR_NEXT_HCF                         AR_GEN_TIMERS(3)
+#define AR_NEXT_TIM                         AR_GEN_TIMERS(4)
+#define AR_NEXT_DTIM                        AR_GEN_TIMERS(5)
+#define AR_NEXT_QUIET_TIMER                 AR_GEN_TIMERS(6)
+#define AR_NEXT_NDP_TIMER                   AR_GEN_TIMERS(7)
+
+#define AR_BEACON_PERIOD                    AR_GEN_TIMERS(8)
+#define AR_DMA_BEACON_PERIOD                AR_GEN_TIMERS(9)
+#define AR_SWBA_PERIOD                      AR_GEN_TIMERS(10)
+#define AR_HCF_PERIOD                       AR_GEN_TIMERS(11)
+#define AR_TIM_PERIOD                       AR_GEN_TIMERS(12)
+#define AR_DTIM_PERIOD                      AR_GEN_TIMERS(13)
+#define AR_QUIET_PERIOD                     AR_GEN_TIMERS(14)
+#define AR_NDP_PERIOD                       AR_GEN_TIMERS(15)
 
 #define AR_TIMER_MODE                       0x8240
 #define AR_TBTT_TIMER_EN                    0x00000001
@@ -1716,4 +1789,32 @@ enum {
 #define AR9271_CORE_CLOCK      117   /* clock to 117Mhz */
 #define AR9271_TARGET_BAUD_RATE        19200 /* 115200 */
 
+#define AR_AGG_WEP_ENABLE_FIX          0x00000008  /* This allows the use of AR_AGG_WEP_ENABLE */
+#define AR_ADHOC_MCAST_KEYID_ENABLE     0x00000040  /* This bit enables the Multicast search
+                                                    * based on both MAC Address and Key ID.
+                                                    * If bit is 0, then Multicast search is
+                                                    * based on MAC address only.
+                                                    * For Merlin and above only.
+                                                    */
+#define AR_AGG_WEP_ENABLE               0x00020000  /* This field enables AGG_WEP feature,
+                                                    * when it is enable, AGG_WEP would takes
+                                                    * charge of the encryption interface of
+                                                    * pcu_txsm.
+                                                    */
+
+#define AR9300_SM_BASE                         0xa200
+#define AR9002_PHY_AGC_CONTROL                 0x9860
+#define AR9003_PHY_AGC_CONTROL                 AR9300_SM_BASE + 0xc4
+#define AR_PHY_AGC_CONTROL                     (AR_SREV_9300_20_OR_LATER(ah) ? AR9003_PHY_AGC_CONTROL : AR9002_PHY_AGC_CONTROL)
+#define AR_PHY_AGC_CONTROL_CAL                 0x00000001  /* do internal calibration */
+#define AR_PHY_AGC_CONTROL_NF                  0x00000002  /* do noise-floor calibration */
+#define AR_PHY_AGC_CONTROL_OFFSET_CAL          0x00000800  /* allow offset calibration */
+#define AR_PHY_AGC_CONTROL_ENABLE_NF           0x00008000  /* enable noise floor calibration to happen */
+#define AR_PHY_AGC_CONTROL_FLTR_CAL            0x00010000  /* allow tx filter calibration */
+#define AR_PHY_AGC_CONTROL_NO_UPDATE_NF                0x00020000  /* don't update noise floor automatically */
+#define AR_PHY_AGC_CONTROL_EXT_NF_PWR_MEAS     0x00040000  /* extend noise floor power measurement */
+#define AR_PHY_AGC_CONTROL_CLC_SUCCESS         0x00080000  /* carrier leak calibration done */
+#define AR_PHY_AGC_CONTROL_YCOK_MAX            0x000003c0
+#define AR_PHY_AGC_CONTROL_YCOK_MAX_S          6
+
 #endif
index 00c0e21a4af77269fb2b013a3bf25291ce39adc3..105ad40968f6a41af2b7de50299a97d239b58d21 100644 (file)
@@ -220,7 +220,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
 
        memset(&txctl, 0, sizeof(struct ath_tx_control));
        txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]];
-       txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE;
+       txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE;
 
        if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
                goto exit;
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
new file mode 100644 (file)
index 0000000..e23172c
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2010 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 "htc.h"
+
+static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
+{
+       switch (wmi_cmd) {
+       case WMI_ECHO_CMDID:
+               return "WMI_ECHO_CMDID";
+       case WMI_ACCESS_MEMORY_CMDID:
+               return "WMI_ACCESS_MEMORY_CMDID";
+       case WMI_DISABLE_INTR_CMDID:
+               return "WMI_DISABLE_INTR_CMDID";
+       case WMI_ENABLE_INTR_CMDID:
+               return "WMI_ENABLE_INTR_CMDID";
+       case WMI_RX_LINK_CMDID:
+               return "WMI_RX_LINK_CMDID";
+       case WMI_ATH_INIT_CMDID:
+               return "WMI_ATH_INIT_CMDID";
+       case WMI_ABORT_TXQ_CMDID:
+               return "WMI_ABORT_TXQ_CMDID";
+       case WMI_STOP_TX_DMA_CMDID:
+               return "WMI_STOP_TX_DMA_CMDID";
+       case WMI_STOP_DMA_RECV_CMDID:
+               return "WMI_STOP_DMA_RECV_CMDID";
+       case WMI_ABORT_TX_DMA_CMDID:
+               return "WMI_ABORT_TX_DMA_CMDID";
+       case WMI_DRAIN_TXQ_CMDID:
+               return "WMI_DRAIN_TXQ_CMDID";
+       case WMI_DRAIN_TXQ_ALL_CMDID:
+               return "WMI_DRAIN_TXQ_ALL_CMDID";
+       case WMI_START_RECV_CMDID:
+               return "WMI_START_RECV_CMDID";
+       case WMI_STOP_RECV_CMDID:
+               return "WMI_STOP_RECV_CMDID";
+       case WMI_FLUSH_RECV_CMDID:
+               return "WMI_FLUSH_RECV_CMDID";
+       case WMI_SET_MODE_CMDID:
+               return "WMI_SET_MODE_CMDID";
+       case WMI_RESET_CMDID:
+               return "WMI_RESET_CMDID";
+       case WMI_NODE_CREATE_CMDID:
+               return "WMI_NODE_CREATE_CMDID";
+       case WMI_NODE_REMOVE_CMDID:
+               return "WMI_NODE_REMOVE_CMDID";
+       case WMI_VAP_REMOVE_CMDID:
+               return "WMI_VAP_REMOVE_CMDID";
+       case WMI_VAP_CREATE_CMDID:
+               return "WMI_VAP_CREATE_CMDID";
+       case WMI_BEACON_UPDATE_CMDID:
+               return "WMI_BEACON_UPDATE_CMDID";
+       case WMI_REG_READ_CMDID:
+               return "WMI_REG_READ_CMDID";
+       case WMI_REG_WRITE_CMDID:
+               return "WMI_REG_WRITE_CMDID";
+       case WMI_RC_STATE_CHANGE_CMDID:
+               return "WMI_RC_STATE_CHANGE_CMDID";
+       case WMI_RC_RATE_UPDATE_CMDID:
+               return "WMI_RC_RATE_UPDATE_CMDID";
+       case WMI_DEBUG_INFO_CMDID:
+               return "WMI_DEBUG_INFO_CMDID";
+       case WMI_HOST_ATTACH:
+               return "WMI_HOST_ATTACH";
+       case WMI_TARGET_IC_UPDATE_CMDID:
+               return "WMI_TARGET_IC_UPDATE_CMDID";
+       case WMI_TGT_STATS_CMDID:
+               return "WMI_TGT_STATS_CMDID";
+       case WMI_TX_AGGR_ENABLE_CMDID:
+               return "WMI_TX_AGGR_ENABLE_CMDID";
+       case WMI_TGT_DETACH_CMDID:
+               return "WMI_TGT_DETACH_CMDID";
+       case WMI_TGT_TXQ_ENABLE_CMDID:
+               return "WMI_TGT_TXQ_ENABLE_CMDID";
+       }
+
+       return "Bogus";
+}
+
+struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
+{
+       struct wmi *wmi;
+
+       wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL);
+       if (!wmi)
+               return NULL;
+
+       wmi->drv_priv = priv;
+       wmi->stopped = false;
+       mutex_init(&wmi->op_mutex);
+       mutex_init(&wmi->multi_write_mutex);
+       init_completion(&wmi->cmd_wait);
+
+       return wmi;
+}
+
+void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
+{
+       struct wmi *wmi = priv->wmi;
+
+       mutex_lock(&wmi->op_mutex);
+       wmi->stopped = true;
+       mutex_unlock(&wmi->op_mutex);
+
+       kfree(priv->wmi);
+}
+
+void ath9k_wmi_tasklet(unsigned long data)
+{
+       struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct wmi_cmd_hdr *hdr;
+       struct wmi_swba *swba_hdr;
+       enum wmi_event_id event;
+       struct sk_buff *skb;
+       void *wmi_event;
+       unsigned long flags;
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+       __be32 txrate;
+#endif
+
+       spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+       skb = priv->wmi->wmi_skb;
+       spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+
+       hdr = (struct wmi_cmd_hdr *) skb->data;
+       event = be16_to_cpu(hdr->command_id);
+       wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+       ath_print(common, ATH_DBG_WMI,
+                 "WMI Event: 0x%x\n", event);
+
+       switch (event) {
+       case WMI_TGT_RDY_EVENTID:
+               break;
+       case WMI_SWBA_EVENTID:
+               swba_hdr = (struct wmi_swba *) wmi_event;
+               ath9k_htc_swba(priv, swba_hdr->beacon_pending);
+               break;
+       case WMI_FATAL_EVENTID:
+               break;
+       case WMI_TXTO_EVENTID:
+               break;
+       case WMI_BMISS_EVENTID:
+               break;
+       case WMI_WLAN_TXCOMP_EVENTID:
+               break;
+       case WMI_DELBA_EVENTID:
+               break;
+       case WMI_TXRATE_EVENTID:
+#ifdef CONFIG_ATH9K_HTC_DEBUGFS
+               txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
+               priv->debug.txrate = be32_to_cpu(txrate);
+#endif
+               break;
+       default:
+               break;
+       }
+
+       kfree_skb(skb);
+}
+
+static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb)
+{
+       skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+       if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0)
+               memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len);
+
+       complete(&wmi->cmd_wait);
+}
+
+static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
+                             enum htc_endpoint_id epid)
+{
+       struct wmi *wmi = (struct wmi *) priv;
+       struct wmi_cmd_hdr *hdr;
+       u16 cmd_id;
+
+       if (unlikely(wmi->stopped))
+               goto free_skb;
+
+       hdr = (struct wmi_cmd_hdr *) skb->data;
+       cmd_id = be16_to_cpu(hdr->command_id);
+
+       if (cmd_id & 0x1000) {
+               spin_lock(&wmi->wmi_lock);
+               wmi->wmi_skb = skb;
+               spin_unlock(&wmi->wmi_lock);
+               tasklet_schedule(&wmi->drv_priv->wmi_tasklet);
+               return;
+       }
+
+       /* Check if there has been a timeout. */
+       spin_lock(&wmi->wmi_lock);
+       if (cmd_id != wmi->last_cmd_id) {
+               spin_unlock(&wmi->wmi_lock);
+               goto free_skb;
+       }
+       spin_unlock(&wmi->wmi_lock);
+
+       /* WMI command response */
+       ath9k_wmi_rsp_callback(wmi, skb);
+
+free_skb:
+       kfree_skb(skb);
+}
+
+static void ath9k_wmi_ctrl_tx(void *priv, struct sk_buff *skb,
+                             enum htc_endpoint_id epid, bool txok)
+{
+       kfree_skb(skb);
+}
+
+int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
+                     enum htc_endpoint_id *wmi_ctrl_epid)
+{
+       struct htc_service_connreq connect;
+       int ret;
+
+       wmi->htc = htc;
+
+       memset(&connect, 0, sizeof(connect));
+
+       connect.ep_callbacks.priv = wmi;
+       connect.ep_callbacks.tx = ath9k_wmi_ctrl_tx;
+       connect.ep_callbacks.rx = ath9k_wmi_ctrl_rx;
+       connect.service_id = WMI_CONTROL_SVC;
+
+       ret = htc_connect_service(htc, &connect, &wmi->ctrl_epid);
+       if (ret)
+               return ret;
+
+       *wmi_ctrl_epid = wmi->ctrl_epid;
+
+       return 0;
+}
+
+static int ath9k_wmi_cmd_issue(struct wmi *wmi,
+                              struct sk_buff *skb,
+                              enum wmi_cmd_id cmd, u16 len)
+{
+       struct wmi_cmd_hdr *hdr;
+
+       hdr = (struct wmi_cmd_hdr *) skb_push(skb, sizeof(struct wmi_cmd_hdr));
+       hdr->command_id = cpu_to_be16(cmd);
+       hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
+
+       return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL);
+}
+
+int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
+                 u8 *cmd_buf, u32 cmd_len,
+                 u8 *rsp_buf, u32 rsp_len,
+                 u32 timeout)
+{
+       struct ath_hw *ah = wmi->drv_priv->ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       u16 headroom = sizeof(struct htc_frame_hdr) +
+                      sizeof(struct wmi_cmd_hdr);
+       struct sk_buff *skb;
+       u8 *data;
+       int time_left, ret = 0;
+       unsigned long flags;
+
+       if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
+               return 0;
+
+       if (!wmi)
+               return -EINVAL;
+
+       skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reserve(skb, headroom);
+
+       if (cmd_len != 0 && cmd_buf != NULL) {
+               data = (u8 *) skb_put(skb, cmd_len);
+               memcpy(data, cmd_buf, cmd_len);
+       }
+
+       mutex_lock(&wmi->op_mutex);
+
+       /* check if wmi stopped flag is set */
+       if (unlikely(wmi->stopped)) {
+               ret = -EPROTO;
+               goto out;
+       }
+
+       /* record the rsp buffer and length */
+       wmi->cmd_rsp_buf = rsp_buf;
+       wmi->cmd_rsp_len = rsp_len;
+
+       spin_lock_irqsave(&wmi->wmi_lock, flags);
+       wmi->last_cmd_id = cmd_id;
+       spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
+       ret = ath9k_wmi_cmd_issue(wmi, skb, cmd_id, cmd_len);
+       if (ret)
+               goto out;
+
+       time_left = wait_for_completion_timeout(&wmi->cmd_wait, timeout);
+       if (!time_left) {
+               ath_print(common, ATH_DBG_WMI,
+                         "Timeout waiting for WMI command: %s\n",
+                         wmi_cmd_to_name(cmd_id));
+               mutex_unlock(&wmi->op_mutex);
+               return -ETIMEDOUT;
+       }
+
+       mutex_unlock(&wmi->op_mutex);
+
+       return 0;
+
+out:
+       ath_print(common, ATH_DBG_WMI,
+                 "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id));
+       mutex_unlock(&wmi->op_mutex);
+       kfree_skb(skb);
+
+       return ret;
+}
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
new file mode 100644 (file)
index 0000000..765db5f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+#ifndef WMI_H
+#define WMI_H
+
+
+struct wmi_event_txrate {
+       __be32 txrate;
+       struct {
+               u8 rssi_thresh;
+               u8 per;
+       } rc_stats;
+} __packed;
+
+struct wmi_cmd_hdr {
+       __be16 command_id;
+       __be16 seq_no;
+} __packed;
+
+struct wmi_swba {
+       u8 beacon_pending;
+} __packed;
+
+enum wmi_cmd_id {
+       WMI_ECHO_CMDID = 0x0001,
+       WMI_ACCESS_MEMORY_CMDID,
+
+       /* Commands to Target */
+       WMI_DISABLE_INTR_CMDID,
+       WMI_ENABLE_INTR_CMDID,
+       WMI_RX_LINK_CMDID,
+       WMI_ATH_INIT_CMDID,
+       WMI_ABORT_TXQ_CMDID,
+       WMI_STOP_TX_DMA_CMDID,
+       WMI_STOP_DMA_RECV_CMDID,
+       WMI_ABORT_TX_DMA_CMDID,
+       WMI_DRAIN_TXQ_CMDID,
+       WMI_DRAIN_TXQ_ALL_CMDID,
+       WMI_START_RECV_CMDID,
+       WMI_STOP_RECV_CMDID,
+       WMI_FLUSH_RECV_CMDID,
+       WMI_SET_MODE_CMDID,
+       WMI_RESET_CMDID,
+       WMI_NODE_CREATE_CMDID,
+       WMI_NODE_REMOVE_CMDID,
+       WMI_VAP_REMOVE_CMDID,
+       WMI_VAP_CREATE_CMDID,
+       WMI_BEACON_UPDATE_CMDID,
+       WMI_REG_READ_CMDID,
+       WMI_REG_WRITE_CMDID,
+       WMI_RC_STATE_CHANGE_CMDID,
+       WMI_RC_RATE_UPDATE_CMDID,
+       WMI_DEBUG_INFO_CMDID,
+       WMI_HOST_ATTACH,
+       WMI_TARGET_IC_UPDATE_CMDID,
+       WMI_TGT_STATS_CMDID,
+       WMI_TX_AGGR_ENABLE_CMDID,
+       WMI_TGT_DETACH_CMDID,
+       WMI_TGT_TXQ_ENABLE_CMDID,
+};
+
+enum wmi_event_id {
+       WMI_TGT_RDY_EVENTID = 0x1001,
+       WMI_SWBA_EVENTID,
+       WMI_FATAL_EVENTID,
+       WMI_TXTO_EVENTID,
+       WMI_BMISS_EVENTID,
+       WMI_WLAN_TXCOMP_EVENTID,
+       WMI_DELBA_EVENTID,
+       WMI_TXRATE_EVENTID,
+};
+
+#define MAX_CMD_NUMBER 62
+
+struct register_write {
+       __be32 reg;
+       __be32 val;
+};
+
+struct wmi {
+       struct ath9k_htc_priv *drv_priv;
+       struct htc_target *htc;
+       enum htc_endpoint_id ctrl_epid;
+       struct mutex op_mutex;
+       struct completion cmd_wait;
+       enum wmi_cmd_id last_cmd_id;
+       u16 tx_seq_id;
+       u8 *cmd_rsp_buf;
+       u32 cmd_rsp_len;
+       bool stopped;
+
+       struct sk_buff *wmi_skb;
+       spinlock_t wmi_lock;
+
+       atomic_t mwrite_cnt;
+       struct register_write multi_write[MAX_CMD_NUMBER];
+       u32 multi_write_idx;
+       struct mutex multi_write_mutex;
+};
+
+struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv);
+void ath9k_deinit_wmi(struct ath9k_htc_priv *priv);
+int ath9k_wmi_connect(struct htc_target *htc, struct wmi *wmi,
+                     enum htc_endpoint_id *wmi_ctrl_epid);
+int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
+                 u8 *cmd_buf, u32 cmd_len,
+                 u8 *rsp_buf, u32 rsp_len,
+                 u32 timeout);
+void ath9k_wmi_tasklet(unsigned long data);
+
+#define WMI_CMD(_wmi_cmd)                                              \
+       do {                                                            \
+               ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd, NULL, 0,       \
+                                   (u8 *) &cmd_rsp,                    \
+                                   sizeof(cmd_rsp), HZ*2);             \
+       } while (0)
+
+#define WMI_CMD_BUF(_wmi_cmd, _buf)                                    \
+       do {                                                            \
+               ret = ath9k_wmi_cmd(priv->wmi, _wmi_cmd,                \
+                                   (u8 *) _buf, sizeof(*_buf),         \
+                                   &cmd_rsp, sizeof(cmd_rsp), HZ*2);   \
+       } while (0)
+
+#endif /* WMI_H */
index 294b486bc3ed2043d09fc679a9ad76983e854286..3db19172b43b7a1aa165e68463fabaf71dd4d278 100644 (file)
  */
 
 #include "ath9k.h"
+#include "ar9003_mac.h"
 
 #define BITS_PER_BYTE           8
 #define OFDM_PLCP_BITS          22
-#define HT_RC_2_MCS(_rc)        ((_rc) & 0x0f)
+#define HT_RC_2_MCS(_rc)        ((_rc) & 0x1f)
 #define HT_RC_2_STREAMS(_rc)    ((((_rc) & 0x78) >> 3) + 1)
 #define L_STF                   8
 #define L_LTF                   8
@@ -33,7 +34,7 @@
 
 #define OFDM_SIFS_TIME             16
 
-static u32 bits_per_symbol[][2] = {
+static u16 bits_per_symbol[][2] = {
        /* 20MHz 40MHz */
        {    26,   54 },     /*  0: BPSK */
        {    52,  108 },     /*  1: QPSK 1/2 */
@@ -43,14 +44,6 @@ static u32 bits_per_symbol[][2] = {
        {   208,  432 },     /*  5: 64-QAM 2/3 */
        {   234,  486 },     /*  6: 64-QAM 3/4 */
        {   260,  540 },     /*  7: 64-QAM 5/6 */
-       {    52,  108 },     /*  8: BPSK */
-       {   104,  216 },     /*  9: QPSK 1/2 */
-       {   156,  324 },     /* 10: QPSK 3/4 */
-       {   208,  432 },     /* 11: 16-QAM 1/2 */
-       {   312,  648 },     /* 12: 16-QAM 3/4 */
-       {   416,  864 },     /* 13: 64-QAM 2/3 */
-       {   468,  972 },     /* 14: 64-QAM 3/4 */
-       {   520, 1080 },     /* 15: 64-QAM 5/6 */
 };
 
 #define IS_HT_RATE(_rate)     ((_rate) & 0x80)
@@ -59,40 +52,50 @@ static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
                                  struct ath_atx_tid *tid,
                                  struct list_head *bf_head);
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-                               struct ath_txq *txq,
-                               struct list_head *bf_q,
-                               int txok, int sendbar);
+                               struct ath_txq *txq, struct list_head *bf_q,
+                               struct ath_tx_status *ts, int txok, int sendbar);
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
                             struct list_head *head);
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf);
 static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
-                             int txok);
-static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
+                             struct ath_tx_status *ts, int txok);
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
                             int nbad, int txok, bool update_rc);
 
 enum {
-       MCS_DEFAULT,
+       MCS_HT20,
+       MCS_HT20_SGI,
        MCS_HT40,
        MCS_HT40_SGI,
 };
 
-static int ath_max_4ms_framelen[3][16] = {
-       [MCS_DEFAULT] = {
-               3216,  6434,  9650,  12868, 19304, 25740,  28956,  32180,
-               6430,  12860, 19300, 25736, 38600, 51472,  57890,  64320,
+static int ath_max_4ms_framelen[4][32] = {
+       [MCS_HT20] = {
+               3212,  6432,  9648,  12864,  19300,  25736,  28952,  32172,
+               6424,  12852, 19280, 25708,  38568,  51424,  57852,  64280,
+               9628,  19260, 28896, 38528,  57792,  65532,  65532,  65532,
+               12828, 25656, 38488, 51320,  65532,  65532,  65532,  65532,
+       },
+       [MCS_HT20_SGI] = {
+               3572,  7144,  10720,  14296,  21444,  28596,  32172,  35744,
+               7140,  14284, 21428,  28568,  42856,  57144,  64288,  65532,
+               10700, 21408, 32112,  42816,  64228,  65532,  65532,  65532,
+               14256, 28516, 42780,  57040,  65532,  65532,  65532,  65532,
        },
        [MCS_HT40] = {
-               6684,  13368, 20052, 26738, 40104, 53476,  60156,  66840,
-               13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600,
+               6680,  13360,  20044,  26724,  40092,  53456,  60140,  65532,
+               13348, 26700,  40052,  53400,  65532,  65532,  65532,  65532,
+               20004, 40008,  60016,  65532,  65532,  65532,  65532,  65532,
+               26644, 53292,  65532,  65532,  65532,  65532,  65532,  65532,
        },
        [MCS_HT40_SGI] = {
-               /* TODO: Only MCS 7 and 15 updated, recalculate the rest */
-               6684,  13368, 20052, 26738, 40104, 53476,  60156,  74200,
-               13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400,
+               7420,  14844,  22272,  29696,  44544,  59396,  65532,  65532,
+               14832, 29668,  44504,  59340,  65532,  65532,  65532,  65532,
+               22232, 44464,  65532,  65532,  65532,  65532,  65532,  65532,
+               29616, 59232,  65532,  65532,  65532,  65532,  65532,  65532,
        }
 };
 
-
 /*********************/
 /* Aggregation logic */
 /*********************/
@@ -223,6 +226,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 {
        struct ath_buf *bf;
        struct list_head bf_head;
+       struct ath_tx_status ts;
+
+       memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
        for (;;) {
@@ -236,7 +242,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
                        ath_tx_update_baw(sc, tid, bf->bf_seqno);
 
                spin_unlock(&txq->axq_lock);
-               ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
+               ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
                spin_lock(&txq->axq_lock);
        }
 
@@ -259,25 +265,46 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
        hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
 }
 
-static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
+static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
 {
-       struct ath_buf *tbf;
+       struct ath_buf *bf = NULL;
 
        spin_lock_bh(&sc->tx.txbuflock);
-       if (WARN_ON(list_empty(&sc->tx.txbuf))) {
+
+       if (unlikely(list_empty(&sc->tx.txbuf))) {
                spin_unlock_bh(&sc->tx.txbuflock);
                return NULL;
        }
-       tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
-       list_del(&tbf->list);
+
+       bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
+       list_del(&bf->list);
+
        spin_unlock_bh(&sc->tx.txbuflock);
 
+       return bf;
+}
+
+static void ath_tx_return_buffer(struct ath_softc *sc, struct ath_buf *bf)
+{
+       spin_lock_bh(&sc->tx.txbuflock);
+       list_add_tail(&bf->list, &sc->tx.txbuf);
+       spin_unlock_bh(&sc->tx.txbuflock);
+}
+
+static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
+{
+       struct ath_buf *tbf;
+
+       tbf = ath_tx_get_buffer(sc);
+       if (WARN_ON(!tbf))
+               return NULL;
+
        ATH_TXBUF_RESET(tbf);
 
        tbf->aphy = bf->aphy;
        tbf->bf_mpdu = bf->bf_mpdu;
        tbf->bf_buf_addr = bf->bf_buf_addr;
-       *(tbf->bf_desc) = *(bf->bf_desc);
+       memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
        tbf->bf_state = bf->bf_state;
        tbf->bf_dmacontext = bf->bf_dmacontext;
 
@@ -286,7 +313,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
 
 static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                                 struct ath_buf *bf, struct list_head *bf_q,
-                                int txok)
+                                struct ath_tx_status *ts, int txok)
 {
        struct ath_node *an = NULL;
        struct sk_buff *skb;
@@ -296,7 +323,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        struct ieee80211_tx_info *tx_info;
        struct ath_atx_tid *tid = NULL;
        struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
-       struct ath_desc *ds = bf_last->bf_desc;
        struct list_head bf_head, bf_pending;
        u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0;
        u32 ba[WME_BA_BMP_SIZE >> 5];
@@ -325,10 +351,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        memset(ba, 0, WME_BA_BMP_SIZE >> 3);
 
        if (isaggr && txok) {
-               if (ATH_DS_TX_BA(ds)) {
-                       seq_st = ATH_DS_BA_SEQ(ds);
-                       memcpy(ba, ATH_DS_BA_BITMAP(ds),
-                              WME_BA_BMP_SIZE >> 3);
+               if (ts->ts_flags & ATH9K_TX_BA) {
+                       seq_st = ts->ts_seqnum;
+                       memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
                } else {
                        /*
                         * AR5416 can become deaf/mute when BA
@@ -345,7 +370,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
        INIT_LIST_HEAD(&bf_pending);
        INIT_LIST_HEAD(&bf_head);
 
-       nbad = ath_tx_num_badfrms(sc, bf, txok);
+       nbad = ath_tx_num_badfrms(sc, bf, ts, txok);
        while (bf) {
                txfail = txpending = 0;
                bf_next = bf->bf_next;
@@ -359,7 +384,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        acked_cnt++;
                } else {
                        if (!(tid->state & AGGR_CLEANUP) &&
-                           ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) {
+                           !bf_last->bf_tx_aborted) {
                                if (bf->bf_retries < ATH_MAX_SW_RETRIES) {
                                        ath_tx_set_retry(sc, txq, bf);
                                        txpending = 1;
@@ -378,7 +403,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        }
                }
 
-               if (bf_next == NULL) {
+               if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+                   bf_next == NULL) {
                        /*
                         * Make sure the last desc is reclaimed if it
                         * not a holding desc.
@@ -402,45 +428,53 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        spin_unlock_bh(&txq->axq_lock);
 
                        if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
-                               ath_tx_rc_status(bf, ds, nbad, txok, true);
+                               ath_tx_rc_status(bf, ts, nbad, txok, true);
                                rc_update = false;
                        } else {
-                               ath_tx_rc_status(bf, ds, nbad, txok, false);
+                               ath_tx_rc_status(bf, ts, nbad, txok, false);
                        }
 
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, !txfail, sendbar);
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
+                               !txfail, sendbar);
                } else {
                        /* retry the un-acked ones */
-                       if (bf->bf_next == NULL && bf_last->bf_stale) {
-                               struct ath_buf *tbf;
-
-                               tbf = ath_clone_txbuf(sc, bf_last);
-                               /*
-                                * Update tx baw and complete the frame with
-                                * failed status if we run out of tx buf
-                                */
-                               if (!tbf) {
-                                       spin_lock_bh(&txq->axq_lock);
-                                       ath_tx_update_baw(sc, tid,
-                                                         bf->bf_seqno);
-                                       spin_unlock_bh(&txq->axq_lock);
-
-                                       bf->bf_state.bf_type |= BUF_XRETRY;
-                                       ath_tx_rc_status(bf, ds, nbad,
-                                                        0, false);
-                                       ath_tx_complete_buf(sc, bf, txq,
-                                                           &bf_head, 0, 0);
-                                       break;
+                       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
+                               if (bf->bf_next == NULL && bf_last->bf_stale) {
+                                       struct ath_buf *tbf;
+
+                                       tbf = ath_clone_txbuf(sc, bf_last);
+                                       /*
+                                        * Update tx baw and complete the
+                                        * frame with failed status if we
+                                        * run out of tx buf.
+                                        */
+                                       if (!tbf) {
+                                               spin_lock_bh(&txq->axq_lock);
+                                               ath_tx_update_baw(sc, tid,
+                                                               bf->bf_seqno);
+                                               spin_unlock_bh(&txq->axq_lock);
+
+                                               bf->bf_state.bf_type |=
+                                                       BUF_XRETRY;
+                                               ath_tx_rc_status(bf, ts, nbad,
+                                                               0, false);
+                                               ath_tx_complete_buf(sc, bf, txq,
+                                                                   &bf_head,
+                                                                   ts, 0, 0);
+                                               break;
+                                       }
+
+                                       ath9k_hw_cleartxdesc(sc->sc_ah,
+                                                            tbf->bf_desc);
+                                       list_add_tail(&tbf->list, &bf_head);
+                               } else {
+                                       /*
+                                        * Clear descriptor status words for
+                                        * software retry
+                                        */
+                                       ath9k_hw_cleartxdesc(sc->sc_ah,
+                                                            bf->bf_desc);
                                }
-
-                               ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
-                               list_add_tail(&tbf->list, &bf_head);
-                       } else {
-                               /*
-                                * Clear descriptor status words for
-                                * software retry
-                                */
-                               ath9k_hw_cleartxdesc(sc->sc_ah, bf->bf_desc);
                        }
 
                        /*
@@ -508,12 +542,13 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
                                break;
                        }
 
-                       if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
-                               modeidx = MCS_HT40_SGI;
-                       else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+                       if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
                                modeidx = MCS_HT40;
                        else
-                               modeidx = MCS_DEFAULT;
+                               modeidx = MCS_HT20;
+
+                       if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
+                               modeidx++;
 
                        frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
                        max_4ms_framelen = min(max_4ms_framelen, frmlen);
@@ -558,7 +593,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
        u32 nsymbits, nsymbols;
        u16 minlen;
        u8 flags, rix;
-       int width, half_gi, ndelim, mindelim;
+       int width, streams, half_gi, ndelim, mindelim;
 
        /* Select standard number of delimiters based on frame length alone */
        ndelim = ATH_AGGR_GET_NDELIM(frmlen);
@@ -598,7 +633,8 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
        if (nsymbols == 0)
                nsymbols = 1;
 
-       nsymbits = bits_per_symbol[rix][width];
+       streams = HT_RC_2_STREAMS(rix);
+       nsymbits = bits_per_symbol[rix % 8][width] * streams;
        minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
 
        if (frmlen < minlen) {
@@ -664,7 +700,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                bpad = PADBYTES(al_delta) + (ndelim << 2);
 
                bf->bf_next = NULL;
-               bf->bf_desc->ds_link = 0;
+               ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
 
                /* link buffers of this frame to the aggregate */
                ath_tx_addto_baw(sc, tid, bf);
@@ -672,7 +708,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                list_move_tail(&bf->list, bf_q);
                if (bf_prev) {
                        bf_prev->bf_next = bf;
-                       bf_prev->bf_desc->ds_link = bf->bf_daddr;
+                       ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc,
+                                              bf->bf_daddr);
                }
                bf_prev = bf;
 
@@ -752,8 +789,11 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
        struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid);
        struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum];
+       struct ath_tx_status ts;
        struct ath_buf *bf;
        struct list_head bf_head;
+
+       memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
        if (txtid->state & AGGR_CLEANUP)
@@ -780,7 +820,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
                }
                list_move_tail(&bf->list, &bf_head);
                ath_tx_update_baw(sc, txtid, bf->bf_seqno);
-               ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
+               ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
        }
        spin_unlock_bh(&txq->axq_lock);
 
@@ -849,7 +889,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_tx_queue_info qi;
-       int qnum;
+       int qnum, i;
 
        memset(&qi, 0, sizeof(qi));
        qi.tqi_subtype = subtype;
@@ -873,11 +913,16 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
         * The UAPSD queue is an exception, since we take a desc-
         * based intr on the EOSP frames.
         */
-       if (qtype == ATH9K_TX_QUEUE_UAPSD)
-               qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
-       else
-               qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
-                       TXQ_FLAG_TXDESCINT_ENABLE;
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               qi.tqi_qflags = TXQ_FLAG_TXOKINT_ENABLE |
+                               TXQ_FLAG_TXERRINT_ENABLE;
+       } else {
+               if (qtype == ATH9K_TX_QUEUE_UAPSD)
+                       qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE;
+               else
+                       qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
+                                       TXQ_FLAG_TXDESCINT_ENABLE;
+       }
        qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
        if (qnum == -1) {
                /*
@@ -904,6 +949,11 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
                txq->axq_depth = 0;
                txq->axq_tx_inprogress = false;
                sc->tx.txqsetup |= 1<<qnum;
+
+               txq->txq_headidx = txq->txq_tailidx = 0;
+               for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
+                       INIT_LIST_HEAD(&txq->txq_fifo[i]);
+               INIT_LIST_HEAD(&txq->txq_fifo_pending);
        }
        return &sc->tx.txq[qnum];
 }
@@ -1028,45 +1078,63 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
 {
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
+       struct ath_tx_status ts;
 
+       memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
        for (;;) {
                spin_lock_bh(&txq->axq_lock);
 
-               if (list_empty(&txq->axq_q)) {
-                       txq->axq_link = NULL;
-                       spin_unlock_bh(&txq->axq_lock);
-                       break;
-               }
-
-               bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
+               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+                       if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+                               txq->txq_headidx = txq->txq_tailidx = 0;
+                               spin_unlock_bh(&txq->axq_lock);
+                               break;
+                       } else {
+                               bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
+                                                     struct ath_buf, list);
+                       }
+               } else {
+                       if (list_empty(&txq->axq_q)) {
+                               txq->axq_link = NULL;
+                               spin_unlock_bh(&txq->axq_lock);
+                               break;
+                       }
+                       bf = list_first_entry(&txq->axq_q, struct ath_buf,
+                                             list);
 
-               if (bf->bf_stale) {
-                       list_del(&bf->list);
-                       spin_unlock_bh(&txq->axq_lock);
+                       if (bf->bf_stale) {
+                               list_del(&bf->list);
+                               spin_unlock_bh(&txq->axq_lock);
 
-                       spin_lock_bh(&sc->tx.txbuflock);
-                       list_add_tail(&bf->list, &sc->tx.txbuf);
-                       spin_unlock_bh(&sc->tx.txbuflock);
-                       continue;
+                               ath_tx_return_buffer(sc, bf);
+                               continue;
+                       }
                }
 
                lastbf = bf->bf_lastbf;
                if (!retry_tx)
-                       lastbf->bf_desc->ds_txstat.ts_flags =
-                               ATH9K_TX_SW_ABORTED;
+                       lastbf->bf_tx_aborted = true;
+
+               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+                       list_cut_position(&bf_head,
+                                         &txq->txq_fifo[txq->txq_tailidx],
+                                         &lastbf->list);
+                       INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
+               } else {
+                       /* remove ath_buf's of the same mpdu from txq */
+                       list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
+               }
 
-               /* remove ath_buf's of the same mpdu from txq */
-               list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
                txq->axq_depth--;
 
                spin_unlock_bh(&txq->axq_lock);
 
                if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, 0);
+                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0);
                else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, 0, 0);
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
        }
 
        spin_lock_bh(&txq->axq_lock);
@@ -1081,6 +1149,27 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
                        spin_unlock_bh(&txq->axq_lock);
                }
        }
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               spin_lock_bh(&txq->axq_lock);
+               while (!list_empty(&txq->txq_fifo_pending)) {
+                       bf = list_first_entry(&txq->txq_fifo_pending,
+                                             struct ath_buf, list);
+                       list_cut_position(&bf_head,
+                                         &txq->txq_fifo_pending,
+                                         &bf->bf_lastbf->list);
+                       spin_unlock_bh(&txq->axq_lock);
+
+                       if (bf_isampdu(bf))
+                               ath_tx_complete_aggr(sc, txq, bf, &bf_head,
+                                                    &ts, 0);
+                       else
+                               ath_tx_complete_buf(sc, bf, txq, &bf_head,
+                                                   &ts, 0, 0);
+                       spin_lock_bh(&txq->axq_lock);
+               }
+               spin_unlock_bh(&txq->axq_lock);
+       }
 }
 
 void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
@@ -1218,44 +1307,47 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
 
        bf = list_first_entry(head, struct ath_buf, list);
 
-       list_splice_tail_init(head, &txq->axq_q);
-       txq->axq_depth++;
-
        ath_print(common, ATH_DBG_QUEUE,
                  "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
 
-       if (txq->axq_link == NULL) {
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
+                       list_splice_tail_init(head, &txq->txq_fifo_pending);
+                       return;
+               }
+               if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
+                       ath_print(common, ATH_DBG_XMIT,
+                                 "Initializing tx fifo %d which "
+                                 "is non-empty\n",
+                                 txq->txq_headidx);
+               INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
+               list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
+               INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
                ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
                ath_print(common, ATH_DBG_XMIT,
                          "TXDP[%u] = %llx (%p)\n",
                          txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
        } else {
-               *txq->axq_link = bf->bf_daddr;
-               ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
-                         txq->axq_qnum, txq->axq_link,
-                         ito64(bf->bf_daddr), bf->bf_desc);
-       }
-       txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
-       ath9k_hw_txstart(ah, txq->axq_qnum);
-}
+               list_splice_tail_init(head, &txq->axq_q);
 
-static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
-{
-       struct ath_buf *bf = NULL;
-
-       spin_lock_bh(&sc->tx.txbuflock);
-
-       if (unlikely(list_empty(&sc->tx.txbuf))) {
-               spin_unlock_bh(&sc->tx.txbuflock);
-               return NULL;
+               if (txq->axq_link == NULL) {
+                       ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+                       ath_print(common, ATH_DBG_XMIT,
+                                       "TXDP[%u] = %llx (%p)\n",
+                                       txq->axq_qnum, ito64(bf->bf_daddr),
+                                       bf->bf_desc);
+               } else {
+                       *txq->axq_link = bf->bf_daddr;
+                       ath_print(common, ATH_DBG_XMIT,
+                                       "link[%u] (%p)=%llx (%p)\n",
+                                       txq->axq_qnum, txq->axq_link,
+                                       ito64(bf->bf_daddr), bf->bf_desc);
+               }
+               ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
+                                      &txq->axq_link);
+               ath9k_hw_txstart(ah, txq->axq_qnum);
        }
-
-       bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
-       list_del(&bf->list);
-
-       spin_unlock_bh(&sc->tx.txbuflock);
-
-       return bf;
+       txq->axq_depth++;
 }
 
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
@@ -1402,8 +1494,7 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
        INCR(tid->seq_next, IEEE80211_SEQ_MAX);
 }
 
-static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
-                         struct ath_txq *txq)
+static int setup_tx_flags(struct sk_buff *skb, bool use_ldpc)
 {
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        int flags = 0;
@@ -1414,6 +1505,9 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
                flags |= ATH9K_TXDESC_NOACK;
 
+       if (use_ldpc)
+               flags |= ATH9K_TXDESC_LDPC;
+
        return flags;
 }
 
@@ -1432,8 +1526,9 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
        pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
 
        /* find number of symbols: PLCP + data */
+       streams = HT_RC_2_STREAMS(rix);
        nbits = (pktlen << 3) + OFDM_PLCP_BITS;
-       nsymbits = bits_per_symbol[rix][width];
+       nsymbits = bits_per_symbol[rix % 8][width] * streams;
        nsymbols = (nbits + nsymbits - 1) / nsymbits;
 
        if (!half_gi)
@@ -1442,7 +1537,6 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
                duration = SYMBOL_TIME_HALFGI(nsymbols);
 
        /* addup duration for legacy/ht training and signal fields */
-       streams = HT_RC_2_STREAMS(rix);
        duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
 
        return duration;
@@ -1513,6 +1607,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
                        series[i].Rate = rix | 0x80;
                        series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
                                 is_40, is_sgi, is_sp);
+                       if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
+                               series[i].RateFlags |= ATH9K_RATESERIES_STBC;
                        continue;
                }
 
@@ -1565,15 +1661,16 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
        int hdrlen;
        __le16 fc;
        int padpos, padsize;
+       bool use_ldpc = false;
 
        tx_info->pad[0] = 0;
        switch (txctl->frame_type) {
-       case ATH9K_NOT_INTERNAL:
+       case ATH9K_IFT_NOT_INTERNAL:
                break;
-       case ATH9K_INT_PAUSE:
+       case ATH9K_IFT_PAUSE:
                tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
                /* fall through */
-       case ATH9K_INT_UNPAUSE:
+       case ATH9K_IFT_UNPAUSE:
                tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
                break;
        }
@@ -1591,10 +1688,13 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
                bf->bf_frmlen -= padsize;
        }
 
-       if (conf_is_ht(&hw->conf))
+       if (conf_is_ht(&hw->conf)) {
                bf->bf_state.bf_type |= BUF_HT;
+               if (tx_info->flags & IEEE80211_TX_CTL_LDPC)
+                       use_ldpc = true;
+       }
 
-       bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
+       bf->bf_flags = setup_tx_flags(skb, use_ldpc);
 
        bf->bf_keytype = get_hw_crypto_keytype(skb);
        if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) {
@@ -1653,8 +1753,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
        list_add_tail(&bf->list, &bf_head);
 
        ds = bf->bf_desc;
-       ds->ds_link = 0;
-       ds->ds_data = bf->bf_buf_addr;
+       ath9k_hw_set_desc_link(ah, ds, 0);
 
        ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER,
                               bf->bf_keyix, bf->bf_keytype, bf->bf_flags);
@@ -1663,7 +1762,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                            skb->len,   /* segment length */
                            true,       /* first segment */
                            true,       /* last segment */
-                           ds);        /* first descriptor */
+                           ds,         /* first descriptor */
+                           bf->bf_buf_addr,
+                           txctl->txq->axq_qnum);
 
        spin_lock_bh(&txctl->txq->axq_lock);
 
@@ -1732,9 +1833,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                }
                spin_unlock_bh(&txq->axq_lock);
 
-               spin_lock_bh(&sc->tx.txbuflock);
-               list_add_tail(&bf->list, &sc->tx.txbuf);
-               spin_unlock_bh(&sc->tx.txbuflock);
+               ath_tx_return_buffer(sc, bf);
 
                return r;
        }
@@ -1852,9 +1951,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
-                               struct ath_txq *txq,
-                               struct list_head *bf_q,
-                               int txok, int sendbar)
+                               struct ath_txq *txq, struct list_head *bf_q,
+                               struct ath_tx_status *ts, int txok, int sendbar)
 {
        struct sk_buff *skb = bf->bf_mpdu;
        unsigned long flags;
@@ -1872,7 +1970,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 
        dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
        ath_tx_complete(sc, skb, bf->aphy, tx_flags);
-       ath_debug_stat_tx(sc, txq, bf);
+       ath_debug_stat_tx(sc, txq, bf, ts);
 
        /*
         * Return the list of ath_buf of this mpdu to free queue
@@ -1883,23 +1981,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
 }
 
 static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
-                             int txok)
+                             struct ath_tx_status *ts, int txok)
 {
-       struct ath_buf *bf_last = bf->bf_lastbf;
-       struct ath_desc *ds = bf_last->bf_desc;
        u16 seq_st = 0;
        u32 ba[WME_BA_BMP_SIZE >> 5];
        int ba_index;
        int nbad = 0;
        int isaggr = 0;
 
-       if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED)
+       if (bf->bf_tx_aborted)
                return 0;
 
        isaggr = bf_isaggr(bf);
        if (isaggr) {
-               seq_st = ATH_DS_BA_SEQ(ds);
-               memcpy(ba, ATH_DS_BA_BITMAP(ds), WME_BA_BMP_SIZE >> 3);
+               seq_st = ts->ts_seqnum;
+               memcpy(ba, &ts->ba_low, WME_BA_BMP_SIZE >> 3);
        }
 
        while (bf) {
@@ -1913,7 +2009,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
        return nbad;
 }
 
-static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
+static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
                             int nbad, int txok, bool update_rc)
 {
        struct sk_buff *skb = bf->bf_mpdu;
@@ -1923,24 +2019,24 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
        u8 i, tx_rateindex;
 
        if (txok)
-               tx_info->status.ack_signal = ds->ds_txstat.ts_rssi;
+               tx_info->status.ack_signal = ts->ts_rssi;
 
-       tx_rateindex = ds->ds_txstat.ts_rateindex;
+       tx_rateindex = ts->ts_rateindex;
        WARN_ON(tx_rateindex >= hw->max_rates);
 
-       if (update_rc)
-               tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC;
-       if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
+       if (ts->ts_status & ATH9K_TXERR_FILT)
                tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+       if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
+               tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
 
-       if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
+       if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
            (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
                if (ieee80211_is_data(hdr->frame_control)) {
-                       if (ds->ds_txstat.ts_flags &
+                       if (ts->ts_flags &
                            (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
                                tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
-                       if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
-                           (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
+                       if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
+                           (ts->ts_status & ATH9K_TXERR_FIFO))
                                tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
                        tx_info->status.ampdu_len = bf->bf_nframes;
                        tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
@@ -1978,6 +2074,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
        struct ath_buf *bf, *lastbf, *bf_held = NULL;
        struct list_head bf_head;
        struct ath_desc *ds;
+       struct ath_tx_status ts;
        int txok;
        int status;
 
@@ -2017,7 +2114,8 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                lastbf = bf->bf_lastbf;
                ds = lastbf->bf_desc;
 
-               status = ath9k_hw_txprocdesc(ah, ds);
+               memset(&ts, 0, sizeof(ts));
+               status = ath9k_hw_txprocdesc(ah, ds, &ts);
                if (status == -EINPROGRESS) {
                        spin_unlock_bh(&txq->axq_lock);
                        break;
@@ -2028,7 +2126,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                 * can disable RX.
                 */
                if (bf->bf_isnullfunc &&
-                   (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
+                   (ts.ts_status & ATH9K_TX_ACKED)) {
                        if ((sc->ps_flags & PS_ENABLED))
                                ath9k_enable_ps(sc);
                        else
@@ -2047,31 +2145,30 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                                &txq->axq_q, lastbf->list.prev);
 
                txq->axq_depth--;
-               txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK);
+               txok = !(ts.ts_status & ATH9K_TXERR_MASK);
                txq->axq_tx_inprogress = false;
+               if (bf_held)
+                       list_del(&bf_held->list);
                spin_unlock_bh(&txq->axq_lock);
 
-               if (bf_held) {
-                       spin_lock_bh(&sc->tx.txbuflock);
-                       list_move_tail(&bf_held->list, &sc->tx.txbuf);
-                       spin_unlock_bh(&sc->tx.txbuflock);
-               }
+               if (bf_held)
+                       ath_tx_return_buffer(sc, bf_held);
 
                if (!bf_isampdu(bf)) {
                        /*
                         * This frame is sent out as a single frame.
                         * Use hardware retry status for this frame.
                         */
-                       bf->bf_retries = ds->ds_txstat.ts_longretry;
-                       if (ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY)
+                       bf->bf_retries = ts.ts_longretry;
+                       if (ts.ts_status & ATH9K_TXERR_XRETRY)
                                bf->bf_state.bf_type |= BUF_XRETRY;
-                       ath_tx_rc_status(bf, ds, 0, txok, true);
+                       ath_tx_rc_status(bf, &ts, 0, txok, true);
                }
 
                if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, txok);
+                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
                else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, txok, 0);
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
 
                ath_wake_mac80211_queue(sc, txq);
 
@@ -2133,10 +2230,121 @@ void ath_tx_tasklet(struct ath_softc *sc)
        }
 }
 
+void ath_tx_edma_tasklet(struct ath_softc *sc)
+{
+       struct ath_tx_status txs;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_txq *txq;
+       struct ath_buf *bf, *lastbf;
+       struct list_head bf_head;
+       int status;
+       int txok;
+
+       for (;;) {
+               status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
+               if (status == -EINPROGRESS)
+                       break;
+               if (status == -EIO) {
+                       ath_print(common, ATH_DBG_XMIT,
+                                 "Error processing tx status\n");
+                       break;
+               }
+
+               /* Skip beacon completions */
+               if (txs.qid == sc->beacon.beaconq)
+                       continue;
+
+               txq = &sc->tx.txq[txs.qid];
+
+               spin_lock_bh(&txq->axq_lock);
+               if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+                       spin_unlock_bh(&txq->axq_lock);
+                       return;
+               }
+
+               bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
+                                     struct ath_buf, list);
+               lastbf = bf->bf_lastbf;
+
+               INIT_LIST_HEAD(&bf_head);
+               list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
+                                 &lastbf->list);
+               INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
+               txq->axq_depth--;
+               txq->axq_tx_inprogress = false;
+               spin_unlock_bh(&txq->axq_lock);
+
+               txok = !(txs.ts_status & ATH9K_TXERR_MASK);
+
+               if (!bf_isampdu(bf)) {
+                       bf->bf_retries = txs.ts_longretry;
+                       if (txs.ts_status & ATH9K_TXERR_XRETRY)
+                               bf->bf_state.bf_type |= BUF_XRETRY;
+                       ath_tx_rc_status(bf, &txs, 0, txok, true);
+               }
+
+               if (bf_isampdu(bf))
+                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
+               else
+                       ath_tx_complete_buf(sc, bf, txq, &bf_head,
+                                           &txs, txok, 0);
+
+               ath_wake_mac80211_queue(sc, txq);
+
+               spin_lock_bh(&txq->axq_lock);
+               if (!list_empty(&txq->txq_fifo_pending)) {
+                       INIT_LIST_HEAD(&bf_head);
+                       bf = list_first_entry(&txq->txq_fifo_pending,
+                               struct ath_buf, list);
+                       list_cut_position(&bf_head, &txq->txq_fifo_pending,
+                               &bf->bf_lastbf->list);
+                       ath_tx_txqaddbuf(sc, txq, &bf_head);
+               } else if (sc->sc_flags & SC_OP_TXAGGR)
+                       ath_txq_schedule(sc, txq);
+               spin_unlock_bh(&txq->axq_lock);
+       }
+}
+
 /*****************/
 /* Init, Cleanup */
 /*****************/
 
+static int ath_txstatus_setup(struct ath_softc *sc, int size)
+{
+       struct ath_descdma *dd = &sc->txsdma;
+       u8 txs_len = sc->sc_ah->caps.txs_len;
+
+       dd->dd_desc_len = size * txs_len;
+       dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
+                                        &dd->dd_desc_paddr, GFP_KERNEL);
+       if (!dd->dd_desc)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int ath_tx_edma_init(struct ath_softc *sc)
+{
+       int err;
+
+       err = ath_txstatus_setup(sc, ATH_TXSTATUS_RING_SIZE);
+       if (!err)
+               ath9k_hw_setup_statusring(sc->sc_ah, sc->txsdma.dd_desc,
+                                         sc->txsdma.dd_desc_paddr,
+                                         ATH_TXSTATUS_RING_SIZE);
+
+       return err;
+}
+
+static void ath_tx_edma_cleanup(struct ath_softc *sc)
+{
+       struct ath_descdma *dd = &sc->txsdma;
+
+       dma_free_coherent(sc->dev, dd->dd_desc_len, dd->dd_desc,
+                         dd->dd_desc_paddr);
+}
+
 int ath_tx_init(struct ath_softc *sc, int nbufs)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -2145,7 +2353,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
        spin_lock_init(&sc->tx.txbuflock);
 
        error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
-                                 "tx", nbufs, 1);
+                                 "tx", nbufs, 1, 1);
        if (error != 0) {
                ath_print(common, ATH_DBG_FATAL,
                          "Failed to allocate tx descriptors: %d\n", error);
@@ -2153,7 +2361,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
        }
 
        error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
-                                 "beacon", ATH_BCBUF, 1);
+                                 "beacon", ATH_BCBUF, 1, 1);
        if (error != 0) {
                ath_print(common, ATH_DBG_FATAL,
                          "Failed to allocate beacon descriptors: %d\n", error);
@@ -2162,6 +2370,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
 
        INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
 
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
+               error = ath_tx_edma_init(sc);
+               if (error)
+                       goto err;
+       }
+
 err:
        if (error != 0)
                ath_tx_cleanup(sc);
@@ -2176,6 +2390,9 @@ void ath_tx_cleanup(struct ath_softc *sc)
 
        if (sc->tx.txdma.dd_desc_len != 0)
                ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf);
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
+               ath_tx_edma_cleanup(sc);
 }
 
 void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
index 8263633c003c050c1640a6994c8a33743cd1ba43..873bf526e11f7f1ec5507112660bc53953c53436 100644 (file)
@@ -59,6 +59,7 @@ enum ATH_DEBUG {
        ATH_DBG_PS              = 0x00000800,
        ATH_DBG_HWTIMER         = 0x00001000,
        ATH_DBG_BTCOEX          = 0x00002000,
+       ATH_DBG_WMI             = 0x00004000,
        ATH_DBG_ANY             = 0xffffffff
 };
 
index ecc9eb01f4fa12bddfd7ab044c79847bfe643c84..a8f81ea09f143cc56c981f80db73469196ddb4c6 100644 (file)
@@ -19,8 +19,8 @@
 #include "ath.h"
 #include "reg.h"
 
-#define REG_READ       common->ops->read
-#define REG_WRITE      common->ops->write
+#define REG_READ       (common->ops->read)
+#define REG_WRITE      (common->ops->write)
 
 /**
  * ath_hw_set_bssid_mask - filter out bssids we listen
index 00489c40be0cb66ec6993122bc3b2c8793fa1798..3f4244f56ce58590a94334f1cf00228307844949 100644 (file)
@@ -50,6 +50,7 @@
 
 #define ATH9K_5GHZ_ALL         ATH9K_5GHZ_5150_5350, \
                                ATH9K_5GHZ_5470_5850
+
 /* This one skips what we call "mid band" */
 #define ATH9K_5GHZ_NO_MIDBAND  ATH9K_5GHZ_5150_5350, \
                                ATH9K_5GHZ_5725_5850
@@ -332,7 +333,6 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
                ath_reg_apply_active_scan_flags(wiphy, initiator);
                break;
        }
-       return;
 }
 
 int ath_reg_notifier_apply(struct wiphy *wiphy,
@@ -360,7 +360,7 @@ EXPORT_SYMBOL(ath_reg_notifier_apply);
 
 static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
 {
-        u16 rd = ath_regd_get_eepromRD(reg);
+       u16 rd = ath_regd_get_eepromRD(reg);
        int i;
 
        if (rd & COUNTRY_ERD_FLAG) {
index 3edbbcf0f54837b5c1ef52d870910df86150ab40..c8f7090b27d3a69cc0792b176812bdc28300e867 100644 (file)
@@ -865,7 +865,6 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
 
        /* low bit of first byte of destination tells us if broadcast */
        tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA);
-       dev->trans_start = jiffies;
        dev->stats.tx_bytes += len;
 
        spin_unlock_irqrestore(&priv->irqlock, flags);
index b8807fb12c925611972eff166f2dbc79657e71bc..3a003e6803a5cf6c3a5040bf2af6399ab3e4eaec 100644 (file)
 #define B43_MMIO_MACFILTER_CONTROL     0x420
 #define B43_MMIO_MACFILTER_DATA                0x422
 #define B43_MMIO_RCMTA_COUNT           0x43C
+#define B43_MMIO_PSM_PHY_HDR           0x492
 #define B43_MMIO_RADIO_HWENABLED_LO    0x49A
 #define B43_MMIO_GPIO_CONTROL          0x49C
 #define B43_MMIO_GPIO_MASK             0x49E
index 9a374ef83a224e151b5dc66c7fb4956dace905de..7965b70efbab5de2d1149eda5eba68f0bd871a9b 100644 (file)
@@ -4349,11 +4349,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_set_phytxctl_defaults(dev);
 
        /* Minimum Contention Window */
-       if (phy->type == B43_PHYTYPE_B) {
+       if (phy->type == B43_PHYTYPE_B)
                b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
-       } else {
+       else
                b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
-       }
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
@@ -4572,6 +4571,23 @@ static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
        mutex_unlock(&wl->mutex);
 }
 
+static int b43_op_get_survey(struct ieee80211_hw *hw, int idx,
+                            struct survey_info *survey)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev = wl->current_dev;
+       struct ieee80211_conf *conf = &hw->conf;
+
+       if (idx != 0)
+               return -ENOENT;
+
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = dev->stats.link_noise;
+
+       return 0;
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
        .tx                     = b43_op_tx,
        .conf_tx                = b43_op_conf_tx,
@@ -4591,6 +4607,7 @@ static const struct ieee80211_ops b43_hw_ops = {
        .sta_notify             = b43_op_sta_notify,
        .sw_scan_start          = b43_op_sw_scan_start_notifier,
        .sw_scan_complete       = b43_op_sw_scan_complete_notifier,
+       .get_survey             = b43_op_get_survey,
        .rfkill_poll            = b43_rfkill_poll,
 };
 
@@ -4906,8 +4923,7 @@ static int b43_wireless_init(struct ssb_device *dev)
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_SIGNAL_DBM;
 
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
index 9c7cd282e46c5c9423e9f976f4098a688942f58f..3d6b33775964add64b73f96dab9c5890cd6d4275 100644 (file)
@@ -73,6 +73,22 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
                                                u16 value, u8 core, bool off);
 static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
                                                u16 value, u8 core);
+static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel);
+
+static inline bool b43_empty_chanspec(struct b43_chanspec *chanspec)
+{
+       return !chanspec->channel && !chanspec->sideband &&
+               !chanspec->b_width && !chanspec->b_freq;
+}
+
+static inline bool b43_eq_chanspecs(struct b43_chanspec *chanspec1,
+                                       struct b43_chanspec *chanspec2)
+{
+       return (chanspec1->channel == chanspec2->channel &&
+               chanspec1->sideband == chanspec2->sideband &&
+               chanspec1->b_width == chanspec2->b_width &&
+               chanspec1->b_freq == chanspec2->b_freq);
+}
 
 void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
 {//TODO
@@ -89,34 +105,44 @@ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
 }
 
 static void b43_chantab_radio_upload(struct b43_wldev *dev,
-                                    const struct b43_nphy_channeltab_entry *e)
-{
-       b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref);
-       b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
-       b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
-       b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
-       b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
-       b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
-       b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
-       b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
-       b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
-       b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
-       b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
-       b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
-       b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
-       b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
-       b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
-       b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
-       b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
-       b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
-       b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
-       b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
-       b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
-       b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
+                               const struct b43_nphy_channeltab_entry_rev2 *e)
+{
+       b43_radio_write(dev, B2055_PLL_REF, e->radio_pll_ref);
+       b43_radio_write(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
+       b43_radio_write(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
+       b43_radio_write(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+
+       b43_radio_write(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
+       b43_radio_write(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
+       b43_radio_write(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
+       b43_radio_write(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+
+       b43_radio_write(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
+       b43_radio_write(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
+       b43_radio_write(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
+       b43_radio_write(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+
+       b43_radio_write(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
+       b43_radio_write(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
+       b43_radio_write(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
+       b43_radio_write(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+
+       b43_radio_write(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
+       b43_radio_write(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
+       b43_radio_write(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
+       b43_radio_write(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+
+       b43_radio_write(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
+       b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
 }
 
 static void b43_chantab_phy_upload(struct b43_wldev *dev,
-                                  const struct b43_nphy_channeltab_entry *e)
+                                  const struct b43_phy_n_sfo_cfg *e)
 {
        b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
        b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
@@ -131,34 +157,20 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
        //TODO
 }
 
-/* Tune the hardware to a new channel. */
-static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
-{
-       const struct b43_nphy_channeltab_entry *tabent;
 
-       tabent = b43_nphy_get_chantabent(dev, channel);
-       if (!tabent)
-               return -ESRCH;
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */
+static void b43_radio_2055_setup(struct b43_wldev *dev,
+                               const struct b43_nphy_channeltab_entry_rev2 *e)
+{
+       B43_WARN_ON(dev->phy.rev >= 3);
 
-       //FIXME enable/disable band select upper20 in RXCTL
-       if (0 /*FIXME 5Ghz*/)
-               b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20);
-       else
-               b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50);
-       b43_chantab_radio_upload(dev, tabent);
+       b43_chantab_radio_upload(dev, e);
        udelay(50);
-       b43_radio_write16(dev, B2055_VCO_CAL10, 5);
-       b43_radio_write16(dev, B2055_VCO_CAL10, 45);
-       b43_radio_write16(dev, B2055_VCO_CAL10, 65);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x05);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x45);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x65);
        udelay(300);
-       if (0 /*FIXME 5Ghz*/)
-               b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
-       else
-               b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
-       b43_chantab_phy_upload(dev, tabent);
-       b43_nphy_tx_power_fix(dev);
-
-       return 0;
 }
 
 static void b43_radio_init2055_pre(struct b43_wldev *dev)
@@ -174,52 +186,64 @@ static void b43_radio_init2055_pre(struct b43_wldev *dev)
 
 static void b43_radio_init2055_post(struct b43_wldev *dev)
 {
+       struct b43_phy_n *nphy = dev->phy.n;
        struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
        struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
        int i;
        u16 val;
+       bool workaround = false;
+
+       if (sprom->revision < 4)
+               workaround = (binfo->vendor != PCI_VENDOR_ID_BROADCOM ||
+                               binfo->type != 0x46D ||
+                               binfo->rev < 0x41);
+       else
+               workaround = ((sprom->boardflags_hi & B43_BFH_NOPA) == 0);
 
        b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
-       msleep(1);
-       if ((sprom->revision != 4) ||
-          !(sprom->boardflags_hi & B43_BFH_RSSIINV)) {
-               if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) ||
-                   (binfo->type != 0x46D) ||
-                   (binfo->rev < 0x41)) {
-                       b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
-                       b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
-                       msleep(1);
-               }
+       if (workaround) {
+               b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+               b43_radio_mask(dev, B2055_C2_RX_BB_REG, 0x7F);
        }
-       b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C);
-       msleep(1);
-       b43_radio_write16(dev, B2055_CAL_MISC, 0x3C);
-       msleep(1);
+       b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0xFFC0, 0x2C);
+       b43_radio_write(dev, B2055_CAL_MISC, 0x3C);
        b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
-       msleep(1);
        b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
-       msleep(1);
        b43_radio_set(dev, B2055_CAL_MISC, 0x1);
        msleep(1);
        b43_radio_set(dev, B2055_CAL_MISC, 0x40);
-       msleep(1);
-       for (i = 0; i < 100; i++) {
-               val = b43_radio_read16(dev, B2055_CAL_COUT2);
-               if (val & 0x80)
+       for (i = 0; i < 200; i++) {
+               val = b43_radio_read(dev, B2055_CAL_COUT2);
+               if (val & 0x80) {
+                       i = 0;
                        break;
+               }
                udelay(10);
        }
-       msleep(1);
+       if (i)
+               b43err(dev->wl, "radio post init timeout\n");
        b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
-       msleep(1);
        nphy_channel_switch(dev, dev->phy.channel);
-       b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9);
-       b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9);
-       b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
-       b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+       b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9);
+       b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9);
+       b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
+       b43_radio_write(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+       b43_radio_maskset(dev, B2055_C1_LNA_GAINBST, 0xFFF8, 0x6);
+       b43_radio_maskset(dev, B2055_C2_LNA_GAINBST, 0xFFF8, 0x6);
+       if (!nphy->gain_boost) {
+               b43_radio_set(dev, B2055_C1_RX_RFSPC1, 0x2);
+               b43_radio_set(dev, B2055_C2_RX_RFSPC1, 0x2);
+       } else {
+               b43_radio_mask(dev, B2055_C1_RX_RFSPC1, 0xFFFD);
+               b43_radio_mask(dev, B2055_C2_RX_RFSPC1, 0xFFFD);
+       }
+       udelay(2);
 }
 
-/* Initialize a Broadcom 2055 N-radio */
+/*
+ * Initialize a Broadcom 2055 N-radio
+ * http://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init
+ */
 static void b43_radio_init2055(struct b43_wldev *dev)
 {
        b43_radio_init2055_pre(dev);
@@ -230,16 +254,15 @@ static void b43_radio_init2055(struct b43_wldev *dev)
        b43_radio_init2055_post(dev);
 }
 
-void b43_nphy_radio_turn_on(struct b43_wldev *dev)
+/*
+ * Initialize a Broadcom 2056 N-radio
+ * http://bcm-v4.sipsolutions.net/802.11/Radio/2056/Init
+ */
+static void b43_radio_init2056(struct b43_wldev *dev)
 {
-       b43_radio_init2055(dev);
+       /* TODO */
 }
 
-void b43_nphy_radio_turn_off(struct b43_wldev *dev)
-{
-       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
-                    ~B43_NPHY_RFCTL_CMD_EN);
-}
 
 /*
  * Upload the N-PHY tables.
@@ -647,6 +670,41 @@ static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
        clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */
+static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
+{
+       if (dev->phy.rev >= 3) {
+               if (!init)
+                       return;
+               if (0 /* FIXME */) {
+                       b43_ntab_write(dev, B43_NTAB16(9, 2), 0x211);
+                       b43_ntab_write(dev, B43_NTAB16(9, 3), 0x222);
+                       b43_ntab_write(dev, B43_NTAB16(9, 8), 0x144);
+                       b43_ntab_write(dev, B43_NTAB16(9, 12), 0x188);
+               }
+       } else {
+               b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
+               b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
+
+               ssb_chipco_gpio_control(&dev->dev->bus->chipco, 0xFC00,
+                                       0xFC00);
+               b43_write32(dev, B43_MMIO_MACCTL,
+                       b43_read32(dev, B43_MMIO_MACCTL) &
+                       ~B43_MACCTL_GPOUTSMSK);
+               b43_write16(dev, B43_MMIO_GPIO_MASK,
+                       b43_read16(dev, B43_MMIO_GPIO_MASK) | 0xFC00);
+               b43_write16(dev, B43_MMIO_GPIO_CONTROL,
+                       b43_read16(dev, B43_MMIO_GPIO_CONTROL) & ~0xFC00);
+
+               if (init) {
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+               }
+       }
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
 static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
 {
@@ -723,7 +781,7 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
 
-       unsigned int channel;
+       u8 channel = nphy->radio_chanspec.channel;
        int tone[2] = { 57, 58 };
        u32 noise[2] = { 0x3FF, 0x3FF };
 
@@ -732,8 +790,6 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
        if (nphy->hang_avoid)
                b43_nphy_stay_in_carrier_search(dev, 1);
 
-       /* FIXME: channel = radio_chanspec */
-
        if (nphy->gband_spurwar_en) {
                /* TODO: N PHY Adjust Analog Pfbw (7) */
                if (channel == 11 && dev->phy.is_40mhz)
@@ -779,6 +835,62 @@ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
                b43_nphy_stay_in_carrier_search(dev, 0);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */
+static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       u8 i;
+       s16 tmp;
+       u16 data[4];
+       s16 gain[2];
+       u16 minmax[2];
+       u16 lna_gain[4] = { -2, 10, 19, 25 };
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+
+       if (nphy->gain_boost) {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                       gain[0] = 6;
+                       gain[1] = 6;
+               } else {
+                       tmp = 40370 - 315 * nphy->radio_chanspec.channel;
+                       gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
+                       tmp = 23242 - 224 * nphy->radio_chanspec.channel;
+                       gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
+               }
+       } else {
+               gain[0] = 0;
+               gain[1] = 0;
+       }
+
+       for (i = 0; i < 2; i++) {
+               if (nphy->elna_gain_config) {
+                       data[0] = 19 + gain[i];
+                       data[1] = 25 + gain[i];
+                       data[2] = 25 + gain[i];
+                       data[3] = 25 + gain[i];
+               } else {
+                       data[0] = lna_gain[0] + gain[i];
+                       data[1] = lna_gain[1] + gain[i];
+                       data[2] = lna_gain[2] + gain[i];
+                       data[3] = lna_gain[3] + gain[i];
+               }
+               b43_ntab_write_bulk(dev, B43_NTAB16(10, 8), 4, data);
+
+               minmax[i] = 23 + gain[i];
+       }
+
+       b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, ~B43_NPHY_C1_MINGAIN,
+                               minmax[0] << B43_NPHY_C1_MINGAIN_SHIFT);
+       b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, ~B43_NPHY_C2_MINGAIN,
+                               minmax[1] << B43_NPHY_C2_MINGAIN_SHIFT);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
 static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
 {
@@ -863,7 +975,7 @@ static void b43_nphy_gain_crtl_workarounds(struct b43_wldev *dev)
                b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
                                        (code << 8 | 0x7C));
 
-               /* TODO: b43_nphy_adjust_lna_gain_table(dev); */
+               b43_nphy_adjust_lna_gain_table(dev);
 
                if (nphy->elna_gain_config) {
                        b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
@@ -1970,12 +2082,12 @@ static void b43_nphy_restore_rssi_cal(struct b43_wldev *dev)
        u16 *rssical_phy_regs = NULL;
 
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               if (!nphy->rssical_chanspec_2G)
+               if (b43_empty_chanspec(&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)
+               if (b43_empty_chanspec(&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;
@@ -2395,7 +2507,7 @@ static void b43_nphy_save_cal(struct b43_wldev *dev)
 
        struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
        u16 *txcal_radio_regs = NULL;
-       u8 *iqcal_chanspec;
+       struct b43_chanspec *iqcal_chanspec;
        u16 *table = NULL;
 
        if (nphy->hang_avoid)
@@ -2451,12 +2563,12 @@ static void b43_nphy_restore_cal(struct b43_wldev *dev)
        struct b43_phy_n_iq_comp *rxcal_coeffs = NULL;
 
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               if (nphy->iqcal_chanspec_2G == 0)
+               if (b43_empty_chanspec(&nphy->iqcal_chanspec_2G))
                        return;
                table = nphy->cal_cache.txcal_coeffs_2G;
                loft = &nphy->cal_cache.txcal_coeffs_2G[5];
        } else {
-               if (nphy->iqcal_chanspec_5G == 0)
+               if (b43_empty_chanspec(&nphy->iqcal_chanspec_5G))
                        return;
                table = nphy->cal_cache.txcal_coeffs_5G;
                loft = &nphy->cal_cache.txcal_coeffs_5G[5];
@@ -2689,7 +2801,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                        }
                        b43_ntab_write_bulk(dev, B43_NTAB16(15, 88), 4,
                                                buffer);
-                       b43_ntab_write_bulk(dev, B43_NTAB16(15, 101), 2,
+                       b43_ntab_read_bulk(dev, B43_NTAB16(15, 101), 2,
                                                buffer);
                        b43_ntab_write_bulk(dev, B43_NTAB16(15, 85), 2,
                                                buffer);
@@ -2701,8 +2813,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
                        b43_ntab_read_bulk(dev, B43_NTAB16(15, 96), length,
                                                nphy->txiqlocal_bestc);
                        nphy->txiqlocal_coeffsvalid = true;
-                       /* TODO: Set nphy->txiqlocal_chanspec to
-                               the current channel */
+                       nphy->txiqlocal_chanspec = nphy->radio_chanspec;
                } else {
                        length = 11;
                        if (dev->phy.rev < 3)
@@ -2737,7 +2848,8 @@ static void b43_nphy_reapply_tx_cal_coeffs(struct b43_wldev *dev)
        u16 buffer[7];
        bool equal = true;
 
-       if (!nphy->txiqlocal_coeffsvalid || 1 /* FIXME */)
+       if (!nphy->txiqlocal_coeffsvalid ||
+           b43_eq_chanspecs(&nphy->txiqlocal_chanspec, &nphy->radio_chanspec))
                return;
 
        b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
@@ -3092,9 +3204,11 @@ int b43_phy_initn(struct b43_wldev *dev)
        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);
+                       do_rssi_cal =
+                               b43_empty_chanspec(&nphy->rssical_chanspec_2G);
                else
-                       do_rssi_cal = (nphy->rssical_chanspec_5G == 0);
+                       do_rssi_cal =
+                               b43_empty_chanspec(&nphy->rssical_chanspec_5G);
 
                if (do_rssi_cal)
                        b43_nphy_rssi_cal(dev);
@@ -3106,9 +3220,9 @@ int b43_phy_initn(struct b43_wldev *dev)
 
        if (!((nphy->measure_hold & 0x6) != 0)) {
                if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
-                       do_cal = (nphy->iqcal_chanspec_2G == 0);
+                       do_cal = b43_empty_chanspec(&nphy->iqcal_chanspec_2G);
                else
-                       do_cal = (nphy->iqcal_chanspec_5G == 0);
+                       do_cal = b43_empty_chanspec(&nphy->iqcal_chanspec_5G);
 
                if (nphy->mute)
                        do_cal = false;
@@ -3117,7 +3231,7 @@ int b43_phy_initn(struct b43_wldev *dev)
                        target = b43_nphy_get_tx_gains(dev);
 
                        if (nphy->antsel_type == 2)
-                               ;/*TODO NPHY Superswitch Init with argument 1*/
+                               b43_nphy_superswitch_init(dev, true);
                        if (nphy->perical != 2) {
                                b43_nphy_rssi_cal(dev);
                                if (phy->rev >= 3) {
@@ -3155,6 +3269,133 @@ int b43_phy_initn(struct b43_wldev *dev)
        return 0;
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ChanspecSetup */
+static void b43_nphy_chanspec_setup(struct b43_wldev *dev,
+                               const struct b43_phy_n_sfo_cfg *e,
+                               struct b43_chanspec chanspec)
+{
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       u16 tmp;
+       u32 tmp32;
+
+       tmp = b43_phy_read(dev, B43_NPHY_BANDCTL) & B43_NPHY_BANDCTL_5GHZ;
+       if (chanspec.b_freq == 1 && tmp == 0) {
+               tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
+               b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
+               b43_phy_set(dev, B43_PHY_B_BBCFG, 0xC000);
+               b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
+               b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ);
+       } else if (chanspec.b_freq == 1) {
+               b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ);
+               tmp32 = b43_read32(dev, B43_MMIO_PSM_PHY_HDR);
+               b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32 | 4);
+               b43_phy_mask(dev, B43_PHY_B_BBCFG, (u16)~0xC000);
+               b43_write32(dev, B43_MMIO_PSM_PHY_HDR, tmp32);
+       }
+
+       b43_chantab_phy_upload(dev, e);
+
+       tmp = chanspec.channel;
+       if (chanspec.b_freq == 1)
+               tmp |= 0x0100;
+       if (chanspec.b_width == 3)
+               tmp |= 0x0200;
+       b43_shm_write16(dev, B43_SHM_SHARED, 0xA0, tmp);
+
+       if (nphy->radio_chanspec.channel == 14) {
+               b43_nphy_classifier(dev, 2, 0);
+               b43_phy_set(dev, B43_PHY_B_TEST, 0x0800);
+       } else {
+               b43_nphy_classifier(dev, 2, 2);
+               if (chanspec.b_freq == 2)
+                       b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840);
+       }
+
+       if (nphy->txpwrctrl)
+               b43_nphy_tx_power_fix(dev);
+
+       if (dev->phy.rev < 3)
+               b43_nphy_adjust_lna_gain_table(dev);
+
+       b43_nphy_tx_lp_fbw(dev);
+
+       if (dev->phy.rev >= 3 && 0) {
+               /* TODO */
+       }
+
+       b43_phy_write(dev, B43_NPHY_NDATAT_DUP40, 0x3830);
+
+       if (phy->rev >= 3)
+               b43_nphy_spur_workaround(dev);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetChanspec */
+static int b43_nphy_set_chanspec(struct b43_wldev *dev,
+                                       struct b43_chanspec chanspec)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
+       const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
+
+       u8 tmp;
+       u8 channel = chanspec.channel;
+
+       if (dev->phy.rev >= 3) {
+               /* TODO */
+               tabent_r3 = NULL;
+               if (!tabent_r3)
+                       return -ESRCH;
+       } else {
+               tabent_r2 = b43_nphy_get_chantabent_rev2(dev, channel);
+               if (!tabent_r2)
+                       return -ESRCH;
+       }
+
+       nphy->radio_chanspec = chanspec;
+
+       if (chanspec.b_width != nphy->b_width)
+               ; /* TODO: BMAC BW Set (chanspec.b_width) */
+
+       /* TODO: use defines */
+       if (chanspec.b_width == 3) {
+               if (chanspec.sideband == 2)
+                       b43_phy_set(dev, B43_NPHY_RXCTL,
+                                       B43_NPHY_RXCTL_BSELU20);
+               else
+                       b43_phy_mask(dev, B43_NPHY_RXCTL,
+                                       ~B43_NPHY_RXCTL_BSELU20);
+       }
+
+       if (dev->phy.rev >= 3) {
+               tmp = (chanspec.b_freq == 1) ? 4 : 0;
+               b43_radio_maskset(dev, 0x08, 0xFFFB, tmp);
+               /* TODO: PHY Radio2056 Setup (dev, tabent_r3); */
+               b43_nphy_chanspec_setup(dev, &(tabent_r3->phy_regs), chanspec);
+       } else {
+               tmp = (chanspec.b_freq == 1) ? 0x0020 : 0x0050;
+               b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, tmp);
+               b43_radio_2055_setup(dev, tabent_r2);
+               b43_nphy_chanspec_setup(dev, &(tabent_r2->phy_regs), chanspec);
+       }
+
+       return 0;
+}
+
+/* Tune the hardware to a new channel */
+static int nphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       struct b43_chanspec chanspec;
+       chanspec = nphy->radio_chanspec;
+       chanspec.channel = channel;
+
+       return b43_nphy_set_chanspec(dev, chanspec);
+}
+
 static int b43_nphy_op_allocate(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy;
@@ -3243,9 +3484,43 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
        b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, value);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/Radio/Switch%20Radio */
 static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
                                        bool blocked)
-{//TODO
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+
+       if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED)
+               b43err(dev->wl, "MAC not suspended\n");
+
+       if (blocked) {
+               b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                               ~B43_NPHY_RFCTL_CMD_CHIP0PU);
+               if (dev->phy.rev >= 3) {
+                       b43_radio_mask(dev, 0x09, ~0x2);
+
+                       b43_radio_write(dev, 0x204D, 0);
+                       b43_radio_write(dev, 0x2053, 0);
+                       b43_radio_write(dev, 0x2058, 0);
+                       b43_radio_write(dev, 0x205E, 0);
+                       b43_radio_mask(dev, 0x2062, ~0xF0);
+                       b43_radio_write(dev, 0x2064, 0);
+
+                       b43_radio_write(dev, 0x304D, 0);
+                       b43_radio_write(dev, 0x3053, 0);
+                       b43_radio_write(dev, 0x3058, 0);
+                       b43_radio_write(dev, 0x305E, 0);
+                       b43_radio_mask(dev, 0x3062, ~0xF0);
+                       b43_radio_write(dev, 0x3064, 0);
+               }
+       } else {
+               if (dev->phy.rev >= 3) {
+                       b43_radio_init2056(dev);
+                       b43_nphy_set_chanspec(dev, nphy->radio_chanspec);
+               } else {
+                       b43_radio_init2055(dev);
+               }
+       }
 }
 
 static void b43_nphy_op_switch_analog(struct b43_wldev *dev, bool on)
index 403aad3f894f10039b734bde81ffa5775e5486b2..8b6d570dd0aa963878b31e8b76fda75e9ea92d1b 100644 (file)
 #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 */
 
+#define B43_PHY_B_BBCFG                                B43_PHY_N_BMODE(0x001) /* BB config */
+#define B43_PHY_B_TEST                         B43_PHY_N_BMODE(0x00A)
 
 
 /* Broadcom 2055 radio registers */
 
 struct b43_wldev;
 
+struct b43_chanspec {
+       u8 channel;
+       u8 sideband;
+       u8 b_width;
+       u8 b_freq;
+};
+
 struct b43_phy_n_iq_comp {
        s16 a0;
        s16 b0;
@@ -975,7 +984,8 @@ struct b43_phy_n {
        u16 papd_epsilon_offset[2];
        s32 preamble_override;
        u32 bb_mult_save;
-       u16 radio_chanspec;
+       u8 b_width;
+       struct b43_chanspec radio_chanspec;
 
        bool gain_boost;
        bool elna_gain_config;
@@ -991,6 +1001,7 @@ struct b43_phy_n {
        u16 txiqlocal_bestc[11];
        bool txiqlocal_coeffsvalid;
        struct b43_phy_n_txpwrindex txpwrindex[2];
+       struct b43_chanspec txiqlocal_chanspec;
 
        u8 txrx_chain;
        u16 tx_rx_cal_phy_saveregs[11];
@@ -1006,12 +1017,12 @@ struct b43_phy_n {
        bool gband_spurwar_en;
 
        bool ipa2g_on;
-       u8 iqcal_chanspec_2G;
-       u8 rssical_chanspec_2G;
+       struct b43_chanspec iqcal_chanspec_2G;
+       struct b43_chanspec rssical_chanspec_2G;
 
        bool ipa5g_on;
-       u8 iqcal_chanspec_5G;
-       u8 rssical_chanspec_5G;
+       struct b43_chanspec iqcal_chanspec_5G;
+       struct b43_chanspec rssical_chanspec_5G;
 
        struct b43_phy_n_rssical_cache rssical_cache;
        struct b43_phy_n_cal_cache cal_cache;
index a00d509150f77082f741fa18ff6c7f3e4d0bc1d4..d96e870ab8fe8cea97c821c27076b2b99a47dfc8 100644 (file)
@@ -318,14 +318,14 @@ void b2055_upload_inittab(struct b43_wldev *dev,
        .radio_c2_tx_mxbgtrim   = r21
 
 #define PHYREGS(r0, r1, r2, r3, r4, r5)        \
-       .phy_bw1a       = r0,           \
-       .phy_bw2        = r1,           \
-       .phy_bw3        = r2,           \
-       .phy_bw4        = r3,           \
-       .phy_bw5        = r4,           \
-       .phy_bw6        = r5
-
-static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
+       .phy_regs.phy_bw1a      = r0,   \
+       .phy_regs.phy_bw2       = r1,   \
+       .phy_regs.phy_bw3       = r2,   \
+       .phy_regs.phy_bw4       = r3,   \
+       .phy_regs.phy_bw5       = r4,   \
+       .phy_regs.phy_bw6       = r5
+
+static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab[] = {
   {    .channel                = 184,
        .freq                   = 4920, /* MHz */
        .unk2                   = 3280,
@@ -1320,10 +1320,10 @@ static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = {
   },
 };
 
-const struct b43_nphy_channeltab_entry *
-b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel)
+const struct b43_nphy_channeltab_entry_rev2 *
+b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel)
 {
-       const struct b43_nphy_channeltab_entry *e;
+       const struct b43_nphy_channeltab_entry_rev2 *e;
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) {
index 9c1c6ecd36725f9475f3d781ea46472b7f02a7e6..8fc1da9f8fe57bce8bf0a531f4ef56b2d248dac9 100644 (file)
@@ -4,9 +4,22 @@
 #include <linux/types.h>
 
 
-struct b43_nphy_channeltab_entry {
+struct b43_phy_n_sfo_cfg {
+       u16 phy_bw1a;
+       u16 phy_bw2;
+       u16 phy_bw3;
+       u16 phy_bw4;
+       u16 phy_bw5;
+       u16 phy_bw6;
+};
+
+struct b43_nphy_channeltab_entry_rev2 {
        /* The channel number */
        u8 channel;
+       /* The channel frequency in MHz */
+       u16 freq;
+       /* An unknown value */
+       u16 unk2;
        /* Radio register values on channelswitch */
        u8 radio_pll_ref;
        u8 radio_rf_pllmod0;
@@ -31,16 +44,18 @@ struct b43_nphy_channeltab_entry {
        u8 radio_c2_tx_pgapadtn;
        u8 radio_c2_tx_mxbgtrim;
        /* PHY register values on channelswitch */
-       u16 phy_bw1a;
-       u16 phy_bw2;
-       u16 phy_bw3;
-       u16 phy_bw4;
-       u16 phy_bw5;
-       u16 phy_bw6;
+       struct b43_phy_n_sfo_cfg phy_regs;
+};
+
+struct b43_nphy_channeltab_entry_rev3 {
+       /* The channel number */
+       u8 channel;
        /* The channel frequency in MHz */
        u16 freq;
-       /* An unknown value */
-       u16 unk2;
+       /* Radio register values on channelswitch */
+       /* TODO */
+       /* PHY register values on channelswitch */
+       struct b43_phy_n_sfo_cfg phy_regs;
 };
 
 
@@ -77,8 +92,8 @@ void b2055_upload_inittab(struct b43_wldev *dev,
 
 /* Get the NPHY Channel Switch Table entry for a channel number.
  * Returns NULL on failure to find an entry. */
-const struct b43_nphy_channeltab_entry *
-b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel);
+const struct b43_nphy_channeltab_entry_rev2 *
+b43_nphy_get_chantabent_rev2(struct b43_wldev *dev, u8 channel);
 
 
 /* The N-PHY tables. */
index eda06529ef5f493384179272216af98b8e420ab5..e6b0528f3b52a31d38fb2c93e3a609f1eae14d2e 100644 (file)
@@ -610,7 +610,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        }
 
        /* Link quality statistics */
-       status.noise = dev->stats.link_noise;
        if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) {
 //             s8 rssi = max(rxhdr->power0, rxhdr->power1);
                //TODO: Find out what the rssi value is (dBm or percentage?)
index bb2dd9329aa0fd88ff7f7b2dc85d841e1a193209..1713f5f7a58b0571c57876cdee4ac6b4f4b63019 100644 (file)
@@ -3482,6 +3482,23 @@ static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw,
        return 0;
 }
 
+static int b43legacy_op_get_survey(struct ieee80211_hw *hw, int idx,
+                                  struct survey_info *survey)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       struct ieee80211_conf *conf = &hw->conf;
+
+       if (idx != 0)
+               return -ENOENT;
+
+       survey->channel = conf->channel;
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = dev->stats.link_noise;
+
+       return 0;
+}
+
 static const struct ieee80211_ops b43legacy_hw_ops = {
        .tx                     = b43legacy_op_tx,
        .conf_tx                = b43legacy_op_conf_tx,
@@ -3494,6 +3511,7 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
        .start                  = b43legacy_op_start,
        .stop                   = b43legacy_op_stop,
        .set_tim                = b43legacy_op_beacon_set_tim,
+       .get_survey             = b43legacy_op_get_survey,
        .rfkill_poll            = b43legacy_rfkill_poll,
 };
 
@@ -3769,8 +3787,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev)
 
        /* fill hw info */
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
+                   IEEE80211_HW_SIGNAL_DBM;
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_STATION) |
index 9c8882d9275edf203ee11a4c975d9c6d815d4ee1..7d177d97f1f7ff82803ed6dbbeabd4ce3bdb594f 100644 (file)
@@ -548,7 +548,6 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
                                      (phystat0 & B43legacy_RX_PHYST0_OFDM),
                                      (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
                                      (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
-       status.noise = dev->stats.link_noise;
        /* change to support A PHY */
        if (phystat0 & B43legacy_RX_PHYST0_OFDM)
                status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false);
index f4c56121d3878307f63fa9552b3e084ae89af130..e0b3e8d406b36f692ebc996024ae79885c5a1096 100644 (file)
@@ -355,8 +355,7 @@ static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid,
                list_del(&bss->list);
                local->num_bss_info--;
        } else {
-               bss = (struct hostap_bss_info *)
-                       kmalloc(sizeof(*bss), GFP_ATOMIC);
+               bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
                if (bss == NULL)
                        return NULL;
        }
index 7e72ac1de49b96b4abb8672240e26d3c3f121eb4..231dbd77f5f5b31669116799ceeab36467b79963 100644 (file)
@@ -349,7 +349,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
        default:
                policy_txt = "unknown";
                break;
-       };
+       }
        p += sprintf(p, "MAC policy: %s\n", policy_txt);
        p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
        p += sprintf(p, "MAC list:\n");
index 89d3849abfe002f67a53ea2ea4111625f7e6358e..e73bf739fd9bd56871c7b6ef902c3622ba71c003 100644 (file)
@@ -744,7 +744,7 @@ static int prism2_download(local_info_t *local,
                       local->dev->name, param->dl_cmd);
                ret = -EINVAL;
                break;
-       };
+       }
 
  out:
        if (ret == 0 && dl &&
index 9a082308a9d467ae5e431b5ffb716df9f944d67a..a85e43a8d75823142bdc3b986adf7954e1e65d61 100644 (file)
@@ -3039,8 +3039,7 @@ static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
            p->length > 1024 || !p->pointer)
                return -EINVAL;
 
-       param = (struct prism2_download_param *)
-               kmalloc(p->length, GFP_KERNEL);
+       param = kmalloc(p->length, GFP_KERNEL);
        if (param == NULL)
                return -ENOMEM;
 
index 2b05fe5e994c4da25ed3cdd52b98c9a8f60bde74..0bd4dfa59a8ab526db141832b37d5caf681ce2cb 100644 (file)
@@ -2141,7 +2141,7 @@ static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
        DECLARE_SSID_BUF(ssid);
 
        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
-                 "disassociated: '%s' %pM \n",
+                 "disassociated: '%s' %pM\n",
                  print_ssid(ssid, priv->essid, priv->essid_len),
                  priv->bssid);
 
@@ -3240,7 +3240,6 @@ static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
                               IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
                               txq->next);
        }
-       return;
 }
 
 static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
@@ -3286,7 +3285,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
 
        if (inta & IPW2100_INTA_PARITY_ERROR) {
                printk(KERN_ERR DRV_NAME
-                      ": ***** PARITY ERROR INTERRUPT !!!! \n");
+                      ": ***** PARITY ERROR INTERRUPT !!!!\n");
                priv->inta_other++;
                write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
        }
@@ -6103,7 +6102,7 @@ static const struct net_device_ops ipw2100_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/* Look into using netdev destructor to shutdown ieee80211? */
+/* Look into using netdev destructor to shutdown libipw? */
 
 static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
                                               void __iomem * base_addr,
@@ -6113,7 +6112,7 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        struct ipw2100_priv *priv;
        struct net_device *dev;
 
-       dev = alloc_ieee80211(sizeof(struct ipw2100_priv), 0);
+       dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
        if (!dev)
                return NULL;
        priv = libipw_priv(dev);
@@ -6426,7 +6425,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
                sysfs_remove_group(&pci_dev->dev.kobj,
                                   &ipw2100_attribute_group);
 
-               free_ieee80211(dev, 0);
+               free_libipw(dev, 0);
                pci_set_drvdata(pci_dev, NULL);
        }
 
@@ -6484,10 +6483,10 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
                if (dev->base_addr)
                        iounmap((void __iomem *)dev->base_addr);
 
-               /* wiphy_unregister needs to be here, before free_ieee80211 */
+               /* wiphy_unregister needs to be here, before free_libipw */
                wiphy_unregister(priv->ieee->wdev.wiphy);
                kfree(priv->ieee->bg_band.channels);
-               free_ieee80211(dev, 0);
+               free_libipw(dev, 0);
        }
 
        pci_release_regions(pci_dev);
@@ -6754,7 +6753,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev,
                err = -EOPNOTSUPP;
                goto done;
        } else {                /* Set the channel */
-               IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+               IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
                err = ipw2100_set_channel(priv, fwrq->m, 0);
        }
 
@@ -6783,7 +6782,7 @@ static int ipw2100_wx_get_freq(struct net_device *dev,
        else
                wrqu->freq.m = 0;
 
-       IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+       IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
        return 0;
 
 }
@@ -6795,7 +6794,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev,
        struct ipw2100_priv *priv = libipw_priv(dev);
        int err = 0;
 
-       IPW_DEBUG_WX("SET Mode -> %d \n", wrqu->mode);
+       IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
 
        if (wrqu->mode == priv->ieee->iw_mode)
                return 0;
@@ -7150,7 +7149,7 @@ static int ipw2100_wx_set_nick(struct net_device *dev,
        memset(priv->nick, 0, sizeof(priv->nick));
        memcpy(priv->nick, extra, wrqu->data.length);
 
-       IPW_DEBUG_WX("SET Nickname -> %s \n", priv->nick);
+       IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
 
        return 0;
 }
@@ -7169,7 +7168,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
        memcpy(extra, priv->nick, wrqu->data.length);
        wrqu->data.flags = 1;   /* active */
 
-       IPW_DEBUG_WX("GET Nickname -> %s \n", extra);
+       IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
 
        return 0;
 }
@@ -7208,7 +7207,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev,
 
        err = ipw2100_set_tx_rates(priv, rate, 0);
 
-       IPW_DEBUG_WX("SET Rate -> %04X \n", rate);
+       IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
       done:
        mutex_unlock(&priv->action_mutex);
        return err;
@@ -7259,7 +7258,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev,
                wrqu->bitrate.value = 0;
        }
 
-       IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+       IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
 
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7295,7 +7294,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev,
 
        err = ipw2100_set_rts_threshold(priv, value);
 
-       IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value);
+       IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
       done:
        mutex_unlock(&priv->action_mutex);
        return err;
@@ -7317,7 +7316,7 @@ static int ipw2100_wx_get_rts(struct net_device *dev,
        /* If RTS is set to the default value, then it is disabled */
        wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
 
-       IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X \n", wrqu->rts.value);
+       IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
 
        return 0;
 }
@@ -7356,7 +7355,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev,
 
        err = ipw2100_set_tx_power(priv, value);
 
-       IPW_DEBUG_WX("SET TX Power -> %d \n", value);
+       IPW_DEBUG_WX("SET TX Power -> %d\n", value);
 
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7385,7 +7384,7 @@ static int ipw2100_wx_get_txpow(struct net_device *dev,
 
        wrqu->txpower.flags = IW_TXPOW_DBM;
 
-       IPW_DEBUG_WX("GET TX Power -> %d \n", wrqu->txpower.value);
+       IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
 
        return 0;
 }
@@ -7415,7 +7414,7 @@ static int ipw2100_wx_set_frag(struct net_device *dev,
                priv->frag_threshold = priv->ieee->fts;
        }
 
-       IPW_DEBUG_WX("SET Frag Threshold -> %d \n", priv->ieee->fts);
+       IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
 
        return 0;
 }
@@ -7433,7 +7432,7 @@ static int ipw2100_wx_get_frag(struct net_device *dev,
        wrqu->frag.fixed = 0;   /* no auto select */
        wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
 
-       IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+       IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
 
        return 0;
 }
@@ -7459,14 +7458,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
 
        if (wrqu->retry.flags & IW_RETRY_SHORT) {
                err = ipw2100_set_short_retry(priv, wrqu->retry.value);
-               IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
+               IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
                             wrqu->retry.value);
                goto done;
        }
 
        if (wrqu->retry.flags & IW_RETRY_LONG) {
                err = ipw2100_set_long_retry(priv, wrqu->retry.value);
-               IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
+               IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
                             wrqu->retry.value);
                goto done;
        }
@@ -7475,7 +7474,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
        if (!err)
                err = ipw2100_set_long_retry(priv, wrqu->retry.value);
 
-       IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value);
+       IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
 
       done:
        mutex_unlock(&priv->action_mutex);
@@ -7509,7 +7508,7 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
                wrqu->retry.value = priv->short_retry_limit;
        }
 
-       IPW_DEBUG_WX("GET Retry -> %d \n", wrqu->retry.value);
+       IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
 
        return 0;
 }
index 8d72e3d1958680bfaa9dbb79974cabf889e7b0ac..3aa3bb18f615fc98b790e0dd3b91dd8f79ddf630 100644 (file)
@@ -459,7 +459,7 @@ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
 {
        u32 word;
        _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
-       IPW_DEBUG_IO(" reg = 0x%8X : \n", reg);
+       IPW_DEBUG_IO(" reg = 0x%8X :\n", reg);
        word = _ipw_read32(priv, IPW_INDIRECT_DATA);
        return (word >> ((reg & 0x3) * 8)) & 0xff;
 }
@@ -473,7 +473,7 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
 
        _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
        value = _ipw_read32(priv, IPW_INDIRECT_DATA);
-       IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x \n", reg, value);
+       IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x\n", reg, value);
        return value;
 }
 
@@ -2349,16 +2349,25 @@ static void ipw_bg_adapter_restart(struct work_struct *work)
        mutex_unlock(&priv->mutex);
 }
 
-#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
+static void ipw_abort_scan(struct ipw_priv *priv);
+
+#define IPW_SCAN_CHECK_WATCHDOG        (5 * HZ)
 
 static void ipw_scan_check(void *data)
 {
        struct ipw_priv *priv = data;
-       if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) {
+
+       if (priv->status & STATUS_SCAN_ABORTING) {
                IPW_DEBUG_SCAN("Scan completion watchdog resetting "
                               "adapter after (%dms).\n",
                               jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
                queue_work(priv->workqueue, &priv->adapter_restart);
+       } else if (priv->status & STATUS_SCANNING) {
+               IPW_DEBUG_SCAN("Scan completion watchdog aborting scan "
+                              "after (%dms).\n",
+                              jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
+               ipw_abort_scan(priv);
+               queue_delayed_work(priv->workqueue, &priv->scan_check, HZ);
        }
 }
 
@@ -2598,8 +2607,6 @@ static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
 
        /* the eeprom requires some time to complete the operation */
        udelay(p->eeprom_delay);
-
-       return;
 }
 
 /* perform a chip select operation */
@@ -2739,7 +2746,7 @@ static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
 static int ipw_fw_dma_enable(struct ipw_priv *priv)
 {                              /* start dma engine but no transfers yet */
 
-       IPW_DEBUG_FW(">> : \n");
+       IPW_DEBUG_FW(">> :\n");
 
        /* Start the dma */
        ipw_fw_dma_reset_command_blocks(priv);
@@ -2747,7 +2754,7 @@ static int ipw_fw_dma_enable(struct ipw_priv *priv)
        /* Write CB base address */
        ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
 
-       IPW_DEBUG_FW("<< : \n");
+       IPW_DEBUG_FW("<< :\n");
        return 0;
 }
 
@@ -2762,7 +2769,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
        ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
        priv->sram_desc.last_cb_index = 0;
 
-       IPW_DEBUG_FW("<< \n");
+       IPW_DEBUG_FW("<<\n");
 }
 
 static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
@@ -2813,29 +2820,29 @@ static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
 
        IPW_DEBUG_FW(">> :\n");
        address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
-       IPW_DEBUG_FW_INFO("Current CB is 0x%x \n", address);
+       IPW_DEBUG_FW_INFO("Current CB is 0x%x\n", address);
 
        /* Read the DMA Controlor register */
        register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
-       IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x\n", register_value);
 
        /* Print the CB values */
        cb_fields_address = address;
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB ControlField is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("Current CB Control Field is 0x%x\n", register_value);
 
        cb_fields_address += sizeof(u32);
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x\n", register_value);
 
        cb_fields_address += sizeof(u32);
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x \n",
+       IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x\n",
                          register_value);
 
        cb_fields_address += sizeof(u32);
        register_value = ipw_read_reg32(priv, cb_fields_address);
-       IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x \n", register_value);
+       IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x\n", register_value);
 
        IPW_DEBUG_FW(">> :\n");
 }
@@ -2851,7 +2858,7 @@ static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
        current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
            sizeof(struct command_block);
 
-       IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X \n",
+       IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X\n",
                          current_cb_index, current_cb_address);
 
        IPW_DEBUG_FW(">> :\n");
@@ -2910,7 +2917,7 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
        int ret, i;
        u32 size;
 
-       IPW_DEBUG_FW(">> \n");
+       IPW_DEBUG_FW(">>\n");
        IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n",
                          nr, dest_address, len);
 
@@ -2927,7 +2934,7 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
                        IPW_DEBUG_FW_INFO(": Added new cb\n");
        }
 
-       IPW_DEBUG_FW("<< \n");
+       IPW_DEBUG_FW("<<\n");
        return 0;
 }
 
@@ -2936,7 +2943,7 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv)
        u32 current_index = 0, previous_index;
        u32 watchdog = 0;
 
-       IPW_DEBUG_FW(">> : \n");
+       IPW_DEBUG_FW(">> :\n");
 
        current_index = ipw_fw_dma_command_block_index(priv);
        IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
@@ -2965,7 +2972,7 @@ static int ipw_fw_dma_wait(struct ipw_priv *priv)
        ipw_set_bit(priv, IPW_RESET_REG,
                    IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
 
-       IPW_DEBUG_FW("<< dmaWaitSync \n");
+       IPW_DEBUG_FW("<< dmaWaitSync\n");
        return 0;
 }
 
@@ -3026,7 +3033,7 @@ static int ipw_stop_master(struct ipw_priv *priv)
 {
        int rc;
 
-       IPW_DEBUG_TRACE(">> \n");
+       IPW_DEBUG_TRACE(">>\n");
        /* stop master. typical delay - 0 */
        ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
 
@@ -3045,7 +3052,7 @@ static int ipw_stop_master(struct ipw_priv *priv)
 
 static void ipw_arc_release(struct ipw_priv *priv)
 {
-       IPW_DEBUG_TRACE(">> \n");
+       IPW_DEBUG_TRACE(">>\n");
        mdelay(5);
 
        ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
@@ -3067,7 +3074,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
 
        image = (__le16 *) data;
 
-       IPW_DEBUG_TRACE(">> \n");
+       IPW_DEBUG_TRACE(">>\n");
 
        rc = ipw_stop_master(priv);
 
@@ -3181,7 +3188,7 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
        void **virts;
        dma_addr_t *phys;
 
-       IPW_DEBUG_TRACE("<< : \n");
+       IPW_DEBUG_TRACE("<< :\n");
 
        virts = kmalloc(sizeof(void *) * CB_NUMBER_OF_ELEMENTS_SMALL,
                        GFP_KERNEL);
@@ -4482,7 +4489,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                        case CMAS_ASSOCIATED:{
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "associated: '%s' %pM \n",
+                                                 "associated: '%s' %pM\n",
                                                  print_ssid(ssid, priv->essid,
                                                             priv->essid_len),
                                                  priv->bssid);
@@ -4563,7 +4570,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                                                          IPW_DL_ASSOC,
                                                          "deauthenticated: '%s' "
                                                          "%pM"
-                                                         ": (0x%04X) - %s \n",
+                                                         ": (0x%04X) - %s\n",
                                                          print_ssid(ssid,
                                                                     priv->
                                                                     essid,
@@ -4614,7 +4621,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
 
                                        IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
                                                  IPW_DL_ASSOC,
-                                                 "disassociated: '%s' %pM \n",
+                                                 "disassociated: '%s' %pM\n",
                                                  print_ssid(ssid, priv->essid,
                                                             priv->essid_len),
                                                  priv->bssid);
@@ -4652,7 +4659,7 @@ static void ipw_rx_notification(struct ipw_priv *priv,
                        switch (auth->state) {
                        case CMAS_AUTHENTICATED:
                                IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-                                         "authenticated: '%s' %pM \n",
+                                         "authenticated: '%s' %pM\n",
                                          print_ssid(ssid, priv->essid,
                                                     priv->essid_len),
                                          priv->bssid);
@@ -6925,7 +6932,7 @@ static u8 ipw_qos_current_mode(struct ipw_priv * priv)
        } else {
                mode = priv->ieee->mode;
        }
-       IPW_DEBUG_QOS("QoS network/card mode %d \n", mode);
+       IPW_DEBUG_QOS("QoS network/card mode %d\n", mode);
        return mode;
 }
 
@@ -6965,7 +6972,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
                               &def_parameters_OFDM, size);
 
                if ((network->qos_data.active == 1) && (active_network == 1)) {
-                       IPW_DEBUG_QOS("QoS was disabled call qos_activate \n");
+                       IPW_DEBUG_QOS("QoS was disabled call qos_activate\n");
                        schedule_work(&priv->qos_activate);
                }
 
@@ -7542,7 +7549,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
                return err;
        }
 
-       IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n",
+       IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM\n",
                  print_ssid(ssid, priv->essid, priv->essid_len),
                  priv->bssid);
 
@@ -8793,7 +8800,7 @@ static int ipw_wx_set_freq(struct net_device *dev,
                }
        }
 
-       IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m);
+       IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
        mutex_lock(&priv->mutex);
        ret = ipw_set_channel(priv, channel);
        mutex_unlock(&priv->mutex);
@@ -8835,7 +8842,7 @@ static int ipw_wx_get_freq(struct net_device *dev,
                wrqu->freq.m = 0;
 
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel);
+       IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
        return 0;
 }
 
@@ -9230,7 +9237,7 @@ static int ipw_wx_get_sens(struct net_device *dev,
        wrqu->sens.value = priv->roaming_threshold;
        mutex_unlock(&priv->mutex);
 
-       IPW_DEBUG_WX("GET roaming threshold -> %s %d \n",
+       IPW_DEBUG_WX("GET roaming threshold -> %s %d\n",
                     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
 
        return 0;
@@ -9358,7 +9365,7 @@ static int ipw_wx_get_rate(struct net_device *dev,
        wrqu->bitrate.value = priv->last_rate;
        wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value);
+       IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
        return 0;
 }
 
@@ -9381,7 +9388,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
 
        ipw_send_rts_threshold(priv, priv->rts_threshold);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold);
+       IPW_DEBUG_WX("SET RTS Threshold -> %d\n", priv->rts_threshold);
        return 0;
 }
 
@@ -9395,7 +9402,7 @@ static int ipw_wx_get_rts(struct net_device *dev,
        wrqu->rts.fixed = 0;    /* no auto select */
        wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value);
+       IPW_DEBUG_WX("GET RTS Threshold -> %d\n", wrqu->rts.value);
        return 0;
 }
 
@@ -9445,7 +9452,7 @@ static int ipw_wx_get_txpow(struct net_device *dev,
        wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
        mutex_unlock(&priv->mutex);
 
-       IPW_DEBUG_WX("GET TX Power -> %s %d \n",
+       IPW_DEBUG_WX("GET TX Power -> %s %d\n",
                     wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
 
        return 0;
@@ -9471,7 +9478,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
 
        ipw_send_frag_threshold(priv, wrqu->frag.value);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value);
+       IPW_DEBUG_WX("SET Frag Threshold -> %d\n", wrqu->frag.value);
        return 0;
 }
 
@@ -9485,7 +9492,7 @@ static int ipw_wx_get_frag(struct net_device *dev,
        wrqu->frag.fixed = 0;   /* no auto select */
        wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
        mutex_unlock(&priv->mutex);
-       IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value);
+       IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
 
        return 0;
 }
@@ -9549,7 +9556,7 @@ static int ipw_wx_get_retry(struct net_device *dev,
        }
        mutex_unlock(&priv->mutex);
 
-       IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value);
+       IPW_DEBUG_WX("GET retry -> %d\n", wrqu->retry.value);
 
        return 0;
 }
@@ -9996,49 +10003,48 @@ static int ipw_wx_sw_reset(struct net_device *dev,
 }
 
 /* Rebase the WE IOCTLs to zero for the handler array */
-#define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
 static iw_handler ipw_wx_handlers[] = {
-       IW_IOCTL(SIOCGIWNAME) = (iw_handler) cfg80211_wext_giwname,
-       IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq,
-       IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq,
-       IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode,
-       IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode,
-       IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens,
-       IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens,
-       IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range,
-       IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap,
-       IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap,
-       IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan,
-       IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan,
-       IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid,
-       IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid,
-       IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick,
-       IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick,
-       IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate,
-       IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate,
-       IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts,
-       IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts,
-       IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag,
-       IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag,
-       IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow,
-       IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow,
-       IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry,
-       IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry,
-       IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode,
-       IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode,
-       IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power,
-       IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power,
-       IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy,
-       IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy,
-       IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy,
-       IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy,
-       IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie,
-       IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie,
-       IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme,
-       IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth,
-       IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth,
-       IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext,
-       IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext,
+       IW_HANDLER(SIOCGIWNAME, (iw_handler)cfg80211_wext_giwname),
+       IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq),
+       IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq),
+       IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode),
+       IW_HANDLER(SIOCGIWMODE, ipw_wx_get_mode),
+       IW_HANDLER(SIOCSIWSENS, ipw_wx_set_sens),
+       IW_HANDLER(SIOCGIWSENS, ipw_wx_get_sens),
+       IW_HANDLER(SIOCGIWRANGE, ipw_wx_get_range),
+       IW_HANDLER(SIOCSIWAP, ipw_wx_set_wap),
+       IW_HANDLER(SIOCGIWAP, ipw_wx_get_wap),
+       IW_HANDLER(SIOCSIWSCAN, ipw_wx_set_scan),
+       IW_HANDLER(SIOCGIWSCAN, ipw_wx_get_scan),
+       IW_HANDLER(SIOCSIWESSID, ipw_wx_set_essid),
+       IW_HANDLER(SIOCGIWESSID, ipw_wx_get_essid),
+       IW_HANDLER(SIOCSIWNICKN, ipw_wx_set_nick),
+       IW_HANDLER(SIOCGIWNICKN, ipw_wx_get_nick),
+       IW_HANDLER(SIOCSIWRATE, ipw_wx_set_rate),
+       IW_HANDLER(SIOCGIWRATE, ipw_wx_get_rate),
+       IW_HANDLER(SIOCSIWRTS, ipw_wx_set_rts),
+       IW_HANDLER(SIOCGIWRTS, ipw_wx_get_rts),
+       IW_HANDLER(SIOCSIWFRAG, ipw_wx_set_frag),
+       IW_HANDLER(SIOCGIWFRAG, ipw_wx_get_frag),
+       IW_HANDLER(SIOCSIWTXPOW, ipw_wx_set_txpow),
+       IW_HANDLER(SIOCGIWTXPOW, ipw_wx_get_txpow),
+       IW_HANDLER(SIOCSIWRETRY, ipw_wx_set_retry),
+       IW_HANDLER(SIOCGIWRETRY, ipw_wx_get_retry),
+       IW_HANDLER(SIOCSIWENCODE, ipw_wx_set_encode),
+       IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode),
+       IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power),
+       IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power),
+       IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
+       IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
+       IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
+       IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
+       IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie),
+       IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie),
+       IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme),
+       IW_HANDLER(SIOCSIWAUTH, ipw_wx_set_auth),
+       IW_HANDLER(SIOCGIWAUTH, ipw_wx_get_auth),
+       IW_HANDLER(SIOCSIWENCODEEXT, ipw_wx_set_encodeext),
+       IW_HANDLER(SIOCGIWENCODEEXT, ipw_wx_get_encodeext),
 };
 
 enum {
@@ -11667,7 +11673,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
        if (priv->prom_net_dev)
                return -EPERM;
 
-       priv->prom_net_dev = alloc_ieee80211(sizeof(struct ipw_prom_priv), 1);
+       priv->prom_net_dev = alloc_libipw(sizeof(struct ipw_prom_priv), 1);
        if (priv->prom_net_dev == NULL)
                return -ENOMEM;
 
@@ -11686,7 +11692,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
 
        rc = register_netdev(priv->prom_net_dev);
        if (rc) {
-               free_ieee80211(priv->prom_net_dev, 1);
+               free_libipw(priv->prom_net_dev, 1);
                priv->prom_net_dev = NULL;
                return rc;
        }
@@ -11700,7 +11706,7 @@ static void ipw_prom_free(struct ipw_priv *priv)
                return;
 
        unregister_netdev(priv->prom_net_dev);
-       free_ieee80211(priv->prom_net_dev, 1);
+       free_libipw(priv->prom_net_dev, 1);
 
        priv->prom_net_dev = NULL;
 }
@@ -11728,7 +11734,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        struct ipw_priv *priv;
        int i;
 
-       net_dev = alloc_ieee80211(sizeof(struct ipw_priv), 0);
+       net_dev = alloc_libipw(sizeof(struct ipw_priv), 0);
        if (net_dev == NULL) {
                err = -ENOMEM;
                goto out;
@@ -11748,7 +11754,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        mutex_init(&priv->mutex);
        if (pci_enable_device(pdev)) {
                err = -ENODEV;
-               goto out_free_ieee80211;
+               goto out_free_libipw;
        }
 
        pci_set_master(pdev);
@@ -11875,8 +11881,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
       out_pci_disable_device:
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
-      out_free_ieee80211:
-       free_ieee80211(priv->net_dev, 0);
+      out_free_libipw:
+       free_libipw(priv->net_dev, 0);
       out:
        return err;
 }
@@ -11943,11 +11949,11 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
        pci_release_regions(pdev);
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
-       /* wiphy_unregister needs to be here, before free_ieee80211 */
+       /* wiphy_unregister needs to be here, before free_libipw */
        wiphy_unregister(priv->ieee->wdev.wiphy);
        kfree(priv->ieee->a_band.channels);
        kfree(priv->ieee->bg_band.channels);
-       free_ieee80211(priv->net_dev, 0);
+       free_libipw(priv->net_dev, 0);
        free_firmware();
 }
 
index a6d5e42647e4c2f0aae15dfd1ba1a598ffba633f..284b0e4cb815545369652c3c2222314e7557981f 100644 (file)
@@ -64,7 +64,7 @@
 extern u32 libipw_debug_level;
 #define LIBIPW_DEBUG(level, fmt, args...) \
 do { if (libipw_debug_level & (level)) \
-  printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
+  printk(KERN_DEBUG "libipw: %c %s " fmt, \
          in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
 static inline bool libipw_ratelimit_debug(u32 level)
 {
@@ -116,8 +116,8 @@ static inline bool libipw_ratelimit_debug(u32 level)
 #define LIBIPW_DL_RX            (1<<9)
 #define LIBIPW_DL_QOS           (1<<31)
 
-#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
-#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "libipw: " f, ## a)
+#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "libipw: " f, ## a)
 #define LIBIPW_DEBUG_INFO(f, a...)   LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a)
 
 #define LIBIPW_DEBUG_WX(f, a...)     LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a)
@@ -905,7 +905,7 @@ struct libipw_device {
                                       struct libipw_reassoc_request * req);
 
        /* This must be the last item so that it points to the data
-        * allocated beyond this structure by alloc_ieee80211 */
+        * allocated beyond this structure by alloc_libipw */
        u8 priv[0];
 };
 
@@ -1017,9 +1017,9 @@ static inline int libipw_is_cck_rate(u8 rate)
        return 0;
 }
 
-/* ieee80211.c */
-extern void free_ieee80211(struct net_device *dev, int monitor);
-extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor);
+/* libipw.c */
+extern void free_libipw(struct net_device *dev, int monitor);
+extern struct net_device *alloc_libipw(int sizeof_priv, int monitor);
 extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
 
 extern void libipw_networks_age(struct libipw_device *ieee,
index 2fa55867bd8bb66a931738c50d58f89aee30dda2..55965408ff3f3786e07f0117f5def525f55c8a20 100644 (file)
@@ -53,7 +53,7 @@
 #include "libipw.h"
 
 #define DRV_DESCRIPTION "802.11 data/management/control stack"
-#define DRV_NAME        "ieee80211"
+#define DRV_NAME        "libipw"
 #define DRV_VERSION    LIBIPW_VERSION
 #define DRV_COPYRIGHT   "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
 
@@ -140,7 +140,7 @@ int libipw_change_mtu(struct net_device *dev, int new_mtu)
 }
 EXPORT_SYMBOL(libipw_change_mtu);
 
-struct net_device *alloc_ieee80211(int sizeof_priv, int monitor)
+struct net_device *alloc_libipw(int sizeof_priv, int monitor)
 {
        struct libipw_device *ieee;
        struct net_device *dev;
@@ -222,8 +222,9 @@ failed_free_netdev:
 failed:
        return NULL;
 }
+EXPORT_SYMBOL(alloc_libipw);
 
-void free_ieee80211(struct net_device *dev, int monitor)
+void free_libipw(struct net_device *dev, int monitor)
 {
        struct libipw_device *ieee = netdev_priv(dev);
 
@@ -237,6 +238,7 @@ void free_ieee80211(struct net_device *dev, int monitor)
 
        free_netdev(dev);
 }
+EXPORT_SYMBOL(free_libipw);
 
 #ifdef CONFIG_LIBIPW_DEBUG
 
@@ -291,7 +293,7 @@ static int __init libipw_init(void)
        struct proc_dir_entry *e;
 
        libipw_debug_level = debug;
-       libipw_proc = proc_mkdir(DRV_NAME, init_net.proc_net);
+       libipw_proc = proc_mkdir("ieee80211", init_net.proc_net);
        if (libipw_proc == NULL) {
                LIBIPW_ERROR("Unable to create " DRV_NAME
                                " proc directory\n");
@@ -331,6 +333,3 @@ MODULE_PARM_DESC(debug, "debug output mask");
 
 module_exit(libipw_exit);
 module_init(libipw_init);
-
-EXPORT_SYMBOL(alloc_ieee80211);
-EXPORT_SYMBOL(free_ieee80211);
index 39a34da52d52858d89c439067066cfa2110ae23a..0de1b189322019e80e37e56b564a05e3fe508897 100644 (file)
@@ -918,7 +918,6 @@ void libipw_rx_any(struct libipw_device *ieee,
 drop_free:
        dev_kfree_skb_irq(skb);
        ieee->dev->stats.rx_dropped++;
-       return;
 }
 
 #define MGMT_FRAME_FIXED_PART_LENGTH           0x24
index 4e378faee6505f710d69c6309e24c9cf66a7c36a..7c7235385513b8464c22aca463f76ab549bb9b25 100644 (file)
@@ -9,7 +9,10 @@ CFLAGS_iwl-devtrace.o := -I$(src)
 
 # AGN
 obj-$(CONFIG_IWLAGN)   += iwlagn.o
-iwlagn-objs            := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
+iwlagn-objs            := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o
+iwlagn-objs            += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o
+iwlagn-objs            += iwl-agn-lib.o
+iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
 
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
 iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
@@ -19,5 +22,6 @@ iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
 # 3945
 obj-$(CONFIG_IWL3945)  += iwl3945.o
 iwl3945-objs           := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
+iwl3945-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-3945-debugfs.o
 
 ccflags-y += -D__CHECK_ENDIAN__
index 3bf2e6e9b2d954caa181eaa19f843e18cbb7fff6..6be2992f8f210dbe3b0d0dee0b0c43ddd78efe94 100644 (file)
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-sta.h"
+#include "iwl-agn.h"
 #include "iwl-helpers.h"
-#include "iwl-5000-hw.h"
+#include "iwl-agn-hw.h"
 #include "iwl-agn-led.h"
+#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL1000_UCODE_API_MAX 3
@@ -117,7 +119,7 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
 static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
                priv->cfg->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
@@ -125,13 +127,13 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->num_of_queues *
-                       sizeof(struct iwl5000_scd_bc_tbl);
+                       sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 
-       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
-       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+       priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
        priv->hw_params.max_bsm_size = 0;
        priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
@@ -161,25 +163,25 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
 
 static struct iwl_lib_ops iwl1000_lib = {
        .set_hw_params = iwl1000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
-       .load_ucode = iwl5000_load_ucode,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .apm_ops = {
                .init = iwl_apm_init,
@@ -189,40 +191,47 @@ static struct iwl_lib_ops iwl1000_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl1000_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
 };
 
 static const struct iwl_ops iwl1000_ops = {
-       .ucode = &iwl5000_ucode,
        .lib = &iwl1000_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
 struct iwl_cfg iwl1000_bgn_cfg = {
-       .name = "1000 Series BGN",
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BGN",
        .fw_name_pre = IWL1000_FW_PRE,
        .ucode_api_max = IWL1000_UCODE_API_MAX,
        .ucode_api_min = IWL1000_UCODE_API_MIN,
@@ -230,10 +239,10 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .ops = &iwl1000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -248,10 +257,15 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 128,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl1000_bg_cfg = {
-       .name = "1000 Series BG",
+       .name = "Intel(R) Centrino(R) Wireless-N 1000 BG",
        .fw_name_pre = IWL1000_FW_PRE,
        .ucode_api_max = IWL1000_UCODE_API_MAX,
        .ucode_api_min = IWL1000_UCODE_API_MIN,
@@ -259,10 +273,10 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .ops = &iwl1000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -270,12 +284,16 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .use_bsm = false,
        .max_ll_items = OTP_MAX_LL_ITEMS_1000,
        .shadow_ram_support = false,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 128,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 MODULE_FIRMWARE(IWL1000_MODULE_FIRMWARE(IWL1000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
new file mode 100644 (file)
index 0000000..6a9c64a
--- /dev/null
@@ -0,0 +1,500 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include "iwl-3945-debugfs.h"
+
+ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
+                                   char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = sizeof(struct iwl39_statistics_rx_phy) * 40 +
+                   sizeof(struct iwl39_statistics_rx_non_phy) * 40 + 400;
+       ssize_t ret;
+       struct iwl39_statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+       struct iwl39_statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+       struct iwl39_statistics_rx_non_phy *general, *accum_general;
+       struct iwl39_statistics_rx_non_phy *delta_general, *max_general;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(priv, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * The statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+       ofdm = &priv->_3945.statistics.rx.ofdm;
+       cck = &priv->_3945.statistics.rx.cck;
+       general = &priv->_3945.statistics.rx.general;
+       accum_ofdm = &priv->_3945.accum_statistics.rx.ofdm;
+       accum_cck = &priv->_3945.accum_statistics.rx.cck;
+       accum_general = &priv->_3945.accum_statistics.rx.general;
+       delta_ofdm = &priv->_3945.delta_statistics.rx.ofdm;
+       delta_cck = &priv->_3945.delta_statistics.rx.cck;
+       delta_general = &priv->_3945.delta_statistics.rx.general;
+       max_ofdm = &priv->_3945.max_delta.rx.ofdm;
+       max_cck = &priv->_3945.max_delta.rx.cck;
+       max_general = &priv->_3945.max_delta.rx.general;
+
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - OFDM:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
+                        accum_ofdm->ina_cnt,
+                        delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_cnt:",
+                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+                        delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "plcp_err:",
+                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+                        delta_ofdm->plcp_err, max_ofdm->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",  "crc32_err:",
+                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+                        delta_ofdm->crc32_err, max_ofdm->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "overrun_err:",
+                        le32_to_cpu(ofdm->overrun_err),
+                        accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+                        max_ofdm->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "early_overrun_err:",
+                        le32_to_cpu(ofdm->early_overrun_err),
+                        accum_ofdm->early_overrun_err,
+                        delta_ofdm->early_overrun_err,
+                        max_ofdm->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_good:", le32_to_cpu(ofdm->crc32_good),
+                        accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+                        max_ofdm->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "false_alarm_cnt:",
+                        le32_to_cpu(ofdm->false_alarm_cnt),
+                        accum_ofdm->false_alarm_cnt,
+                        delta_ofdm->false_alarm_cnt,
+                        max_ofdm->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_sync_err_cnt:",
+                        le32_to_cpu(ofdm->fina_sync_err_cnt),
+                        accum_ofdm->fina_sync_err_cnt,
+                        delta_ofdm->fina_sync_err_cnt,
+                        max_ofdm->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sfd_timeout:",
+                        le32_to_cpu(ofdm->sfd_timeout),
+                        accum_ofdm->sfd_timeout,
+                        delta_ofdm->sfd_timeout,
+                        max_ofdm->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_timeout:",
+                        le32_to_cpu(ofdm->fina_timeout),
+                        accum_ofdm->fina_timeout,
+                        delta_ofdm->fina_timeout,
+                        max_ofdm->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "unresponded_rts:",
+                        le32_to_cpu(ofdm->unresponded_rts),
+                        accum_ofdm->unresponded_rts,
+                        delta_ofdm->unresponded_rts,
+                        max_ofdm->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rxe_frame_lmt_ovrun:",
+                        le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+                        accum_ofdm->rxe_frame_limit_overrun,
+                        delta_ofdm->rxe_frame_limit_overrun,
+                        max_ofdm->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sent_ack_cnt:",
+                        le32_to_cpu(ofdm->sent_ack_cnt),
+                        accum_ofdm->sent_ack_cnt,
+                        delta_ofdm->sent_ack_cnt,
+                        max_ofdm->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sent_cts_cnt:",
+                        le32_to_cpu(ofdm->sent_cts_cnt),
+                        accum_ofdm->sent_cts_cnt,
+                        delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - CCK:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ina_cnt:",
+                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+                        delta_cck->ina_cnt, max_cck->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_cnt:",
+                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+                        delta_cck->fina_cnt, max_cck->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "plcp_err:",
+                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+                        delta_cck->plcp_err, max_cck->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_err:",
+                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+                        delta_cck->crc32_err, max_cck->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "overrun_err:",
+                        le32_to_cpu(cck->overrun_err),
+                        accum_cck->overrun_err,
+                        delta_cck->overrun_err, max_cck->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "early_overrun_err:",
+                        le32_to_cpu(cck->early_overrun_err),
+                        accum_cck->early_overrun_err,
+                        delta_cck->early_overrun_err,
+                        max_cck->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_good:",
+                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+                        delta_cck->crc32_good,
+                        max_cck->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "false_alarm_cnt:",
+                        le32_to_cpu(cck->false_alarm_cnt),
+                        accum_cck->false_alarm_cnt,
+                        delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_sync_err_cnt:",
+                        le32_to_cpu(cck->fina_sync_err_cnt),
+                        accum_cck->fina_sync_err_cnt,
+                        delta_cck->fina_sync_err_cnt,
+                        max_cck->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sfd_timeout:",
+                        le32_to_cpu(cck->sfd_timeout),
+                        accum_cck->sfd_timeout,
+                        delta_cck->sfd_timeout, max_cck->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_timeout:",
+                        le32_to_cpu(cck->fina_timeout),
+                        accum_cck->fina_timeout,
+                        delta_cck->fina_timeout, max_cck->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "unresponded_rts:",
+                        le32_to_cpu(cck->unresponded_rts),
+                        accum_cck->unresponded_rts,
+                        delta_cck->unresponded_rts,
+                        max_cck->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rxe_frame_lmt_ovrun:",
+                        le32_to_cpu(cck->rxe_frame_limit_overrun),
+                        accum_cck->rxe_frame_limit_overrun,
+                        delta_cck->rxe_frame_limit_overrun,
+                        max_cck->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sent_ack_cnt:",
+                        le32_to_cpu(cck->sent_ack_cnt),
+                        accum_cck->sent_ack_cnt,
+                        delta_cck->sent_ack_cnt,
+                        max_cck->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sent_cts_cnt:",
+                        le32_to_cpu(cck->sent_cts_cnt),
+                        accum_cck->sent_cts_cnt,
+                        delta_cck->sent_cts_cnt,
+                        max_cck->sent_cts_cnt);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - GENERAL:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "bogus_cts:",
+                        le32_to_cpu(general->bogus_cts),
+                        accum_general->bogus_cts,
+                        delta_general->bogus_cts, max_general->bogus_cts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "bogus_ack:",
+                        le32_to_cpu(general->bogus_ack),
+                        accum_general->bogus_ack,
+                        delta_general->bogus_ack, max_general->bogus_ack);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "non_bssid_frames:",
+                        le32_to_cpu(general->non_bssid_frames),
+                        accum_general->non_bssid_frames,
+                        delta_general->non_bssid_frames,
+                        max_general->non_bssid_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "filtered_frames:",
+                        le32_to_cpu(general->filtered_frames),
+                        accum_general->filtered_frames,
+                        delta_general->filtered_frames,
+                        max_general->filtered_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "non_channel_beacons:",
+                        le32_to_cpu(general->non_channel_beacons),
+                        accum_general->non_channel_beacons,
+                        delta_general->non_channel_beacons,
+                        max_general->non_channel_beacons);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
+                                   char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = (sizeof(struct iwl39_statistics_tx) * 48) + 250;
+       ssize_t ret;
+       struct iwl39_statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(priv, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * The statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+       tx = &priv->_3945.statistics.tx;
+       accum_tx = &priv->_3945.accum_statistics.tx;
+       delta_tx = &priv->_3945.delta_statistics.tx;
+       max_tx = &priv->_3945.max_delta.tx;
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Tx:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "preamble:",
+                        le32_to_cpu(tx->preamble_cnt),
+                        accum_tx->preamble_cnt,
+                        delta_tx->preamble_cnt, max_tx->preamble_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rx_detected_cnt:",
+                        le32_to_cpu(tx->rx_detected_cnt),
+                        accum_tx->rx_detected_cnt,
+                        delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "bt_prio_defer_cnt:",
+                        le32_to_cpu(tx->bt_prio_defer_cnt),
+                        accum_tx->bt_prio_defer_cnt,
+                        delta_tx->bt_prio_defer_cnt,
+                        max_tx->bt_prio_defer_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "bt_prio_kill_cnt:",
+                        le32_to_cpu(tx->bt_prio_kill_cnt),
+                        accum_tx->bt_prio_kill_cnt,
+                        delta_tx->bt_prio_kill_cnt,
+                        max_tx->bt_prio_kill_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "few_bytes_cnt:",
+                        le32_to_cpu(tx->few_bytes_cnt),
+                        accum_tx->few_bytes_cnt,
+                        delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "cts_timeout:",
+                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+                        delta_tx->cts_timeout, max_tx->cts_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ack_timeout:",
+                        le32_to_cpu(tx->ack_timeout),
+                        accum_tx->ack_timeout,
+                        delta_tx->ack_timeout, max_tx->ack_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "expected_ack_cnt:",
+                        le32_to_cpu(tx->expected_ack_cnt),
+                        accum_tx->expected_ack_cnt,
+                        delta_tx->expected_ack_cnt,
+                        max_tx->expected_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "actual_ack_cnt:",
+                        le32_to_cpu(tx->actual_ack_cnt),
+                        accum_tx->actual_ack_cnt,
+                        delta_tx->actual_ack_cnt,
+                        max_tx->actual_ack_cnt);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = sizeof(struct iwl39_statistics_general) * 10 + 300;
+       ssize_t ret;
+       struct iwl39_statistics_general *general, *accum_general;
+       struct iwl39_statistics_general *delta_general, *max_general;
+       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+       struct iwl39_statistics_div *div, *accum_div, *delta_div, *max_div;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(priv, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * The statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+       general = &priv->_3945.statistics.general;
+       dbg = &priv->_3945.statistics.general.dbg;
+       div = &priv->_3945.statistics.general.div;
+       accum_general = &priv->_3945.accum_statistics.general;
+       delta_general = &priv->_3945.delta_statistics.general;
+       max_general = &priv->_3945.max_delta.general;
+       accum_dbg = &priv->_3945.accum_statistics.general.dbg;
+       delta_dbg = &priv->_3945.delta_statistics.general.dbg;
+       max_dbg = &priv->_3945.max_delta.general.dbg;
+       accum_div = &priv->_3945.accum_statistics.general.div;
+       delta_div = &priv->_3945.delta_statistics.general.div;
+       max_div = &priv->_3945.max_delta.general.div;
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_General:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "burst_check:",
+                        le32_to_cpu(dbg->burst_check),
+                        accum_dbg->burst_check,
+                        delta_dbg->burst_check, max_dbg->burst_check);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "burst_count:",
+                        le32_to_cpu(dbg->burst_count),
+                        accum_dbg->burst_count,
+                        delta_dbg->burst_count, max_dbg->burst_count);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sleep_time:",
+                        le32_to_cpu(general->sleep_time),
+                        accum_general->sleep_time,
+                        delta_general->sleep_time, max_general->sleep_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "slots_out:",
+                        le32_to_cpu(general->slots_out),
+                        accum_general->slots_out,
+                        delta_general->slots_out, max_general->slots_out);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "slots_idle:",
+                        le32_to_cpu(general->slots_idle),
+                        accum_general->slots_idle,
+                        delta_general->slots_idle, max_general->slots_idle);
+       pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
+                        le32_to_cpu(general->ttl_timestamp));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "tx_on_a:",
+                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+                        delta_div->tx_on_a, max_div->tx_on_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "tx_on_b:",
+                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+                        delta_div->tx_on_b, max_div->tx_on_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "exec_time:",
+                        le32_to_cpu(div->exec_time), accum_div->exec_time,
+                        delta_div->exec_time, max_div->exec_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "probe_time:",
+                        le32_to_cpu(div->probe_time), accum_div->probe_time,
+                        delta_div->probe_time, max_div->probe_time);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.h
new file mode 100644 (file)
index 0000000..70809c5
--- /dev/null
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-debug.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ssize_t iwl3945_ucode_rx_stats_read(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos);
+ssize_t iwl3945_ucode_tx_stats_read(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos);
+ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+                                        char __user *user_buf, size_t count,
+                                        loff_t *ppos);
+#else
+static ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
+                                          char __user *user_buf, size_t count,
+                                          loff_t *ppos)
+{
+       return 0;
+}
+static ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
+                                          char __user *user_buf, size_t count,
+                                          loff_t *ppos)
+{
+       return 0;
+}
+static ssize_t iwl3945_ucode_general_stats_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+#endif
index 3a876a8ece388a73eaf824d4baa31836e155c131..91bcb4e3cdfbbe7b6e106bd27d209ef39dda5e43 100644 (file)
 
 #include "iwl-eeprom.h"
 
-/* Time constants */
-#define SHORT_SLOT_TIME 9
-#define LONG_SLOT_TIME 20
-
 /* RSSI to dBm */
 #define IWL39_RSSI_OFFSET      95
 
+#define IWL_DEFAULT_TX_POWER   0x0F
+
 /*
  * EEPROM related constants, enums, and structures.
  */
@@ -228,7 +226,6 @@ struct iwl3945_eeprom {
 
 /* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
 #define IWL39_NUM_QUEUES        5
-#define IWL_NUM_SCAN_RATES         (2)
 
 #define IWL_DEFAULT_TX_RETRY  15
 
index 902c4d4293e9634bbcfd135c880c79d7a3b27772..8e84a08ff9519ae28031853c62cf3941adf0e93e 100644 (file)
@@ -330,16 +330,25 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
 
 }
 
-static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta)
+/*
+ * Called after adding a new station to initialize rate scaling
+ */
+void iwl3945_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
 {
-       struct iwl3945_rs_sta *rs_sta = priv_sta;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct ieee80211_hw *hw = priv->hw;
+       struct ieee80211_conf *conf = &priv->hw->conf;
+       struct iwl3945_sta_priv *psta;
+       struct iwl3945_rs_sta *rs_sta;
+       struct ieee80211_supported_band *sband;
        int i;
 
-       IWL_DEBUG_RATE(priv, "enter\n");
+       IWL_DEBUG_INFO(priv, "enter\n");
+       if (sta_id == priv->hw_params.bcast_sta_id)
+               goto out;
 
-       spin_lock_init(&rs_sta->lock);
+       psta = (struct iwl3945_sta_priv *) sta->drv_priv;
+       rs_sta = &psta->rs_sta;
+       sband = hw->wiphy->bands[conf->channel->band];
 
        rs_sta->priv = priv;
 
@@ -352,9 +361,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
        rs_sta->last_flush = jiffies;
        rs_sta->flush_time = IWL_RATE_FLUSH;
        rs_sta->last_tx_packets = 0;
-       rs_sta->ibss_sta_added = 0;
 
-       init_timer(&rs_sta->rate_scale_flush);
        rs_sta->rate_scale_flush.data = (unsigned long)rs_sta;
        rs_sta->rate_scale_flush.function = iwl3945_bg_rate_scale_flush;
 
@@ -373,16 +380,18 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
                }
        }
 
-       priv->sta_supp_rates = sta->supp_rates[sband->band];
+       priv->_3945.sta_supp_rates = sta->supp_rates[sband->band];
        /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */
        if (sband->band == IEEE80211_BAND_5GHZ) {
                rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
-               priv->sta_supp_rates = priv->sta_supp_rates <<
+               priv->_3945.sta_supp_rates = priv->_3945.sta_supp_rates <<
                                                IWL_FIRST_OFDM_RATE;
        }
 
+out:
+       priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
 
-       IWL_DEBUG_RATE(priv, "leave\n");
+       IWL_DEBUG_INFO(priv, "leave\n");
 }
 
 static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
@@ -406,6 +415,9 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp)
 
        rs_sta = &psta->rs_sta;
 
+       spin_lock_init(&rs_sta->lock);
+       init_timer(&rs_sta->rate_scale_flush);
+
        IWL_DEBUG_RATE(priv, "leave\n");
 
        return rs_sta;
@@ -414,13 +426,14 @@ static void *rs_alloc_sta(void *iwl_priv, struct ieee80211_sta *sta, gfp_t gfp)
 static void rs_free_sta(void *iwl_priv, struct ieee80211_sta *sta,
                        void *priv_sta)
 {
-       struct iwl3945_sta_priv *psta = (void *) sta->drv_priv;
-       struct iwl3945_rs_sta *rs_sta = &psta->rs_sta;
-       struct iwl_priv *priv __maybe_unused = rs_sta->priv;
+       struct iwl3945_rs_sta *rs_sta = priv_sta;
 
-       IWL_DEBUG_RATE(priv, "enter\n");
+       /*
+        * Be careful not to use any members of iwl3945_rs_sta (like trying
+        * to use iwl_priv to print out debugging) since it may not be fully
+        * initialized at this point.
+        */
        del_timer_sync(&rs_sta->rate_scale_flush);
-       IWL_DEBUG_RATE(priv, "leave\n");
 }
 
 
@@ -459,6 +472,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
                return;
        }
 
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (!rs_sta->priv) {
+               IWL_DEBUG_RATE(priv, "leave: STA priv data uninitialized!\n");
+               return;
+       }
+
+
        rs_sta->tx_packets++;
 
        scale_rate_index = first_index;
@@ -525,8 +545,6 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
        spin_unlock_irqrestore(&rs_sta->lock, flags);
 
        IWL_DEBUG_RATE(priv, "leave\n");
-
-       return;
 }
 
 static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta,
@@ -626,14 +644,19 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
        u32 fail_count;
        s8 scale_action = 0;
        unsigned long flags;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
        s8 max_rate_idx = -1;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        IWL_DEBUG_RATE(priv, "enter\n");
 
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (rs_sta && !rs_sta->priv) {
+               IWL_DEBUG_RATE(priv, "Rate scaling information not initialized yet.\n");
+               priv_sta = NULL;
+       }
+
        if (rate_control_send_low(sta, priv_sta, txrc))
                return;
 
@@ -651,20 +674,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
        if (sband->band == IEEE80211_BAND_5GHZ)
                rate_mask = rate_mask << IWL_FIRST_OFDM_RATE;
 
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-           !rs_sta->ibss_sta_added) {
-               u8 sta_id = iwl_find_station(priv, hdr->addr1);
-
-               if (sta_id == IWL_INVALID_STATION) {
-                       IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
-                                      hdr->addr1);
-                       sta_id = iwl_add_station(priv, hdr->addr1, false,
-                               CMD_ASYNC, NULL);
-               }
-               if (sta_id != IWL_INVALID_STATION)
-                       rs_sta->ibss_sta_added = 1;
-       }
-
        spin_lock_irqsave(&rs_sta->lock, flags);
 
        /* for recent assoc, choose best rate regarding
@@ -884,12 +893,22 @@ static void iwl3945_remove_debugfs(void *priv, void *priv_sta)
 }
 #endif
 
+/*
+ * Initialization of rate scaling information is done by driver after
+ * the station is added. Since mac80211 calls this function before a
+ * station is added we ignore it.
+ */
+static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
+                             struct ieee80211_sta *sta, void *priv_sta)
+{
+}
+
 static struct rate_control_ops rs_ops = {
        .module = NULL,
        .name = RS_NAME,
        .tx_status = rs_tx_status,
        .get_rate = rs_get_rate,
-       .rate_init = rs_rate_init,
+       .rate_init = rs_rate_init_stub,
        .alloc = rs_alloc,
        .free = rs_free,
        .alloc_sta = rs_alloc_sta,
@@ -900,7 +919,6 @@ static struct rate_control_ops rs_ops = {
 #endif
 
 };
-
 void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 {
        struct iwl_priv *priv = hw->priv;
@@ -917,6 +935,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
        sta = ieee80211_find_sta(priv->vif,
                                 priv->stations[sta_id].sta.sta.addr);
        if (!sta) {
+               IWL_DEBUG_RATE(priv, "Unable to find station to initialize rate scaling.\n");
                rcu_read_unlock();
                return;
        }
@@ -947,7 +966,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
 
        spin_unlock_irqrestore(&rs_sta->lock, flags);
 
-       rssi = priv->last_rx_rssi;
+       rssi = priv->_3945.last_rx_rssi;
        if (rssi == 0)
                rssi = IWL_MIN_RSSI_VAL;
 
index 0728054a22d4f15f7cbfa9801300fb598bee7fa0..068f7f8435c5d98c63626062a98f46f1853c6e2e 100644 (file)
@@ -50,6 +50,7 @@
 #include "iwl-helpers.h"
 #include "iwl-led.h"
 #include "iwl-3945-led.h"
+#include "iwl-3945-debugfs.h"
 
 #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
        [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \
@@ -192,12 +193,12 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp)
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_ENTRY(x) case TX_3945_STATUS_FAIL_ ## x: return #x
 
 static const char *iwl3945_get_tx_fail_reason(u32 status)
 {
        switch (status & TX_STATUS_MSK) {
-       case TX_STATUS_SUCCESS:
+       case TX_3945_STATUS_SUCCESS:
                return "SUCCESS";
                TX_STATUS_ENTRY(SHORT_LIMIT);
                TX_STATUS_ENTRY(LONG_LIMIT);
@@ -243,7 +244,7 @@ int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate)
                        next_rate = IWL_RATE_6M_INDEX;
                break;
        case IEEE80211_BAND_2GHZ:
-               if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+               if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
                    iwl_is_associated(priv)) {
                        if (rate == IWL_RATE_11M_INDEX)
                                next_rate = IWL_RATE_5M_INDEX;
@@ -293,7 +294,7 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
  * iwl3945_rx_reply_tx - Handle Tx response
  */
 static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb)
+                               struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -351,18 +352,143 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
  *  RX handler implementations
  *
  *****************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+/*
+ *  based on the assumption of all statistics counter are in DWORD
+ *  FIXME: This function is for debugging, do not deal with
+ *  the case of counters roll-over.
+ */
+static void iwl3945_accumulative_statistics(struct iwl_priv *priv,
+                                           __le32 *stats)
+{
+       int i;
+       __le32 *prev_stats;
+       u32 *accum_stats;
+       u32 *delta, *max_delta;
+
+       prev_stats = (__le32 *)&priv->_3945.statistics;
+       accum_stats = (u32 *)&priv->_3945.accum_statistics;
+       delta = (u32 *)&priv->_3945.delta_statistics;
+       max_delta = (u32 *)&priv->_3945.max_delta;
+
+       for (i = sizeof(__le32); i < sizeof(struct iwl3945_notif_statistics);
+            i += sizeof(__le32), stats++, prev_stats++, delta++,
+            max_delta++, accum_stats++) {
+               if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {
+                       *delta = (le32_to_cpu(*stats) -
+                               le32_to_cpu(*prev_stats));
+                       *accum_stats += *delta;
+                       if (*delta > *max_delta)
+                               *max_delta = *delta;
+               }
+       }
+
+       /* reset accumulative statistics for "no-counter" type statistics */
+       priv->_3945.accum_statistics.general.temperature =
+               priv->_3945.statistics.general.temperature;
+       priv->_3945.accum_statistics.general.ttl_timestamp =
+               priv->_3945.statistics.general.ttl_timestamp;
+}
+#endif
+
+/**
+ * iwl3945_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+static bool iwl3945_good_plcp_health(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
+{
+       bool rc = true;
+       struct iwl3945_notif_statistics current_stat;
+       int combined_plcp_delta;
+       unsigned int plcp_msec;
+       unsigned long plcp_received_jiffies;
+
+       memcpy(&current_stat, pkt->u.raw, sizeof(struct
+                       iwl3945_notif_statistics));
+       /*
+        * check for plcp_err and trigger radio reset if it exceeds
+        * the plcp error threshold plcp_delta.
+        */
+       plcp_received_jiffies = jiffies;
+       plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -
+                                       (long) priv->plcp_jiffies);
+       priv->plcp_jiffies = plcp_received_jiffies;
+       /*
+        * check to make sure plcp_msec is not 0 to prevent division
+        * by zero.
+        */
+       if (plcp_msec) {
+               combined_plcp_delta =
+                       (le32_to_cpu(current_stat.rx.ofdm.plcp_err) -
+                       le32_to_cpu(priv->_3945.statistics.rx.ofdm.plcp_err));
+
+               if ((combined_plcp_delta > 0) &&
+                       ((combined_plcp_delta * 100) / plcp_msec) >
+                       priv->cfg->plcp_delta_threshold) {
+                       /*
+                        * if plcp_err exceed the threshold, the following
+                        * data is printed in csv format:
+                        *    Text: plcp_err exceeded %d,
+                        *    Received ofdm.plcp_err,
+                        *    Current ofdm.plcp_err,
+                        *    combined_plcp_delta,
+                        *    plcp_msec
+                        */
+                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
+                               "%u, %d, %u mSecs\n",
+                               priv->cfg->plcp_delta_threshold,
+                               le32_to_cpu(current_stat.rx.ofdm.plcp_err),
+                               combined_plcp_delta, plcp_msec);
+                       /*
+                        * Reset the RF radio due to the high plcp
+                        * error rate
+                        */
+                       rc = false;
+               }
+       }
+       return rc;
+}
 
 void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
        IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
                     (int)sizeof(struct iwl3945_notif_statistics),
                     le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
+#endif
+       iwl_recover_from_statistics(priv, pkt);
+
+       memcpy(&priv->_3945.statistics, pkt->u.raw, sizeof(priv->_3945.statistics));
+}
+
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       __le32 *flag = (__le32 *)&pkt->u.raw;
 
-       memcpy(&priv->statistics_39, pkt->u.raw, sizeof(priv->statistics_39));
+       if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
+#ifdef CONFIG_IWLWIFI_DEBUG
+               memset(&priv->_3945.accum_statistics, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+               memset(&priv->_3945.delta_statistics, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+               memset(&priv->_3945.max_delta, 0,
+                       sizeof(struct iwl3945_notif_statistics));
+#endif
+               IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
+       }
+       iwl3945_hw_rx_statistics(priv, rxb);
 }
 
+
 /******************************************************************************
  *
  * Misc. internal state and helper functions
@@ -487,7 +613,7 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
                 *    but you can hack it to show more, if you'd like to. */
                if (dataframe)
                        IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-                                    "len=%u, rssi=%d, chnl=%d, rate=%d, \n",
+                                    "len=%u, rssi=%d, chnl=%d, rate=%d,\n",
                                     title, le16_to_cpu(fc), header->addr1[5],
                                     length, rssi, channel, rate);
                else {
@@ -549,7 +675,6 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
        u16 len = le16_to_cpu(rx_hdr->len);
        struct sk_buff *skb;
-       int ret;
        __le16 fc = hdr->frame_control;
 
        /* We received data from the HW, so stop the watchdog */
@@ -566,9 +691,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                return;
        }
 
-       skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
+       skb = dev_alloc_skb(128);
        if (!skb) {
-               IWL_ERR(priv, "alloc_skb failed\n");
+               IWL_ERR(priv, "dev_alloc_skb failed\n");
                return;
        }
 
@@ -577,37 +702,13 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                                       (struct ieee80211_hdr *)rxb_addr(rxb),
                                       le32_to_cpu(rx_end->status), stats);
 
-       skb_reserve(skb, IWL_LINK_HDR_MAX);
        skb_add_rx_frag(skb, 0, rxb->page,
                        (void *)rx_hdr->payload - (void *)pkt, len);
 
-       /* mac80211 currently doesn't support paged SKB. Convert it to
-        * linear SKB for management frame and data frame requires
-        * software decryption or software defragementation. */
-       if (ieee80211_is_mgmt(fc) ||
-           ieee80211_has_protected(fc) ||
-           ieee80211_has_morefrags(fc) ||
-           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
-               ret = skb_linearize(skb);
-       else
-               ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
-                       0 : -ENOMEM;
-
-       if (ret) {
-               kfree_skb(skb);
-               goto out;
-       }
-
-       /*
-        * XXX: We cannot touch the page and its virtual memory (pkt) after
-        * here. It might have already been freed by the above skb change.
-        */
-
        iwl_update_stats(priv, false, fc, len);
        memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
 
        ieee80211_rx(priv->hw, skb);
- out:
        priv->alloc_rxb_page--;
        rxb->page = NULL;
 }
@@ -623,9 +724,8 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
        struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
        struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
-       int snr;
-       u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
-       u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
+       u16 rx_stats_sig_avg __maybe_unused = le16_to_cpu(rx_stats->sig_avg);
+       u16 rx_stats_noise_diff __maybe_unused = le16_to_cpu(rx_stats->noise_diff);
        u8 network_packet;
 
        rx_status.flag = 0;
@@ -663,53 +763,29 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
        /* Convert 3945's rssi indicator to dBm */
        rx_status.signal = rx_stats->rssi - IWL39_RSSI_OFFSET;
 
-       /* Set default noise value to -127 */
-       if (priv->last_rx_noise == 0)
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-       /* 3945 provides noise info for OFDM frames only.
-        * sig_avg and noise_diff are measured by the 3945's digital signal
-        *   processor (DSP), and indicate linear levels of signal level and
-        *   distortion/noise within the packet preamble after
-        *   automatic gain control (AGC).  sig_avg should stay fairly
-        *   constant if the radio's AGC is working well.
-        * Since these values are linear (not dB or dBm), linear
-        *   signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
-        * Convert linear SNR to dB SNR, then subtract that from rssi dBm
-        *   to obtain noise level in dBm.
-        * Calculate rx_status.signal (quality indicator in %) based on SNR. */
-       if (rx_stats_noise_diff) {
-               snr = rx_stats_sig_avg / rx_stats_noise_diff;
-               rx_status.noise = rx_status.signal -
-                                       iwl3945_calc_db_from_ratio(snr);
-       } else {
-               rx_status.noise = priv->last_rx_noise;
-       }
-
-
-       IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n",
-                       rx_status.signal, rx_status.noise,
-                       rx_stats_sig_avg, rx_stats_noise_diff);
+       IWL_DEBUG_STATS(priv, "Rssi %d sig_avg %d noise_diff %d\n",
+                       rx_status.signal, rx_stats_sig_avg,
+                       rx_stats_noise_diff);
 
        header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 
        network_packet = iwl3945_is_network_packet(priv, header);
 
-       IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Noise:%u, Rate:%u\n",
+       IWL_DEBUG_STATS_LIMIT(priv, "[%c] %d RSSI:%d Signal:%u, Rate:%u\n",
                              network_packet ? '*' : ' ',
                              le16_to_cpu(rx_hdr->channel),
                              rx_status.signal, rx_status.signal,
-                             rx_status.noise, rx_status.rate_idx);
+                             rx_status.rate_idx);
 
        /* Set "1" to report good data frames in groups of 100 */
        iwl3945_dbg_report_frame(priv, pkt, header, 1);
        iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
 
        if (network_packet) {
-               priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
-               priv->last_tsf = le64_to_cpu(rx_end->timestamp);
-               priv->last_rx_rssi = rx_status.signal;
-               priv->last_rx_noise = rx_status.noise;
+               priv->_3945.last_beacon_time =
+                       le32_to_cpu(rx_end->beacon_timestamp);
+               priv->_3945.last_tsf = le64_to_cpu(rx_end->timestamp);
+               priv->_3945.last_rx_rssi = rx_status.signal;
        }
 
        iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
@@ -871,7 +947,8 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
                       tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
 }
 
-u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
+static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
+                          u16 tx_rate, u8 flags)
 {
        unsigned long flags_spin;
        struct iwl_station_entry *station;
@@ -957,7 +1034,7 @@ static int iwl3945_tx_reset(struct iwl_priv *priv)
        iwl_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005);
 
        iwl_write_direct32(priv, FH39_TSSR_CBB_BASE,
-                            priv->shared_phys);
+                            priv->_3945.shared_phys);
 
        iwl_write_direct32(priv, FH39_TSSR_MSG_CONFIG,
                FH39_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
@@ -1049,7 +1126,7 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
 
        if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
-               IWL_DEBUG_INFO(priv, "RTP type \n");
+               IWL_DEBUG_INFO(priv, "RTP type\n");
        else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
                IWL_DEBUG_INFO(priv, "3945 RADIO-MB type\n");
                iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
@@ -1607,7 +1684,7 @@ static int iwl3945_hw_reg_set_new_power(struct iwl_priv *priv,
        int power;
 
        /* Get this chnlgrp's rate-to-max/clip-powers table */
-       clip_pwrs = priv->clip39_groups[ch_info->group_index].clip_powers;
+       clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers;
 
        /* Get this channel's rate-to-current-power settings table */
        power_info = ch_info->power_info;
@@ -1701,6 +1778,11 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
        int ref_temp;
        int temperature = priv->temperature;
 
+       if (priv->disable_tx_power_cal ||
+           test_bit(STATUS_SCANNING, &priv->status)) {
+               /* do not perform tx power calibration */
+               return 0;
+       }
        /* set up new Tx power info for each and every channel, 2.4 and 5.x */
        for (i = 0; i < priv->channel_count; i++) {
                ch_info = &priv->channel_info[i];
@@ -1733,7 +1815,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
                }
 
                /* Get this chnlgrp's rate-to-max/clip-powers table */
-               clip_pwrs = priv->clip39_groups[ch_info->group_index].clip_powers;
+               clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers;
 
                /* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
                for (scan_tbl_index = 0;
@@ -1911,6 +1993,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                                  "configuration (%d).\n", rc);
                        return rc;
                }
+               iwl_clear_ucode_stations(priv);
+               iwl_restore_stations(priv);
        }
 
        IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -1941,7 +2025,10 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
 
        memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
 
-       iwl_clear_stations_table(priv);
+       if (!new_assoc) {
+               iwl_clear_ucode_stations(priv);
+               iwl_restore_stations(priv);
+       }
 
        /* If we issue a new RXON command which required a tune then we must
         * send a new TXPOWER command or we won't be able to Tx any frames */
@@ -1951,19 +2038,6 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                return rc;
        }
 
-       /* Add the broadcast address so we can send broadcast frames */
-       priv->cfg->ops->lib->add_bcast_station(priv);
-
-       /* If we have set the ASSOC_MSK and we are in BSS mode then
-        * add the IWL_AP_ID to the station rate table */
-       if (iwl_is_associated(priv) &&
-           (priv->iw_mode == NL80211_IFTYPE_STATION))
-               if (iwl_add_station(priv, priv->active_rxon.bssid_addr,
-                               true, CMD_SYNC, NULL) == IWL_INVALID_STATION) {
-                       IWL_ERR(priv, "Error adding AP address for transmit\n");
-                       return -EIO;
-               }
-
        /* Init the hardware's rate fallback order based on the band */
        rc = iwl3945_init_hw_rate_table(priv);
        if (rc) {
@@ -1998,13 +2072,13 @@ void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
 
  reschedule:
        queue_delayed_work(priv->workqueue,
-                          &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
+                          &priv->_3945.thermal_periodic, REG_RECALIB_PERIOD * HZ);
 }
 
 static void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                                            thermal_periodic.work);
+                                            _3945.thermal_periodic.work);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -2140,7 +2214,7 @@ static void iwl3945_hw_reg_init_channel_groups(struct iwl_priv *priv)
                 *   power peaks, without too much distortion (clipping).
                 */
                /* we'll fill in this array with h/w max power levels */
-               clip_pwrs = (s8 *) priv->clip39_groups[i].clip_powers;
+               clip_pwrs = (s8 *) priv->_3945.clip_groups[i].clip_powers;
 
                /* divide factory saturation power by 2 to find -3dB level */
                satur_pwr = (s8) (group->saturation_power >> 1);
@@ -2224,7 +2298,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
                        iwl3945_hw_reg_get_ch_grp_index(priv, ch_info);
 
                /* Get this chnlgrp's rate->max/clip-powers table */
-               clip_pwrs = priv->clip39_groups[ch_info->group_index].clip_powers;
+               clip_pwrs = priv->_3945.clip_groups[ch_info->group_index].clip_powers;
 
                /* calculate power index *adjustment* value according to
                 *  diff between current temperature and factory temperature */
@@ -2332,7 +2406,7 @@ int iwl3945_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 {
        int txq_id = txq->q.id;
 
-       struct iwl3945_shared *shared_data = priv->shared_virt;
+       struct iwl3945_shared *shared_data = priv->_3945.shared_virt;
 
        shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
 
@@ -2385,6 +2459,30 @@ static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
        return (u16)sizeof(struct iwl3945_addsta_cmd);
 }
 
+static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
+                                      struct ieee80211_vif *vif, bool add)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       int ret;
+
+       if (add) {
+               ret = iwl_add_bssid_station(priv, vif->bss_conf.bssid, false,
+                                           &vif_priv->ibss_bssid_sta_id);
+               if (ret)
+                       return ret;
+
+               iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id,
+                                (priv->band == IEEE80211_BAND_5GHZ) ?
+                                IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+                                CMD_ASYNC);
+               iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id);
+
+               return 0;
+       }
+
+       return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
+                                 vif->bss_conf.bssid);
+}
 
 /**
  * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
@@ -2432,7 +2530,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
                /* If an OFDM rate is used, have it fall back to the
                 * 1M CCK rates */
 
-               if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) &&
+               if (!(priv->_3945.sta_supp_rates & IWL_OFDM_RATES_MASK) &&
                    iwl_is_associated(priv)) {
 
                        index = IWL_FIRST_CCK_RATE;
@@ -2471,12 +2569,12 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
        memset((void *)&priv->hw_params, 0,
               sizeof(struct iwl_hw_params));
 
-       priv->shared_virt = dma_alloc_coherent(&priv->pci_dev->dev,
-                                              sizeof(struct iwl3945_shared),
-                                              &priv->shared_phys, GFP_KERNEL);
-       if (!priv->shared_virt) {
+       priv->_3945.shared_virt =
+               dma_alloc_coherent(&priv->pci_dev->dev,
+                                  sizeof(struct iwl3945_shared),
+                                  &priv->_3945.shared_phys, GFP_KERNEL);
+       if (!priv->_3945.shared_virt) {
                IWL_ERR(priv, "failed to allocate pci memory\n");
-               mutex_unlock(&priv->mutex);
                return -ENOMEM;
        }
 
@@ -2537,13 +2635,13 @@ void iwl3945_hw_rx_handler_setup(struct iwl_priv *priv)
 
 void iwl3945_hw_setup_deferred_work(struct iwl_priv *priv)
 {
-       INIT_DELAYED_WORK(&priv->thermal_periodic,
+       INIT_DELAYED_WORK(&priv->_3945.thermal_periodic,
                          iwl3945_bg_reg_txpower_periodic);
 }
 
 void iwl3945_hw_cancel_deferred_work(struct iwl_priv *priv)
 {
-       cancel_delayed_work(&priv->thermal_periodic);
+       cancel_delayed_work(&priv->_3945.thermal_periodic);
 }
 
 /* check contents of special bootstrap uCode SRAM */
@@ -2714,48 +2812,10 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
        return 0;
 }
 
-#define IWL3945_UCODE_GET(item)                                                \
-static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       return le32_to_cpu(ucode->u.v1.item);                           \
-}
-
-static u32 iwl3945_ucode_get_header_size(u32 api_ver)
-{
-       return UCODE_HEADER_SIZE(1);
-}
-static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       return 0;
-}
-static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       return (u8 *) ucode->u.v1.data;
-}
-
-IWL3945_UCODE_GET(inst_size);
-IWL3945_UCODE_GET(data_size);
-IWL3945_UCODE_GET(init_size);
-IWL3945_UCODE_GET(init_data_size);
-IWL3945_UCODE_GET(boot_size);
-
 static struct iwl_hcmd_ops iwl3945_hcmd = {
        .rxon_assoc = iwl3945_send_rxon_assoc,
        .commit_rxon = iwl3945_commit_rxon,
-};
-
-static struct iwl_ucode_ops iwl3945_ucode = {
-       .get_header_size = iwl3945_ucode_get_header_size,
-       .get_build = iwl3945_ucode_get_build,
-       .get_inst_size = iwl3945_ucode_get_inst_size,
-       .get_data_size = iwl3945_ucode_get_data_size,
-       .get_init_size = iwl3945_ucode_get_init_size,
-       .get_init_data_size = iwl3945_ucode_get_init_data_size,
-       .get_boot_size = iwl3945_ucode_get_boot_size,
-       .get_data = iwl3945_ucode_get_data,
+       .send_bt_config = iwl_send_bt_config,
 };
 
 static struct iwl_lib_ops iwl3945_lib = {
@@ -2791,17 +2851,24 @@ static struct iwl_lib_ops iwl3945_lib = {
        .post_associate = iwl3945_post_associate,
        .isr = iwl_isr_legacy,
        .config_ap = iwl3945_config_ap,
-       .add_bcast_station = iwl3945_add_bcast_station,
+       .manage_ibss_station = iwl3945_manage_ibss_station,
+       .check_plcp_health = iwl3945_good_plcp_health,
+
+       .debugfs_ops = {
+               .rx_stats_read = iwl3945_ucode_rx_stats_read,
+               .tx_stats_read = iwl3945_ucode_tx_stats_read,
+               .general_stats_read = iwl3945_ucode_general_stats_read,
+       },
 };
 
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
        .get_hcmd_size = iwl3945_get_hcmd_size,
        .build_addsta_hcmd = iwl3945_build_addsta_hcmd,
        .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
+       .request_scan = iwl3945_request_scan,
 };
 
 static const struct iwl_ops iwl3945_ops = {
-       .ucode = &iwl3945_ucode,
        .lib = &iwl3945_lib,
        .hcmd = &iwl3945_hcmd,
        .utils = &iwl3945_hcmd_utils,
@@ -2826,7 +2893,10 @@ static struct iwl_cfg iwl3945_bg_cfg = {
        .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .tx_power_by_driver = true,
 };
 
 static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2844,7 +2914,10 @@ static struct iwl_cfg iwl3945_abg_cfg = {
        .ht_greenfield_support = false,
        .led_compensation = 64,
        .broken_powersave = true,
-       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .tx_power_by_driver = true,
 };
 
 DEFINE_PCI_DEVICE_TABLE(iwl3945_hw_card_ids) = {
index 452dfd5456c6ed5506a1efbcc3a6e281c8d39240..bb2aeebf3652c1ce38bb8620f822a64e3f2f4782 100644 (file)
@@ -95,7 +95,6 @@ struct iwl3945_rs_sta {
        u8 tgg;
        u8 flush_pending;
        u8 start_rate;
-       u8 ibss_sta_added;
        struct timer_list rate_scale_flush;
        struct iwl3945_rate_scale_data win[IWL_RATE_COUNT_3945];
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -107,7 +106,12 @@ struct iwl3945_rs_sta {
 };
 
 
+/*
+ * The common struct MUST be first because it is shared between
+ * 3945 and agn!
+ */
 struct iwl3945_sta_priv {
+       struct iwl_station_priv_common common;
        struct iwl3945_rs_sta rs_sta;
 };
 
@@ -212,13 +216,6 @@ 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);
 
-/*
- * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
- * call this... todo... fix that.
-*/
-extern u8 iwl3945_sync_station(struct iwl_priv *priv, int sta_id,
-                          u16 tx_rate, u8 flags);
-
 /******************************************************************************
  *
  * Functions implemented in iwl-[34]*.c which are forward declared here
@@ -265,10 +262,14 @@ extern int iwl3945_hw_reg_send_txpower(struct iwl_priv *priv);
 extern int iwl3945_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
 extern void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
                                 struct iwl_rx_mem_buffer *rxb);
+void iwl3945_reply_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb);
 extern void iwl3945_disable_events(struct iwl_priv *priv);
 extern int iwl4965_get_temperature(const struct iwl_priv *priv);
-extern void iwl3945_post_associate(struct iwl_priv *priv);
-extern void iwl3945_config_ap(struct iwl_priv *priv);
+extern void iwl3945_post_associate(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif);
+extern void iwl3945_config_ap(struct iwl_priv *priv,
+                             struct ieee80211_vif *vif);
 
 /**
  * iwl3945_hw_find_station - Find station id for a given BSSID
@@ -287,14 +288,15 @@ extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
 extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
 extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
 extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
-extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
-                u16 tx_rate, u8 flags);
 
 extern const struct iwl_channel_info *iwl3945_get_channel_info(
        const struct iwl_priv *priv, enum ieee80211_band band, u16 channel);
 
 extern int iwl3945_rs_next_rate(struct iwl_priv *priv, int rate);
 
+/* scanning */
+void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
+
 /* Requires full declaration of iwl_priv before including */
 #include "iwl-io.h"
 
index 67ef562e8db164694fb13ef5fe6e6c7f939dcbef..cd4b61ae25b787021b7392187529c87d7962252f 100644 (file)
  */
 #define IWL49_FIRST_AMPDU_QUEUE        7
 
-/* Time constants */
-#define SHORT_SLOT_TIME 9
-#define LONG_SLOT_TIME 20
-
-/* RSSI to dBm */
-#define IWL49_RSSI_OFFSET      44
-
-
-/* PCI registers */
-#define PCI_CFG_RETRY_TIMEOUT  0x041
-
-/* PCI register values */
-#define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
-#define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
-
-#define IWL_NUM_SCAN_RATES         (2)
-
-#define IWL_DEFAULT_TX_RETRY  15
-
-
 /* Sizes and addresses for instruction and data memory (SRAM) in
  * 4965's embedded processor.  Driver access is via HBUS_TARG_MEM_* regs. */
 #define IWL49_RTC_INST_LOWER_BOUND             (0x000000)
@@ -393,10 +373,6 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr)
  *     location(s) in command (struct iwl4965_txpowertable_cmd).
  */
 
-/* Limit range of txpower output target to be between these values */
-#define IWL_TX_POWER_TARGET_POWER_MIN       (0)        /* 0 dBm = 1 milliwatt */
-#define IWL_TX_POWER_TARGET_POWER_MAX      (16)        /* 16 dBm */
-
 /**
  * When MIMO is used (2 transmitters operating simultaneously), driver should
  * limit each transmitter to deliver a max of 3 dB below the regulatory limit
index 8972166386cb5f79f1c214dda5f8e9a1164e341f..d3afddae8d9f18d6f308bb79189ed5deb5921d39 100644 (file)
@@ -46,6 +46,8 @@
 #include "iwl-calib.h"
 #include "iwl-sta.h"
 #include "iwl-agn-led.h"
+#include "iwl-agn.h"
+#include "iwl-agn-debugfs.h"
 
 static int iwl4965_send_tx_power(struct iwl_priv *priv);
 static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
@@ -60,14 +62,6 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv);
 #define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode"
 #define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api)
 
-
-/* module parameters */
-static struct iwl_mod_params iwl4965_mod_params = {
-       .amsdu_size_8K = 1,
-       .restart_fw = 1,
-       /* the rest are 0 by default */
-};
-
 /* check contents of special bootstrap uCode SRAM */
 static int iwl4965_verify_bsm(struct iwl_priv *priv)
 {
@@ -417,7 +411,7 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
                                      sizeof(cmd), &cmd);
                if (ret)
                        IWL_DEBUG_CALIB(priv, "fail sending cmd "
-                                    "REPLY_PHY_CALIBRATION_CMD \n");
+                                    "REPLY_PHY_CALIBRATION_CMD\n");
 
                /* TODO we might want recalculate
                 * rx_chain in rxon cmd */
@@ -502,14 +496,14 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
                       scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
 }
 
-static const u16 default_queue_to_tx_fifo[] = {
-       IWL_TX_FIFO_AC3,
-       IWL_TX_FIFO_AC2,
-       IWL_TX_FIFO_AC1,
-       IWL_TX_FIFO_AC0,
+static const s8 default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
        IWL49_CMD_FIFO_NUM,
-       IWL_TX_FIFO_HCCA_1,
-       IWL_TX_FIFO_HCCA_2
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
 };
 
 static int iwl4965_alive_notify(struct iwl_priv *priv)
@@ -589,9 +583,15 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
        /* reset to 0 to enable all the queue first */
        priv->txq_ctx_active_msk = 0;
        /* Map each Tx/cmd queue to its corresponding fifo */
+       BUILD_BUG_ON(ARRAY_SIZE(default_queue_to_tx_fifo) != 7);
        for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
                int ac = default_queue_to_tx_fifo[i];
+
                iwl_txq_ctx_activate(priv, i);
+
+               if (ac == IWL_TX_FIFO_UNUSED)
+                       continue;
+
                iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
        }
 
@@ -1613,19 +1613,19 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
 
        /* get absolute value */
        if (temp_diff < 0) {
-               IWL_DEBUG_POWER(priv, "Getting cooler, delta %d\n", temp_diff);
+               IWL_DEBUG_POWER(priv, "Getting cooler, delta %d\n", temp_diff);
                temp_diff = -temp_diff;
        } else if (temp_diff == 0)
-               IWL_DEBUG_POWER(priv, "Same temp, \n");
+               IWL_DEBUG_POWER(priv, "Temperature unchanged\n");
        else
-               IWL_DEBUG_POWER(priv, "Getting warmer, delta %d\n", temp_diff);
+               IWL_DEBUG_POWER(priv, "Getting warmer, delta %d\n", temp_diff);
 
        if (temp_diff < IWL_TEMPERATURE_THRESHOLD) {
-               IWL_DEBUG_POWER(priv, "Thermal txpower calib not needed\n");
+               IWL_DEBUG_POWER(priv, " => thermal txpower calib not needed\n");
                return 0;
        }
 
-       IWL_DEBUG_POWER(priv, "Thermal txpower calib needed\n");
+       IWL_DEBUG_POWER(priv, " => thermal txpower calib needed\n");
 
        return 1;
 }
@@ -1874,7 +1874,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
+               iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
                /* FIXME: code repetition end */
 
                IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
@@ -1953,6 +1953,60 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
        return 0;
 }
 
+static u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+       int i;
+       int start = 0;
+       int ret = IWL_INVALID_STATION;
+       unsigned long flags;
+
+       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
+           (priv->iw_mode == NL80211_IFTYPE_AP))
+               start = IWL_STA_ID;
+
+       if (is_broadcast_ether_addr(addr))
+               return priv->hw_params.bcast_sta_id;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       for (i = start; i < priv->hw_params.max_stations; i++)
+               if (priv->stations[i].used &&
+                   (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+                                        addr))) {
+                       ret = i;
+                       goto out;
+               }
+
+       IWL_DEBUG_ASSOC_LIMIT(priv, "can not find STA %pM total %d\n",
+                             addr, priv->num_stations);
+
+ out:
+       /*
+        * It may be possible that more commands interacting with stations
+        * arrive before we completed processing the adding of
+        * station
+        */
+       if (ret != IWL_INVALID_STATION &&
+           (!(priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) ||
+            ((priv->stations[ret].used & IWL_STA_UCODE_ACTIVE) &&
+             (priv->stations[ret].used & IWL_STA_UCODE_INPROGRESS)))) {
+               IWL_ERR(priv, "Requested station info for sta %d before ready.\n",
+                       ret);
+               ret = IWL_INVALID_STATION;
+       }
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       return ret;
+}
+
+static int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+               return IWL_AP_ID;
+       } else {
+               u8 *da = ieee80211_get_DA(hdr);
+               return iwl_find_station(priv, da);
+       }
+}
+
 /**
  * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response
  */
@@ -2014,7 +2068,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                        index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
                        IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
                                           "%d index %d\n", scd_ssn , index);
-                       freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+                       freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
                        if (qc)
                                iwl_free_tfds_in_queue(priv, sta_id,
                                                       tid, freed);
@@ -2031,7 +2085,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
        } else {
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv,
+               iwlagn_hwrate_to_tx_control(priv,
                                        le32_to_cpu(tx_resp->rate_n_flags),
                                        info);
 
@@ -2042,7 +2096,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                                   le32_to_cpu(tx_resp->rate_n_flags),
                                   tx_resp->failure_frame);
 
-               freed = iwl_tx_queue_reclaim(priv, txq_id, index);
+               freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
                if (qc && likely(sta_id != IWL_INVALID_STATION))
                        iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
                else if (sta_id == IWL_INVALID_STATION)
@@ -2053,10 +2107,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                        iwl_wake_queue(priv, txq_id);
        }
        if (qc && likely(sta_id != IWL_INVALID_STATION))
-               iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+               iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
 
-       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
-               IWL_ERR(priv, "TODO:  Implement Tx ABORT REQUIRED!!!\n");
+       iwl_check_abort_status(priv, tx_resp->frame_count, status);
 }
 
 static int iwl4965_calc_rssi(struct iwl_priv *priv,
@@ -2090,7 +2143,7 @@ static int iwl4965_calc_rssi(struct iwl_priv *priv,
 
        /* dBm = max_rssi dB - agc dB - constant.
         * Higher AGC (higher radio gain) means lower signal. */
-       return max_rssi - agc - IWL49_RSSI_OFFSET;
+       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
 }
 
 
@@ -2098,7 +2151,7 @@ static int iwl4965_calc_rssi(struct iwl_priv *priv,
 static void iwl4965_rx_handler_setup(struct iwl_priv *priv)
 {
        /* Legacy Rx frames */
-       priv->rx_handlers[REPLY_RX] = iwl_rx_reply_rx;
+       priv->rx_handlers[REPLY_RX] = iwlagn_rx_reply_rx;
        /* Tx response */
        priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx;
 }
@@ -2113,50 +2166,13 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
        cancel_work_sync(&priv->txpower_work);
 }
 
-#define IWL4965_UCODE_GET(item)                                                \
-static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       return le32_to_cpu(ucode->u.v1.item);                           \
-}
-
-static u32 iwl4965_ucode_get_header_size(u32 api_ver)
-{
-       return UCODE_HEADER_SIZE(1);
-}
-static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       return 0;
-}
-static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       return (u8 *) ucode->u.v1.data;
-}
-
-IWL4965_UCODE_GET(inst_size);
-IWL4965_UCODE_GET(data_size);
-IWL4965_UCODE_GET(init_size);
-IWL4965_UCODE_GET(init_data_size);
-IWL4965_UCODE_GET(boot_size);
-
 static struct iwl_hcmd_ops iwl4965_hcmd = {
        .rxon_assoc = iwl4965_send_rxon_assoc,
        .commit_rxon = iwl_commit_rxon,
        .set_rxon_chain = iwl_set_rxon_chain,
+       .send_bt_config = iwl_send_bt_config,
 };
 
-static struct iwl_ucode_ops iwl4965_ucode = {
-       .get_header_size = iwl4965_ucode_get_header_size,
-       .get_build = iwl4965_ucode_get_build,
-       .get_inst_size = iwl4965_ucode_get_inst_size,
-       .get_data_size = iwl4965_ucode_get_data_size,
-       .get_init_size = iwl4965_ucode_get_init_size,
-       .get_init_data_size = iwl4965_ucode_get_init_data_size,
-       .get_boot_size = iwl4965_ucode_get_boot_size,
-       .get_data = iwl4965_ucode_get_data,
-};
 static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
        .get_hcmd_size = iwl4965_get_hcmd_size,
        .build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2164,6 +2180,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
        .gain_computation = iwl4965_gain_computation,
        .rts_tx_cmd_flag = iwlcore_rts_tx_cmd_flag,
        .calc_rssi = iwl4965_calc_rssi,
+       .request_scan = iwlagn_request_scan,
 };
 
 static struct iwl_lib_ops iwl4965_lib = {
@@ -2184,6 +2201,7 @@ static struct iwl_lib_ops iwl4965_lib = {
        .load_ucode = iwl4965_load_bsm,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
+       .dump_fh = iwl_dump_fh,
        .set_channel_switch = iwl4965_hw_channel_switch,
        .apm_ops = {
                .init = iwl_apm_init,
@@ -2216,11 +2234,16 @@ static struct iwl_lib_ops iwl4965_lib = {
                .temperature = iwl4965_temperature_calib,
                .set_ct_kill = iwl4965_set_ct_threshold,
        },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+       },
+       .check_plcp_health = iwl_good_plcp_health,
 };
 
 static const struct iwl_ops iwl4965_ops = {
-       .ucode = &iwl4965_ucode,
        .lib = &iwl4965_lib,
        .hcmd = &iwl4965_hcmd,
        .utils = &iwl4965_hcmd_utils,
@@ -2228,7 +2251,7 @@ static const struct iwl_ops iwl4965_ops = {
 };
 
 struct iwl_cfg iwl4965_agn_cfg = {
-       .name = "4965AGN",
+       .name = "Intel(R) Wireless WiFi Link 4965AGN",
        .fw_name_pre = IWL4965_FW_PRE,
        .ucode_api_max = IWL4965_UCODE_API_MAX,
        .ucode_api_min = IWL4965_UCODE_API_MIN,
@@ -2239,7 +2262,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .ops = &iwl4965_ops,
        .num_of_queues = IWL49_NUM_QUEUES,
        .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl4965_mod_params,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = 0,
@@ -2251,27 +2274,20 @@ struct iwl_cfg iwl4965_agn_cfg = {
        .led_compensation = 61,
        .chain_noise_num_beacons = IWL4965_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .temperature_kelvin = true,
+       .max_event_log_size = 512,
+       .tx_power_by_driver = true,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+       /*
+        * Force use of chains B and C for scan RX on 5 GHz band
+        * because the device has off-channel reception on chain A.
+        */
+       .scan_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
 };
 
 /* Module firmware */
 MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX));
 
-module_param_named(antenna, iwl4965_mod_params.antenna, int, S_IRUGO);
-MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
-module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, S_IRUGO);
-MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(
-       disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-/* 11n */
-module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, S_IRUGO);
-MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K, iwl4965_mod_params.amsdu_size_8K,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-
-module_param_named(fw_restart4965, iwl4965_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart4965, "restart firmware in case of error");
index 714e032f6217138ad0152e9398c924326e54c11c..146e6431ae950686b266f6d42f38c42b2be06470 100644 (file)
 #ifndef __iwl_5000_hw_h__
 #define __iwl_5000_hw_h__
 
-#define IWL50_RTC_INST_LOWER_BOUND             (0x000000)
-#define IWL50_RTC_INST_UPPER_BOUND             (0x020000)
-
-#define IWL50_RTC_DATA_LOWER_BOUND             (0x800000)
-#define IWL50_RTC_DATA_UPPER_BOUND             (0x80C000)
-
-#define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - \
-                               IWL50_RTC_INST_LOWER_BOUND)
-#define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - \
-                               IWL50_RTC_DATA_LOWER_BOUND)
-
-/* EEPROM */
-#define IWL_5000_EEPROM_IMG_SIZE                       2048
-
-#define IWL50_CMD_FIFO_NUM                 7
-#define IWL50_NUM_QUEUES                  20
-#define IWL50_NUM_AMPDU_QUEUES           10
-#define IWL50_FIRST_AMPDU_QUEUE                  10
-
 /* 5150 only */
 #define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF  (-5)
 
@@ -103,19 +84,5 @@ static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
        return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF);
 }
 
-/* Fixed (non-configurable) rx data from phy */
-
-/**
- * struct iwl5000_schedq_bc_tbl scheduler byte count table
- *     base physical address of iwl5000_shared
- *     is provided to SCD_DRAM_BASE_ADDR
- * @tfd_offset  0-12 - tx command byte count
- *            12-16 - station index
- */
-struct iwl5000_scd_bc_tbl {
-       __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
-} __attribute__ ((packed));
-
-
 #endif /* __iwl_5000_hw_h__ */
 
index e476acb53aa7a56e193a5b8b418a5659c8372e33..a28af7eb67eb464775369f7ff0617aed88847547 100644 (file)
@@ -19,6 +19,7 @@
  * file called LICENSE.
  *
  * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
  *
  *****************************************************************************/
 #include "iwl-io.h"
 #include "iwl-sta.h"
 #include "iwl-helpers.h"
+#include "iwl-agn.h"
 #include "iwl-agn-led.h"
+#include "iwl-agn-hw.h"
 #include "iwl-5000-hw.h"
-#include "iwl-6000-hw.h"
+#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 2
 #define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
 #define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
 
-static const u16 iwl5000_default_queue_to_tx_fifo[] = {
-       IWL_TX_FIFO_AC3,
-       IWL_TX_FIFO_AC2,
-       IWL_TX_FIFO_AC1,
-       IWL_TX_FIFO_AC0,
-       IWL50_CMD_FIFO_NUM,
-       IWL_TX_FIFO_HCCA_1,
-       IWL_TX_FIFO_HCCA_2
-};
-
 /* NIC configuration for 5000 series */
-void iwl5000_nic_config(struct iwl_priv *priv)
+static void iwl5000_nic_config(struct iwl_priv *priv)
 {
        unsigned long flags;
        u16 radio_cfg;
@@ -107,162 +100,6 @@ void iwl5000_nic_config(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-
-/*
- * EEPROM
- */
-static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
-{
-       u16 offset = 0;
-
-       if ((address & INDIRECT_ADDRESS) == 0)
-               return address;
-
-       switch (address & INDIRECT_TYPE_MSK) {
-       case INDIRECT_HOST:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_HOST);
-               break;
-       case INDIRECT_GENERAL:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_GENERAL);
-               break;
-       case INDIRECT_REGULATORY:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_REGULATORY);
-               break;
-       case INDIRECT_CALIBRATION:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_CALIBRATION);
-               break;
-       case INDIRECT_PROCESS_ADJST:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_PROCESS_ADJST);
-               break;
-       case INDIRECT_OTHERS:
-               offset = iwl_eeprom_query16(priv, EEPROM_5000_LINK_OTHERS);
-               break;
-       default:
-               IWL_ERR(priv, "illegal indirect type: 0x%X\n",
-               address & INDIRECT_TYPE_MSK);
-               break;
-       }
-
-       /* translate the offset from words to byte */
-       return (address & ADDRESS_MSK) + (offset << 1);
-}
-
-u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv)
-{
-       struct iwl_eeprom_calib_hdr {
-               u8 version;
-               u8 pa_type;
-               u16 voltage;
-       } *hdr;
-
-       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
-                                                       EEPROM_5000_CALIB_ALL);
-       return hdr->version;
-
-}
-
-static void iwl5000_gain_computation(struct iwl_priv *priv,
-               u32 average_noise[NUM_RX_CHAINS],
-               u16 min_average_noise_antenna_i,
-               u32 min_average_noise,
-               u8 default_chain)
-{
-       int i;
-       s32 delta_g;
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-
-       /*
-        * Find Gain Code for the chains based on "default chain"
-        */
-       for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
-               if ((data->disconn_array[i])) {
-                       data->delta_gain_code[i] = 0;
-                       continue;
-               }
-
-               delta_g = (priv->cfg->chain_noise_scale *
-                       ((s32)average_noise[default_chain] -
-                       (s32)average_noise[i])) / 1500;
-
-               /* bound gain by 2 bits value max, 3rd bit is sign */
-               data->delta_gain_code[i] =
-                       min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
-
-               if (delta_g < 0)
-                       /*
-                        * set negative sign ...
-                        * note to Intel developers:  This is uCode API format,
-                        *   not the format of any internal device registers.
-                        *   Do not change this format for e.g. 6050 or similar
-                        *   devices.  Change format only if more resolution
-                        *   (i.e. more than 2 bits magnitude) is needed.
-                        */
-                       data->delta_gain_code[i] |= (1 << 2);
-       }
-
-       IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
-                       data->delta_gain_code[1], data->delta_gain_code[2]);
-
-       if (!data->radio_write) {
-               struct iwl_calib_chain_noise_gain_cmd cmd;
-
-               memset(&cmd, 0, sizeof(cmd));
-
-               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
-               cmd.hdr.first_group = 0;
-               cmd.hdr.groups_num = 1;
-               cmd.hdr.data_valid = 1;
-               cmd.delta_gain_1 = data->delta_gain_code[1];
-               cmd.delta_gain_2 = data->delta_gain_code[2];
-               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
-                       sizeof(cmd), &cmd, NULL);
-
-               data->radio_write = 1;
-               data->state = IWL_CHAIN_NOISE_CALIBRATED;
-       }
-
-       data->chain_noise_a = 0;
-       data->chain_noise_b = 0;
-       data->chain_noise_c = 0;
-       data->chain_signal_a = 0;
-       data->chain_signal_b = 0;
-       data->chain_signal_c = 0;
-       data->beacon_count = 0;
-}
-
-static void iwl5000_chain_noise_reset(struct iwl_priv *priv)
-{
-       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
-       int ret;
-
-       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
-               struct iwl_calib_chain_noise_reset_cmd cmd;
-               memset(&cmd, 0, sizeof(cmd));
-
-               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
-               cmd.hdr.first_group = 0;
-               cmd.hdr.groups_num = 1;
-               cmd.hdr.data_valid = 1;
-               ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
-                                       sizeof(cmd), &cmd);
-               if (ret)
-                       IWL_ERR(priv,
-                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
-               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
-               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
-       }
-}
-
-void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                       __le32 *tx_flags)
-{
-       if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
-           (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
-               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
-       else
-               *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
-}
-
 static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
        .min_nrg_cck = 95,
        .max_nrg_cck = 0, /* not used, set to 0 */
@@ -314,14 +151,6 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
        .nrg_th_cca = 62,
 };
 
-const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
-                                          size_t offset)
-{
-       u32 address = eeprom_indirect_address(priv, offset);
-       BUG_ON(address >= priv->cfg->eeprom_size);
-       return &priv->eeprom[address];
-}
-
 static void iwl5150_set_ct_threshold(struct iwl_priv *priv)
 {
        const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF;
@@ -337,356 +166,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
        priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY;
 }
 
-/*
- *  Calibration
- */
-static int iwl5000_set_Xtal_calib(struct iwl_priv *priv)
-{
-       struct iwl_calib_xtal_freq_cmd cmd;
-       __le16 *xtal_calib =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL);
-
-       cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
-       cmd.hdr.first_group = 0;
-       cmd.hdr.groups_num = 1;
-       cmd.hdr.data_valid = 1;
-       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
-       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
-       return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
-                            (u8 *)&cmd, sizeof(cmd));
-}
-
-static int iwl5000_send_calib_cfg(struct iwl_priv *priv)
-{
-       struct iwl_calib_cfg_cmd calib_cfg_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = CALIBRATION_CFG_CMD,
-               .len = sizeof(struct iwl_calib_cfg_cmd),
-               .data = &calib_cfg_cmd,
-       };
-
-       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
-       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
-       calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
-
-       return iwl_send_cmd(priv, &cmd);
-}
-
-static void iwl5000_rx_calib_result(struct iwl_priv *priv,
-                            struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
-       int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
-       int index;
-
-       /* reduce the size of the length field itself */
-       len -= 4;
-
-       /* Define the order in which the results will be sent to the runtime
-        * uCode. iwl_send_calib_results sends them in a row according to their
-        * index. We sort them here */
-       switch (hdr->op_code) {
-       case IWL_PHY_CALIBRATE_DC_CMD:
-               index = IWL_CALIB_DC;
-               break;
-       case IWL_PHY_CALIBRATE_LO_CMD:
-               index = IWL_CALIB_LO;
-               break;
-       case IWL_PHY_CALIBRATE_TX_IQ_CMD:
-               index = IWL_CALIB_TX_IQ;
-               break;
-       case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
-               index = IWL_CALIB_TX_IQ_PERD;
-               break;
-       case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
-               index = IWL_CALIB_BASE_BAND;
-               break;
-       default:
-               IWL_ERR(priv, "Unknown calibration notification %d\n",
-                         hdr->op_code);
-               return;
-       }
-       iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
-}
-
-static void iwl5000_rx_calib_complete(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb)
-{
-       IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
-       queue_work(priv->workqueue, &priv->restart);
-}
-
-/*
- * ucode
- */
-static int iwl5000_load_section(struct iwl_priv *priv, const char *name,
-                               struct fw_desc *image, u32 dst_addr)
-{
-       dma_addr_t phy_addr = image->p_addr;
-       u32 byte_cnt = image->len;
-       int ret;
-
-       priv->ucode_write_complete = 0;
-
-       iwl_write_direct32(priv,
-               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
-
-       iwl_write_direct32(priv,
-               FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
-
-       iwl_write_direct32(priv,
-               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
-               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
-
-       iwl_write_direct32(priv,
-               FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
-               (iwl_get_dma_hi_addr(phy_addr)
-                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
-
-       iwl_write_direct32(priv,
-               FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
-               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
-               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
-               FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
-
-       iwl_write_direct32(priv,
-               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
-               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
-               FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
-
-       IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
-                                       priv->ucode_write_complete, 5 * HZ);
-       if (ret == -ERESTARTSYS) {
-               IWL_ERR(priv, "Could not load the %s uCode section due "
-                       "to interrupt\n", name);
-               return ret;
-       }
-       if (!ret) {
-               IWL_ERR(priv, "Could not load the %s uCode section\n",
-                       name);
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int iwl5000_load_given_ucode(struct iwl_priv *priv,
-               struct fw_desc *inst_image,
-               struct fw_desc *data_image)
-{
-       int ret = 0;
-
-       ret = iwl5000_load_section(priv, "INST", inst_image,
-                                  IWL50_RTC_INST_LOWER_BOUND);
-       if (ret)
-               return ret;
-
-       return iwl5000_load_section(priv, "DATA", data_image,
-                                   IWL50_RTC_DATA_LOWER_BOUND);
-}
-
-int iwl5000_load_ucode(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       /* check whether init ucode should be loaded, or rather runtime ucode */
-       if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
-               IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
-               ret = iwl5000_load_given_ucode(priv,
-                       &priv->ucode_init, &priv->ucode_init_data);
-               if (!ret) {
-                       IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
-                       priv->ucode_type = UCODE_INIT;
-               }
-       } else {
-               IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
-                       "Loading runtime ucode...\n");
-               ret = iwl5000_load_given_ucode(priv,
-                       &priv->ucode_code, &priv->ucode_data);
-               if (!ret) {
-                       IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
-                       priv->ucode_type = UCODE_RT;
-               }
-       }
-
-       return ret;
-}
-
-void iwl5000_init_alive_start(struct iwl_priv *priv)
-{
-       int ret = 0;
-
-       /* Check alive response for "valid" sign from uCode */
-       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
-               /* We had an error bringing up the hardware, so take it
-                * all the way back down so we can try again */
-               IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n");
-               goto restart;
-       }
-
-       /* initialize uCode was loaded... verify inst image.
-        * This is a paranoid check, because we would not have gotten the
-        * "initialize" alive if code weren't properly loaded.  */
-       if (iwl_verify_ucode(priv)) {
-               /* Runtime instruction load was bad;
-                * take it all the way back down so we can try again */
-               IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
-               goto restart;
-       }
-
-       iwl_clear_stations_table(priv);
-       ret = priv->cfg->ops->lib->alive_notify(priv);
-       if (ret) {
-               IWL_WARN(priv,
-                       "Could not complete ALIVE transition: %d\n", ret);
-               goto restart;
-       }
-
-       iwl5000_send_calib_cfg(priv);
-       return;
-
-restart:
-       /* real restart (first load init_ucode) */
-       queue_work(priv->workqueue, &priv->restart);
-}
-
-static void iwl5000_set_wr_ptrs(struct iwl_priv *priv,
-                               int txq_id, u32 index)
-{
-       iwl_write_direct32(priv, HBUS_TARG_WRPTR,
-                       (index & 0xff) | (txq_id << 8));
-       iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(txq_id), index);
-}
-
-static void iwl5000_tx_queue_set_status(struct iwl_priv *priv,
-                                       struct iwl_tx_queue *txq,
-                                       int tx_fifo_id, int scd_retry)
-{
-       int txq_id = txq->q.id;
-       int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
-
-       iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
-                       (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
-                       (tx_fifo_id << IWL50_SCD_QUEUE_STTS_REG_POS_TXF) |
-                       (1 << IWL50_SCD_QUEUE_STTS_REG_POS_WSL) |
-                       IWL50_SCD_QUEUE_STTS_REG_MSK);
-
-       txq->sched_retry = scd_retry;
-
-       IWL_DEBUG_INFO(priv, "%s %s Queue %d on AC %d\n",
-                      active ? "Activate" : "Deactivate",
-                      scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
-}
-
-int iwl5000_alive_notify(struct iwl_priv *priv)
-{
-       u32 a;
-       unsigned long flags;
-       int i, chan;
-       u32 reg_val;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       priv->scd_base_addr = iwl_read_prph(priv, IWL50_SCD_SRAM_BASE_ADDR);
-       a = priv->scd_base_addr + IWL50_SCD_CONTEXT_DATA_OFFSET;
-       for (; a < priv->scd_base_addr + IWL50_SCD_TX_STTS_BITMAP_OFFSET;
-               a += 4)
-               iwl_write_targ_mem(priv, a, 0);
-       for (; a < priv->scd_base_addr + IWL50_SCD_TRANSLATE_TBL_OFFSET;
-               a += 4)
-               iwl_write_targ_mem(priv, a, 0);
-       for (; a < priv->scd_base_addr +
-              IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
-               iwl_write_targ_mem(priv, a, 0);
-
-       iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR,
-                      priv->scd_bc_tbls.dma >> 10);
-
-       /* Enable DMA channel */
-       for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
-               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
-       /* Update FH chicken bits */
-       reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
-       iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
-                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
-       iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL,
-               IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
-       iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0);
-
-       /* initiate the queues */
-       for (i = 0; i < priv->hw_params.max_txq_num; i++) {
-               iwl_write_prph(priv, IWL50_SCD_QUEUE_RDPTR(i), 0);
-               iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
-               iwl_write_targ_mem(priv, priv->scd_base_addr +
-                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
-               iwl_write_targ_mem(priv, priv->scd_base_addr +
-                               IWL50_SCD_CONTEXT_QUEUE_OFFSET(i) +
-                               sizeof(u32),
-                               ((SCD_WIN_SIZE <<
-                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                               ((SCD_FRAME_LIMIT <<
-                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-       }
-
-       iwl_write_prph(priv, IWL50_SCD_INTERRUPT_MASK,
-                       IWL_MASK(0, priv->hw_params.max_txq_num));
-
-       /* Activate all Tx DMA/FIFO channels */
-       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
-
-       iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
-
-       /* make sure all queue are not stopped */
-       memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
-       for (i = 0; i < 4; i++)
-               atomic_set(&priv->queue_stop_count[i], 0);
-
-       /* reset to 0 to enable all the queue first */
-       priv->txq_ctx_active_msk = 0;
-       /* map qos queues to fifos one-to-one */
-       for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) {
-               int ac = iwl5000_default_queue_to_tx_fifo[i];
-               iwl_txq_ctx_activate(priv, i);
-               iwl5000_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
-       }
-
-       /*
-        * TODO - need to initialize these queues and map them to FIFOs
-        * in the loop above, not only mark them as active. We do this
-        * because we want the first aggregation queue to be queue #10,
-        * but do not use 8 or 9 otherwise yet.
-        */
-       iwl_txq_ctx_activate(priv, 7);
-       iwl_txq_ctx_activate(priv, 8);
-       iwl_txq_ctx_activate(priv, 9);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-
-       iwl_send_wimax_coex(priv);
-
-       iwl5000_set_Xtal_calib(priv);
-       iwl_send_calib_results(priv);
-
-       return 0;
-}
-
-int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
+static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
                priv->cfg->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
@@ -694,13 +177,13 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->num_of_queues *
-                       sizeof(struct iwl5000_scd_bc_tbl);
+                       sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 
-       priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE;
-       priv->hw_params.max_inst_size = IWL50_RTC_INST_SIZE;
+       priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
        priv->hw_params.max_bsm_size = 0;
        priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
@@ -717,571 +200,61 @@ int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
 
        /* Set initial sensitivity parameters */
        /* Set initial calibration set */
-       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_5150:
-               priv->hw_params.sens = &iwl5150_sensitivity;
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_DC)               |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_BASE_BAND);
-
-               break;
-       default:
-               priv->hw_params.sens = &iwl5000_sensitivity;
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_XTAL)             |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_TX_IQ_PERD)       |
-                       BIT(IWL_CALIB_BASE_BAND);
-               break;
-       }
-
-       return 0;
-}
-
-/**
- * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
- */
-void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
-                                           struct iwl_tx_queue *txq,
-                                           u16 byte_cnt)
-{
-       struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
-       int write_ptr = txq->q.write_ptr;
-       int txq_id = txq->q.id;
-       u8 sec_ctl = 0;
-       u8 sta_id = 0;
-       u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
-       __le16 bc_ent;
-
-       WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
-
-       if (txq_id != IWL_CMD_QUEUE_NUM) {
-               sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
-               sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
-
-               switch (sec_ctl & TX_CMD_SEC_MSK) {
-               case TX_CMD_SEC_CCM:
-                       len += CCMP_MIC_LEN;
-                       break;
-               case TX_CMD_SEC_TKIP:
-                       len += TKIP_ICV_LEN;
-                       break;
-               case TX_CMD_SEC_WEP:
-                       len += WEP_IV_LEN + WEP_ICV_LEN;
-                       break;
-               }
-       }
-
-       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
-
-       scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
-
-       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
-}
-
-void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
-                                          struct iwl_tx_queue *txq)
-{
-       struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
-       int txq_id = txq->q.id;
-       int read_ptr = txq->q.read_ptr;
-       u8 sta_id = 0;
-       __le16 bc_ent;
-
-       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
-
-       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));
-       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
-
-       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
-}
-
-static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
-                                       u16 txq_id)
-{
-       u32 tbl_dw_addr;
-       u32 tbl_dw;
-       u16 scd_q2ratid;
-
-       scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
-
-       tbl_dw_addr = priv->scd_base_addr +
-                       IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
-
-       tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
-
-       if (txq_id & 0x1)
-               tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
-       else
-               tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
-
-       iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
-
-       return 0;
-}
-static void iwl5000_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
-{
-       /* Simply stop the queue, but don't change any configuration;
-        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
-       iwl_write_prph(priv,
-               IWL50_SCD_QUEUE_STATUS_BITS(txq_id),
-               (0 << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
-               (1 << IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
-int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-                                 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
-{
-       unsigned long flags;
-       u16 ra_tid;
-
-       if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
-               IWL_WARN(priv,
-                       "queue number out of range: %d, must be %d to %d\n",
-                       txq_id, IWL50_FIRST_AMPDU_QUEUE,
-                       IWL50_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
-               return -EINVAL;
-       }
-
-       ra_tid = BUILD_RAxTID(sta_id, tid);
-
-       /* Modify device's station table to Tx this TID */
-       iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Stop this Tx queue before configuring it */
-       iwl5000_tx_queue_stop_scheduler(priv, txq_id);
-
-       /* Map receiver-address / traffic-ID to this queue */
-       iwl5000_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
-
-       /* Set this queue as a chain-building queue */
-       iwl_set_bits_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, (1<<txq_id));
-
-       /* enable aggregations for the queue */
-       iwl_set_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1<<txq_id));
-
-       /* Place first TFD at index corresponding to start sequence number.
-        * Assumes that ssn_idx is valid (!= 0xFFF) */
-       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
-       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
-       iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx);
-
-       /* Set up Tx window size and frame limit for this queue */
-       iwl_write_targ_mem(priv, priv->scd_base_addr +
-                       IWL50_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
-                       sizeof(u32),
-                       ((SCD_WIN_SIZE <<
-                       IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                       IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                       ((SCD_FRAME_LIMIT <<
-                       IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                       IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-
-       iwl_set_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
-
-       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
-       iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw_params.sens = &iwl5000_sensitivity;
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_XTAL)             |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_TX_IQ_PERD)       |
+               BIT(IWL_CALIB_BASE_BAND);
 
        return 0;
 }
 
-int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
-                                  u16 ssn_idx, u8 tx_fifo)
+static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
 {
-       if ((IWL50_FIRST_AMPDU_QUEUE > txq_id) ||
-           (IWL50_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
-            <= txq_id)) {
-               IWL_ERR(priv,
-                       "queue number out of range: %d, must be %d to %d\n",
-                       txq_id, IWL50_FIRST_AMPDU_QUEUE,
-                       IWL50_FIRST_AMPDU_QUEUE +
-                       priv->cfg->num_of_ampdu_queues - 1);
-               return -EINVAL;
-       }
-
-       iwl5000_tx_queue_stop_scheduler(priv, txq_id);
-
-       iwl_clear_bits_prph(priv, IWL50_SCD_AGGR_SEL, (1 << txq_id));
-
-       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
-       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
-       /* supposes that ssn_idx is valid (!= 0xFFF) */
-       iwl5000_set_wr_ptrs(priv, txq_id, ssn_idx);
-
-       iwl_clear_bits_prph(priv, IWL50_SCD_INTERRUPT_MASK, (1 << txq_id));
-       iwl_txq_ctx_deactivate(priv, txq_id);
-       iwl5000_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
-
-       return 0;
-}
-
-u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
-{
-       u16 size = (u16)sizeof(struct iwl_addsta_cmd);
-       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
-       memcpy(addsta, cmd, size);
-       /* resrved in 5000 */
-       addsta->rate_n_flags = cpu_to_le16(0);
-       return size;
-}
-
-
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under priv->lock and mac access
- */
-void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask)
-{
-       iwl_write_prph(priv, IWL50_SCD_TXFACT, mask);
-}
-
-
-static inline u32 iwl5000_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
-{
-       return le32_to_cpup((__le32 *)&tx_resp->status +
-                           tx_resp->frame_count) & MAX_SN;
-}
-
-static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv,
-                                     struct iwl_ht_agg *agg,
-                                     struct iwl5000_tx_resp *tx_resp,
-                                     int txq_id, u16 start_idx)
-{
-       u16 status;
-       struct agg_tx_status *frame_status = &tx_resp->status;
-       struct ieee80211_tx_info *info = NULL;
-       struct ieee80211_hdr *hdr = NULL;
-       u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
-       int i, sh, idx;
-       u16 seq;
-
-       if (agg->wait_for_ba)
-               IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n");
-
-       agg->frame_count = tx_resp->frame_count;
-       agg->start_idx = start_idx;
-       agg->rate_n_flags = rate_n_flags;
-       agg->bitmap = 0;
-
-       /* # frames attempted by Tx command */
-       if (agg->frame_count == 1) {
-               /* Only one frame was attempted; no block-ack will arrive */
-               status = le16_to_cpu(frame_status[0].status);
-               idx = start_idx;
-
-               /* FIXME: code repetition */
-               IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
-                                  agg->frame_count, agg->start_idx, idx);
-
-               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
-               info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
-               info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv, rate_n_flags, info);
-
-               /* FIXME: code repetition end */
-
-               IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
-                                   status & 0xff, tx_resp->failure_frame);
-               IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags);
-
-               agg->wait_for_ba = 0;
-       } else {
-               /* Two or more frames were attempted; expect block-ack */
-               u64 bitmap = 0;
-               int start = agg->start_idx;
-
-               /* Construct bit-map of pending frames within Tx window */
-               for (i = 0; i < agg->frame_count; i++) {
-                       u16 sc;
-                       status = le16_to_cpu(frame_status[i].status);
-                       seq  = le16_to_cpu(frame_status[i].sequence);
-                       idx = SEQ_TO_INDEX(seq);
-                       txq_id = SEQ_TO_QUEUE(seq);
-
-                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
-                                     AGG_TX_STATE_ABORT_MSK))
-                               continue;
+       if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+               priv->cfg->num_of_queues =
+                       priv->cfg->mod_params->num_of_queues;
 
-                       IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n",
-                                          agg->frame_count, txq_id, idx);
+       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+       priv->hw_params.scd_bc_tbls_size =
+                       priv->cfg->num_of_queues *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+       priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
 
-                       hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
-                       if (!hdr) {
-                               IWL_ERR(priv,
-                                       "BUG_ON idx doesn't point to valid skb"
-                                       " idx=%d, txq_id=%d\n", idx, txq_id);
-                               return -1;
-                       }
+       priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE;
 
-                       sc = le16_to_cpu(hdr->seq_ctrl);
-                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
-                               IWL_ERR(priv,
-                                       "BUG_ON idx doesn't match seq control"
-                                       " idx=%d, seq_idx=%d, seq=%d\n",
-                                         idx, SEQ_TO_SN(sc),
-                                         hdr->seq_ctrl);
-                               return -1;
-                       }
+       priv->hw_params.max_bsm_size = 0;
+       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
+                                       BIT(IEEE80211_BAND_5GHZ);
+       priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
 
-                       IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
-                                          i, idx, SEQ_TO_SN(sc));
+       priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+       priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+       priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+       priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
 
-                       sh = idx - start;
-                       if (sh > 64) {
-                               sh = (start - idx) + 0xff;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                               start = idx;
-                       } else if (sh < -64)
-                               sh  = 0xff - (start - idx);
-                       else if (sh < 0) {
-                               sh = start - idx;
-                               start = idx;
-                               bitmap = bitmap << sh;
-                               sh = 0;
-                       }
-                       bitmap |= 1ULL << sh;
-                       IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
-                                          start, (unsigned long long)bitmap);
-               }
+       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
 
-               agg->bitmap = bitmap;
-               agg->start_idx = start;
-               IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
-                                  agg->frame_count, agg->start_idx,
-                                  (unsigned long long)agg->bitmap);
+       /* Set initial sensitivity parameters */
+       /* Set initial calibration set */
+       priv->hw_params.sens = &iwl5150_sensitivity;
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_DC)               |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_BASE_BAND);
 
-               if (bitmap)
-                       agg->wait_for_ba = 1;
-       }
        return 0;
 }
 
-static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int index = SEQ_TO_INDEX(sequence);
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct ieee80211_tx_info *info;
-       struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
-       u32  status = le16_to_cpu(tx_resp->status.status);
-       int tid;
-       int sta_id;
-       int freed;
-
-       if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
-                         "is out of range [0-%d] %d %d\n", txq_id,
-                         index, txq->q.n_bd, txq->q.write_ptr,
-                         txq->q.read_ptr);
-               return;
-       }
-
-       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
-       memset(&info->status, 0, sizeof(info->status));
-
-       tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
-       sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
-
-       if (txq->sched_retry) {
-               const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp);
-               struct iwl_ht_agg *agg = NULL;
-
-               agg = &priv->stations[sta_id].tid[tid].agg;
-
-               iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
-
-               /* check if BAR is needed */
-               if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
-                       info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
-               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
-                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
-                       IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim "
-                                       "scd_ssn=%d idx=%d txq=%d swq=%d\n",
-                                       scd_ssn , index, txq_id, txq->swq_id);
-
-                       freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
-                       if (priv->mac80211_registered &&
-                           (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
-                           (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
-                               if (agg->state == IWL_AGG_OFF)
-                                       iwl_wake_queue(priv, txq_id);
-                               else
-                                       iwl_wake_queue(priv, txq->swq_id);
-                       }
-               }
-       } else {
-               BUG_ON(txq_id != txq->swq_id);
-
-               info->status.rates[0].count = tx_resp->failure_frame + 1;
-               info->flags |= iwl_tx_status_to_mac80211(status);
-               iwl_hwrate_to_tx_control(priv,
-                                       le32_to_cpu(tx_resp->rate_n_flags),
-                                       info);
-
-               IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
-                                  "0x%x retries %d\n",
-                                  txq_id,
-                                  iwl_get_tx_fail_reason(status), status,
-                                  le32_to_cpu(tx_resp->rate_n_flags),
-                                  tx_resp->failure_frame);
-
-               freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
-               if (priv->mac80211_registered &&
-                   (iwl_queue_space(&txq->q) > txq->q.low_mark))
-                       iwl_wake_queue(priv, txq_id);
-       }
-
-       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
-
-       if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
-               IWL_ERR(priv, "TODO:  Implement Tx ABORT REQUIRED!!!\n");
-}
-
-/* Currently 5000 is the superset of everything */
-u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len)
-{
-       return len;
-}
-
-void iwl5000_setup_deferred_work(struct iwl_priv *priv)
-{
-       /* in 5000 the tx power calibration is done in uCode */
-       priv->disable_tx_power_cal = 1;
-}
-
-void iwl5000_rx_handler_setup(struct iwl_priv *priv)
-{
-       /* init calibration handlers */
-       priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
-                                       iwl5000_rx_calib_result;
-       priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
-                                       iwl5000_rx_calib_complete;
-       priv->rx_handlers[REPLY_TX] = iwl5000_rx_reply_tx;
-}
-
-
-int iwl5000_hw_valid_rtc_data_addr(u32 addr)
-{
-       return (addr >= IWL50_RTC_DATA_LOWER_BOUND) &&
-               (addr < IWL50_RTC_DATA_UPPER_BOUND);
-}
-
-static int iwl5000_send_rxon_assoc(struct iwl_priv *priv)
-{
-       int ret = 0;
-       struct iwl5000_rxon_assoc_cmd rxon_assoc;
-       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
-
-       if ((rxon1->flags == rxon2->flags) &&
-           (rxon1->filter_flags == rxon2->filter_flags) &&
-           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
-           (rxon1->ofdm_ht_single_stream_basic_rates ==
-            rxon2->ofdm_ht_single_stream_basic_rates) &&
-           (rxon1->ofdm_ht_dual_stream_basic_rates ==
-            rxon2->ofdm_ht_dual_stream_basic_rates) &&
-           (rxon1->ofdm_ht_triple_stream_basic_rates ==
-            rxon2->ofdm_ht_triple_stream_basic_rates) &&
-           (rxon1->acquisition_data == rxon2->acquisition_data) &&
-           (rxon1->rx_chain == rxon2->rx_chain) &&
-           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
-               IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
-               return 0;
-       }
-
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
-       rxon_assoc.reserved1 = 0;
-       rxon_assoc.reserved2 = 0;
-       rxon_assoc.reserved3 = 0;
-       rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
-       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
-       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
-                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
-       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
-
-       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
-                                    sizeof(rxon_assoc), &rxon_assoc, NULL);
-       if (ret)
-               return ret;
-
-       return ret;
-}
-int  iwl5000_send_tx_power(struct iwl_priv *priv)
-{
-       struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
-       u8 tx_ant_cfg_cmd;
-
-       /* half dBm need to multiply */
-       tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
-
-       if (priv->tx_power_lmt_in_half_dbm &&
-           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
-               /*
-                * For the newer devices which using enhanced/extend tx power
-                * table in EEPROM, the format is in half dBm. driver need to
-                * convert to dBm format before report to mac80211.
-                * By doing so, there is a possibility of 1/2 dBm resolution
-                * lost. driver will perform "round-up" operation before
-                * reporting, but it will cause 1/2 dBm tx power over the
-                * regulatory limit. Perform the checking here, if the
-                * "tx_power_user_lmt" is higher than EEPROM value (in
-                * half-dBm format), lower the tx power based on EEPROM
-                */
-               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
-       }
-       tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
-       tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
-
-       if (IWL_UCODE_API(priv->ucode_ver) == 1)
-               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
-       else
-               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
-
-       return  iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd,
-                                      sizeof(tx_power_cmd), &tx_power_cmd,
-                                      NULL);
-}
-
-void iwl5000_temperature(struct iwl_priv *priv)
-{
-       /* store temperature from statistics (in Celsius) */
-       priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
-       iwl_tt_handler(priv);
-}
-
 static void iwl5150_temperature(struct iwl_priv *priv)
 {
        u32 vt = 0;
@@ -1294,100 +267,6 @@ static void iwl5150_temperature(struct iwl_priv *priv)
        iwl_tt_handler(priv);
 }
 
-/* Calc max signal level (dBm) among 3 possible receivers */
-int iwl5000_calc_rssi(struct iwl_priv *priv,
-                            struct iwl_rx_phy_res *rx_resp)
-{
-       /* data from PHY/DSP regarding signal strength, etc.,
-        *   contents are always there, not configurable by host
-        */
-       struct iwl5000_non_cfg_phy *ncphy =
-               (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
-       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
-       u8 agc;
-
-       val  = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
-       agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
-
-       /* Find max rssi among 3 possible receivers.
-        * These values are measured by the digital signal processor (DSP).
-        * They should stay fairly constant even as the signal strength varies,
-        *   if the radio's automatic gain control (AGC) is working right.
-        * AGC value (see below) will provide the "interesting" info.
-        */
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
-       rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
-       rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
-       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
-       rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
-
-       max_rssi = max_t(u32, rssi_a, rssi_b);
-       max_rssi = max_t(u32, max_rssi, rssi_c);
-
-       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
-               rssi_a, rssi_b, rssi_c, max_rssi, agc);
-
-       /* dBm = max_rssi dB - agc dB - constant.
-        * Higher AGC (higher radio gain) means lower signal. */
-       return max_rssi - agc - IWL49_RSSI_OFFSET;
-}
-
-static int iwl5000_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
-{
-       struct iwl_tx_ant_config_cmd tx_ant_cmd = {
-         .valid = cpu_to_le32(valid_tx_ant),
-       };
-
-       if (IWL_UCODE_API(priv->ucode_ver) > 1) {
-               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
-               return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
-                                       sizeof(struct iwl_tx_ant_config_cmd),
-                                       &tx_ant_cmd);
-       } else {
-               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
-               return -EOPNOTSUPP;
-       }
-}
-
-
-#define IWL5000_UCODE_GET(item)                                                \
-static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
-                                   u32 api_ver)                        \
-{                                                                      \
-       if (api_ver <= 2)                                               \
-               return le32_to_cpu(ucode->u.v1.item);                   \
-       return le32_to_cpu(ucode->u.v2.item);                           \
-}
-
-static u32 iwl5000_ucode_get_header_size(u32 api_ver)
-{
-       if (api_ver <= 2)
-               return UCODE_HEADER_SIZE(1);
-       return UCODE_HEADER_SIZE(2);
-}
-
-static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
-                                  u32 api_ver)
-{
-       if (api_ver <= 2)
-               return 0;
-       return le32_to_cpu(ucode->u.v2.build);
-}
-
-static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
-                                 u32 api_ver)
-{
-       if (api_ver <= 2)
-               return (u8 *) ucode->u.v1.data;
-       return (u8 *) ucode->u.v2.data;
-}
-
-IWL5000_UCODE_GET(inst_size);
-IWL5000_UCODE_GET(data_size);
-IWL5000_UCODE_GET(init_size);
-IWL5000_UCODE_GET(init_data_size);
-IWL5000_UCODE_GET(boot_size);
-
 static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
 {
        struct iwl5000_channel_switch_cmd cmd;
@@ -1420,54 +299,27 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
        return iwl_send_cmd_sync(priv, &hcmd);
 }
 
-struct iwl_hcmd_ops iwl5000_hcmd = {
-       .rxon_assoc = iwl5000_send_rxon_assoc,
-       .commit_rxon = iwl_commit_rxon,
-       .set_rxon_chain = iwl_set_rxon_chain,
-       .set_tx_ant = iwl5000_send_tx_ant_config,
-};
-
-struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
-       .get_hcmd_size = iwl5000_get_hcmd_size,
-       .build_addsta_hcmd = iwl5000_build_addsta_hcmd,
-       .gain_computation = iwl5000_gain_computation,
-       .chain_noise_reset = iwl5000_chain_noise_reset,
-       .rts_tx_cmd_flag = iwl5000_rts_tx_cmd_flag,
-       .calc_rssi = iwl5000_calc_rssi,
-};
-
-struct iwl_ucode_ops iwl5000_ucode = {
-       .get_header_size = iwl5000_ucode_get_header_size,
-       .get_build = iwl5000_ucode_get_build,
-       .get_inst_size = iwl5000_ucode_get_inst_size,
-       .get_data_size = iwl5000_ucode_get_data_size,
-       .get_init_size = iwl5000_ucode_get_init_size,
-       .get_init_data_size = iwl5000_ucode_get_init_data_size,
-       .get_boot_size = iwl5000_ucode_get_boot_size,
-       .get_data = iwl5000_ucode_get_data,
-};
-
-struct iwl_lib_ops iwl5000_lib = {
+static struct iwl_lib_ops iwl5000_lib = {
        .set_hw_params = iwl5000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_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,
        .dump_fh = iwl_dump_fh,
-       .load_ucode = iwl5000_load_ucode,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .load_ucode = iwlagn_load_ucode,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
@@ -1478,50 +330,58 @@ struct iwl_lib_ops iwl5000_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl5000_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
 };
 
 static struct iwl_lib_ops iwl5150_lib = {
-       .set_hw_params = iwl5000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .set_hw_params = iwl5150_hw_set_hw_params,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_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,
-       .send_tx_power = iwl5000_send_tx_power,
+       .load_ucode = iwlagn_load_ucode,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
@@ -1532,19 +392,19 @@ static struct iwl_lib_ops iwl5150_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
-                       EEPROM_5000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_24_HT40_CHANNELS,
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
@@ -1553,45 +413,44 @@ static struct iwl_lib_ops iwl5150_lib = {
                .temperature = iwl5150_temperature,
                .set_ct_kill = iwl5150_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
 };
 
 static const struct iwl_ops iwl5000_ops = {
-       .ucode = &iwl5000_ucode,
        .lib = &iwl5000_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
 static const struct iwl_ops iwl5150_ops = {
-       .ucode = &iwl5000_ucode,
        .lib = &iwl5150_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
-struct iwl_mod_params iwl50_mod_params = {
-       .amsdu_size_8K = 1,
-       .restart_fw = 1,
-       /* the rest are 0 by default */
-};
-
-
 struct iwl_cfg iwl5300_agn_cfg = {
-       .name = "5300AGN",
+       .name = "Intel(R) Ultimate N WiFi Link 5300 AGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1603,21 +462,26 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5100_bgn_cfg = {
-       .name = "5100BGN",
+       .name = "Intel(R) WiFi Link 5100 BGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1629,21 +493,26 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5100_abg_cfg = {
-       .name = "5100ABG",
+       .name = "Intel(R) WiFi Link 5100 ABG",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1653,21 +522,26 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5100_agn_cfg = {
-       .name = "5100AGN",
+       .name = "Intel(R) WiFi Link 5100 AGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_B,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1679,21 +553,26 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5350_agn_cfg = {
-       .name = "5350AGN",
+       .name = "Intel(R) WiMAX/WiFi Link 5350 AGN",
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1705,21 +584,26 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5150_agn_cfg = {
-       .name = "5150AGN",
+       .name = "Intel(R) WiMAX/WiFi Link 5150 AGN",
        .fw_name_pre = IWL5150_FW_PRE,
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5150_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1731,21 +615,26 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl5150_abg_cfg = {
-       .name = "5150ABG",
+       .name = "Intel(R) WiMAX/WiFi Link 5150 ABG",
        .fw_name_pre = IWL5150_FW_PRE,
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
        .sku = IWL_SKU_A|IWL_SKU_G,
        .ops = &iwl5150_ops,
-       .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+       .eeprom_size = IWLAGN_EEPROM_IMG_SIZE,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_A,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
@@ -1755,20 +644,12 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
-
-module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, S_IRUGO);
-MODULE_PARM_DESC(swcrypto50,
-                 "using software crypto engine (default 0 [hardware])\n");
-module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
-module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, S_IRUGO);
-MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality");
-module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K,
-                  int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K50, "enable 8K amsdu size in 50XX series");
-module_param_named(fw_restart50, iwl50_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart50, "restart firmware in case of error");
index 92b3e64fc14dd941f80831a107d958740e87c662..9fbf54cd3e1a971b057392d5edec2f2cabcac4c5 100644 (file)
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-sta.h"
+#include "iwl-agn.h"
 #include "iwl-helpers.h"
-#include "iwl-5000-hw.h"
+#include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
 #include "iwl-agn-led.h"
+#include "iwl-agn-debugfs.h"
 
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
 #define IWL6050_UCODE_API_MAX 4
+#define IWL6000G2_UCODE_API_MAX 4
 
 /* Lowest firmware API version supported */
 #define IWL6000_UCODE_API_MIN 4
 #define IWL6050_UCODE_API_MIN 4
+#define IWL6000G2_UCODE_API_MIN 4
 
 #define IWL6000_FW_PRE "iwlwifi-6000-"
 #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
 #define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
 #define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
 
+#define IWL6000G2A_FW_PRE "iwlwifi-6000g2a-"
+#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode"
+#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api)
+
+
 static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
 {
        /* want Celsius */
@@ -136,7 +145,7 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
 static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
 {
        if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
-           priv->cfg->mod_params->num_of_queues <= IWL50_NUM_QUEUES)
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
                priv->cfg->num_of_queues =
                        priv->cfg->mod_params->num_of_queues;
 
@@ -144,7 +153,7 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
        priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
        priv->hw_params.scd_bc_tbls_size =
                        priv->cfg->num_of_queues *
-                       sizeof(struct iwl5000_scd_bc_tbl);
+                       sizeof(struct iwlagn_scd_bc_tbl);
        priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
        priv->hw_params.max_stations = IWL5000_STATION_COUNT;
        priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
@@ -168,24 +177,56 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
        /* Set initial sensitivity parameters */
        /* Set initial calibration set */
        priv->hw_params.sens = &iwl6000_sensitivity;
-       switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
-       case CSR_HW_REV_TYPE_6x50:
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_XTAL)             |
-                       BIT(IWL_CALIB_DC)               |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_BASE_BAND);
-
-               break;
-       default:
-               priv->hw_params.calib_init_cfg =
-                       BIT(IWL_CALIB_XTAL)             |
-                       BIT(IWL_CALIB_LO)               |
-                       BIT(IWL_CALIB_TX_IQ)            |
-                       BIT(IWL_CALIB_BASE_BAND);
-               break;
-       }
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_XTAL)             |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_BASE_BAND);
+
+       return 0;
+}
+
+static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
+{
+       if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES &&
+           priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES)
+               priv->cfg->num_of_queues =
+                       priv->cfg->mod_params->num_of_queues;
+
+       priv->hw_params.max_txq_num = priv->cfg->num_of_queues;
+       priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
+       priv->hw_params.scd_bc_tbls_size =
+                       priv->cfg->num_of_queues *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+       priv->hw_params.tfd_size = sizeof(struct iwl_tfd);
+       priv->hw_params.max_stations = IWL5000_STATION_COUNT;
+       priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID;
+
+       priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE;
+       priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE;
+
+       priv->hw_params.max_bsm_size = 0;
+       priv->hw_params.ht40_channel =  BIT(IEEE80211_BAND_2GHZ) |
+                                       BIT(IEEE80211_BAND_5GHZ);
+       priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
+
+       priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
+       priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
+       priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
+       priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant;
+
+       if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
+               priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+
+       /* Set initial sensitivity parameters */
+       /* Set initial calibration set */
+       priv->hw_params.sens = &iwl6000_sensitivity;
+       priv->hw_params.calib_init_cfg =
+               BIT(IWL_CALIB_XTAL)             |
+               BIT(IWL_CALIB_DC)               |
+               BIT(IWL_CALIB_LO)               |
+               BIT(IWL_CALIB_TX_IQ)            |
+               BIT(IWL_CALIB_BASE_BAND);
 
        return 0;
 }
@@ -225,25 +266,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
 
 static struct iwl_lib_ops iwl6000_lib = {
        .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
-       .load_ucode = iwl5000_load_ucode,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .apm_ops = {
@@ -254,60 +295,67 @@ static struct iwl_lib_ops iwl6000_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
 };
 
 static const struct iwl_ops iwl6000_ops = {
-       .ucode = &iwl5000_ucode,
        .lib = &iwl6000_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
 static struct iwl_lib_ops iwl6050_lib = {
-       .set_hw_params = iwl6000_hw_set_hw_params,
-       .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
-       .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl,
-       .txq_set_sched = iwl5000_txq_set_sched,
-       .txq_agg_enable = iwl5000_txq_agg_enable,
-       .txq_agg_disable = iwl5000_txq_agg_disable,
+       .set_hw_params = iwl6050_hw_set_hw_params,
+       .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
+       .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
+       .txq_set_sched = iwlagn_txq_set_sched,
+       .txq_agg_enable = iwlagn_txq_agg_enable,
+       .txq_agg_disable = iwlagn_txq_agg_disable,
        .txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
        .txq_free_tfd = iwl_hw_txq_free_tfd,
        .txq_init = iwl_hw_tx_queue_init,
-       .rx_handler_setup = iwl5000_rx_handler_setup,
-       .setup_deferred_work = iwl5000_setup_deferred_work,
-       .is_valid_rtc_data_addr = iwl5000_hw_valid_rtc_data_addr,
-       .load_ucode = iwl5000_load_ucode,
+       .rx_handler_setup = iwlagn_rx_handler_setup,
+       .setup_deferred_work = iwlagn_setup_deferred_work,
+       .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
+       .load_ucode = iwlagn_load_ucode,
        .dump_nic_event_log = iwl_dump_nic_event_log,
        .dump_nic_error_log = iwl_dump_nic_error_log,
        .dump_csr = iwl_dump_csr,
        .dump_fh = iwl_dump_fh,
-       .init_alive_start = iwl5000_init_alive_start,
-       .alive_notify = iwl5000_alive_notify,
-       .send_tx_power = iwl5000_send_tx_power,
+       .init_alive_start = iwlagn_init_alive_start,
+       .alive_notify = iwlagn_alive_notify,
+       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .apm_ops = {
@@ -318,45 +366,90 @@ static struct iwl_lib_ops iwl6050_lib = {
        },
        .eeprom_ops = {
                .regulatory_bands = {
-                       EEPROM_5000_REG_BAND_1_CHANNELS,
-                       EEPROM_5000_REG_BAND_2_CHANNELS,
-                       EEPROM_5000_REG_BAND_3_CHANNELS,
-                       EEPROM_5000_REG_BAND_4_CHANNELS,
-                       EEPROM_5000_REG_BAND_5_CHANNELS,
+                       EEPROM_REG_BAND_1_CHANNELS,
+                       EEPROM_REG_BAND_2_CHANNELS,
+                       EEPROM_REG_BAND_3_CHANNELS,
+                       EEPROM_REG_BAND_4_CHANNELS,
+                       EEPROM_REG_BAND_5_CHANNELS,
                        EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
-                       EEPROM_5000_REG_BAND_52_HT40_CHANNELS
+                       EEPROM_REG_BAND_52_HT40_CHANNELS
                },
                .verify_signature  = iwlcore_eeprom_verify_signature,
                .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
                .release_semaphore = iwlcore_eeprom_release_semaphore,
-               .calib_version  = iwl5000_eeprom_calib_version,
-               .query_addr = iwl5000_eeprom_query_addr,
+               .calib_version  = iwlagn_eeprom_calib_version,
+               .query_addr = iwlagn_eeprom_query_addr,
                .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower,
        },
        .post_associate = iwl_post_associate,
        .isr = iwl_isr_ict,
        .config_ap = iwl_config_ap,
        .temp_ops = {
-               .temperature = iwl5000_temperature,
+               .temperature = iwlagn_temperature,
                .set_ct_kill = iwl6000_set_ct_threshold,
                .set_calib_version = iwl6050_set_calib_version,
         },
-       .add_bcast_station = iwl_add_bcast_station,
+       .manage_ibss_station = iwlagn_manage_ibss_station,
+       .debugfs_ops = {
+               .rx_stats_read = iwl_ucode_rx_stats_read,
+               .tx_stats_read = iwl_ucode_tx_stats_read,
+               .general_stats_read = iwl_ucode_general_stats_read,
+       },
+       .recover_from_tx_stall = iwl_bg_monitor_recover,
+       .check_plcp_health = iwl_good_plcp_health,
+       .check_ack_health = iwl_good_ack_health,
 };
 
 static const struct iwl_ops iwl6050_ops = {
-       .ucode = &iwl5000_ucode,
        .lib = &iwl6050_lib,
-       .hcmd = &iwl5000_hcmd,
-       .utils = &iwl5000_hcmd_utils,
+       .hcmd = &iwlagn_hcmd,
+       .utils = &iwlagn_hcmd_utils,
        .led = &iwlagn_led_ops,
 };
 
+
+struct iwl_cfg iwl6000g2a_2agn_cfg = {
+       .name = "6000 Series 2x2 AGN Gen2a",
+       .fw_name_pre = IWL6000G2A_FW_PRE,
+       .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+       .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+       .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+       .ops = &iwl6000_ops,
+       .eeprom_size = OTP_LOW_IMAGE_SIZE,
+       .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+       .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
+       .valid_tx_ant = ANT_AB,
+       .valid_rx_ant = ANT_AB,
+       .pll_cfg_val = 0,
+       .set_l0s = true,
+       .use_bsm = false,
+       .pa_type = IWL_PA_SYSTEM,
+       .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+       .shadow_ram_support = true,
+       .ht_greenfield_support = true,
+       .led_compensation = 51,
+       .use_rts_for_ht = true, /* use rts/cts protection */
+       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+       .supports_idle = true,
+       .adv_thermal_throttle = true,
+       .support_ct_kill_exit = true,
+       .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+       .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 512,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
+};
+
 /*
  * "i": Internal configuration, use internal Power Amplifier
  */
 struct iwl_cfg iwl6000i_2agn_cfg = {
-       .name = "6000 Series 2x2 AGN",
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 AGN",
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
@@ -364,10 +457,10 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_BC,
        .valid_rx_ant = ANT_BC,
        .pll_cfg_val = 0,
@@ -385,10 +478,15 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000i_2abg_cfg = {
-       .name = "6000 Series 2x2 ABG",
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 ABG",
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
@@ -396,10 +494,10 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_BC,
        .valid_rx_ant = ANT_BC,
        .pll_cfg_val = 0,
@@ -408,7 +506,6 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .pa_type = IWL_PA_INTERNAL,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
@@ -416,10 +513,15 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000i_2bg_cfg = {
-       .name = "6000 Series 2x2 BG",
+       .name = "Intel(R) Centrino(R) Advanced-N 6200 BG",
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
@@ -427,10 +529,10 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_BC,
        .valid_rx_ant = ANT_BC,
        .pll_cfg_val = 0,
@@ -439,7 +541,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .pa_type = IWL_PA_INTERNAL,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
@@ -447,10 +548,15 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6050_2agn_cfg = {
-       .name = "6050 Series 2x2 AGN",
+       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 AGN",
        .fw_name_pre = IWL6050_FW_PRE,
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
@@ -458,10 +564,10 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .ops = &iwl6050_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = 0,
@@ -479,10 +585,15 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1500,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6050_2abg_cfg = {
-       .name = "6050 Series 2x2 ABG",
+       .name = "Intel(R) Centrino(R) Advanced-N + WiMAX 6250 ABG",
        .fw_name_pre = IWL6050_FW_PRE,
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
@@ -490,10 +601,10 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .ops = &iwl6050_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_AB,
        .valid_rx_ant = ANT_AB,
        .pll_cfg_val = 0,
@@ -502,7 +613,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .pa_type = IWL_PA_SYSTEM,
        .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
        .shadow_ram_support = true,
-       .ht_greenfield_support = true,
        .led_compensation = 51,
        .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .supports_idle = true,
@@ -510,10 +620,15 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1500,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
-       .name = "6000 Series 3x3 AGN",
+       .name = "Intel(R) Centrino(R) Ultimate-N 6300 AGN",
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
@@ -521,10 +636,10 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .ops = &iwl6000_ops,
        .eeprom_size = OTP_LOW_IMAGE_SIZE,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
-       .num_of_queues = IWL50_NUM_QUEUES,
-       .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES,
-       .mod_params = &iwl50_mod_params,
+       .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
+       .num_of_queues = IWLAGN_NUM_QUEUES,
+       .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+       .mod_params = &iwlagn_mod_params,
        .valid_tx_ant = ANT_ABC,
        .valid_rx_ant = ANT_ABC,
        .pll_cfg_val = 0,
@@ -542,7 +657,13 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
+       .monitor_recover_period = IWL_MONITORING_PERIOD,
+       .max_event_log_size = 1024,
+       .ucode_tracing = true,
+       .sensitivity_calib_by_driver = true,
+       .chain_noise_calib_by_driver = true,
 };
 
 MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
new file mode 100644 (file)
index 0000000..48c023b
--- /dev/null
@@ -0,0 +1,850 @@
+/******************************************************************************
+*
+* GPL LICENSE SUMMARY
+*
+* Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+* USA
+*
+* The full GNU General Public License is included in this distribution
+* in the file called LICENSE.GPL.
+*
+* Contact Information:
+*  Intel Linux Wireless <ilw@linux.intel.com>
+* Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+*****************************************************************************/
+
+#include "iwl-agn-debugfs.h"
+
+ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
+  {
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+                   sizeof(struct statistics_rx_non_phy) * 40 +
+                   sizeof(struct statistics_rx_ht_phy) * 40 + 400;
+       ssize_t ret;
+       struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+       struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+       struct statistics_rx_non_phy *general, *accum_general;
+       struct statistics_rx_non_phy *delta_general, *max_general;
+       struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(priv, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * the statistic information display here is based on
+        * the last statistics notification from uCode
+        * might not reflect the current uCode activity
+        */
+       ofdm = &priv->statistics.rx.ofdm;
+       cck = &priv->statistics.rx.cck;
+       general = &priv->statistics.rx.general;
+       ht = &priv->statistics.rx.ofdm_ht;
+       accum_ofdm = &priv->accum_statistics.rx.ofdm;
+       accum_cck = &priv->accum_statistics.rx.cck;
+       accum_general = &priv->accum_statistics.rx.general;
+       accum_ht = &priv->accum_statistics.rx.ofdm_ht;
+       delta_ofdm = &priv->delta_statistics.rx.ofdm;
+       delta_cck = &priv->delta_statistics.rx.cck;
+       delta_general = &priv->delta_statistics.rx.general;
+       delta_ht = &priv->delta_statistics.rx.ofdm_ht;
+       max_ofdm = &priv->max_delta.rx.ofdm;
+       max_cck = &priv->max_delta.rx.cck;
+       max_general = &priv->max_delta.rx.general;
+       max_ht = &priv->max_delta.rx.ofdm_ht;
+
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - OFDM:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
+                        accum_ofdm->ina_cnt,
+                        delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_cnt:",
+                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+                        delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "plcp_err:",
+                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+                        delta_ofdm->plcp_err, max_ofdm->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "crc32_err:",
+                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+                        delta_ofdm->crc32_err, max_ofdm->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "overrun_err:",
+                        le32_to_cpu(ofdm->overrun_err),
+                        accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+                        max_ofdm->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "early_overrun_err:",
+                        le32_to_cpu(ofdm->early_overrun_err),
+                        accum_ofdm->early_overrun_err,
+                        delta_ofdm->early_overrun_err,
+                        max_ofdm->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_good:", le32_to_cpu(ofdm->crc32_good),
+                        accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+                        max_ofdm->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "false_alarm_cnt:",
+                        le32_to_cpu(ofdm->false_alarm_cnt),
+                        accum_ofdm->false_alarm_cnt,
+                        delta_ofdm->false_alarm_cnt,
+                        max_ofdm->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_sync_err_cnt:",
+                        le32_to_cpu(ofdm->fina_sync_err_cnt),
+                        accum_ofdm->fina_sync_err_cnt,
+                        delta_ofdm->fina_sync_err_cnt,
+                        max_ofdm->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "sfd_timeout:",
+                        le32_to_cpu(ofdm->sfd_timeout),
+                        accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
+                        max_ofdm->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "fina_timeout:",
+                        le32_to_cpu(ofdm->fina_timeout),
+                        accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
+                        max_ofdm->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "unresponded_rts:",
+                        le32_to_cpu(ofdm->unresponded_rts),
+                        accum_ofdm->unresponded_rts,
+                        delta_ofdm->unresponded_rts,
+                        max_ofdm->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rxe_frame_lmt_ovrun:",
+                        le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+                        accum_ofdm->rxe_frame_limit_overrun,
+                        delta_ofdm->rxe_frame_limit_overrun,
+                        max_ofdm->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "sent_ack_cnt:",
+                        le32_to_cpu(ofdm->sent_ack_cnt),
+                        accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
+                        max_ofdm->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "sent_cts_cnt:",
+                        le32_to_cpu(ofdm->sent_cts_cnt),
+                        accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
+                        max_ofdm->sent_cts_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sent_ba_rsp_cnt:",
+                        le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+                        accum_ofdm->sent_ba_rsp_cnt,
+                        delta_ofdm->sent_ba_rsp_cnt,
+                        max_ofdm->sent_ba_rsp_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "dsp_self_kill:",
+                        le32_to_cpu(ofdm->dsp_self_kill),
+                        accum_ofdm->dsp_self_kill,
+                        delta_ofdm->dsp_self_kill,
+                        max_ofdm->dsp_self_kill);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "mh_format_err:",
+                        le32_to_cpu(ofdm->mh_format_err),
+                        accum_ofdm->mh_format_err,
+                        delta_ofdm->mh_format_err,
+                        max_ofdm->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "re_acq_main_rssi_sum:",
+                        le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+                        accum_ofdm->re_acq_main_rssi_sum,
+                        delta_ofdm->re_acq_main_rssi_sum,
+                        max_ofdm->re_acq_main_rssi_sum);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - CCK:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ina_cnt:",
+                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+                        delta_cck->ina_cnt, max_cck->ina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_cnt:",
+                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+                        delta_cck->fina_cnt, max_cck->fina_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "plcp_err:",
+                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+                        delta_cck->plcp_err, max_cck->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_err:",
+                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+                        delta_cck->crc32_err, max_cck->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "overrun_err:",
+                        le32_to_cpu(cck->overrun_err),
+                        accum_cck->overrun_err, delta_cck->overrun_err,
+                        max_cck->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "early_overrun_err:",
+                        le32_to_cpu(cck->early_overrun_err),
+                        accum_cck->early_overrun_err,
+                        delta_cck->early_overrun_err,
+                        max_cck->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_good:",
+                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+                        delta_cck->crc32_good, max_cck->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "false_alarm_cnt:",
+                        le32_to_cpu(cck->false_alarm_cnt),
+                        accum_cck->false_alarm_cnt,
+                        delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "fina_sync_err_cnt:",
+                        le32_to_cpu(cck->fina_sync_err_cnt),
+                        accum_cck->fina_sync_err_cnt,
+                        delta_cck->fina_sync_err_cnt,
+                        max_cck->fina_sync_err_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sfd_timeout:",
+                        le32_to_cpu(cck->sfd_timeout),
+                        accum_cck->sfd_timeout, delta_cck->sfd_timeout,
+                        max_cck->sfd_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "fina_timeout:",
+                        le32_to_cpu(cck->fina_timeout),
+                        accum_cck->fina_timeout, delta_cck->fina_timeout,
+                        max_cck->fina_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "unresponded_rts:",
+                        le32_to_cpu(cck->unresponded_rts),
+                        accum_cck->unresponded_rts, delta_cck->unresponded_rts,
+                        max_cck->unresponded_rts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rxe_frame_lmt_ovrun:",
+                        le32_to_cpu(cck->rxe_frame_limit_overrun),
+                        accum_cck->rxe_frame_limit_overrun,
+                        delta_cck->rxe_frame_limit_overrun,
+                        max_cck->rxe_frame_limit_overrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "sent_ack_cnt:",
+                        le32_to_cpu(cck->sent_ack_cnt),
+                        accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
+                        max_cck->sent_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "sent_cts_cnt:",
+                        le32_to_cpu(cck->sent_cts_cnt),
+                        accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
+                        max_cck->sent_cts_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "sent_ba_rsp_cnt:",
+                        le32_to_cpu(cck->sent_ba_rsp_cnt),
+                        accum_cck->sent_ba_rsp_cnt,
+                        delta_cck->sent_ba_rsp_cnt,
+                        max_cck->sent_ba_rsp_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "dsp_self_kill:",
+                        le32_to_cpu(cck->dsp_self_kill),
+                        accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
+                        max_cck->dsp_self_kill);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "mh_format_err:",
+                        le32_to_cpu(cck->mh_format_err),
+                        accum_cck->mh_format_err, delta_cck->mh_format_err,
+                        max_cck->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "re_acq_main_rssi_sum:",
+                        le32_to_cpu(cck->re_acq_main_rssi_sum),
+                        accum_cck->re_acq_main_rssi_sum,
+                        delta_cck->re_acq_main_rssi_sum,
+                        max_cck->re_acq_main_rssi_sum);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - GENERAL:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "bogus_cts:",
+                        le32_to_cpu(general->bogus_cts),
+                        accum_general->bogus_cts, delta_general->bogus_cts,
+                        max_general->bogus_cts);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n", "bogus_ack:",
+                        le32_to_cpu(general->bogus_ack),
+                        accum_general->bogus_ack, delta_general->bogus_ack,
+                        max_general->bogus_ack);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "non_bssid_frames:",
+                        le32_to_cpu(general->non_bssid_frames),
+                        accum_general->non_bssid_frames,
+                        delta_general->non_bssid_frames,
+                        max_general->non_bssid_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "filtered_frames:",
+                        le32_to_cpu(general->filtered_frames),
+                        accum_general->filtered_frames,
+                        delta_general->filtered_frames,
+                        max_general->filtered_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "non_channel_beacons:",
+                        le32_to_cpu(general->non_channel_beacons),
+                        accum_general->non_channel_beacons,
+                        delta_general->non_channel_beacons,
+                        max_general->non_channel_beacons);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "channel_beacons:",
+                        le32_to_cpu(general->channel_beacons),
+                        accum_general->channel_beacons,
+                        delta_general->channel_beacons,
+                        max_general->channel_beacons);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "num_missed_bcon:",
+                        le32_to_cpu(general->num_missed_bcon),
+                        accum_general->num_missed_bcon,
+                        delta_general->num_missed_bcon,
+                        max_general->num_missed_bcon);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "adc_rx_saturation_time:",
+                        le32_to_cpu(general->adc_rx_saturation_time),
+                        accum_general->adc_rx_saturation_time,
+                        delta_general->adc_rx_saturation_time,
+                        max_general->adc_rx_saturation_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ina_detect_search_tm:",
+                        le32_to_cpu(general->ina_detection_search_time),
+                        accum_general->ina_detection_search_time,
+                        delta_general->ina_detection_search_time,
+                        max_general->ina_detection_search_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_silence_rssi_a:",
+                        le32_to_cpu(general->beacon_silence_rssi_a),
+                        accum_general->beacon_silence_rssi_a,
+                        delta_general->beacon_silence_rssi_a,
+                        max_general->beacon_silence_rssi_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_silence_rssi_b:",
+                        le32_to_cpu(general->beacon_silence_rssi_b),
+                        accum_general->beacon_silence_rssi_b,
+                        delta_general->beacon_silence_rssi_b,
+                        max_general->beacon_silence_rssi_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_silence_rssi_c:",
+                        le32_to_cpu(general->beacon_silence_rssi_c),
+                        accum_general->beacon_silence_rssi_c,
+                        delta_general->beacon_silence_rssi_c,
+                        max_general->beacon_silence_rssi_c);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "interference_data_flag:",
+                        le32_to_cpu(general->interference_data_flag),
+                        accum_general->interference_data_flag,
+                        delta_general->interference_data_flag,
+                        max_general->interference_data_flag);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "channel_load:",
+                        le32_to_cpu(general->channel_load),
+                        accum_general->channel_load,
+                        delta_general->channel_load,
+                        max_general->channel_load);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "dsp_false_alarms:",
+                        le32_to_cpu(general->dsp_false_alarms),
+                        accum_general->dsp_false_alarms,
+                        delta_general->dsp_false_alarms,
+                        max_general->dsp_false_alarms);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_rssi_a:",
+                        le32_to_cpu(general->beacon_rssi_a),
+                        accum_general->beacon_rssi_a,
+                        delta_general->beacon_rssi_a,
+                        max_general->beacon_rssi_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_rssi_b:",
+                        le32_to_cpu(general->beacon_rssi_b),
+                        accum_general->beacon_rssi_b,
+                        delta_general->beacon_rssi_b,
+                        max_general->beacon_rssi_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_rssi_c:",
+                        le32_to_cpu(general->beacon_rssi_c),
+                        accum_general->beacon_rssi_c,
+                        delta_general->beacon_rssi_c,
+                        max_general->beacon_rssi_c);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_energy_a:",
+                        le32_to_cpu(general->beacon_energy_a),
+                        accum_general->beacon_energy_a,
+                        delta_general->beacon_energy_a,
+                        max_general->beacon_energy_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_energy_b:",
+                        le32_to_cpu(general->beacon_energy_b),
+                        accum_general->beacon_energy_b,
+                        delta_general->beacon_energy_b,
+                        max_general->beacon_energy_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "beacon_energy_c:",
+                        le32_to_cpu(general->beacon_energy_c),
+                        accum_general->beacon_energy_c,
+                        delta_general->beacon_energy_c,
+                        max_general->beacon_energy_c);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Rx - OFDM_HT:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "plcp_err:",
+                        le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+                        delta_ht->plcp_err, max_ht->plcp_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "overrun_err:",
+                        le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+                        delta_ht->overrun_err, max_ht->overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "early_overrun_err:",
+                        le32_to_cpu(ht->early_overrun_err),
+                        accum_ht->early_overrun_err,
+                        delta_ht->early_overrun_err,
+                        max_ht->early_overrun_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_good:",
+                        le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+                        delta_ht->crc32_good, max_ht->crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "crc32_err:",
+                        le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+                        delta_ht->crc32_err, max_ht->crc32_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "mh_format_err:",
+                        le32_to_cpu(ht->mh_format_err),
+                        accum_ht->mh_format_err,
+                        delta_ht->mh_format_err, max_ht->mh_format_err);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg_crc32_good:",
+                        le32_to_cpu(ht->agg_crc32_good),
+                        accum_ht->agg_crc32_good,
+                        delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg_mpdu_cnt:",
+                        le32_to_cpu(ht->agg_mpdu_cnt),
+                        accum_ht->agg_mpdu_cnt,
+                        delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg_cnt:",
+                        le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+                        delta_ht->agg_cnt, max_ht->agg_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "unsupport_mcs:",
+                        le32_to_cpu(ht->unsupport_mcs),
+                        accum_ht->unsupport_mcs,
+                        delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+ssize_t iwl_ucode_tx_stats_read(struct file *file,
+                               char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
+       ssize_t ret;
+       struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(priv, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       /* the statistic information display here is based on
+         * the last statistics notification from uCode
+         * might not reflect the current uCode activity
+         */
+       tx = &priv->statistics.tx;
+       accum_tx = &priv->accum_statistics.tx;
+       delta_tx = &priv->delta_statistics.tx;
+       max_tx = &priv->max_delta.tx;
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos,  "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_Tx:");
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "preamble:",
+                        le32_to_cpu(tx->preamble_cnt),
+                        accum_tx->preamble_cnt,
+                        delta_tx->preamble_cnt, max_tx->preamble_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rx_detected_cnt:",
+                        le32_to_cpu(tx->rx_detected_cnt),
+                        accum_tx->rx_detected_cnt,
+                        delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "bt_prio_defer_cnt:",
+                        le32_to_cpu(tx->bt_prio_defer_cnt),
+                        accum_tx->bt_prio_defer_cnt,
+                        delta_tx->bt_prio_defer_cnt,
+                        max_tx->bt_prio_defer_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "bt_prio_kill_cnt:",
+                        le32_to_cpu(tx->bt_prio_kill_cnt),
+                        accum_tx->bt_prio_kill_cnt,
+                        delta_tx->bt_prio_kill_cnt,
+                        max_tx->bt_prio_kill_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "few_bytes_cnt:",
+                        le32_to_cpu(tx->few_bytes_cnt),
+                        accum_tx->few_bytes_cnt,
+                        delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "cts_timeout:",
+                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+                        delta_tx->cts_timeout, max_tx->cts_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ack_timeout:",
+                        le32_to_cpu(tx->ack_timeout),
+                        accum_tx->ack_timeout,
+                        delta_tx->ack_timeout, max_tx->ack_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "expected_ack_cnt:",
+                        le32_to_cpu(tx->expected_ack_cnt),
+                        accum_tx->expected_ack_cnt,
+                        delta_tx->expected_ack_cnt,
+                        max_tx->expected_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "actual_ack_cnt:",
+                        le32_to_cpu(tx->actual_ack_cnt),
+                        accum_tx->actual_ack_cnt,
+                        delta_tx->actual_ack_cnt,
+                        max_tx->actual_ack_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "dump_msdu_cnt:",
+                        le32_to_cpu(tx->dump_msdu_cnt),
+                        accum_tx->dump_msdu_cnt,
+                        delta_tx->dump_msdu_cnt,
+                        max_tx->dump_msdu_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "abort_nxt_frame_mismatch:",
+                        le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+                        accum_tx->burst_abort_next_frame_mismatch_cnt,
+                        delta_tx->burst_abort_next_frame_mismatch_cnt,
+                        max_tx->burst_abort_next_frame_mismatch_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "abort_missing_nxt_frame:",
+                        le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+                        accum_tx->burst_abort_missing_next_frame_cnt,
+                        delta_tx->burst_abort_missing_next_frame_cnt,
+                        max_tx->burst_abort_missing_next_frame_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "cts_timeout_collision:",
+                        le32_to_cpu(tx->cts_timeout_collision),
+                        accum_tx->cts_timeout_collision,
+                        delta_tx->cts_timeout_collision,
+                        max_tx->cts_timeout_collision);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "ack_ba_timeout_collision:",
+                        le32_to_cpu(tx->ack_or_ba_timeout_collision),
+                        accum_tx->ack_or_ba_timeout_collision,
+                        delta_tx->ack_or_ba_timeout_collision,
+                        max_tx->ack_or_ba_timeout_collision);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg ba_timeout:",
+                        le32_to_cpu(tx->agg.ba_timeout),
+                        accum_tx->agg.ba_timeout,
+                        delta_tx->agg.ba_timeout,
+                        max_tx->agg.ba_timeout);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg ba_resched_frames:",
+                        le32_to_cpu(tx->agg.ba_reschedule_frames),
+                        accum_tx->agg.ba_reschedule_frames,
+                        delta_tx->agg.ba_reschedule_frames,
+                        max_tx->agg.ba_reschedule_frames);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg scd_query_agg_frame:",
+                        le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+                        accum_tx->agg.scd_query_agg_frame_cnt,
+                        delta_tx->agg.scd_query_agg_frame_cnt,
+                        max_tx->agg.scd_query_agg_frame_cnt);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg scd_query_no_agg:",
+                        le32_to_cpu(tx->agg.scd_query_no_agg),
+                        accum_tx->agg.scd_query_no_agg,
+                        delta_tx->agg.scd_query_no_agg,
+                        max_tx->agg.scd_query_no_agg);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg scd_query_agg:",
+                        le32_to_cpu(tx->agg.scd_query_agg),
+                        accum_tx->agg.scd_query_agg,
+                        delta_tx->agg.scd_query_agg,
+                        max_tx->agg.scd_query_agg);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg scd_query_mismatch:",
+                        le32_to_cpu(tx->agg.scd_query_mismatch),
+                        accum_tx->agg.scd_query_mismatch,
+                        delta_tx->agg.scd_query_mismatch,
+                        max_tx->agg.scd_query_mismatch);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg frame_not_ready:",
+                        le32_to_cpu(tx->agg.frame_not_ready),
+                        accum_tx->agg.frame_not_ready,
+                        delta_tx->agg.frame_not_ready,
+                        max_tx->agg.frame_not_ready);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg underrun:",
+                        le32_to_cpu(tx->agg.underrun),
+                        accum_tx->agg.underrun,
+                        delta_tx->agg.underrun, max_tx->agg.underrun);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg bt_prio_kill:",
+                        le32_to_cpu(tx->agg.bt_prio_kill),
+                        accum_tx->agg.bt_prio_kill,
+                        delta_tx->agg.bt_prio_kill,
+                        max_tx->agg.bt_prio_kill);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "agg rx_ba_rsp_cnt:",
+                        le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+                        accum_tx->agg.rx_ba_rsp_cnt,
+                        delta_tx->agg.rx_ba_rsp_cnt,
+                        max_tx->agg.rx_ba_rsp_cnt);
+
+       if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "tx power: (1/2 dB step)\n");
+               if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "\tantenna A: 0x%X\n",
+                                       tx->tx_power.ant_a);
+               if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "\tantenna B: 0x%X\n",
+                                       tx->tx_power.ant_b);
+               if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                       "\tantenna C: 0x%X\n",
+                                       tx->tx_power.ant_c);
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       int pos = 0;
+       char *buf;
+       int bufsz = sizeof(struct statistics_general) * 10 + 300;
+       ssize_t ret;
+       struct statistics_general *general, *accum_general;
+       struct statistics_general *delta_general, *max_general;
+       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
+       struct statistics_div *div, *accum_div, *delta_div, *max_div;
+
+       if (!iwl_is_alive(priv))
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(priv, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       /* the statistic information display here is based on
+         * the last statistics notification from uCode
+         * might not reflect the current uCode activity
+         */
+       general = &priv->statistics.general;
+       dbg = &priv->statistics.general.dbg;
+       div = &priv->statistics.general.div;
+       accum_general = &priv->accum_statistics.general;
+       delta_general = &priv->delta_statistics.general;
+       max_general = &priv->max_delta.general;
+       accum_dbg = &priv->accum_statistics.general.dbg;
+       delta_dbg = &priv->delta_statistics.general.dbg;
+       max_dbg = &priv->max_delta.general.dbg;
+       accum_div = &priv->accum_statistics.general.div;
+       delta_div = &priv->delta_statistics.general.div;
+       max_div = &priv->max_delta.general.div;
+       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+       pos += scnprintf(buf + pos, bufsz - pos, "%-32s     current"
+                        "acumulative       delta         max\n",
+                        "Statistics_General:");
+       pos += scnprintf(buf + pos, bufsz - pos, "  %-30s %10u\n",
+                        "temperature:",
+                        le32_to_cpu(general->temperature));
+       pos += scnprintf(buf + pos, bufsz - pos, "  %-30s %10u\n",
+                        "temperature_m:",
+                        le32_to_cpu(general->temperature_m));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "burst_check:",
+                        le32_to_cpu(dbg->burst_check),
+                        accum_dbg->burst_check,
+                        delta_dbg->burst_check, max_dbg->burst_check);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "burst_count:",
+                        le32_to_cpu(dbg->burst_count),
+                        accum_dbg->burst_count,
+                        delta_dbg->burst_count, max_dbg->burst_count);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "sleep_time:",
+                        le32_to_cpu(general->sleep_time),
+                        accum_general->sleep_time,
+                        delta_general->sleep_time, max_general->sleep_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "slots_out:",
+                        le32_to_cpu(general->slots_out),
+                        accum_general->slots_out,
+                        delta_general->slots_out, max_general->slots_out);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "slots_idle:",
+                        le32_to_cpu(general->slots_idle),
+                        accum_general->slots_idle,
+                        delta_general->slots_idle, max_general->slots_idle);
+       pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
+                        le32_to_cpu(general->ttl_timestamp));
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "tx_on_a:",
+                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+                        delta_div->tx_on_a, max_div->tx_on_a);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "tx_on_b:",
+                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+                        delta_div->tx_on_b, max_div->tx_on_b);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "exec_time:",
+                        le32_to_cpu(div->exec_time), accum_div->exec_time,
+                        delta_div->exec_time, max_div->exec_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "probe_time:",
+                        le32_to_cpu(div->probe_time), accum_div->probe_time,
+                        delta_div->probe_time, max_div->probe_time);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "rx_enable_counter:",
+                        le32_to_cpu(general->rx_enable_counter),
+                        accum_general->rx_enable_counter,
+                        delta_general->rx_enable_counter,
+                        max_general->rx_enable_counter);
+       pos += scnprintf(buf + pos, bufsz - pos,
+                        "  %-30s %10u  %10u  %10u  %10u\n",
+                        "num_of_sos_states:",
+                        le32_to_cpu(general->num_of_sos_states),
+                        accum_general->num_of_sos_states,
+                        delta_general->num_of_sos_states,
+                        max_general->num_of_sos_states);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
new file mode 100644 (file)
index 0000000..59b1f25
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-debug.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos);
+ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos);
+ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
+                                    size_t count, loff_t *ppos);
+#else
+static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       return 0;
+}
+static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       return 0;
+}
+static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
+                                           size_t count, loff_t *ppos)
+{
+       return 0;
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
new file mode 100644 (file)
index 0000000..44ef5d9
--- /dev/null
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn.h"
+
+static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+{
+       int ret = 0;
+       struct iwl5000_rxon_assoc_cmd rxon_assoc;
+       const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+       const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+       if ((rxon1->flags == rxon2->flags) &&
+           (rxon1->filter_flags == rxon2->filter_flags) &&
+           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+           (rxon1->ofdm_ht_single_stream_basic_rates ==
+            rxon2->ofdm_ht_single_stream_basic_rates) &&
+           (rxon1->ofdm_ht_dual_stream_basic_rates ==
+            rxon2->ofdm_ht_dual_stream_basic_rates) &&
+           (rxon1->ofdm_ht_triple_stream_basic_rates ==
+            rxon2->ofdm_ht_triple_stream_basic_rates) &&
+           (rxon1->acquisition_data == rxon2->acquisition_data) &&
+           (rxon1->rx_chain == rxon2->rx_chain) &&
+           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+               IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC.  Not resending.\n");
+               return 0;
+       }
+
+       rxon_assoc.flags = priv->staging_rxon.flags;
+       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+       rxon_assoc.reserved1 = 0;
+       rxon_assoc.reserved2 = 0;
+       rxon_assoc.reserved3 = 0;
+       rxon_assoc.ofdm_ht_single_stream_basic_rates =
+           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+       rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+                priv->staging_rxon.ofdm_ht_triple_stream_basic_rates;
+       rxon_assoc.acquisition_data = priv->staging_rxon.acquisition_data;
+
+       ret = iwl_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
+                                    sizeof(rxon_assoc), &rxon_assoc, NULL);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+{
+       struct iwl_tx_ant_config_cmd tx_ant_cmd = {
+         .valid = cpu_to_le32(valid_tx_ant),
+       };
+
+       if (IWL_UCODE_API(priv->ucode_ver) > 1) {
+               IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant);
+               return iwl_send_cmd_pdu(priv, TX_ANT_CONFIGURATION_CMD,
+                                       sizeof(struct iwl_tx_ant_config_cmd),
+                                       &tx_ant_cmd);
+       } else {
+               IWL_DEBUG_HC(priv, "TX_ANT_CONFIGURATION_CMD not supported\n");
+               return -EOPNOTSUPP;
+       }
+}
+
+/* Currently this is the superset of everything */
+static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len)
+{
+       return len;
+}
+
+static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
+{
+       u16 size = (u16)sizeof(struct iwl_addsta_cmd);
+       struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
+       memcpy(addsta, cmd, size);
+       /* resrved in 5000 */
+       addsta->rate_n_flags = cpu_to_le16(0);
+       return size;
+}
+
+static void iwlagn_gain_computation(struct iwl_priv *priv,
+               u32 average_noise[NUM_RX_CHAINS],
+               u16 min_average_noise_antenna_i,
+               u32 min_average_noise,
+               u8 default_chain)
+{
+       int i;
+       s32 delta_g;
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+
+       /*
+        * Find Gain Code for the chains based on "default chain"
+        */
+       for (i = default_chain + 1; i < NUM_RX_CHAINS; i++) {
+               if ((data->disconn_array[i])) {
+                       data->delta_gain_code[i] = 0;
+                       continue;
+               }
+
+               delta_g = (priv->cfg->chain_noise_scale *
+                       ((s32)average_noise[default_chain] -
+                       (s32)average_noise[i])) / 1500;
+
+               /* bound gain by 2 bits value max, 3rd bit is sign */
+               data->delta_gain_code[i] =
+                       min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+
+               if (delta_g < 0)
+                       /*
+                        * set negative sign ...
+                        * note to Intel developers:  This is uCode API format,
+                        *   not the format of any internal device registers.
+                        *   Do not change this format for e.g. 6050 or similar
+                        *   devices.  Change format only if more resolution
+                        *   (i.e. more than 2 bits magnitude) is needed.
+                        */
+                       data->delta_gain_code[i] |= (1 << 2);
+       }
+
+       IWL_DEBUG_CALIB(priv, "Delta gains: ANT_B = %d  ANT_C = %d\n",
+                       data->delta_gain_code[1], data->delta_gain_code[2]);
+
+       if (!data->radio_write) {
+               struct iwl_calib_chain_noise_gain_cmd cmd;
+
+               memset(&cmd, 0, sizeof(cmd));
+
+               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD;
+               cmd.hdr.first_group = 0;
+               cmd.hdr.groups_num = 1;
+               cmd.hdr.data_valid = 1;
+               cmd.delta_gain_1 = data->delta_gain_code[1];
+               cmd.delta_gain_2 = data->delta_gain_code[2];
+               iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD,
+                       sizeof(cmd), &cmd, NULL);
+
+               data->radio_write = 1;
+               data->state = IWL_CHAIN_NOISE_CALIBRATED;
+       }
+
+       data->chain_noise_a = 0;
+       data->chain_noise_b = 0;
+       data->chain_noise_c = 0;
+       data->chain_signal_a = 0;
+       data->chain_signal_b = 0;
+       data->chain_signal_c = 0;
+       data->beacon_count = 0;
+}
+
+static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
+{
+       struct iwl_chain_noise_data *data = &priv->chain_noise_data;
+       int ret;
+
+       if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+               struct iwl_calib_chain_noise_reset_cmd cmd;
+               memset(&cmd, 0, sizeof(cmd));
+
+               cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
+               cmd.hdr.first_group = 0;
+               cmd.hdr.groups_num = 1;
+               cmd.hdr.data_valid = 1;
+               ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+                                       sizeof(cmd), &cmd);
+               if (ret)
+                       IWL_ERR(priv,
+                               "Could not send REPLY_PHY_CALIBRATION_CMD\n");
+               data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+               IWL_DEBUG_CALIB(priv, "Run chain_noise_calibrate\n");
+       }
+}
+
+static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
+                       __le32 *tx_flags)
+{
+       if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
+               *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
+       else
+               *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwlagn_calc_rssi(struct iwl_priv *priv,
+                            struct iwl_rx_phy_res *rx_resp)
+{
+       /* data from PHY/DSP regarding signal strength, etc.,
+        *   contents are always there, not configurable by host
+        */
+       struct iwl5000_non_cfg_phy *ncphy =
+               (struct iwl5000_non_cfg_phy *)rx_resp->non_cfg_phy_buf;
+       u32 val, rssi_a, rssi_b, rssi_c, max_rssi;
+       u8 agc;
+
+       val  = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_AGC_IDX]);
+       agc = (val & IWL50_OFDM_AGC_MSK) >> IWL50_OFDM_AGC_BIT_POS;
+
+       /* Find max rssi among 3 possible receivers.
+        * These values are measured by the digital signal processor (DSP).
+        * They should stay fairly constant even as the signal strength varies,
+        *   if the radio's automatic gain control (AGC) is working right.
+        * AGC value (see below) will provide the "interesting" info.
+        */
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_AB_IDX]);
+       rssi_a = (val & IWL50_OFDM_RSSI_A_MSK) >> IWL50_OFDM_RSSI_A_BIT_POS;
+       rssi_b = (val & IWL50_OFDM_RSSI_B_MSK) >> IWL50_OFDM_RSSI_B_BIT_POS;
+       val = le32_to_cpu(ncphy->non_cfg_phy[IWL50_RX_RES_RSSI_C_IDX]);
+       rssi_c = (val & IWL50_OFDM_RSSI_C_MSK) >> IWL50_OFDM_RSSI_C_BIT_POS;
+
+       max_rssi = max_t(u32, rssi_a, rssi_b);
+       max_rssi = max_t(u32, max_rssi, rssi_c);
+
+       IWL_DEBUG_STATS(priv, "Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+               rssi_a, rssi_b, rssi_c, max_rssi, agc);
+
+       /* dBm = max_rssi dB - agc dB - constant.
+        * Higher AGC (higher radio gain) means lower signal. */
+       return max_rssi - agc - IWLAGN_RSSI_OFFSET;
+}
+
+struct iwl_hcmd_ops iwlagn_hcmd = {
+       .rxon_assoc = iwlagn_send_rxon_assoc,
+       .commit_rxon = iwl_commit_rxon,
+       .set_rxon_chain = iwl_set_rxon_chain,
+       .set_tx_ant = iwlagn_send_tx_ant_config,
+       .send_bt_config = iwl_send_bt_config,
+};
+
+struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
+       .get_hcmd_size = iwlagn_get_hcmd_size,
+       .build_addsta_hcmd = iwlagn_build_addsta_hcmd,
+       .gain_computation = iwlagn_gain_computation,
+       .chain_noise_reset = iwlagn_chain_noise_reset,
+       .rts_tx_cmd_flag = iwlagn_rts_tx_cmd_flag,
+       .calc_rssi = iwlagn_calc_rssi,
+       .request_scan = iwlagn_request_scan,
+};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
new file mode 100644 (file)
index 0000000..f9a3fbb
--- /dev/null
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+/*
+ * Please use this file (iwl-agn-hw.h) only for hardware-related definitions.
+ */
+
+#ifndef __iwl_agn_hw_h__
+#define __iwl_agn_hw_h__
+
+#define IWLAGN_RTC_INST_LOWER_BOUND            (0x000000)
+#define IWLAGN_RTC_INST_UPPER_BOUND            (0x020000)
+
+#define IWLAGN_RTC_DATA_LOWER_BOUND            (0x800000)
+#define IWLAGN_RTC_DATA_UPPER_BOUND            (0x80C000)
+
+#define IWLAGN_RTC_INST_SIZE (IWLAGN_RTC_INST_UPPER_BOUND - \
+                               IWLAGN_RTC_INST_LOWER_BOUND)
+#define IWLAGN_RTC_DATA_SIZE (IWLAGN_RTC_DATA_UPPER_BOUND - \
+                               IWLAGN_RTC_DATA_LOWER_BOUND)
+
+/* RSSI to dBm */
+#define IWLAGN_RSSI_OFFSET     44
+
+/* PCI registers */
+#define PCI_CFG_RETRY_TIMEOUT  0x041
+
+/* PCI register values */
+#define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
+#define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
+
+#define IWLAGN_DEFAULT_TX_RETRY  15
+
+/* Limit range of txpower output target to be between these values */
+#define IWLAGN_TX_POWER_TARGET_POWER_MIN       (0)     /* 0 dBm: 1 milliwatt */
+#define IWLAGN_TX_POWER_TARGET_POWER_MAX       (16)    /* 16 dBm */
+
+/* EEPROM */
+#define IWLAGN_EEPROM_IMG_SIZE         2048
+
+#define IWLAGN_CMD_FIFO_NUM            7
+#define IWLAGN_NUM_QUEUES              20
+#define IWLAGN_NUM_AMPDU_QUEUES                10
+#define IWLAGN_FIRST_AMPDU_QUEUE       10
+
+/* Fixed (non-configurable) rx data from phy */
+
+/**
+ * struct iwlagn_schedq_bc_tbl scheduler byte count table
+ *     base physical address provided by SCD_DRAM_BASE_ADDR
+ * @tfd_offset  0-12 - tx command byte count
+ *            12-16 - station index
+ */
+struct iwlagn_scd_bc_tbl {
+       __le16 tfd_offset[TFD_QUEUE_BC_SIZE];
+} __attribute__ ((packed));
+
+
+#endif /* __iwl_agn_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
new file mode 100644 (file)
index 0000000..a273e37
--- /dev/null
@@ -0,0 +1,307 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/sched.h>
+#include <net/mac80211.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-agn.h"
+#include "iwl-helpers.h"
+
+#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
+
+/* Free dram table */
+void iwl_free_isr_ict(struct iwl_priv *priv)
+{
+       if (priv->_agn.ict_tbl_vir) {
+               dma_free_coherent(&priv->pci_dev->dev,
+                                 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
+                                 priv->_agn.ict_tbl_vir,
+                                 priv->_agn.ict_tbl_dma);
+               priv->_agn.ict_tbl_vir = NULL;
+       }
+}
+
+
+/* allocate dram shared table it is a PAGE_SIZE aligned
+ * also reset all data related to ICT table interrupt.
+ */
+int iwl_alloc_isr_ict(struct iwl_priv *priv)
+{
+
+       if (priv->cfg->use_isr_legacy)
+               return 0;
+       /* allocate shrared data table */
+       priv->_agn.ict_tbl_vir =
+               dma_alloc_coherent(&priv->pci_dev->dev,
+                                  (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
+                                  &priv->_agn.ict_tbl_dma, GFP_KERNEL);
+       if (!priv->_agn.ict_tbl_vir)
+               return -ENOMEM;
+
+       /* align table to PAGE_SIZE boundry */
+       priv->_agn.aligned_ict_tbl_dma = ALIGN(priv->_agn.ict_tbl_dma, PAGE_SIZE);
+
+       IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
+                            (unsigned long long)priv->_agn.ict_tbl_dma,
+                            (unsigned long long)priv->_agn.aligned_ict_tbl_dma,
+                       (int)(priv->_agn.aligned_ict_tbl_dma - priv->_agn.ict_tbl_dma));
+
+       priv->_agn.ict_tbl =  priv->_agn.ict_tbl_vir +
+                         (priv->_agn.aligned_ict_tbl_dma - priv->_agn.ict_tbl_dma);
+
+       IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
+                            priv->_agn.ict_tbl, priv->_agn.ict_tbl_vir,
+                       (int)(priv->_agn.aligned_ict_tbl_dma - priv->_agn.ict_tbl_dma));
+
+       /* reset table and index to all 0 */
+       memset(priv->_agn.ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
+       priv->_agn.ict_index = 0;
+
+       /* add periodic RX interrupt */
+       priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
+       return 0;
+}
+
+/* Device is going up inform it about using ICT interrupt table,
+ * also we need to tell the driver to start using ICT interrupt.
+ */
+int iwl_reset_ict(struct iwl_priv *priv)
+{
+       u32 val;
+       unsigned long flags;
+
+       if (!priv->_agn.ict_tbl_vir)
+               return 0;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl_disable_interrupts(priv);
+
+       memset(&priv->_agn.ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
+
+       val = priv->_agn.aligned_ict_tbl_dma >> PAGE_SHIFT;
+
+       val |= CSR_DRAM_INT_TBL_ENABLE;
+       val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
+
+       IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
+                       "aligned dma address %Lx\n",
+                       val, (unsigned long long)priv->_agn.aligned_ict_tbl_dma);
+
+       iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
+       priv->_agn.use_ict = true;
+       priv->_agn.ict_index = 0;
+       iwl_write32(priv, CSR_INT, priv->inta_mask);
+       iwl_enable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+/* Device is going down disable ict interrupt usage */
+void iwl_disable_ict(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->_agn.use_ict = false;
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+       struct iwl_priv *priv = data;
+       u32 inta, inta_mask;
+       unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       u32 inta_fh;
+#endif
+       if (!priv)
+               return IRQ_NONE;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        *    back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here. */
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(priv, CSR_INT);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!inta) {
+               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
+               goto none;
+       }
+
+       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /* Hardware disappeared. It might have already raised
+                * an interrupt */
+               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               goto unplugged;
+       }
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
+               inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+               IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
+                             "fh 0x%08x\n", inta, inta_mask, inta_fh);
+       }
+#endif
+
+       priv->_agn.inta |= inta;
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta))
+               tasklet_schedule(&priv->irq_tasklet);
+       else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
+               iwl_enable_interrupts(priv);
+
+ unplugged:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service. */
+       /* only Re-enable if diabled by irq  and no schedules tasklet. */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
+               iwl_enable_interrupts(priv);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return IRQ_NONE;
+}
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+irqreturn_t iwl_isr_ict(int irq, void *data)
+{
+       struct iwl_priv *priv = data;
+       u32 inta, inta_mask;
+       u32 val = 0;
+       unsigned long flags;
+
+       if (!priv)
+               return IRQ_NONE;
+
+       /* dram interrupt table not set yet,
+        * use legacy interrupt.
+        */
+       if (!priv->_agn.use_ict)
+               return iwl_isr(irq, data);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        * back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here.
+        */
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!priv->_agn.ict_tbl[priv->_agn.ict_index]) {
+               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
+               goto none;
+       }
+
+       /* read all entries that not 0 start with ict_index */
+       while (priv->_agn.ict_tbl[priv->_agn.ict_index]) {
+
+               val |= le32_to_cpu(priv->_agn.ict_tbl[priv->_agn.ict_index]);
+               IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
+                               priv->_agn.ict_index,
+                               le32_to_cpu(priv->_agn.ict_tbl[priv->_agn.ict_index]));
+               priv->_agn.ict_tbl[priv->_agn.ict_index] = 0;
+               priv->_agn.ict_index = iwl_queue_inc_wrap(priv->_agn.ict_index,
+                                                    ICT_COUNT);
+
+       }
+
+       /* We should not get this value, just ignore it. */
+       if (val == 0xffffffff)
+               val = 0;
+
+       /*
+        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+        * (bit 15 before shifting it to 31) to clear when using interrupt
+        * coalescing. fortunately, bits 18 and 19 stay set when this happens
+        * so we use them to decide on the real state of the Rx bit.
+        * In order words, bit 15 is set if bit 18 or bit 19 are set.
+        */
+       if (val & 0xC0000)
+               val |= 0x8000;
+
+       inta = (0xff & val) | ((0xff00 & val) << 16);
+       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
+                       inta, inta_mask, val);
+
+       inta &= priv->inta_mask;
+       priv->_agn.inta |= inta;
+
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta))
+               tasklet_schedule(&priv->irq_tasklet);
+       else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta) {
+               /* Allow interrupt if was disabled by this handler and
+                * no tasklet was schedules, We should not enable interrupt,
+                * tasklet will enable it.
+                */
+               iwl_enable_interrupts(priv);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service.
+        * only Re-enable if disabled by irq.
+        */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->_agn.inta)
+               iwl_enable_interrupts(priv);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return IRQ_NONE;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
new file mode 100644 (file)
index 0000000..1004cfc
--- /dev/null
@@ -0,0 +1,1530 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/etherdevice.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+#include "iwl-sta.h"
+
+static inline u32 iwlagn_get_scd_ssn(struct iwl5000_tx_resp *tx_resp)
+{
+       return le32_to_cpup((__le32 *)&tx_resp->status +
+                           tx_resp->frame_count) & MAX_SN;
+}
+
+static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
+                                     struct iwl_ht_agg *agg,
+                                     struct iwl5000_tx_resp *tx_resp,
+                                     int txq_id, u16 start_idx)
+{
+       u16 status;
+       struct agg_tx_status *frame_status = &tx_resp->status;
+       struct ieee80211_tx_info *info = NULL;
+       struct ieee80211_hdr *hdr = NULL;
+       u32 rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+       int i, sh, idx;
+       u16 seq;
+
+       if (agg->wait_for_ba)
+               IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n");
+
+       agg->frame_count = tx_resp->frame_count;
+       agg->start_idx = start_idx;
+       agg->rate_n_flags = rate_n_flags;
+       agg->bitmap = 0;
+
+       /* # frames attempted by Tx command */
+       if (agg->frame_count == 1) {
+               /* Only one frame was attempted; no block-ack will arrive */
+               status = le16_to_cpu(frame_status[0].status);
+               idx = start_idx;
+
+               /* FIXME: code repetition */
+               IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
+                                  agg->frame_count, agg->start_idx, idx);
+
+               info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+               info->flags |= iwl_tx_status_to_mac80211(status);
+               iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info);
+
+               /* FIXME: code repetition end */
+
+               IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n",
+                                   status & 0xff, tx_resp->failure_frame);
+               IWL_DEBUG_TX_REPLY(priv, "Rate Info rate_n_flags=%x\n", rate_n_flags);
+
+               agg->wait_for_ba = 0;
+       } else {
+               /* Two or more frames were attempted; expect block-ack */
+               u64 bitmap = 0;
+               int start = agg->start_idx;
+
+               /* Construct bit-map of pending frames within Tx window */
+               for (i = 0; i < agg->frame_count; i++) {
+                       u16 sc;
+                       status = le16_to_cpu(frame_status[i].status);
+                       seq  = le16_to_cpu(frame_status[i].sequence);
+                       idx = SEQ_TO_INDEX(seq);
+                       txq_id = SEQ_TO_QUEUE(seq);
+
+                       if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+                                     AGG_TX_STATE_ABORT_MSK))
+                               continue;
+
+                       IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n",
+                                          agg->frame_count, txq_id, idx);
+
+                       hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+                       if (!hdr) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't point to valid skb"
+                                       " idx=%d, txq_id=%d\n", idx, txq_id);
+                               return -1;
+                       }
+
+                       sc = le16_to_cpu(hdr->seq_ctrl);
+                       if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+                               IWL_ERR(priv,
+                                       "BUG_ON idx doesn't match seq control"
+                                       " idx=%d, seq_idx=%d, seq=%d\n",
+                                         idx, SEQ_TO_SN(sc),
+                                         hdr->seq_ctrl);
+                               return -1;
+                       }
+
+                       IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
+                                          i, idx, SEQ_TO_SN(sc));
+
+                       sh = idx - start;
+                       if (sh > 64) {
+                               sh = (start - idx) + 0xff;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                               start = idx;
+                       } else if (sh < -64)
+                               sh  = 0xff - (start - idx);
+                       else if (sh < 0) {
+                               sh = start - idx;
+                               start = idx;
+                               bitmap = bitmap << sh;
+                               sh = 0;
+                       }
+                       bitmap |= 1ULL << sh;
+                       IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
+                                          start, (unsigned long long)bitmap);
+               }
+
+               agg->bitmap = bitmap;
+               agg->start_idx = start;
+               IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
+                                  agg->frame_count, agg->start_idx,
+                                  (unsigned long long)agg->bitmap);
+
+               if (bitmap)
+                       agg->wait_for_ba = 1;
+       }
+       return 0;
+}
+
+void iwl_check_abort_status(struct iwl_priv *priv,
+                           u8 frame_count, u32 status)
+{
+       if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) {
+               IWL_ERR(priv, "TODO: Implement Tx flush command!!!\n");
+       }
+}
+
+static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+       int txq_id = SEQ_TO_QUEUE(sequence);
+       int index = SEQ_TO_INDEX(sequence);
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct ieee80211_tx_info *info;
+       struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+       u32  status = le16_to_cpu(tx_resp->status.status);
+       int tid;
+       int sta_id;
+       int freed;
+
+       if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
+               IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
+                         "is out of range [0-%d] %d %d\n", txq_id,
+                         index, txq->q.n_bd, txq->q.write_ptr,
+                         txq->q.read_ptr);
+               return;
+       }
+
+       info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
+
+       tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
+       sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+
+       if (txq->sched_retry) {
+               const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
+               struct iwl_ht_agg *agg = NULL;
+
+               agg = &priv->stations[sta_id].tid[tid].agg;
+
+               iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index);
+
+               /* check if BAR is needed */
+               if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status))
+                       info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+
+               if (txq->q.read_ptr != (scd_ssn & 0xff)) {
+                       index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+                       IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim "
+                                       "scd_ssn=%d idx=%d txq=%d swq=%d\n",
+                                       scd_ssn , index, txq_id, txq->swq_id);
+
+                       freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
+                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+
+                       if (priv->mac80211_registered &&
+                           (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+                           (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) {
+                               if (agg->state == IWL_AGG_OFF)
+                                       iwl_wake_queue(priv, txq_id);
+                               else
+                                       iwl_wake_queue(priv, txq->swq_id);
+                       }
+               }
+       } else {
+               BUG_ON(txq_id != txq->swq_id);
+
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
+               info->flags |= iwl_tx_status_to_mac80211(status);
+               iwlagn_hwrate_to_tx_control(priv,
+                                       le32_to_cpu(tx_resp->rate_n_flags),
+                                       info);
+
+               IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
+                                  "0x%x retries %d\n",
+                                  txq_id,
+                                  iwl_get_tx_fail_reason(status), status,
+                                  le32_to_cpu(tx_resp->rate_n_flags),
+                                  tx_resp->failure_frame);
+
+               freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+
+               if (priv->mac80211_registered &&
+                   (iwl_queue_space(&txq->q) > txq->q.low_mark))
+                       iwl_wake_queue(priv, txq_id);
+       }
+
+       iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
+
+       iwl_check_abort_status(priv, tx_resp->frame_count, status);
+}
+
+void iwlagn_rx_handler_setup(struct iwl_priv *priv)
+{
+       /* init calibration handlers */
+       priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
+                                       iwlagn_rx_calib_result;
+       priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
+                                       iwlagn_rx_calib_complete;
+       priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
+}
+
+void iwlagn_setup_deferred_work(struct iwl_priv *priv)
+{
+       /* in agn, the tx power calibration is done in uCode */
+       priv->disable_tx_power_cal = 1;
+}
+
+int iwlagn_hw_valid_rtc_data_addr(u32 addr)
+{
+       return (addr >= IWLAGN_RTC_DATA_LOWER_BOUND) &&
+               (addr < IWLAGN_RTC_DATA_UPPER_BOUND);
+}
+
+int iwlagn_send_tx_power(struct iwl_priv *priv)
+{
+       struct iwl5000_tx_power_dbm_cmd tx_power_cmd;
+       u8 tx_ant_cfg_cmd;
+
+       /* half dBm need to multiply */
+       tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt);
+
+       if (priv->tx_power_lmt_in_half_dbm &&
+           priv->tx_power_lmt_in_half_dbm < tx_power_cmd.global_lmt) {
+               /*
+                * For the newer devices which using enhanced/extend tx power
+                * table in EEPROM, the format is in half dBm. driver need to
+                * convert to dBm format before report to mac80211.
+                * By doing so, there is a possibility of 1/2 dBm resolution
+                * lost. driver will perform "round-up" operation before
+                * reporting, but it will cause 1/2 dBm tx power over the
+                * regulatory limit. Perform the checking here, if the
+                * "tx_power_user_lmt" is higher than EEPROM value (in
+                * half-dBm format), lower the tx power based on EEPROM
+                */
+               tx_power_cmd.global_lmt = priv->tx_power_lmt_in_half_dbm;
+       }
+       tx_power_cmd.flags = IWL50_TX_POWER_NO_CLOSED;
+       tx_power_cmd.srv_chan_lmt = IWL50_TX_POWER_AUTO;
+
+       if (IWL_UCODE_API(priv->ucode_ver) == 1)
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD_V1;
+       else
+               tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD;
+
+       return  iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd,
+                                      sizeof(tx_power_cmd), &tx_power_cmd,
+                                      NULL);
+}
+
+void iwlagn_temperature(struct iwl_priv *priv)
+{
+       /* store temperature from statistics (in Celsius) */
+       priv->temperature = le32_to_cpu(priv->statistics.general.temperature);
+       iwl_tt_handler(priv);
+}
+
+u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv)
+{
+       struct iwl_eeprom_calib_hdr {
+               u8 version;
+               u8 pa_type;
+               u16 voltage;
+       } *hdr;
+
+       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
+                                                       EEPROM_CALIB_ALL);
+       return hdr->version;
+
+}
+
+/*
+ * EEPROM
+ */
+static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address)
+{
+       u16 offset = 0;
+
+       if ((address & INDIRECT_ADDRESS) == 0)
+               return address;
+
+       switch (address & INDIRECT_TYPE_MSK) {
+       case INDIRECT_HOST:
+               offset = iwl_eeprom_query16(priv, EEPROM_LINK_HOST);
+               break;
+       case INDIRECT_GENERAL:
+               offset = iwl_eeprom_query16(priv, EEPROM_LINK_GENERAL);
+               break;
+       case INDIRECT_REGULATORY:
+               offset = iwl_eeprom_query16(priv, EEPROM_LINK_REGULATORY);
+               break;
+       case INDIRECT_CALIBRATION:
+               offset = iwl_eeprom_query16(priv, EEPROM_LINK_CALIBRATION);
+               break;
+       case INDIRECT_PROCESS_ADJST:
+               offset = iwl_eeprom_query16(priv, EEPROM_LINK_PROCESS_ADJST);
+               break;
+       case INDIRECT_OTHERS:
+               offset = iwl_eeprom_query16(priv, EEPROM_LINK_OTHERS);
+               break;
+       default:
+               IWL_ERR(priv, "illegal indirect type: 0x%X\n",
+               address & INDIRECT_TYPE_MSK);
+               break;
+       }
+
+       /* translate the offset from words to byte */
+       return (address & ADDRESS_MSK) + (offset << 1);
+}
+
+const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
+                                          size_t offset)
+{
+       u32 address = eeprom_indirect_address(priv, offset);
+       BUG_ON(address >= priv->cfg->eeprom_size);
+       return &priv->eeprom[address];
+}
+
+struct iwl_mod_params iwlagn_mod_params = {
+       .amsdu_size_8K = 1,
+       .restart_fw = 1,
+       /* the rest are 0 by default */
+};
+
+void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       unsigned long flags;
+       int i;
+       spin_lock_irqsave(&rxq->lock, flags);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+               /* In the reset function, these buffers may have been allocated
+                * to an SKB, so we need to unmap and free potential storage */
+               if (rxq->pool[i].page != NULL) {
+                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+                               PAGE_SIZE << priv->hw_params.rx_page_order,
+                               PCI_DMA_FROMDEVICE);
+                       __iwl_free_pages(priv, rxq->pool[i].page);
+                       rxq->pool[i].page = NULL;
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+
+       for (i = 0; i < RX_QUEUE_SIZE; i++)
+               rxq->queue[i] = NULL;
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->write_actual = 0;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       u32 rb_size;
+       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+       u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
+
+       if (!priv->cfg->use_isr_legacy)
+               rb_timeout = RX_RB_TIMEOUT;
+
+       if (priv->cfg->mod_params->amsdu_size_8K)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+       /* Stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+       /* Reset driver's Rx queue write index */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+       /* Tell device where to find RBD circular buffer in DRAM */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+                          (u32)(rxq->dma_addr >> 8));
+
+       /* Tell device where in DRAM to update its Rx status */
+       iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+                          rxq->rb_stts_dma >> 4);
+
+       /* Enable Rx DMA
+        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+        *      the credit mechanism in 5000 HW RX FIFO
+        * Direct rx interrupts to hosts
+        * Rx buffer size 4 or 8k
+        * RB timeout 0x10
+        * 256 RBDs
+        */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
+                          rb_size|
+                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+
+       return 0;
+}
+
+int iwlagn_hw_nic_init(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       int ret;
+
+       /* nic_init */
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->cfg->ops->lib->apm_ops.init(priv);
+
+       /* Set interrupt coalescing calibration timer to default (512 usecs) */
+       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
+
+       priv->cfg->ops->lib->apm_ops.config(priv);
+
+       /* Allocate the RX queue, or reset if it is already allocated */
+       if (!rxq->bd) {
+               ret = iwl_rx_queue_alloc(priv);
+               if (ret) {
+                       IWL_ERR(priv, "Unable to initialize Rx queue\n");
+                       return -ENOMEM;
+               }
+       } else
+               iwlagn_rx_queue_reset(priv, rxq);
+
+       iwlagn_rx_replenish(priv);
+
+       iwlagn_rx_init(priv, rxq);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       rxq->need_update = 1;
+       iwl_rx_queue_update_write_ptr(priv, rxq);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Allocate or reset and init all Tx and Command queues */
+       if (!priv->txq) {
+               ret = iwlagn_txq_ctx_alloc(priv);
+               if (ret)
+                       return ret;
+       } else
+               iwlagn_txq_ctx_reset(priv);
+
+       set_bit(STATUS_INIT, &priv->status);
+
+       return 0;
+}
+
+/**
+ * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwlagn_dma_addr2rbd_ptr(struct iwl_priv *priv,
+                                         dma_addr_t dma_addr)
+{
+       return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/**
+ * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can, pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+void iwlagn_rx_queue_restock(struct iwl_priv *priv)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+               /* The overwritten rxb must be a used one */
+               rxb = rxq->queue[rxq->write];
+               BUG_ON(rxb && rxb->page);
+
+               /* Get next free Rx buffer, remove from free list */
+               element = rxq->rx_free.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               /* Point to Rx buffer via next RBD in circular buffer */
+               rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(priv,
+                                                             rxb->page_dma);
+               rxq->queue[rxq->write] = rxb;
+               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+               rxq->free_count--;
+       }
+       spin_unlock_irqrestore(&rxq->lock, flags);
+       /* If the pre-allocated buffer pool is dropping low, schedule to
+        * refill it */
+       if (rxq->free_count <= RX_LOW_WATERMARK)
+               queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+       /* If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8. */
+       if (rxq->write_actual != (rxq->write & ~0x7)) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               rxq->need_update = 1;
+               spin_unlock_irqrestore(&rxq->lock, flags);
+               iwl_rx_queue_update_write_ptr(priv, rxq);
+       }
+}
+
+/**
+ * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during initialization)
+ */
+void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority)
+{
+       struct iwl_rx_queue *rxq = &priv->rxq;
+       struct list_head *element;
+       struct iwl_rx_mem_buffer *rxb;
+       struct page *page;
+       unsigned long flags;
+       gfp_t gfp_mask = priority;
+
+       while (1) {
+               spin_lock_irqsave(&rxq->lock, flags);
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       return;
+               }
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               if (rxq->free_count > RX_LOW_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
+
+               if (priv->hw_params.rx_page_order > 0)
+                       gfp_mask |= __GFP_COMP;
+
+               /* Alloc a new receive buffer */
+               page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
+               if (!page) {
+                       if (net_ratelimit())
+                               IWL_DEBUG_INFO(priv, "alloc_pages failed, "
+                                              "order: %d\n",
+                                              priv->hw_params.rx_page_order);
+
+                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+                           net_ratelimit())
+                               IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
+                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
+                                        rxq->free_count);
+                       /* We don't reschedule replenish work here -- we will
+                        * call the restock method and if it still needs
+                        * more buffers it will schedule replenish */
+                       return;
+               }
+
+               spin_lock_irqsave(&rxq->lock, flags);
+
+               if (list_empty(&rxq->rx_used)) {
+                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       __free_pages(page, priv->hw_params.rx_page_order);
+                       return;
+               }
+               element = rxq->rx_used.next;
+               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+               list_del(element);
+
+               spin_unlock_irqrestore(&rxq->lock, flags);
+
+               BUG_ON(rxb->page);
+               rxb->page = page;
+               /* Get physical address of the RB */
+               rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
+                               PAGE_SIZE << priv->hw_params.rx_page_order,
+                               PCI_DMA_FROMDEVICE);
+               /* dma address must be no more than 36 bits */
+               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
+               /* and also 256 byte aligned! */
+               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
+
+               spin_lock_irqsave(&rxq->lock, flags);
+
+               list_add_tail(&rxb->list, &rxq->rx_free);
+               rxq->free_count++;
+               priv->alloc_rxb_page++;
+
+               spin_unlock_irqrestore(&rxq->lock, flags);
+       }
+}
+
+void iwlagn_rx_replenish(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       iwlagn_rx_allocate(priv, GFP_KERNEL);
+
+       spin_lock_irqsave(&priv->lock, flags);
+       iwlagn_rx_queue_restock(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void iwlagn_rx_replenish_now(struct iwl_priv *priv)
+{
+       iwlagn_rx_allocate(priv, GFP_ATOMIC);
+
+       iwlagn_rx_queue_restock(priv);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have its SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+       int i;
+       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+               if (rxq->pool[i].page != NULL) {
+                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
+                               PAGE_SIZE << priv->hw_params.rx_page_order,
+                               PCI_DMA_FROMDEVICE);
+                       __iwl_free_pages(priv, rxq->pool[i].page);
+                       rxq->pool[i].page = NULL;
+               }
+       }
+
+       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+                         rxq->dma_addr);
+       dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
+                         rxq->rb_stts, rxq->rb_stts_dma);
+       rxq->bd = NULL;
+       rxq->rb_stts  = NULL;
+}
+
+int iwlagn_rxq_stop(struct iwl_priv *priv)
+{
+
+       /* stop Rx DMA */
+       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+
+       return 0;
+}
+
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
+{
+       int idx = 0;
+       int band_offset = 0;
+
+       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
+       if (rate_n_flags & RATE_MCS_HT_MSK) {
+               idx = (rate_n_flags & 0xff);
+               return idx;
+       /* Legacy rate format, search for match in table */
+       } else {
+               if (band == IEEE80211_BAND_5GHZ)
+                       band_offset = IWL_FIRST_OFDM_RATE;
+               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
+                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+                               return idx - band_offset;
+       }
+
+       return -1;
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static inline int iwlagn_calc_rssi(struct iwl_priv *priv,
+                               struct iwl_rx_phy_res *rx_resp)
+{
+       return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+/**
+ * iwlagn_dbg_report_frame - dump frame to syslog during debug sessions
+ *
+ * You may hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good data frames.
+ *    All beacon and probe response frames are printed.
+ */
+static void iwlagn_dbg_report_frame(struct iwl_priv *priv,
+                     struct iwl_rx_phy_res *phy_res, u16 length,
+                     struct ieee80211_hdr *header, int group100)
+{
+       u32 to_us;
+       u32 print_summary = 0;
+       u32 print_dump = 0;     /* set to 1 to dump all frames' contents */
+       u32 hundred = 0;
+       u32 dataframe = 0;
+       __le16 fc;
+       u16 seq_ctl;
+       u16 channel;
+       u16 phy_flags;
+       u32 rate_n_flags;
+       u32 tsf_low;
+       int rssi;
+
+       if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
+               return;
+
+       /* MAC header */
+       fc = header->frame_control;
+       seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+       /* metadata */
+       channel = le16_to_cpu(phy_res->channel);
+       phy_flags = le16_to_cpu(phy_res->phy_flags);
+       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
+
+       /* signal statistics */
+       rssi = iwlagn_calc_rssi(priv, phy_res);
+       tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
+
+       to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+       /* if data frame is to us and all is good,
+        *   (optionally) print summary for only 1 out of every 100 */
+       if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
+           cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+               dataframe = 1;
+               if (!group100)
+                       print_summary = 1;      /* print each frame */
+               else if (priv->framecnt_to_us < 100) {
+                       priv->framecnt_to_us++;
+                       print_summary = 0;
+               } else {
+                       priv->framecnt_to_us = 0;
+                       print_summary = 1;
+                       hundred = 1;
+               }
+       } else {
+               /* print summary for all other frames */
+               print_summary = 1;
+       }
+
+       if (print_summary) {
+               char *title;
+               int rate_idx;
+               u32 bitrate;
+
+               if (hundred)
+                       title = "100Frames";
+               else if (ieee80211_has_retry(fc))
+                       title = "Retry";
+               else if (ieee80211_is_assoc_resp(fc))
+                       title = "AscRsp";
+               else if (ieee80211_is_reassoc_resp(fc))
+                       title = "RasRsp";
+               else if (ieee80211_is_probe_resp(fc)) {
+                       title = "PrbRsp";
+                       print_dump = 1; /* dump frame contents */
+               } else if (ieee80211_is_beacon(fc)) {
+                       title = "Beacon";
+                       print_dump = 1; /* dump frame contents */
+               } else if (ieee80211_is_atim(fc))
+                       title = "ATIM";
+               else if (ieee80211_is_auth(fc))
+                       title = "Auth";
+               else if (ieee80211_is_deauth(fc))
+                       title = "DeAuth";
+               else if (ieee80211_is_disassoc(fc))
+                       title = "DisAssoc";
+               else
+                       title = "Frame";
+
+               rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
+               if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
+                       bitrate = 0;
+                       WARN_ON_ONCE(1);
+               } else {
+                       bitrate = iwl_rates[rate_idx].ieee / 2;
+               }
+
+               /* print frame summary.
+                * MAC addresses show just the last byte (for brevity),
+                *    but you can hack it to show more, if you'd like to. */
+               if (dataframe)
+                       IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
+                                    "len=%u, rssi=%d, chnl=%d, rate=%u,\n",
+                                    title, le16_to_cpu(fc), header->addr1[5],
+                                    length, rssi, channel, bitrate);
+               else {
+                       /* src/dst addresses assume managed mode */
+                       IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
+                                    "len=%u, rssi=%d, tim=%lu usec, "
+                                    "phy=0x%02x, chnl=%d\n",
+                                    title, le16_to_cpu(fc), header->addr1[5],
+                                    header->addr3[5], length, rssi,
+                                    tsf_low - priv->scan_start_tsf,
+                                    phy_flags, channel);
+               }
+       }
+       if (print_dump)
+               iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
+}
+#endif
+
+static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
+{
+       u32 decrypt_out = 0;
+
+       if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
+                                       RX_RES_STATUS_STATION_FOUND)
+               decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
+                               RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
+
+       decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
+
+       /* packet was not encrypted */
+       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+                                       RX_RES_STATUS_SEC_TYPE_NONE)
+               return decrypt_out;
+
+       /* packet was encrypted with unknown alg */
+       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+                                       RX_RES_STATUS_SEC_TYPE_ERR)
+               return decrypt_out;
+
+       /* decryption was not done in HW */
+       if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
+                                       RX_MPDU_RES_STATUS_DEC_DONE_MSK)
+               return decrypt_out;
+
+       switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
+
+       case RX_RES_STATUS_SEC_TYPE_CCMP:
+               /* alg is CCM: check MIC only */
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
+                       /* Bad MIC */
+                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+               else
+                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+
+               break;
+
+       case RX_RES_STATUS_SEC_TYPE_TKIP:
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
+                       /* Bad TTAK */
+                       decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
+                       break;
+               }
+               /* fall through if TTAK OK */
+       default:
+               if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
+                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+               else
+                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+               break;
+       }
+
+       IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
+                                       decrypt_in, decrypt_out);
+
+       return decrypt_out;
+}
+
+static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
+                                       struct ieee80211_hdr *hdr,
+                                       u16 len,
+                                       u32 ampdu_status,
+                                       struct iwl_rx_mem_buffer *rxb,
+                                       struct ieee80211_rx_status *stats)
+{
+       struct sk_buff *skb;
+       __le16 fc = hdr->frame_control;
+
+       /* We only process data packets if the interface is open */
+       if (unlikely(!priv->is_open)) {
+               IWL_DEBUG_DROP_LIMIT(priv,
+                   "Dropping packet while interface is not open.\n");
+               return;
+       }
+
+       /* In case of HW accelerated crypto and bad decryption, drop */
+       if (!priv->cfg->mod_params->sw_crypto &&
+           iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
+               return;
+
+       skb = dev_alloc_skb(128);
+       if (!skb) {
+               IWL_ERR(priv, "dev_alloc_skb failed\n");
+               return;
+       }
+
+       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
+
+       iwl_update_stats(priv, false, fc, len);
+       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+       ieee80211_rx(priv->hw, skb);
+       priv->alloc_rxb_page--;
+       rxb->page = NULL;
+}
+
+/* Called for REPLY_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+void iwlagn_rx_reply_rx(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb)
+{
+       struct ieee80211_hdr *header;
+       struct ieee80211_rx_status rx_status;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_rx_phy_res *phy_res;
+       __le32 rx_pkt_status;
+       struct iwl4965_rx_mpdu_res_start *amsdu;
+       u32 len;
+       u32 ampdu_status;
+       u32 rate_n_flags;
+
+       /**
+        * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
+        *      REPLY_RX: physical layer info is in this buffer
+        *      REPLY_RX_MPDU_CMD: physical layer info was sent in separate
+        *              command and cached in priv->last_phy_res
+        *
+        * Here we set up local variables depending on which command is
+        * received.
+        */
+       if (pkt->hdr.cmd == REPLY_RX) {
+               phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
+               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
+                               + phy_res->cfg_phy_cnt);
+
+               len = le16_to_cpu(phy_res->byte_count);
+               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
+                               phy_res->cfg_phy_cnt + len);
+               ampdu_status = le32_to_cpu(rx_pkt_status);
+       } else {
+               if (!priv->_agn.last_phy_res_valid) {
+                       IWL_ERR(priv, "MPDU frame without cached PHY data\n");
+                       return;
+               }
+               phy_res = &priv->_agn.last_phy_res;
+               amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
+               len = le16_to_cpu(amsdu->byte_count);
+               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
+               ampdu_status = iwlagn_translate_rx_status(priv,
+                               le32_to_cpu(rx_pkt_status));
+       }
+
+       if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
+               IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
+                               phy_res->cfg_phy_cnt);
+               return;
+       }
+
+       if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
+           !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+               IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
+                               le32_to_cpu(rx_pkt_status));
+               return;
+       }
+
+       /* This will be used in several places later */
+       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
+
+       /* rx_status carries information about the packet to mac80211 */
+       rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+       rx_status.freq =
+               ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
+       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+       rx_status.rate_idx =
+               iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
+       rx_status.flag = 0;
+
+       /* TSF isn't reliable. In order to allow smooth user experience,
+        * this W/A doesn't propagate it to the mac80211 */
+       /*rx_status.flag |= RX_FLAG_TSFT;*/
+
+       priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
+
+       /* Find max signal strength (dBm) among 3 antenna/receiver chains */
+       rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       /* Set "1" to report good data frames in groups of 100 */
+       if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
+               iwlagn_dbg_report_frame(priv, phy_res, len, header, 1);
+#endif
+       iwl_dbg_log_rx_data_frame(priv, len, header);
+       IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
+               rx_status.signal, (unsigned long long)rx_status.mactime);
+
+       /*
+        * "antenna number"
+        *
+        * It seems that the antenna field in the phy flags value
+        * is actually a bit field. This is undefined by radiotap,
+        * it wants an actual antenna number but I always get "7"
+        * for most legacy frames I receive indicating that the
+        * same frame was received on all three RX chains.
+        *
+        * I think this field should be removed in favor of a
+        * new 802.11n radiotap field "RX chains" that is defined
+        * as a bitmask.
+        */
+       rx_status.antenna =
+               (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+               >> RX_RES_PHY_FLAGS_ANTENNA_POS;
+
+       /* set the preamble flag if appropriate */
+       if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+               rx_status.flag |= RX_FLAG_SHORTPRE;
+
+       /* Set up the HT phy flags */
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+               rx_status.flag |= RX_FLAG_HT;
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
+               rx_status.flag |= RX_FLAG_40MHZ;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               rx_status.flag |= RX_FLAG_SHORT_GI;
+
+       iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status,
+                                   rxb, &rx_status);
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+                           struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       priv->_agn.last_phy_res_valid = true;
+       memcpy(&priv->_agn.last_phy_res, pkt->u.raw,
+              sizeof(struct iwl_rx_phy_res));
+}
+
+static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
+                                          struct ieee80211_vif *vif,
+                                          enum ieee80211_band band,
+                                          struct iwl_scan_channel *scan_ch)
+{
+       const struct ieee80211_supported_band *sband;
+       const struct iwl_channel_info *ch_info;
+       u16 passive_dwell = 0;
+       u16 active_dwell = 0;
+       int i, added = 0;
+       u16 channel = 0;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband) {
+               IWL_ERR(priv, "invalid band\n");
+               return added;
+       }
+
+       active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
+
+       if (passive_dwell <= active_dwell)
+               passive_dwell = active_dwell + 1;
+
+       /* only scan single channel, good enough to reset the RF */
+       /* pick the first valid not in-use channel */
+       if (band == IEEE80211_BAND_5GHZ) {
+               for (i = 14; i < priv->channel_count; i++) {
+                       if (priv->channel_info[i].channel !=
+                           le16_to_cpu(priv->staging_rxon.channel)) {
+                               channel = priv->channel_info[i].channel;
+                               ch_info = iwl_get_channel_info(priv,
+                                       band, channel);
+                               if (is_channel_valid(ch_info))
+                                       break;
+                       }
+               }
+       } else {
+               for (i = 0; i < 14; i++) {
+                       if (priv->channel_info[i].channel !=
+                           le16_to_cpu(priv->staging_rxon.channel)) {
+                                       channel =
+                                               priv->channel_info[i].channel;
+                                       ch_info = iwl_get_channel_info(priv,
+                                               band, channel);
+                                       if (is_channel_valid(ch_info))
+                                               break;
+                       }
+               }
+       }
+       if (channel) {
+               scan_ch->channel = cpu_to_le16(channel);
+               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               scan_ch->active_dwell = cpu_to_le16(active_dwell);
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+               added++;
+       } else
+               IWL_ERR(priv, "no valid channel found\n");
+       return added;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv,
+                                    struct ieee80211_vif *vif,
+                                    enum ieee80211_band band,
+                                    u8 is_active, u8 n_probes,
+                                    struct iwl_scan_channel *scan_ch)
+{
+       struct ieee80211_channel *chan;
+       const struct ieee80211_supported_band *sband;
+       const struct iwl_channel_info *ch_info;
+       u16 passive_dwell = 0;
+       u16 active_dwell = 0;
+       int added, i;
+       u16 channel;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband)
+               return 0;
+
+       active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
+
+       if (passive_dwell <= active_dwell)
+               passive_dwell = active_dwell + 1;
+
+       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+               chan = priv->scan_request->channels[i];
+
+               if (chan->band != band)
+                       continue;
+
+               channel = ieee80211_frequency_to_channel(chan->center_freq);
+               scan_ch->channel = cpu_to_le16(channel);
+
+               ch_info = iwl_get_channel_info(priv, band, channel);
+               if (!is_channel_valid(ch_info)) {
+                       IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n",
+                                       channel);
+                       continue;
+               }
+
+               if (!is_active || is_channel_passive(ch_info) ||
+                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               else
+                       scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
+
+               if (n_probes)
+                       scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+
+               scan_ch->active_dwell = cpu_to_le16(active_dwell);
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+
+               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+                * power level:
+                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+                */
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+               IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
+                              channel, le32_to_cpu(scan_ch->type),
+                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+                               "ACTIVE" : "PASSIVE",
+                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+                              active_dwell : passive_dwell);
+
+               scan_ch++;
+               added++;
+       }
+
+       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
+       return added;
+}
+
+void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+{
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_SCAN_CMD,
+               .len = sizeof(struct iwl_scan_cmd),
+               .flags = CMD_SIZE_HUGE,
+       };
+       struct iwl_scan_cmd *scan;
+       struct ieee80211_conf *conf = NULL;
+       u32 rate_flags = 0;
+       u16 cmd_len;
+       u16 rx_chain = 0;
+       enum ieee80211_band band;
+       u8 n_probes = 0;
+       u8 rx_ant = priv->hw_params.valid_rx_ant;
+       u8 rate;
+       bool is_active = false;
+       int  chan_mod;
+       u8 active_chains;
+
+       conf = ieee80211_get_hw_conf(priv->hw);
+
+       cancel_delayed_work(&priv->scan_check);
+
+       if (!iwl_is_ready(priv)) {
+               IWL_WARN(priv, "request scan called when driver not ready.\n");
+               goto done;
+       }
+
+       /* Make sure the scan wasn't canceled before this queued work
+        * was given the chance to run... */
+       if (!test_bit(STATUS_SCANNING, &priv->status))
+               goto done;
+
+       /* This should never be called or scheduled if there is currently
+        * a scan active in the hardware. */
+       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+               IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests in parallel. "
+                              "Ignoring second request.\n");
+               goto done;
+       }
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+               IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
+               goto done;
+       }
+
+       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+               IWL_DEBUG_HC(priv, "Scan request while abort pending.  Queuing.\n");
+               goto done;
+       }
+
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
+               goto done;
+       }
+
+       if (!test_bit(STATUS_READY, &priv->status)) {
+               IWL_DEBUG_HC(priv, "Scan request while uninitialized.  Queuing.\n");
+               goto done;
+       }
+
+       if (!priv->scan_cmd) {
+               priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
+                                        IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+               if (!priv->scan_cmd) {
+                       IWL_DEBUG_SCAN(priv,
+                                      "fail to allocate memory for scan\n");
+                       goto done;
+               }
+       }
+       scan = priv->scan_cmd;
+       memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+       if (iwl_is_associated(priv)) {
+               u16 interval = 0;
+               u32 extra;
+               u32 suspend_time = 100;
+               u32 scan_suspend_time = 100;
+               unsigned long flags;
+
+               IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
+               spin_lock_irqsave(&priv->lock, flags);
+               interval = vif ? vif->bss_conf.beacon_int : 0;
+               spin_unlock_irqrestore(&priv->lock, flags);
+
+               scan->suspend_time = 0;
+               scan->max_out_time = cpu_to_le32(200 * 1024);
+               if (!interval)
+                       interval = suspend_time;
+
+               extra = (suspend_time / interval) << 22;
+               scan_suspend_time = (extra |
+                   ((suspend_time % interval) * 1024));
+               scan->suspend_time = cpu_to_le32(scan_suspend_time);
+               IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
+                              scan_suspend_time, interval);
+       }
+
+       if (priv->is_internal_short_scan) {
+               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+       } else if (priv->scan_request->n_ssids) {
+               int i, p = 0;
+               IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+               for (i = 0; i < priv->scan_request->n_ssids; i++) {
+                       /* always does wildcard anyway */
+                       if (!priv->scan_request->ssids[i].ssid_len)
+                               continue;
+                       scan->direct_scan[p].id = WLAN_EID_SSID;
+                       scan->direct_scan[p].len =
+                               priv->scan_request->ssids[i].ssid_len;
+                       memcpy(scan->direct_scan[p].ssid,
+                              priv->scan_request->ssids[i].ssid,
+                              priv->scan_request->ssids[i].ssid_len);
+                       n_probes++;
+                       p++;
+               }
+               is_active = true;
+       } else
+               IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
+
+       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
+       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+       switch (priv->scan_band) {
+       case IEEE80211_BAND_2GHZ:
+               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+               chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK)
+                                      >> RXON_FLG_CHANNEL_MODE_POS;
+               if (chan_mod == CHANNEL_MODE_PURE_40) {
+                       rate = IWL_RATE_6M_PLCP;
+               } else {
+                       rate = IWL_RATE_1M_PLCP;
+                       rate_flags = RATE_MCS_CCK_MSK;
+               }
+               scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
+               break;
+       case IEEE80211_BAND_5GHZ:
+               rate = IWL_RATE_6M_PLCP;
+               /*
+                * If active scanning is requested but a certain channel is
+                * marked passive, we can do active scanning if we detect
+                * transmissions.
+                *
+                * There is an issue with some firmware versions that triggers
+                * a sysassert on a "good CRC threshold" of zero (== disabled),
+                * on a radar channel even though this means that we should NOT
+                * send probes.
+                *
+                * The "good CRC threshold" is the number of frames that we
+                * need to receive during our dwell time on a channel before
+                * sending out probes -- setting this to a huge value will
+                * mean we never reach it, but at the same time work around
+                * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+                * here instead of IWL_GOOD_CRC_TH_DISABLED.
+                */
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_NEVER;
+               break;
+       default:
+               IWL_WARN(priv, "Invalid scan band count\n");
+               goto done;
+       }
+
+       band = priv->scan_band;
+
+       if (priv->cfg->scan_antennas[band])
+               rx_ant = priv->cfg->scan_antennas[band];
+
+       priv->scan_tx_ant[band] =
+                       iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
+       rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
+       scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
+
+       /* In power save mode use one chain, otherwise use all chains */
+       if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+               /* rx_ant has been set to all valid chains previously */
+               active_chains = rx_ant &
+                               ((u8)(priv->chain_noise_data.active_chains));
+               if (!active_chains)
+                       active_chains = rx_ant;
+
+               IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
+                               priv->chain_noise_data.active_chains);
+
+               rx_ant = first_antenna(active_chains);
+       }
+       /* MIMO is not used here, but value is required */
+       rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
+       rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+       scan->rx_chain = cpu_to_le16(rx_chain);
+       if (!priv->is_internal_short_scan) {
+               cmd_len = iwl_fill_probe_req(priv,
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       priv->scan_request->ie,
+                                       priv->scan_request->ie_len,
+                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
+       } else {
+               cmd_len = iwl_fill_probe_req(priv,
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       NULL, 0,
+                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
+
+       }
+       scan->tx_cmd.len = cpu_to_le16(cmd_len);
+
+       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+                              RXON_FILTER_BCON_AWARE_MSK);
+
+       if (priv->is_internal_short_scan) {
+               scan->channel_count =
+                       iwl_get_single_channel_for_scan(priv, vif, band,
+                               (void *)&scan->data[le16_to_cpu(
+                               scan->tx_cmd.len)]);
+       } else {
+               scan->channel_count =
+                       iwl_get_channels_for_scan(priv, vif, band,
+                               is_active, n_probes,
+                               (void *)&scan->data[le16_to_cpu(
+                               scan->tx_cmd.len)]);
+       }
+       if (scan->channel_count == 0) {
+               IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
+               goto done;
+       }
+
+       cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+           scan->channel_count * sizeof(struct iwl_scan_channel);
+       cmd.data = scan;
+       scan->len = cpu_to_le16(cmd.len);
+
+       set_bit(STATUS_SCAN_HW, &priv->status);
+       if (iwl_send_cmd_sync(priv, &cmd))
+               goto done;
+
+       queue_delayed_work(priv->workqueue, &priv->scan_check,
+                          IWL_SCAN_CHECK_WATCHDOG);
+
+       return;
+
+ done:
+       /* Cannot perform scan. Make sure we clear scanning
+       * bits from status so next scan request can be performed.
+       * If we don't clear scanning status bit here all next scan
+       * will fail
+       */
+       clear_bit(STATUS_SCAN_HW, &priv->status);
+       clear_bit(STATUS_SCANNING, &priv->status);
+       /* inform mac80211 scan aborted */
+       queue_work(priv->workqueue, &priv->scan_completed);
+}
+
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif, bool add)
+{
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+
+       if (add)
+               return iwl_add_bssid_station(priv, vif->bss_conf.bssid, true,
+                                            &vif_priv->ibss_bssid_sta_id);
+       return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
+                                 vif->bss_conf.bssid);
+}
index 1460116d329f2c65b39d88ed295069295648b1f2..cf4a95bae4ffb1369ca5a192919a5caf0445f8cc 100644 (file)
@@ -295,11 +295,11 @@ static u32 rs_tl_get_load(struct iwl_lq_sta *lq_data, u8 tid)
        return tl->total;
 }
 
-static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
+static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
                                      struct iwl_lq_sta *lq_data, u8 tid,
                                      struct ieee80211_sta *sta)
 {
-       int ret;
+       int ret = -EAGAIN;
 
        if (rs_tl_get_load(lq_data, tid) > IWL_AGG_LOAD_THRESHOLD) {
                IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n",
@@ -313,29 +313,29 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
                         */
                        IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
                                tid);
-                       ret = ieee80211_stop_tx_ba_session(sta, tid,
+                       ieee80211_stop_tx_ba_session(sta, tid,
                                                WLAN_BACK_INITIATOR);
                }
-       }
+       } else
+               IWL_ERR(priv, "Fail finding valid aggregation tid: %d\n", tid);
+       return ret;
 }
 
 static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
                              struct iwl_lq_sta *lq_data,
                              struct ieee80211_sta *sta)
 {
-       if ((tid < TID_MAX_LOAD_COUNT))
-               rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
-       else if (tid == IWL_AGG_ALL_TID)
-               for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
-                       rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
-       if (priv->cfg->use_rts_for_ht) {
-               /*
-                * switch to RTS/CTS if it is the prefer protection method
-                * for HT traffic
-                */
-               IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
-               priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
-               iwlcore_commit_rxon(priv);
+       if ((tid < TID_MAX_LOAD_COUNT) &&
+           !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) {
+               if (priv->cfg->use_rts_for_ht) {
+                       /*
+                        * switch to RTS/CTS if it is the prefer protection
+                        * method for HT traffic
+                        */
+                       IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
+                       priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+                       iwlcore_commit_rxon(priv);
+               }
        }
 }
 
@@ -611,10 +611,6 @@ static u16 rs_get_supported_rates(struct iwl_lq_sta *lq_sta,
                                  struct ieee80211_hdr *hdr,
                                  enum iwl_table_type rate_type)
 {
-       if (hdr && is_multicast_ether_addr(hdr->addr1) &&
-           lq_sta->active_rate_basic)
-               return lq_sta->active_rate_basic;
-
        if (is_legacy(rate_type)) {
                return lq_sta->active_legacy_rate;
        } else {
@@ -775,6 +771,15 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
 
        IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
 
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (!lq_sta) {
+               IWL_DEBUG_RATE(priv, "Station rate scaling not created yet.\n");
+               return;
+       } else if (!lq_sta->drv) {
+               IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
+               return;
+       }
+
        if (!ieee80211_is_data(hdr->frame_control) ||
            info->flags & IEEE80211_TX_CTL_NO_ACK)
                return;
@@ -784,10 +789,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
            !(info->flags & IEEE80211_TX_STAT_AMPDU))
                return;
 
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-           !lq_sta->ibss_sta_added)
-               return;
-
        /*
         * Ignore this Tx frame response if its initial rate doesn't match
         * that of latest Link Quality command.  There may be stragglers
@@ -833,7 +834,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                lq_sta->missed_rate_counter++;
                if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
                        lq_sta->missed_rate_counter = 0;
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
                }
                /* Regardless, ignore this status info for outdated rate */
                return;
@@ -867,14 +868,14 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
                                &rs_index);
                rs_collect_tx_data(curr_tbl, rs_index,
-                                  info->status.ampdu_ack_len,
-                                  info->status.ampdu_ack_map);
+                                  info->status.ampdu_len,
+                                  info->status.ampdu_ack_len);
 
                /* Update success/fail counts if not searching for new mode */
                if (lq_sta->stay_in_tbl) {
-                       lq_sta->total_success += info->status.ampdu_ack_map;
-                       lq_sta->total_failed += (info->status.ampdu_ack_len -
-                                       info->status.ampdu_ack_map);
+                       lq_sta->total_success += info->status.ampdu_ack_len;
+                       lq_sta->total_failed += (info->status.ampdu_len -
+                                       info->status.ampdu_ack_len);
                }
        } else {
        /*
@@ -1913,7 +1914,7 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
        /* Update uCode's rate table. */
        rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
        rs_fill_link_cmd(priv, lq_sta, rate);
-       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
 
        return rate;
 }
@@ -2002,7 +2003,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        /* rates available for this association, and for modulation mode */
        rate_mask = rs_get_supported_rates(lq_sta, hdr, tbl->lq_type);
 
-       IWL_DEBUG_RATE(priv, "mask 0x%04X \n", rate_mask);
+       IWL_DEBUG_RATE(priv, "mask 0x%04X\n", rate_mask);
 
        /* mask with station rate restriction */
        if (is_legacy(tbl->lq_type)) {
@@ -2077,10 +2078,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        }
        /* Else we have enough samples; calculate estimate of
         * actual average throughput */
-
-       /* Sanity-check TPT calculations */
-       BUG_ON(window->average_tpt != ((window->success_ratio *
-                       tbl->expected_tpt[index] + 64) / 128));
+       if (window->average_tpt != ((window->success_ratio *
+                       tbl->expected_tpt[index] + 64) / 128)) {
+               IWL_ERR(priv, "expected_tpt should have been calculated by now\n");
+               window->average_tpt = ((window->success_ratio *
+                                       tbl->expected_tpt[index] + 64) / 128);
+       }
 
        /* If we are searching for better modulation mode, check success. */
        if (lq_sta->search_better_tbl &&
@@ -2289,7 +2292,7 @@ lq_update:
                        IWL_DEBUG_RATE(priv, "Switch current  mcs: %X index: %d\n",
                                     tbl->current_rate, index);
                        rs_fill_link_cmd(priv, lq_sta, tbl->current_rate);
-                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+                       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC, false);
                } else
                        done_search = 1;
        }
@@ -2334,11 +2337,22 @@ out:
        tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
        i = index;
        lq_sta->last_txrate_idx = i;
-
-       return;
 }
 
-
+/**
+ * rs_initialize_lq - Initialize a station's hardware rate table
+ *
+ * The uCode's station table contains a table of fallback rates
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This sets up a default set of values.  These will be replaced later
+ *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
+ *       rc80211_simple.
+ *
+ * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
+ *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
+ *       which requires station table entry to exist).
+ */
 static void rs_initialize_lq(struct iwl_priv *priv,
                             struct ieee80211_conf *conf,
                             struct ieee80211_sta *sta,
@@ -2357,10 +2371,6 @@ static void rs_initialize_lq(struct iwl_priv *priv,
 
        i = lq_sta->last_txrate_idx;
 
-       if ((lq_sta->lq.sta_id == 0xff) &&
-           (priv->iw_mode == NL80211_IFTYPE_ADHOC))
-               goto out;
-
        valid_tx_ant = priv->hw_params.valid_tx_ant;
 
        if (!lq_sta->search_better_tbl)
@@ -2388,7 +2398,8 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        tbl->current_rate = rate;
        rs_set_expected_tpt_table(lq_sta, tbl);
        rs_fill_link_cmd(NULL, lq_sta, rate);
-       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC);
+       priv->stations[lq_sta->lq.sta_id].lq = &lq_sta->lq;
+       iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_SYNC, true);
  out:
        return;
 }
@@ -2399,10 +2410,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
 
        struct sk_buff *skb = txrc->skb;
        struct ieee80211_supported_band *sband = txrc->sband;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
-       struct ieee80211_conf *conf = &priv->hw->conf;
-       struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct iwl_priv *priv __maybe_unused = (struct iwl_priv *)priv_r;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct iwl_lq_sta *lq_sta = priv_sta;
        int rate_idx;
@@ -2420,30 +2428,18 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
                        lq_sta->max_rate_idx = -1;
        }
 
+       /* Treat uninitialized rate scaling data same as non-existing. */
+       if (lq_sta && !lq_sta->drv) {
+               IWL_DEBUG_RATE(priv, "Rate scaling not initialized yet.\n");
+               priv_sta = NULL;
+       }
+
        /* Send management frames and NO_ACK data using lowest rate. */
        if (rate_control_send_low(sta, priv_sta, txrc))
                return;
 
        rate_idx  = lq_sta->last_txrate_idx;
 
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-           !lq_sta->ibss_sta_added) {
-               u8 sta_id = iwl_find_station(priv, hdr->addr1);
-
-               if (sta_id == IWL_INVALID_STATION) {
-                       IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
-                                      hdr->addr1);
-                       sta_id = iwl_add_station(priv, hdr->addr1,
-                                               false, CMD_ASYNC, ht_cap);
-               }
-               if ((sta_id != IWL_INVALID_STATION)) {
-                       lq_sta->lq.sta_id = sta_id;
-                       lq_sta->lq.rs_table[0].rate_n_flags = 0;
-                       lq_sta->ibss_sta_added = 1;
-                       rs_initialize_lq(priv, conf, sta, lq_sta);
-               }
-       }
-
        if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
                rate_idx -= IWL_FIRST_OFDM_RATE;
                /* 6M and 9M shared same MCS index */
@@ -2493,16 +2489,25 @@ static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
        return lq_sta;
 }
 
-static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta)
+/*
+ * Called after adding a new station to initialize rate scaling
+ */
+void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_id)
 {
        int i, j;
-       struct iwl_priv *priv = (struct iwl_priv *)priv_r;
+       struct ieee80211_hw *hw = priv->hw;
        struct ieee80211_conf *conf = &priv->hw->conf;
        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       struct iwl_lq_sta *lq_sta = priv_sta;
+       struct iwl_station_priv *sta_priv;
+       struct iwl_lq_sta *lq_sta;
+       struct ieee80211_supported_band *sband;
+
+       sta_priv = (struct iwl_station_priv *) sta->drv_priv;
+       lq_sta = &sta_priv->lq_sta;
+       sband = hw->wiphy->bands[conf->channel->band];
 
-       lq_sta->lq.sta_id = 0xff;
+
+       lq_sta->lq.sta_id = sta_id;
 
        for (j = 0; j < LQ_SIZE; j++)
                for (i = 0; i < IWL_RATE_COUNT; i++)
@@ -2514,39 +2519,18 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
                for (i = 0; i < IWL_RATE_COUNT; i++)
                        rs_rate_scale_clear_window(&lq_sta->lq_info[j].win[i]);
 
-       IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init ***\n");
+       IWL_DEBUG_RATE(priv, "LQ: *** rate scale station global init for station %d ***\n",
+                      sta_id);
        /* TODO: what is a good starting rate for STA? About middle? Maybe not
         * the lowest or the highest rate.. Could consider using RSSI from
         * previous packets? Need to have IEEE 802.1X auth succeed immediately
         * after assoc.. */
 
-       lq_sta->ibss_sta_added = 0;
-       if (priv->iw_mode == NL80211_IFTYPE_AP) {
-               u8 sta_id = iwl_find_station(priv,
-                                                               sta->addr);
-
-               /* for IBSS the call are from tasklet */
-               IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
-
-               if (sta_id == IWL_INVALID_STATION) {
-                       IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
-                       sta_id = iwl_add_station(priv, sta->addr, false,
-                                               CMD_ASYNC, ht_cap);
-               }
-               if ((sta_id != IWL_INVALID_STATION)) {
-                       lq_sta->lq.sta_id = sta_id;
-                       lq_sta->lq.rs_table[0].rate_n_flags = 0;
-               }
-               /* FIXME: this is w/a remove it later */
-               priv->assoc_station_added = 1;
-       }
-
        lq_sta->is_dup = 0;
        lq_sta->max_rate_idx = -1;
        lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
        lq_sta->is_green = rs_use_green(sta, &priv->current_ht_config);
        lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000);
-       lq_sta->active_rate_basic = priv->active_rate_basic;
        lq_sta->band = priv->band;
        /*
         * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
@@ -2574,8 +2558,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
                     lq_sta->active_mimo3_rate);
 
        /* These values will be overridden later */
-       lq_sta->lq.general_params.single_stream_ant_msk = ANT_A;
-       lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
+       lq_sta->lq.general_params.single_stream_ant_msk =
+               first_antenna(priv->hw_params.valid_tx_ant);
+       lq_sta->lq.general_params.dual_stream_ant_msk =
+               priv->hw_params.valid_tx_ant &
+               ~first_antenna(priv->hw_params.valid_tx_ant);
+       if (!lq_sta->lq.general_params.dual_stream_ant_msk) {
+               lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB;
+       } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
+               lq_sta->lq.general_params.dual_stream_ant_msk =
+                       priv->hw_params.valid_tx_ant;
+       }
 
        /* as default allow aggregation for all tids */
        lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
@@ -2794,7 +2787,7 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
 
        if (lq_sta->dbg_fixed_rate) {
                rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
-               iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC);
+               iwl_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC, false);
        }
 
        return count;
@@ -2950,12 +2943,6 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
                desc += sprintf(buff+desc,
                                "Bit Rate= %d Mb/s\n",
                                iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
-       desc += sprintf(buff+desc,
-                       "Signal Level= %d dBm\tNoise Level= %d dBm\n",
-                       priv->last_rx_rssi, priv->last_rx_noise);
-       desc += sprintf(buff+desc,
-                       "Tsf= 0x%llx\tBeacon time= 0x%08X\n",
-                       priv->last_tsf, priv->last_beacon_time);
 
        ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
        return ret;
@@ -2995,12 +2982,21 @@ static void rs_remove_debugfs(void *priv, void *priv_sta)
 }
 #endif
 
+/*
+ * Initialization of rate scaling information is done by driver after
+ * the station is added. Since mac80211 calls this function before a
+ * station is added we ignore it.
+ */
+static void rs_rate_init_stub(void *priv_r, struct ieee80211_supported_band *sband,
+                        struct ieee80211_sta *sta, void *priv_sta)
+{
+}
 static struct rate_control_ops rs_ops = {
        .module = NULL,
        .name = RS_NAME,
        .tx_status = rs_tx_status,
        .get_rate = rs_get_rate,
-       .rate_init = rs_rate_init,
+       .rate_init = rs_rate_init_stub,
        .alloc = rs_alloc,
        .free = rs_free,
        .alloc_sta = rs_alloc_sta,
index e71923961e691599f663dd5e279f3d1f07a5a5c3..8292f6d48ec62067cb5dec7f4076038ad0b46430 100644 (file)
@@ -403,7 +403,6 @@ struct iwl_lq_sta {
        u8 is_green;
        u8 is_dup;
        enum ieee80211_band band;
-       u8 ibss_sta_added;
 
        /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
        u32 supp_rates;
@@ -411,7 +410,6 @@ struct iwl_lq_sta {
        u16 active_siso_rate;
        u16 active_mimo2_rate;
        u16 active_mimo3_rate;
-       u16 active_rate_basic;
        s8 max_rate_idx;     /* Max rate set by user */
        u8 missed_rate_counter;
 
@@ -479,6 +477,12 @@ static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index)
  */
 extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
 
+/* Initialize station's rate scaling information after adding station */
+extern void iwl_rs_rate_init(struct iwl_priv *priv,
+                            struct ieee80211_sta *sta, u8 sta_id);
+extern void iwl3945_rs_rate_init(struct iwl_priv *priv,
+                                struct ieee80211_sta *sta, u8 sta_id);
+
 /**
  * iwl_rate_control_register - Register the rate control algorithm callbacks
  *
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
new file mode 100644 (file)
index 0000000..c402bfc
--- /dev/null
@@ -0,0 +1,1340 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-sta.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+/*
+ * mac80211 queues, ACs, hardware queues, FIFOs.
+ *
+ * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues
+ *
+ * Mac80211 uses the following numbers, which we get as from it
+ * by way of skb_get_queue_mapping(skb):
+ *
+ *     VO      0
+ *     VI      1
+ *     BE      2
+ *     BK      3
+ *
+ *
+ * Regular (not A-MPDU) frames are put into hardware queues corresponding
+ * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their
+ * own queue per aggregation session (RA/TID combination), such queues are
+ * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In
+ * order to map frames to the right queue, we also need an AC->hw queue
+ * mapping. This is implemented here.
+ *
+ * Due to the way hw queues are set up (by the hw specific modules like
+ * iwl-4965.c, iwl-5000.c etc.), the AC->hw queue mapping is the identity
+ * mapping.
+ */
+
+static const u8 tid_to_ac[] = {
+       /* this matches the mac80211 numbers */
+       2, 3, 3, 2, 1, 1, 0, 0
+};
+
+static const u8 ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+
+static inline int get_fifo_from_ac(u8 ac)
+{
+       return ac_to_fifo[ac];
+}
+
+static inline int get_ac_from_tid(u16 tid)
+{
+       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+               return tid_to_ac[tid];
+
+       /* no support for TIDs 8-15 yet */
+       return -EINVAL;
+}
+
+static inline int get_fifo_from_tid(u16 tid)
+{
+       if (likely(tid < ARRAY_SIZE(tid_to_ac)))
+               return get_fifo_from_ac(tid_to_ac[tid]);
+
+       /* no support for TIDs 8-15 yet */
+       return -EINVAL;
+}
+
+/**
+ * iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+ */
+void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+                                           struct iwl_tx_queue *txq,
+                                           u16 byte_cnt)
+{
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+       int write_ptr = txq->q.write_ptr;
+       int txq_id = txq->q.id;
+       u8 sec_ctl = 0;
+       u8 sta_id = 0;
+       u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+       __le16 bc_ent;
+
+       WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       if (txq_id != IWL_CMD_QUEUE_NUM) {
+               sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+               sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+
+               switch (sec_ctl & TX_CMD_SEC_MSK) {
+               case TX_CMD_SEC_CCM:
+                       len += CCMP_MIC_LEN;
+                       break;
+               case TX_CMD_SEC_TKIP:
+                       len += TKIP_ICV_LEN;
+                       break;
+               case TX_CMD_SEC_WEP:
+                       len += WEP_IV_LEN + WEP_ICV_LEN;
+                       break;
+               }
+       }
+
+       bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
+
+       scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent;
+
+       if (write_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
+}
+
+void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+                                          struct iwl_tx_queue *txq)
+{
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
+       int txq_id = txq->q.id;
+       int read_ptr = txq->q.read_ptr;
+       u8 sta_id = 0;
+       __le16 bc_ent;
+
+       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       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));
+       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
+
+       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+}
+
+static int iwlagn_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+                                       u16 txq_id)
+{
+       u32 tbl_dw_addr;
+       u32 tbl_dw;
+       u16 scd_q2ratid;
+
+       scd_q2ratid = ra_tid & IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+       tbl_dw_addr = priv->scd_base_addr +
+                       IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+
+       tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr);
+
+       if (txq_id & 0x1)
+               tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+       else
+               tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+       iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw);
+
+       return 0;
+}
+
+static void iwlagn_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+{
+       /* Simply stop the queue, but don't change any configuration;
+        * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
+       iwl_write_prph(priv,
+               IWLAGN_SCD_QUEUE_STATUS_BITS(txq_id),
+               (0 << IWLAGN_SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+               (1 << IWLAGN_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
+                               int txq_id, u32 index)
+{
+       iwl_write_direct32(priv, HBUS_TARG_WRPTR,
+                       (index & 0xff) | (txq_id << 8));
+       iwl_write_prph(priv, IWLAGN_SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
+                                       struct iwl_tx_queue *txq,
+                                       int tx_fifo_id, int scd_retry)
+{
+       int txq_id = txq->q.id;
+       int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0;
+
+       iwl_write_prph(priv, IWLAGN_SCD_QUEUE_STATUS_BITS(txq_id),
+                       (active << IWLAGN_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+                       (tx_fifo_id << IWLAGN_SCD_QUEUE_STTS_REG_POS_TXF) |
+                       (1 << IWLAGN_SCD_QUEUE_STTS_REG_POS_WSL) |
+                       IWLAGN_SCD_QUEUE_STTS_REG_MSK);
+
+       txq->sched_retry = scd_retry;
+
+       IWL_DEBUG_INFO(priv, "%s %s Queue %d on FIFO %d\n",
+                      active ? "Activate" : "Deactivate",
+                      scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
+}
+
+int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+                         int tx_fifo, int sta_id, int tid, u16 ssn_idx)
+{
+       unsigned long flags;
+       u16 ra_tid;
+
+       if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
+           (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+            <= txq_id)) {
+               IWL_WARN(priv,
+                       "queue number out of range: %d, must be %d to %d\n",
+                       txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
+                       IWLAGN_FIRST_AMPDU_QUEUE +
+                       priv->cfg->num_of_ampdu_queues - 1);
+               return -EINVAL;
+       }
+
+       ra_tid = BUILD_RAxTID(sta_id, tid);
+
+       /* Modify device's station table to Tx this TID */
+       iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Stop this Tx queue before configuring it */
+       iwlagn_tx_queue_stop_scheduler(priv, txq_id);
+
+       /* Map receiver-address / traffic-ID to this queue */
+       iwlagn_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+
+       /* Set this queue as a chain-building queue */
+       iwl_set_bits_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL, (1<<txq_id));
+
+       /* enable aggregations for the queue */
+       iwl_set_bits_prph(priv, IWLAGN_SCD_AGGR_SEL, (1<<txq_id));
+
+       /* Place first TFD at index corresponding to start sequence number.
+        * Assumes that ssn_idx is valid (!= 0xFFF) */
+       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+       iwlagn_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+       /* Set up Tx window size and frame limit for this queue */
+       iwl_write_targ_mem(priv, priv->scd_base_addr +
+                       IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
+                       sizeof(u32),
+                       ((SCD_WIN_SIZE <<
+                       IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                       IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                       ((SCD_FRAME_LIMIT <<
+                       IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                       IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+
+       iwl_set_bits_prph(priv, IWLAGN_SCD_INTERRUPT_MASK, (1 << txq_id));
+
+       /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */
+       iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+                          u16 ssn_idx, u8 tx_fifo)
+{
+       if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
+           (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues
+            <= txq_id)) {
+               IWL_ERR(priv,
+                       "queue number out of range: %d, must be %d to %d\n",
+                       txq_id, IWLAGN_FIRST_AMPDU_QUEUE,
+                       IWLAGN_FIRST_AMPDU_QUEUE +
+                       priv->cfg->num_of_ampdu_queues - 1);
+               return -EINVAL;
+       }
+
+       iwlagn_tx_queue_stop_scheduler(priv, txq_id);
+
+       iwl_clear_bits_prph(priv, IWLAGN_SCD_AGGR_SEL, (1 << txq_id));
+
+       priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff);
+       priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff);
+       /* supposes that ssn_idx is valid (!= 0xFFF) */
+       iwlagn_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+       iwl_clear_bits_prph(priv, IWLAGN_SCD_INTERRUPT_MASK, (1 << txq_id));
+       iwl_txq_ctx_deactivate(priv, txq_id);
+       iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+       return 0;
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->lock and mac access
+ */
+void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask)
+{
+       iwl_write_prph(priv, IWLAGN_SCD_TXFACT, mask);
+}
+
+static inline int get_queue_from_ac(u16 ac)
+{
+       return ac;
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv,
+                                 struct iwl_tx_cmd *tx_cmd,
+                                 struct ieee80211_tx_info *info,
+                                 struct ieee80211_hdr *hdr,
+                                 u8 std_id)
+{
+       __le16 fc = hdr->frame_control;
+       __le32 tx_flags = tx_cmd->tx_flags;
+
+       tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+               tx_flags |= TX_CMD_FLG_ACK_MSK;
+               if (ieee80211_is_mgmt(fc))
+                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+               if (ieee80211_is_probe_resp(fc) &&
+                   !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+                       tx_flags |= TX_CMD_FLG_TSF_MSK;
+       } else {
+               tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       if (ieee80211_is_back_req(fc))
+               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
+
+
+       tx_cmd->sta_id = std_id;
+       if (ieee80211_has_morefrags(fc))
+               tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+       if (ieee80211_is_data_qos(fc)) {
+               u8 *qc = ieee80211_get_qos_ctl(hdr);
+               tx_cmd->tid_tspec = qc[0] & 0xf;
+               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+       } else {
+               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+       }
+
+       priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
+
+       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+       tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+       if (ieee80211_is_mgmt(fc)) {
+               if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
+               else
+                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
+       } else {
+               tx_cmd->timeout.pm_frame_timeout = 0;
+       }
+
+       tx_cmd->driver_txop = 0;
+       tx_cmd->tx_flags = tx_flags;
+       tx_cmd->next_frame_len = 0;
+}
+
+#define RTS_DFAULT_RETRY_LIMIT         60
+
+static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
+                             struct iwl_tx_cmd *tx_cmd,
+                             struct ieee80211_tx_info *info,
+                             __le16 fc)
+{
+       u32 rate_flags;
+       int rate_idx;
+       u8 rts_retry_limit;
+       u8 data_retry_limit;
+       u8 rate_plcp;
+
+       /* Set retry limit on DATA packets and Probe Responses*/
+       if (ieee80211_is_probe_resp(fc))
+               data_retry_limit = 3;
+       else
+               data_retry_limit = IWLAGN_DEFAULT_TX_RETRY;
+       tx_cmd->data_retry_limit = data_retry_limit;
+
+       /* Set retry limit on RTS packets */
+       rts_retry_limit = RTS_DFAULT_RETRY_LIMIT;
+       if (data_retry_limit < rts_retry_limit)
+               rts_retry_limit = data_retry_limit;
+       tx_cmd->rts_retry_limit = rts_retry_limit;
+
+       /* DATA packets will use the uCode station table for rate/antenna
+        * selection */
+       if (ieee80211_is_data(fc)) {
+               tx_cmd->initial_rate_index = 0;
+               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+               return;
+       }
+
+       /**
+        * If the current TX rate stored in mac80211 has the MCS bit set, it's
+        * not really a TX rate.  Thus, we use the lowest supported rate for
+        * this band.  Also use the lowest supported rate if the stored rate
+        * index is invalid.
+        */
+       rate_idx = info->control.rates[0].idx;
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
+                       (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
+               rate_idx = rate_lowest_index(&priv->bands[info->band],
+                               info->control.sta);
+       /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
+       if (info->band == IEEE80211_BAND_5GHZ)
+               rate_idx += IWL_FIRST_OFDM_RATE;
+       /* Get PLCP rate for tx_cmd->rate_n_flags */
+       rate_plcp = iwl_rates[rate_idx].plcp;
+       /* Zero out flags for this packet */
+       rate_flags = 0;
+
+       /* Set CCK flag as needed */
+       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
+               rate_flags |= RATE_MCS_CCK_MSK;
+
+       /* Set up RTS and CTS flags for certain packets */
+       switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
+       case cpu_to_le16(IEEE80211_STYPE_AUTH):
+       case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
+       case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
+       case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
+               if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
+                       tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+                       tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
+               }
+               break;
+       default:
+               break;
+       }
+
+       /* Set up antennas */
+       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+       rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
+
+       /* Set the rate in the TX cmd */
+       tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
+}
+
+static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
+                                     struct ieee80211_tx_info *info,
+                                     struct iwl_tx_cmd *tx_cmd,
+                                     struct sk_buff *skb_frag,
+                                     int sta_id)
+{
+       struct ieee80211_key_conf *keyconf = info->control.hw_key;
+
+       switch (keyconf->alg) {
+       case ALG_CCMP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
+               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
+               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
+               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
+               break;
+
+       case ALG_TKIP:
+               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
+               ieee80211_get_tkip_key(keyconf, skb_frag,
+                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
+               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
+               break;
+
+       case ALG_WEP:
+               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
+                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
+
+               if (keyconf->keylen == WEP_KEY_LEN_128)
+                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
+
+               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
+
+               IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
+                            "with key %d\n", keyconf->keyidx);
+               break;
+
+       default:
+               IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
+               break;
+       }
+}
+
+/*
+ * start REPLY_TX command process
+ */
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = info->control.sta;
+       struct iwl_station_priv *sta_priv = NULL;
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       struct iwl_device_cmd *out_cmd;
+       struct iwl_cmd_meta *out_meta;
+       struct iwl_tx_cmd *tx_cmd;
+       int swq_id, txq_id;
+       dma_addr_t phys_addr;
+       dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
+       u16 len, len_org, firstlen, secondlen;
+       u16 seq_number = 0;
+       __le16 fc;
+       u8 hdr_len;
+       u8 sta_id;
+       u8 wait_write_ptr = 0;
+       u8 tid = 0;
+       u8 *qc = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (iwl_is_rfkill(priv)) {
+               IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
+               goto drop_unlock;
+       }
+
+       fc = hdr->frame_control;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (ieee80211_is_auth(fc))
+               IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
+       else if (ieee80211_is_assoc_req(fc))
+               IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
+       else if (ieee80211_is_reassoc_req(fc))
+               IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
+#endif
+
+       hdr_len = ieee80211_hdrlen(fc);
+
+       /* Find index into station table for destination station */
+       if (!info->control.sta)
+               sta_id = priv->hw_params.bcast_sta_id;
+       else
+               sta_id = iwl_sta_id(info->control.sta);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
+                              hdr->addr1);
+               goto drop_unlock;
+       }
+
+       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
+
+       if (sta)
+               sta_priv = (void *)sta->drv_priv;
+
+       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
+           sta_priv->asleep) {
+               WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
+               /*
+                * This sends an asynchronous command to the device,
+                * but we can rely on it being processed before the
+                * next frame is processed -- and the next frame to
+                * this station is the one that will consume this
+                * counter.
+                * For now set the counter to just 1 since we do not
+                * support uAPSD yet.
+                */
+               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
+       }
+
+       txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+       if (ieee80211_is_data_qos(fc)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+               if (unlikely(tid >= MAX_TID_COUNT))
+                       goto drop_unlock;
+               seq_number = priv->stations[sta_id].tid[tid].seq_number;
+               seq_number &= IEEE80211_SCTL_SEQ;
+               hdr->seq_ctrl = hdr->seq_ctrl &
+                               cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(seq_number);
+               seq_number += 0x10;
+               /* aggregation is on for this <sta,tid> */
+               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
+                   priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
+                       txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+               }
+       }
+
+       txq = &priv->txq[txq_id];
+       swq_id = txq->swq_id;
+       q = &txq->q;
+
+       if (unlikely(iwl_queue_space(q) < q->high_mark))
+               goto drop_unlock;
+
+       if (ieee80211_is_data_qos(fc))
+               priv->stations[sta_id].tid[tid].tfds_in_queue++;
+
+       /* Set up driver data for this TFD */
+       memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
+       txq->txb[q->write_ptr].skb[0] = skb;
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
+       out_cmd = txq->cmd[q->write_ptr];
+       out_meta = &txq->meta[q->write_ptr];
+       tx_cmd = &out_cmd->cmd.tx;
+       memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+       memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
+
+       /*
+        * Set up the Tx-command (not MAC!) header.
+        * Store the chosen Tx queue and TFD index within the sequence field;
+        * after Tx, uCode's Tx response will return this value so driver can
+        * locate the frame within the tx queue and do post-tx processing.
+        */
+       out_cmd->hdr.cmd = REPLY_TX;
+       out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+                               INDEX_TO_SEQ(q->write_ptr)));
+
+       /* Copy MAC header from skb into command buffer */
+       memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+
+       /* Total # bytes to be transmitted */
+       len = (u16)skb->len;
+       tx_cmd->len = cpu_to_le16(len);
+
+       if (info->control.hw_key)
+               iwlagn_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
+
+       /* TODO need this for burst mode later on */
+       iwlagn_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
+       iwl_dbg_log_tx_data_frame(priv, len, hdr);
+
+       iwlagn_tx_cmd_build_rate(priv, tx_cmd, info, fc);
+
+       iwl_update_stats(priv, true, fc, len);
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+
+       len_org = len;
+       firstlen = len = (len + 3) & ~3;
+
+       if (len_org != len)
+               len_org = 1;
+       else
+               len_org = 0;
+
+       /* Tell NIC about any 2-byte padding after MAC header */
+       if (len_org)
+               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
+       txcmd_phys = pci_map_single(priv->pci_dev,
+                                   &out_cmd->hdr, len,
+                                   PCI_DMA_BIDIRECTIONAL);
+       pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
+       pci_unmap_len_set(out_meta, len, len);
+       /* Add buffer containing Tx command and MAC(!) header to TFD's
+        * first entry */
+       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
+                                                  txcmd_phys, len, 1, 0);
+
+       if (!ieee80211_has_morefrags(hdr->frame_control)) {
+               txq->need_update = 1;
+               if (qc)
+                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
+       } else {
+               wait_write_ptr = 1;
+               txq->need_update = 0;
+       }
+
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
+       secondlen = len = skb->len - hdr_len;
+       if (len) {
+               phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+                                          len, PCI_DMA_TODEVICE);
+               priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
+                                                          phys_addr, len,
+                                                          0, 0);
+       }
+
+       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+                               offsetof(struct iwl_tx_cmd, scratch);
+
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+       /* take back ownership of DMA buffer to enable update */
+       pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys,
+                                   len, PCI_DMA_BIDIRECTIONAL);
+       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
+
+       IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
+                    le16_to_cpu(out_cmd->hdr.sequence));
+       IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+
+       /* Set up entry for this TFD in Tx byte-count array */
+       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
+                                                    le16_to_cpu(tx_cmd->len));
+
+       pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
+                                      len, PCI_DMA_BIDIRECTIONAL);
+
+       trace_iwlwifi_dev_tx(priv,
+                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &out_cmd->hdr, firstlen,
+                            skb->data + hdr_len, secondlen);
+
+       /* Tell device the write index *just past* this latest filled TFD */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       iwl_txq_update_write_ptr(priv, txq);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /*
+        * At this point the frame is "transmitted" successfully
+        * and we will get a TX status notification eventually,
+        * regardless of the value of ret. "ret" only indicates
+        * whether or not we should update the write pointer.
+        */
+
+       /* avoid atomic ops if it isn't an associated client */
+       if (sta_priv && sta_priv->client)
+               atomic_inc(&sta_priv->pending_frames);
+
+       if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
+               if (wait_write_ptr) {
+                       spin_lock_irqsave(&priv->lock, flags);
+                       txq->need_update = 1;
+                       iwl_txq_update_write_ptr(priv, txq);
+                       spin_unlock_irqrestore(&priv->lock, flags);
+               } else {
+                       iwl_stop_queue(priv, txq->swq_id);
+               }
+       }
+
+       return 0;
+
+drop_unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       return -1;
+}
+
+static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr, size_t size)
+{
+       ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
+                                      GFP_KERNEL);
+       if (!ptr->addr)
+               return -ENOMEM;
+       ptr->size = size;
+       return 0;
+}
+
+static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv,
+                                   struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
+/**
+ * iwlagn_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       /* Tx queues */
+       if (priv->txq) {
+               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+                       if (txq_id == IWL_CMD_QUEUE_NUM)
+                               iwl_cmd_queue_free(priv);
+                       else
+                               iwl_tx_queue_free(priv, txq_id);
+       }
+       iwlagn_free_dma_ptr(priv, &priv->kw);
+
+       iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
+
+       /* free tx queue structure */
+       iwl_free_txq_mem(priv);
+}
+
+/**
+ * iwlagn_txq_ctx_alloc - allocate TX queue context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
+{
+       int ret;
+       int txq_id, slots_num;
+       unsigned long flags;
+
+       /* Free all tx/cmd queues and keep-warm buffer */
+       iwlagn_hw_txq_ctx_free(priv);
+
+       ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
+                               priv->hw_params.scd_bc_tbls_size);
+       if (ret) {
+               IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
+               goto error_bc_tbls;
+       }
+       /* Alloc keep-warm buffer */
+       ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
+       if (ret) {
+               IWL_ERR(priv, "Keep Warm allocation failed\n");
+               goto error_kw;
+       }
+
+       /* allocate tx queue structure */
+       ret = iwl_alloc_txq_mem(priv);
+       if (ret)
+               goto error;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4) */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+                                      txq_id);
+               if (ret) {
+                       IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return ret;
+
+ error:
+       iwlagn_hw_txq_ctx_free(priv);
+       iwlagn_free_dma_ptr(priv, &priv->kw);
+ error_kw:
+       iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls);
+ error_bc_tbls:
+       return ret;
+}
+
+void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
+{
+       int txq_id, slots_num;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4) */
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+               slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
+                           TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
+       }
+}
+
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
+{
+       int ch;
+       unsigned long flags;
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
+               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
+                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                   1000);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/*
+ * Find first available (lowest unused) Tx Queue, mark it "active".
+ * Called only when finding queue for aggregation.
+ * Should never return anything < 7, because they should already
+ * be in use as EDCA AC (0-3), Command (4), reserved (5, 6)
+ */
+static int iwlagn_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+       int txq_id;
+
+       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
+               if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+                       return txq_id;
+       return -1;
+}
+
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+{
+       int sta_id;
+       int tx_fifo;
+       int txq_id;
+       int ret;
+       unsigned long flags;
+       struct iwl_tid_data *tid_data;
+
+       tx_fifo = get_fifo_from_tid(tid);
+       if (unlikely(tx_fifo < 0))
+               return tx_fifo;
+
+       IWL_WARN(priv, "%s on ra = %pM tid = %d\n",
+                       __func__, sta->addr, tid);
+
+       sta_id = iwl_sta_id(sta);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Start AGG on invalid station\n");
+               return -ENXIO;
+       }
+       if (unlikely(tid >= MAX_TID_COUNT))
+               return -EINVAL;
+
+       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
+               IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
+               return -ENXIO;
+       }
+
+       txq_id = iwlagn_txq_ctx_activate_free(priv);
+       if (txq_id == -1) {
+               IWL_ERR(priv, "No free aggregation queue available\n");
+               return -ENXIO;
+       }
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       tid_data = &priv->stations[sta_id].tid[tid];
+       *ssn = SEQ_TO_SN(tid_data->seq_number);
+       tid_data->agg.txq_id = txq_id;
+       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(get_ac_from_tid(tid), txq_id);
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+       ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
+                                                 sta_id, tid, *ssn);
+       if (ret)
+               return ret;
+
+       if (tid_data->tfds_in_queue == 0) {
+               IWL_DEBUG_HT(priv, "HW queue is empty\n");
+               tid_data->agg.state = IWL_AGG_ON;
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+       } else {
+               IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
+                            tid_data->tfds_in_queue);
+               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
+       }
+       return ret;
+}
+
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta, u16 tid)
+{
+       int tx_fifo_id, txq_id, sta_id, ssn = -1;
+       struct iwl_tid_data *tid_data;
+       int write_ptr, read_ptr;
+       unsigned long flags;
+
+       tx_fifo_id = get_fifo_from_tid(tid);
+       if (unlikely(tx_fifo_id < 0))
+               return tx_fifo_id;
+
+       sta_id = iwl_sta_id(sta);
+
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
+               return -ENXIO;
+       }
+
+       if (priv->stations[sta_id].tid[tid].agg.state ==
+                               IWL_EMPTYING_HW_QUEUE_ADDBA) {
+               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+               return 0;
+       }
+
+       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
+               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
+
+       tid_data = &priv->stations[sta_id].tid[tid];
+       ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+       txq_id = tid_data->agg.txq_id;
+       write_ptr = priv->txq[txq_id].q.write_ptr;
+       read_ptr = priv->txq[txq_id].q.read_ptr;
+
+       /* The queue is not empty */
+       if (write_ptr != read_ptr) {
+               IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
+               priv->stations[sta_id].tid[tid].agg.state =
+                               IWL_EMPTYING_HW_QUEUE_DELBA;
+               return 0;
+       }
+
+       IWL_DEBUG_HT(priv, "HW queue is empty\n");
+       priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       /*
+        * the only reason this call can fail is queue number out of range,
+        * which can happen if uCode is reloaded and all the station
+        * information are lost. if it is outside the range, there is no need
+        * to deactivate the uCode queue, just return "success" to allow
+        *  mac80211 to clean up it own data.
+        */
+       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
+                                                  tx_fifo_id);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+
+       return 0;
+}
+
+int iwlagn_txq_check_empty(struct iwl_priv *priv,
+                          int sta_id, u8 tid, int txq_id)
+{
+       struct iwl_queue *q = &priv->txq[txq_id].q;
+       u8 *addr = priv->stations[sta_id].sta.sta.addr;
+       struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+
+       switch (priv->stations[sta_id].tid[tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_DELBA:
+               /* We are reclaiming the last packet of the */
+               /* aggregated HW queue */
+               if ((txq_id  == tid_data->agg.txq_id) &&
+                   (q->read_ptr == q->write_ptr)) {
+                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
+                       int tx_fifo = get_fifo_from_tid(tid);
+                       IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
+                       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
+                                                            ssn, tx_fifo);
+                       tid_data->agg.state = IWL_AGG_OFF;
+                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+               }
+               break;
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /* We are reclaiming the last packet of the queue */
+               if (tid_data->tfds_in_queue == 0) {
+                       IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
+                       tid_data->agg.state = IWL_AGG_ON;
+                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
+               }
+               break;
+       }
+       return 0;
+}
+
+static void iwlagn_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_sta *sta;
+       struct iwl_station_priv *sta_priv;
+
+       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
+       if (sta) {
+               sta_priv = (void *)sta->drv_priv;
+               /* avoid atomic ops if this isn't a client */
+               if (sta_priv->client &&
+                   atomic_dec_return(&sta_priv->pending_frames) == 0)
+                       ieee80211_sta_block_awake(priv->hw, sta, false);
+       }
+
+       ieee80211_tx_status_irqsafe(priv->hw, skb);
+}
+
+int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+       struct iwl_tx_queue *txq = &priv->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       struct iwl_tx_info *tx_info;
+       int nfreed = 0;
+       struct ieee80211_hdr *hdr;
+
+       if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
+               IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
+                         "is out of range [0-%d] %d %d.\n", txq_id,
+                         index, q->n_bd, q->write_ptr, q->read_ptr);
+               return 0;
+       }
+
+       for (index = iwl_queue_inc_wrap(index, q->n_bd);
+            q->read_ptr != index;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+
+               tx_info = &txq->txb[txq->q.read_ptr];
+               iwlagn_tx_status(priv, tx_info->skb[0]);
+
+               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+                       nfreed++;
+               tx_info->skb[0] = NULL;
+
+               if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
+                       priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
+
+               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+       }
+       return nfreed;
+}
+
+/**
+ * iwlagn_tx_status_reply_compressed_ba - Update tx status from block-ack
+ *
+ * Go through block-ack's bitmap of ACK'd frames, update driver's record of
+ * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
+ */
+static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
+                                struct iwl_ht_agg *agg,
+                                struct iwl_compressed_ba_resp *ba_resp)
+
+{
+       int i, sh, ack;
+       u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
+       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+       u64 bitmap;
+       int successes = 0;
+       struct ieee80211_tx_info *info;
+
+       if (unlikely(!agg->wait_for_ba))  {
+               IWL_ERR(priv, "Received BA when not expected\n");
+               return -EINVAL;
+       }
+
+       /* Mark that the expected block-ack response arrived */
+       agg->wait_for_ba = 0;
+       IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
+
+       /* Calculate shift to align block-ack bits with our Tx window bits */
+       sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
+       if (sh < 0) /* tbw something is wrong with indices */
+               sh += 0x100;
+
+       /* don't use 64-bit values for now */
+       bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
+
+       if (agg->frame_count > (64 - sh)) {
+               IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
+               return -1;
+       }
+
+       /* check for success or failure according to the
+        * transmitted bitmap and block-ack bitmap */
+       bitmap &= agg->bitmap;
+
+       /* For each frame attempted in aggregation,
+        * update driver's record of tx frame's status. */
+       for (i = 0; i < agg->frame_count ; i++) {
+               ack = bitmap & (1ULL << i);
+               successes += !!ack;
+               IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
+                       ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
+                       agg->start_idx + i);
+       }
+
+       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+       memset(&info->status, 0, sizeof(info->status));
+       info->flags |= IEEE80211_TX_STAT_ACK;
+       info->flags |= IEEE80211_TX_STAT_AMPDU;
+       info->status.ampdu_ack_len = successes;
+       info->status.ampdu_ack_map = bitmap;
+       info->status.ampdu_len = agg->frame_count;
+       iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
+
+       IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap);
+
+       return 0;
+}
+
+/**
+ * translate ucode response to mac80211 tx status control values
+ */
+void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+                                 struct ieee80211_tx_info *info)
+{
+       struct ieee80211_tx_rate *r = &info->control.rates[0];
+
+       info->antenna_sel_tx =
+               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
+       if (rate_n_flags & RATE_MCS_HT_MSK)
+               r->flags |= IEEE80211_TX_RC_MCS;
+       if (rate_n_flags & RATE_MCS_GF_MSK)
+               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
+       if (rate_n_flags & RATE_MCS_HT40_MSK)
+               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+       if (rate_n_flags & RATE_MCS_DUP_MSK)
+               r->flags |= IEEE80211_TX_RC_DUP_DATA;
+       if (rate_n_flags & RATE_MCS_SGI_MSK)
+               r->flags |= IEEE80211_TX_RC_SHORT_GI;
+       r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band);
+}
+
+/**
+ * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
+ *
+ * Handles block-acknowledge notification from device, which reports success
+ * of frames sent via aggregation.
+ */
+void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                                          struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+       struct iwl_tx_queue *txq = NULL;
+       struct iwl_ht_agg *agg;
+       int index;
+       int sta_id;
+       int tid;
+
+       /* "flow" corresponds to Tx queue */
+       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
+
+       /* "ssn" is start of block-ack Tx window, corresponds to index
+        * (in Tx queue's circular buffer) of first TFD/frame in window */
+       u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+       if (scd_flow >= priv->hw_params.max_txq_num) {
+               IWL_ERR(priv,
+                       "BUG_ON scd_flow is bigger than number of queues\n");
+               return;
+       }
+
+       txq = &priv->txq[scd_flow];
+       sta_id = ba_resp->sta_id;
+       tid = ba_resp->tid;
+       agg = &priv->stations[sta_id].tid[tid].agg;
+
+       /* Find index just before block-ack window */
+       index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+       /* TODO: Need to get this copy more safely - now good for debug */
+
+       IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
+                          "sta_id = %d\n",
+                          agg->wait_for_ba,
+                          (u8 *) &ba_resp->sta_addr_lo32,
+                          ba_resp->sta_id);
+       IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
+                          "%d, scd_ssn = %d\n",
+                          ba_resp->tid,
+                          ba_resp->seq_ctl,
+                          (unsigned long long)le64_to_cpu(ba_resp->bitmap),
+                          ba_resp->scd_flow,
+                          ba_resp->scd_ssn);
+       IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx\n",
+                          agg->start_idx,
+                          (unsigned long long)agg->bitmap);
+
+       /* Update driver's record of ACK vs. not for each frame in window */
+       iwlagn_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+
+       /* Release all TFDs before the SSN, i.e. all TFDs in front of
+        * block-ack window (we assume that they've been successfully
+        * transmitted ... if not, it's too late anyway). */
+       if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
+               /* calculate mac80211 ampdu sw queue to wake */
+               int freed = iwlagn_tx_queue_reclaim(priv, scd_flow, index);
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+
+               if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
+                   priv->mac80211_registered &&
+                   (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
+                       iwl_wake_queue(priv, txq->swq_id);
+
+               iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
+       }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
new file mode 100644 (file)
index 0000000..637286c
--- /dev/null
@@ -0,0 +1,425 @@
+/******************************************************************************
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-helpers.h"
+#include "iwl-agn-hw.h"
+#include "iwl-agn.h"
+
+static const s8 iwlagn_default_queue_to_tx_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+       IWLAGN_CMD_FIFO_NUM,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+       IWL_TX_FIFO_UNUSED,
+};
+
+static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
+       {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
+        0, COEX_UNASSOC_IDLE_FLAGS},
+       {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP,
+        0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
+       {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP,
+        0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
+       {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP,
+        0, COEX_CALIBRATION_FLAGS},
+       {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP,
+        0, COEX_PERIODIC_CALIBRATION_FLAGS},
+       {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP,
+        0, COEX_CONNECTION_ESTAB_FLAGS},
+       {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP,
+        0, COEX_ASSOCIATED_IDLE_FLAGS},
+       {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP,
+        0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
+       {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP,
+        0, COEX_ASSOC_AUTO_SCAN_FLAGS},
+       {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP,
+        0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
+       {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS},
+       {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS},
+       {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP,
+        0, COEX_STAND_ALONE_DEBUG_FLAGS},
+       {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP,
+        0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
+       {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS},
+       {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
+};
+
+/*
+ * ucode
+ */
+static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
+                               struct fw_desc *image, u32 dst_addr)
+{
+       dma_addr_t phy_addr = image->p_addr;
+       u32 byte_cnt = image->len;
+       int ret;
+
+       priv->ucode_write_complete = 0;
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
+
+       iwl_write_direct32(priv,
+               FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
+
+       iwl_write_direct32(priv,
+               FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
+               phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
+
+       iwl_write_direct32(priv,
+               FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
+               (iwl_get_dma_hi_addr(phy_addr)
+                       << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
+               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
+               1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
+               FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
+
+       iwl_write_direct32(priv,
+               FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
+               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
+               FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
+
+       IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name);
+       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+                                       priv->ucode_write_complete, 5 * HZ);
+       if (ret == -ERESTARTSYS) {
+               IWL_ERR(priv, "Could not load the %s uCode section due "
+                       "to interrupt\n", name);
+               return ret;
+       }
+       if (!ret) {
+               IWL_ERR(priv, "Could not load the %s uCode section\n",
+                       name);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int iwlagn_load_given_ucode(struct iwl_priv *priv,
+               struct fw_desc *inst_image,
+               struct fw_desc *data_image)
+{
+       int ret = 0;
+
+       ret = iwlagn_load_section(priv, "INST", inst_image,
+                                  IWLAGN_RTC_INST_LOWER_BOUND);
+       if (ret)
+               return ret;
+
+       return iwlagn_load_section(priv, "DATA", data_image,
+                                   IWLAGN_RTC_DATA_LOWER_BOUND);
+}
+
+int iwlagn_load_ucode(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       /* check whether init ucode should be loaded, or rather runtime ucode */
+       if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
+               IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
+               ret = iwlagn_load_given_ucode(priv,
+                       &priv->ucode_init, &priv->ucode_init_data);
+               if (!ret) {
+                       IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
+                       priv->ucode_type = UCODE_INIT;
+               }
+       } else {
+               IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
+                       "Loading runtime ucode...\n");
+               ret = iwlagn_load_given_ucode(priv,
+                       &priv->ucode_code, &priv->ucode_data);
+               if (!ret) {
+                       IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
+                       priv->ucode_type = UCODE_RT;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ *  Calibration
+ */
+static int iwlagn_set_Xtal_calib(struct iwl_priv *priv)
+{
+       struct iwl_calib_xtal_freq_cmd cmd;
+       __le16 *xtal_calib =
+               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_XTAL);
+
+       cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD;
+       cmd.hdr.first_group = 0;
+       cmd.hdr.groups_num = 1;
+       cmd.hdr.data_valid = 1;
+       cmd.cap_pin1 = le16_to_cpu(xtal_calib[0]);
+       cmd.cap_pin2 = le16_to_cpu(xtal_calib[1]);
+       return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL],
+                            (u8 *)&cmd, sizeof(cmd));
+}
+
+static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
+{
+       struct iwl_calib_cfg_cmd calib_cfg_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = CALIBRATION_CFG_CMD,
+               .len = sizeof(struct iwl_calib_cfg_cmd),
+               .data = &calib_cfg_cmd,
+       };
+
+       memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
+       calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.start = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.once.send_res = IWL_CALIB_INIT_CFG_ALL;
+       calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_INIT_CFG_ALL;
+
+       return iwl_send_cmd(priv, &cmd);
+}
+
+void iwlagn_rx_calib_result(struct iwl_priv *priv,
+                            struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
+       int len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       int index;
+
+       /* reduce the size of the length field itself */
+       len -= 4;
+
+       /* Define the order in which the results will be sent to the runtime
+        * uCode. iwl_send_calib_results sends them in a row according to
+        * their index. We sort them here
+        */
+       switch (hdr->op_code) {
+       case IWL_PHY_CALIBRATE_DC_CMD:
+               index = IWL_CALIB_DC;
+               break;
+       case IWL_PHY_CALIBRATE_LO_CMD:
+               index = IWL_CALIB_LO;
+               break;
+       case IWL_PHY_CALIBRATE_TX_IQ_CMD:
+               index = IWL_CALIB_TX_IQ;
+               break;
+       case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD:
+               index = IWL_CALIB_TX_IQ_PERD;
+               break;
+       case IWL_PHY_CALIBRATE_BASE_BAND_CMD:
+               index = IWL_CALIB_BASE_BAND;
+               break;
+       default:
+               IWL_ERR(priv, "Unknown calibration notification %d\n",
+                         hdr->op_code);
+               return;
+       }
+       iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
+}
+
+void iwlagn_rx_calib_complete(struct iwl_priv *priv,
+                              struct iwl_rx_mem_buffer *rxb)
+{
+       IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
+       queue_work(priv->workqueue, &priv->restart);
+}
+
+void iwlagn_init_alive_start(struct iwl_priv *priv)
+{
+       int ret = 0;
+
+       /* Check alive response for "valid" sign from uCode */
+       if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+               /* We had an error bringing up the hardware, so take it
+                * all the way back down so we can try again */
+               IWL_DEBUG_INFO(priv, "Initialize Alive failed.\n");
+               goto restart;
+       }
+
+       /* initialize uCode was loaded... verify inst image.
+        * This is a paranoid check, because we would not have gotten the
+        * "initialize" alive if code weren't properly loaded.  */
+       if (iwl_verify_ucode(priv)) {
+               /* Runtime instruction load was bad;
+                * take it all the way back down so we can try again */
+               IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
+               goto restart;
+       }
+
+       ret = priv->cfg->ops->lib->alive_notify(priv);
+       if (ret) {
+               IWL_WARN(priv,
+                       "Could not complete ALIVE transition: %d\n", ret);
+               goto restart;
+       }
+
+       iwlagn_send_calib_cfg(priv);
+       return;
+
+restart:
+       /* real restart (first load init_ucode) */
+       queue_work(priv->workqueue, &priv->restart);
+}
+
+static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
+{
+       struct iwl_wimax_coex_cmd coex_cmd;
+
+       if (priv->cfg->support_wimax_coexist) {
+               /* UnMask wake up src at associated sleep */
+               coex_cmd.flags = COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
+
+               /* UnMask wake up src at unassociated sleep */
+               coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK;
+               memcpy(coex_cmd.sta_prio, cu_priorities,
+                       sizeof(struct iwl_wimax_coex_event_entry) *
+                        COEX_NUM_OF_EVENTS);
+
+               /* enabling the coexistence feature */
+               coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK;
+
+               /* enabling the priorities tables */
+               coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK;
+       } else {
+               /* coexistence is disabled */
+               memset(&coex_cmd, 0, sizeof(coex_cmd));
+       }
+       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
+                               sizeof(coex_cmd), &coex_cmd);
+}
+
+int iwlagn_alive_notify(struct iwl_priv *priv)
+{
+       u32 a;
+       unsigned long flags;
+       int i, chan;
+       u32 reg_val;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       priv->scd_base_addr = iwl_read_prph(priv, IWLAGN_SCD_SRAM_BASE_ADDR);
+       a = priv->scd_base_addr + IWLAGN_SCD_CONTEXT_DATA_OFFSET;
+       for (; a < priv->scd_base_addr + IWLAGN_SCD_TX_STTS_BITMAP_OFFSET;
+               a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+       for (; a < priv->scd_base_addr + IWLAGN_SCD_TRANSLATE_TBL_OFFSET;
+               a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+       for (; a < priv->scd_base_addr +
+              IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4)
+               iwl_write_targ_mem(priv, a, 0);
+
+       iwl_write_prph(priv, IWLAGN_SCD_DRAM_BASE_ADDR,
+                      priv->scd_bc_tbls.dma >> 10);
+
+       /* Enable DMA channel */
+       for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++)
+               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+       /* Update FH chicken bits */
+       reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG);
+       iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG,
+                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+       iwl_write_prph(priv, IWLAGN_SCD_QUEUECHAIN_SEL,
+               IWLAGN_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num));
+       iwl_write_prph(priv, IWLAGN_SCD_AGGR_SEL, 0);
+
+       /* initiate the queues */
+       for (i = 0; i < priv->hw_params.max_txq_num; i++) {
+               iwl_write_prph(priv, IWLAGN_SCD_QUEUE_RDPTR(i), 0);
+               iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+               iwl_write_targ_mem(priv, priv->scd_base_addr +
+                               IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(i), 0);
+               iwl_write_targ_mem(priv, priv->scd_base_addr +
+                               IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(i) +
+                               sizeof(u32),
+                               ((SCD_WIN_SIZE <<
+                               IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                               IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                               ((SCD_FRAME_LIMIT <<
+                               IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                               IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+       }
+
+       iwl_write_prph(priv, IWLAGN_SCD_INTERRUPT_MASK,
+                       IWL_MASK(0, priv->hw_params.max_txq_num));
+
+       /* Activate all Tx DMA/FIFO channels */
+       priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+
+       iwlagn_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+
+       /* make sure all queue are not stopped */
+       memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
+       for (i = 0; i < 4; i++)
+               atomic_set(&priv->queue_stop_count[i], 0);
+
+       /* reset to 0 to enable all the queue first */
+       priv->txq_ctx_active_msk = 0;
+       /* map qos queues to fifos one-to-one */
+       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10);
+
+       for (i = 0; i < ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); i++) {
+               int ac = iwlagn_default_queue_to_tx_fifo[i];
+
+               iwl_txq_ctx_activate(priv, i);
+
+               if (ac == IWL_TX_FIFO_UNUSED)
+                       continue;
+
+               iwlagn_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       iwlagn_send_wimax_coex(priv);
+
+       iwlagn_set_Xtal_calib(priv);
+       iwl_send_calib_results(priv);
+
+       return 0;
+}
index bdff56583e114ea6120a21976be0dd9559bdc765..aef4f71f1981c3e31461932228bbdb9f3aedf15b 100644 (file)
@@ -55,6 +55,7 @@
 #include "iwl-helpers.h"
 #include "iwl-sta.h"
 #include "iwl-calib.h"
+#include "iwl-agn.h"
 
 
 /******************************************************************************
@@ -83,13 +84,6 @@ MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("iwl4965");
 
-/*************** STATION TABLE MANAGEMENT ****
- * mac80211 should be examined to determine if sta_info is duplicating
- * the functionality provided here
- */
-
-/**************************************************************/
-
 /**
  * iwl_commit_rxon - commit staging_rxon to hardware
  *
@@ -144,9 +138,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                return 0;
        }
 
-       /* station table will be cleared */
-       priv->assoc_station_added = 0;
-
        /* If we are currently associated and the new config requires
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
@@ -166,6 +157,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                        IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret);
                        return ret;
                }
+               iwl_clear_ucode_stations(priv);
+               iwl_restore_stations(priv);
+               ret = iwl_restore_default_wep_keys(priv);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+                       return ret;
+               }
        }
 
        IWL_DEBUG_INFO(priv, "Sending RXON\n"
@@ -179,9 +177,8 @@ int iwl_commit_rxon(struct iwl_priv *priv)
        iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
 
        /* Apply the new configuration
-        * RXON unassoc clears the station table in uCode, send it before
-        * we add the bcast station. If assoc bit is set, we will send RXON
-        * after having added the bcast and bssid station.
+        * RXON unassoc clears the station table in uCode so restoration of
+        * stations is needed after it (the RXON command) completes
         */
        if (!new_assoc) {
                ret = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -190,35 +187,19 @@ int iwl_commit_rxon(struct iwl_priv *priv)
                        IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
                        return ret;
                }
+               IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n");
                memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+               iwl_clear_ucode_stations(priv);
+               iwl_restore_stations(priv);
+               ret = iwl_restore_default_wep_keys(priv);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+                       return ret;
+               }
        }
 
-       iwl_clear_stations_table(priv);
-
        priv->start_calib = 0;
-
-       /* Add the broadcast address so we can send broadcast frames */
-       priv->cfg->ops->lib->add_bcast_station(priv);
-
-
-       /* If we have set the ASSOC_MSK and we are in BSS mode then
-        * add the IWL_AP_ID to the station rate table */
        if (new_assoc) {
-               if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-                       ret = iwl_rxon_add_station(priv,
-                                          priv->active_rxon.bssid_addr, 1);
-                       if (ret == IWL_INVALID_STATION) {
-                               IWL_ERR(priv,
-                                       "Error adding AP address for TX.\n");
-                               return -EIO;
-                       }
-                       priv->assoc_station_added = 1;
-                       if (priv->default_wep_key &&
-                           iwl_send_static_wepkey_cmd(priv, 0))
-                               IWL_ERR(priv,
-                                       "Could not send WEP static key.\n");
-               }
-
                /*
                 * allow CTS-to-self if possible for new association.
                 * this is relevant only for 5000 series and up,
@@ -907,10 +888,10 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
            iwl_rx_missed_beacon_notif;
        /* Rx handlers */
-       priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy;
-       priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx;
+       priv->rx_handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy;
+       priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx;
        /* block ack */
-       priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl_rx_reply_compressed_ba;
+       priv->rx_handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba;
        /* Set up hardware specific Rx handlers */
        priv->cfg->ops->lib->rx_handler_setup(priv);
 }
@@ -1038,7 +1019,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
                        count++;
                        if (count >= 8) {
                                rxq->read = i;
-                               iwl_rx_replenish_now(priv);
+                               iwlagn_rx_replenish_now(priv);
                                count = 0;
                        }
                }
@@ -1047,9 +1028,9 @@ void iwl_rx_handle(struct iwl_priv *priv)
        /* Backtrack one entry */
        rxq->read = i;
        if (fill_rx)
-               iwl_rx_replenish_now(priv);
+               iwlagn_rx_replenish_now(priv);
        else
-               iwl_rx_queue_restock(priv);
+               iwlagn_rx_queue_restock(priv);
 }
 
 /* call this function to flush any scheduled tasklet */
@@ -1267,9 +1248,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
         * hardware bugs here by ACKing all the possible interrupts so that
         * interrupt coalescing can still be achieved.
         */
-       iwl_write32(priv, CSR_INT, priv->inta | ~priv->inta_mask);
+       iwl_write32(priv, CSR_INT, priv->_agn.inta | ~priv->inta_mask);
 
-       inta = priv->inta;
+       inta = priv->_agn.inta;
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
@@ -1282,8 +1263,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       /* saved interrupt in inta variable now we can reset priv->inta */
-       priv->inta = 0;
+       /* saved interrupt in inta variable now we can reset priv->_agn.inta */
+       priv->_agn.inta = 0;
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
@@ -1448,6 +1429,60 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
                iwl_enable_interrupts(priv);
 }
 
+/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
+#define ACK_CNT_RATIO (50)
+#define BA_TIMEOUT_CNT (5)
+#define BA_TIMEOUT_MAX (16)
+
+/**
+ * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
+ *
+ * When the ACK count ratio is 0 and aggregated BA timeout retries exceeding
+ * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
+ * operation state.
+ */
+bool iwl_good_ack_health(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
+{
+       bool rc = true;
+       int actual_ack_cnt_delta, expected_ack_cnt_delta;
+       int ba_timeout_delta;
+
+       actual_ack_cnt_delta =
+               le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -
+               le32_to_cpu(priv->statistics.tx.actual_ack_cnt);
+       expected_ack_cnt_delta =
+               le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -
+               le32_to_cpu(priv->statistics.tx.expected_ack_cnt);
+       ba_timeout_delta =
+               le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -
+               le32_to_cpu(priv->statistics.tx.agg.ba_timeout);
+       if ((priv->_agn.agg_tids_count > 0) &&
+           (expected_ack_cnt_delta > 0) &&
+           (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)
+               < ACK_CNT_RATIO) &&
+           (ba_timeout_delta > BA_TIMEOUT_CNT)) {
+               IWL_DEBUG_RADIO(priv, "actual_ack_cnt delta = %d,"
+                               " expected_ack_cnt = %d\n",
+                               actual_ack_cnt_delta, expected_ack_cnt_delta);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+               IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
+                               priv->delta_statistics.tx.rx_detected_cnt);
+               IWL_DEBUG_RADIO(priv,
+                               "ack_or_ba_timeout_collision delta = %d\n",
+                               priv->delta_statistics.tx.
+                               ack_or_ba_timeout_collision);
+#endif
+               IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",
+                               ba_timeout_delta);
+               if (!actual_ack_cnt_delta &&
+                   (ba_timeout_delta >= BA_TIMEOUT_MAX))
+                       rc = false;
+       }
+       return rc;
+}
+
 
 /******************************************************************************
  *
@@ -1471,9 +1506,13 @@ static void iwl_nic_start(struct iwl_priv *priv)
        iwl_write32(priv, CSR_RESET, 0);
 }
 
+struct iwlagn_ucode_capabilities {
+       u32 max_probe_length;
+};
 
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwl_mac_setup_register(struct iwl_priv *priv);
+static int iwl_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa);
 
 static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
 {
@@ -1500,6 +1539,199 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
                                       iwl_ucode_callback);
 }
 
+struct iwlagn_firmware_pieces {
+       const void *inst, *data, *init, *init_data, *boot;
+       size_t inst_size, data_size, init_size, init_data_size, boot_size;
+
+       u32 build;
+};
+
+static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
+                                      const struct firmware *ucode_raw,
+                                      struct iwlagn_firmware_pieces *pieces)
+{
+       struct iwl_ucode_header *ucode = (void *)ucode_raw->data;
+       u32 api_ver, hdr_size;
+       const u8 *src;
+
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       api_ver = IWL_UCODE_API(priv->ucode_ver);
+
+       switch (api_ver) {
+       default:
+               /*
+                * 4965 doesn't revision the firmware file format
+                * along with the API version, it always uses v1
+                * file format.
+                */
+               if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
+                               CSR_HW_REV_TYPE_4965) {
+                       hdr_size = 28;
+                       if (ucode_raw->size < hdr_size) {
+                               IWL_ERR(priv, "File size too small!\n");
+                               return -EINVAL;
+                       }
+                       pieces->build = le32_to_cpu(ucode->u.v2.build);
+                       pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+                       pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+                       pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+                       pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+                       pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
+                       src = ucode->u.v2.data;
+                       break;
+               }
+               /* fall through for 4965 */
+       case 0:
+       case 1:
+       case 2:
+               hdr_size = 24;
+               if (ucode_raw->size < hdr_size) {
+                       IWL_ERR(priv, "File size too small!\n");
+                       return -EINVAL;
+               }
+               pieces->build = 0;
+               pieces->inst_size = le32_to_cpu(ucode->u.v1.inst_size);
+               pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
+               pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
+               pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
+               pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
+               src = ucode->u.v1.data;
+               break;
+       }
+
+       /* Verify size of file vs. image size info in file's header */
+       if (ucode_raw->size != hdr_size + pieces->inst_size +
+                               pieces->data_size + pieces->init_size +
+                               pieces->init_data_size + pieces->boot_size) {
+
+               IWL_ERR(priv,
+                       "uCode file size %d does not match expected size\n",
+                       (int)ucode_raw->size);
+               return -EINVAL;
+       }
+
+       pieces->inst = src;
+       src += pieces->inst_size;
+       pieces->data = src;
+       src += pieces->data_size;
+       pieces->init = src;
+       src += pieces->init_size;
+       pieces->init_data = src;
+       src += pieces->init_data_size;
+       pieces->boot = src;
+       src += pieces->boot_size;
+
+       return 0;
+}
+
+static int iwlagn_wanted_ucode_alternative = 1;
+
+static int iwlagn_load_firmware(struct iwl_priv *priv,
+                               const struct firmware *ucode_raw,
+                               struct iwlagn_firmware_pieces *pieces,
+                               struct iwlagn_ucode_capabilities *capa)
+{
+       struct iwl_tlv_ucode_header *ucode = (void *)ucode_raw->data;
+       struct iwl_ucode_tlv *tlv;
+       size_t len = ucode_raw->size;
+       const u8 *data;
+       int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp;
+       u64 alternatives;
+
+       if (len < sizeof(*ucode))
+               return -EINVAL;
+
+       if (ucode->magic != cpu_to_le32(IWL_TLV_UCODE_MAGIC))
+               return -EINVAL;
+
+       /*
+        * Check which alternatives are present, and "downgrade"
+        * when the chosen alternative is not present, warning
+        * the user when that happens. Some files may not have
+        * any alternatives, so don't warn in that case.
+        */
+       alternatives = le64_to_cpu(ucode->alternatives);
+       tmp = wanted_alternative;
+       if (wanted_alternative > 63)
+               wanted_alternative = 63;
+       while (wanted_alternative && !(alternatives & BIT(wanted_alternative)))
+               wanted_alternative--;
+       if (wanted_alternative && wanted_alternative != tmp)
+               IWL_WARN(priv,
+                        "uCode alternative %d not available, choosing %d\n",
+                        tmp, wanted_alternative);
+
+       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       pieces->build = le32_to_cpu(ucode->build);
+       data = ucode->data;
+
+       len -= sizeof(*ucode);
+
+       while (len >= sizeof(*tlv)) {
+               u32 tlv_len;
+               enum iwl_ucode_tlv_type tlv_type;
+               u16 tlv_alt;
+               const u8 *tlv_data;
+
+               len -= sizeof(*tlv);
+               tlv = (void *)data;
+
+               tlv_len = le32_to_cpu(tlv->length);
+               tlv_type = le16_to_cpu(tlv->type);
+               tlv_alt = le16_to_cpu(tlv->alternative);
+               tlv_data = tlv->data;
+
+               if (len < tlv_len)
+                       return -EINVAL;
+               len -= ALIGN(tlv_len, 4);
+               data += sizeof(*tlv) + ALIGN(tlv_len, 4);
+
+               /*
+                * Alternative 0 is always valid.
+                *
+                * Skip alternative TLVs that are not selected.
+                */
+               if (tlv_alt != 0 && tlv_alt != wanted_alternative)
+                       continue;
+
+               switch (tlv_type) {
+               case IWL_UCODE_TLV_INST:
+                       pieces->inst = tlv_data;
+                       pieces->inst_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_DATA:
+                       pieces->data = tlv_data;
+                       pieces->data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_INIT:
+                       pieces->init = tlv_data;
+                       pieces->init_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_INIT_DATA:
+                       pieces->init_data = tlv_data;
+                       pieces->init_data_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_BOOT:
+                       pieces->boot = tlv_data;
+                       pieces->boot_size = tlv_len;
+                       break;
+               case IWL_UCODE_TLV_PROBE_MAX_LEN:
+                       if (tlv_len != 4)
+                               return -EINVAL;
+                       capa->max_probe_length =
+                               le32_to_cpup((__le32 *)tlv_data);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (len)
+               return -EINVAL;
+
+       return 0;
+}
+
 /**
  * iwl_ucode_callback - callback when firmware was loaded
  *
@@ -1510,14 +1742,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 {
        struct iwl_priv *priv = context;
        struct iwl_ucode_header *ucode;
+       int err;
+       struct iwlagn_firmware_pieces pieces;
        const unsigned int api_max = priv->cfg->ucode_api_max;
        const unsigned int api_min = priv->cfg->ucode_api_min;
-       u8 *src;
-       size_t len;
-       u32 api_ver, build;
-       u32 inst_size, data_size, init_size, init_data_size, boot_size;
-       int err;
-       u16 eeprom_ver;
+       u32 api_ver;
+       char buildstr[25];
+       u32 build;
+       struct iwlagn_ucode_capabilities ucode_capa = {
+               .max_probe_length = 200,
+       };
+
+       memset(&pieces, 0, sizeof(pieces));
 
        if (!ucode_raw) {
                IWL_ERR(priv, "request for firmware file '%s' failed.\n",
@@ -1528,8 +1764,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        IWL_DEBUG_INFO(priv, "Loaded firmware file '%s' (%zd bytes).\n",
                       priv->firmware_name, ucode_raw->size);
 
-       /* Make sure that we got at least the v1 header! */
-       if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
+       /* Make sure that we got at least the API version number */
+       if (ucode_raw->size < 4) {
                IWL_ERR(priv, "File size way too small!\n");
                goto try_again;
        }
@@ -1537,21 +1773,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Data from ucode file:  header followed by uCode images */
        ucode = (struct iwl_ucode_header *)ucode_raw->data;
 
-       priv->ucode_ver = le32_to_cpu(ucode->ver);
+       if (ucode->ver)
+               err = iwlagn_load_legacy_firmware(priv, ucode_raw, &pieces);
+       else
+               err = iwlagn_load_firmware(priv, ucode_raw, &pieces,
+                                          &ucode_capa);
+
+       if (err)
+               goto try_again;
+
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
-       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
-       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
-       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
-       init_data_size =
-               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
-       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
-       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
-
-       /* api_ver should match the api version forming part of the
-        * firmware filename ... but we don't check for that and only rely
-        * on the API version read from firmware header from here on forward */
+       build = pieces.build;
 
+       /*
+        * api_ver should match the api version forming part of the
+        * firmware filename ... but we don't check for that and only rely
+        * on the API version read from firmware header from here on forward
+        */
        if (api_ver < api_min || api_ver > api_max) {
                IWL_ERR(priv, "Driver unable to support your firmware API. "
                          "Driver supports v%u, firmware is v%u.\n",
@@ -1565,40 +1803,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                          "from http://www.intellinuxwireless.org.\n",
                          api_max, api_ver);
 
-       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u\n",
-              IWL_UCODE_MAJOR(priv->ucode_ver),
-              IWL_UCODE_MINOR(priv->ucode_ver),
-              IWL_UCODE_API(priv->ucode_ver),
-              IWL_UCODE_SERIAL(priv->ucode_ver));
+       if (build)
+               sprintf(buildstr, " build %u", build);
+       else
+               buildstr[0] = '\0';
+
+       IWL_INFO(priv, "loaded firmware version %u.%u.%u.%u%s\n",
+                IWL_UCODE_MAJOR(priv->ucode_ver),
+                IWL_UCODE_MINOR(priv->ucode_ver),
+                IWL_UCODE_API(priv->ucode_ver),
+                IWL_UCODE_SERIAL(priv->ucode_ver),
+                buildstr);
 
        snprintf(priv->hw->wiphy->fw_version,
                 sizeof(priv->hw->wiphy->fw_version),
-                "%u.%u.%u.%u",
+                "%u.%u.%u.%u%s",
                 IWL_UCODE_MAJOR(priv->ucode_ver),
                 IWL_UCODE_MINOR(priv->ucode_ver),
                 IWL_UCODE_API(priv->ucode_ver),
-                IWL_UCODE_SERIAL(priv->ucode_ver));
-
-       if (build)
-               IWL_DEBUG_INFO(priv, "Build %u\n", build);
-
-       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-       IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
-                      ? "OTP" : "EEPROM", eeprom_ver);
-
-       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
-                      priv->ucode_ver);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
-                      inst_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %u\n",
-                      data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %u\n",
-                      init_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %u\n",
-                      init_data_size);
-       IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %u\n",
-                      boot_size);
+                IWL_UCODE_SERIAL(priv->ucode_ver),
+                buildstr);
 
        /*
         * For any of the failures below (before allocating pci memory)
@@ -1606,43 +1830,47 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
         * user just got a corrupted version of the latest API.
         */
 
-       /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size !=
-               priv->cfg->ops->ucode->get_header_size(api_ver) +
-               inst_size + data_size + init_size +
-               init_data_size + boot_size) {
-
-               IWL_DEBUG_INFO(priv,
-                       "uCode file size %d does not match expected size\n",
-                       (int)ucode_raw->size);
-               goto try_again;
-       }
+       IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
+                      priv->ucode_ver);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %Zd\n",
+                      pieces.inst_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr runtime data size = %Zd\n",
+                      pieces.data_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr init inst size = %Zd\n",
+                      pieces.init_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
+                      pieces.init_data_size);
+       IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
+                      pieces.boot_size);
 
        /* Verify that uCode images will fit in card's SRAM */
-       if (inst_size > priv->hw_params.max_inst_size) {
-               IWL_DEBUG_INFO(priv, "uCode instr len %d too large to fit in\n",
-                              inst_size);
+       if (pieces.inst_size > priv->hw_params.max_inst_size) {
+               IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n",
+                       pieces.inst_size);
                goto try_again;
        }
 
-       if (data_size > priv->hw_params.max_data_size) {
-               IWL_DEBUG_INFO(priv, "uCode data len %d too large to fit in\n",
-                               data_size);
+       if (pieces.data_size > priv->hw_params.max_data_size) {
+               IWL_ERR(priv, "uCode data len %Zd too large to fit in\n",
+                       pieces.data_size);
                goto try_again;
        }
-       if (init_size > priv->hw_params.max_inst_size) {
-               IWL_INFO(priv, "uCode init instr len %d too large to fit in\n",
-                       init_size);
+
+       if (pieces.init_size > priv->hw_params.max_inst_size) {
+               IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n",
+                       pieces.init_size);
                goto try_again;
        }
-       if (init_data_size > priv->hw_params.max_data_size) {
-               IWL_INFO(priv, "uCode init data len %d too large to fit in\n",
-                     init_data_size);
+
+       if (pieces.init_data_size > priv->hw_params.max_data_size) {
+               IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n",
+                       pieces.init_data_size);
                goto try_again;
        }
-       if (boot_size > priv->hw_params.max_bsm_size) {
-               IWL_INFO(priv, "uCode boot instr len %d too large to fit in\n",
-                       boot_size);
+
+       if (pieces.boot_size > priv->hw_params.max_bsm_size) {
+               IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
+                       pieces.boot_size);
                goto try_again;
        }
 
@@ -1651,13 +1879,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
-       priv->ucode_code.len = inst_size;
+       priv->ucode_code.len = pieces.inst_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
 
-       priv->ucode_data.len = data_size;
+       priv->ucode_data.len = pieces.data_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
 
-       priv->ucode_data_backup.len = data_size;
+       priv->ucode_data_backup.len = pieces.data_size;
        iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
 
        if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
@@ -1665,11 +1893,11 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
                goto err_pci_alloc;
 
        /* Initialization instructions and data */
-       if (init_size && init_data_size) {
-               priv->ucode_init.len = init_size;
+       if (pieces.init_size && pieces.init_data_size) {
+               priv->ucode_init.len = pieces.init_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
 
-               priv->ucode_init_data.len = init_data_size;
+               priv->ucode_init_data.len = pieces.init_data_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
 
                if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
@@ -1677,8 +1905,8 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        }
 
        /* Bootstrap (instructions only, no data) */
-       if (boot_size) {
-               priv->ucode_boot.len = boot_size;
+       if (pieces.boot_size) {
+               priv->ucode_boot.len = pieces.boot_size;
                iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
 
                if (!priv->ucode_boot.v_addr)
@@ -1688,51 +1916,48 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Copy images into buffers for card's bus-master reads ... */
 
        /* Runtime instructions (first block of data in file) */
-       len = inst_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
-       memcpy(priv->ucode_code.v_addr, src, len);
-       src += len;
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
+                       pieces.inst_size);
+       memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
 
        IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
                priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
 
-       /* Runtime data (2nd block)
-        * NOTE:  Copy into backup buffer will be done in iwl_up()  */
-       len = data_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
-       memcpy(priv->ucode_data.v_addr, src, len);
-       memcpy(priv->ucode_data_backup.v_addr, src, len);
-       src += len;
-
-       /* Initialization instructions (3rd block) */
-       if (init_size) {
-               len = init_size;
+       /*
+        * Runtime data
+        * NOTE:  Copy into backup buffer will be done in iwl_up()
+        */
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
+                       pieces.data_size);
+       memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
+       memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
+
+       /* Initialization instructions */
+       if (pieces.init_size) {
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
-                               len);
-               memcpy(priv->ucode_init.v_addr, src, len);
-               src += len;
+                               pieces.init_size);
+               memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
        }
 
-       /* Initialization data (4th block) */
-       if (init_data_size) {
-               len = init_data_size;
+       /* Initialization data */
+       if (pieces.init_data_size) {
                IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
-                              len);
-               memcpy(priv->ucode_init_data.v_addr, src, len);
-               src += len;
+                              pieces.init_data_size);
+               memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
+                      pieces.init_data_size);
        }
 
-       /* Bootstrap instructions (5th block) */
-       len = boot_size;
-       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
-       memcpy(priv->ucode_boot.v_addr, src, len);
+       /* Bootstrap instructions */
+       IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
+                       pieces.boot_size);
+       memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
 
        /**************************************************
         * This is still part of probe() in a sense...
         *
         * 9. Setup and register with mac80211 and debugfs
         **************************************************/
-       err = iwl_mac_setup_register(priv);
+       err = iwl_mac_setup_register(priv, &ucode_capa);
        if (err)
                goto out_unbind;
 
@@ -1742,6 +1967,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 
        /* We have our copies now, allow OS release its copies */
        release_firmware(ucode_raw);
+       complete(&priv->_agn.firmware_loading_complete);
        return;
 
  try_again:
@@ -1755,6 +1981,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        IWL_ERR(priv, "failed to allocate pci memory\n");
        iwl_dealloc_ucode_pci(priv);
  out_unbind:
+       complete(&priv->_agn.firmware_loading_complete);
        device_release_driver(&priv->pci_dev->dev);
        release_firmware(ucode_raw);
 }
@@ -1809,6 +2036,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        u32 data2, line;
        u32 desc, time, count, base, data1;
        u32 blink1, blink2, ilink1, ilink2;
+       u32 pc, hcmd;
 
        if (priv->ucode_type == UCODE_INIT)
                base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
@@ -1831,6 +2059,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        }
 
        desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
        blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
        blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
        ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
@@ -1839,6 +2068,7 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
        data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
        line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
        time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+       hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32));
 
        trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
                                      blink1, blink2, ilink1, ilink2);
@@ -1847,10 +2077,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
                "data1      data2      line\n");
        IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
                desc_lookup(desc), desc, time, data1, data2, line);
-       IWL_ERR(priv, "blink1  blink2  ilink1  ilink2\n");
-       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
-               ilink1, ilink2);
-
+       IWL_ERR(priv, "pc      blink1  blink2  ilink1  ilink2  hcmd\n");
+       IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",
+               pc, blink1, blink2, ilink1, ilink2, hcmd);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -1966,9 +2195,6 @@ static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
        return pos;
 }
 
-/* For sanity check only.  Actual size is determined by uCode, typ. 512 */
-#define MAX_EVENT_LOG_SIZE (512)
-
 #define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20)
 
 int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
@@ -2001,16 +2227,16 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-       if (capacity > MAX_EVENT_LOG_SIZE) {
+       if (capacity > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-                       capacity, MAX_EVENT_LOG_SIZE);
-               capacity = MAX_EVENT_LOG_SIZE;
+                       capacity, priv->cfg->max_event_log_size);
+               capacity = priv->cfg->max_event_log_size;
        }
 
-       if (next_entry > MAX_EVENT_LOG_SIZE) {
+       if (next_entry > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, MAX_EVENT_LOG_SIZE);
-               next_entry = MAX_EVENT_LOG_SIZE;
+                       next_entry, priv->cfg->max_event_log_size);
+               next_entry = priv->cfg->max_event_log_size;
        }
 
        size = num_wraps ? capacity : next_entry;
@@ -2095,7 +2321,6 @@ static void iwl_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       iwl_clear_stations_table(priv);
        ret = priv->cfg->ops->lib->alive_notify(priv);
        if (ret) {
                IWL_WARN(priv,
@@ -2106,13 +2331,19 @@ static void iwl_alive_start(struct iwl_priv *priv)
        /* After the ALIVE response, we can send host commands to the uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
+       if (priv->cfg->ops->lib->recover_from_tx_stall) {
+               /* Enable timer to monitor the driver queues */
+               mod_timer(&priv->monitor_recover,
+                       jiffies +
+                       msecs_to_jiffies(priv->cfg->monitor_recover_period));
+       }
+
        if (iwl_is_rfkill(priv))
                return;
 
        ieee80211_wake_queues(priv->hw);
 
-       priv->active_rate = priv->rates_mask;
-       priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+       priv->active_rate = IWL_RATES_MASK;
 
        /* Configure Tx antenna selection based on H/W config */
        if (priv->cfg->ops->hcmd->set_tx_ant)
@@ -2126,7 +2357,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, priv->iw_mode);
+               iwl_connection_init_rx_config(priv, NULL);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2135,7 +2366,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
        }
 
        /* Configure Bluetooth device coexistence support */
-       iwl_send_bt_config(priv);
+       priv->cfg->ops->hcmd->send_bt_config(priv);
 
        iwl_reset_run_time_calib(priv);
 
@@ -2152,18 +2383,8 @@ static void iwl_alive_start(struct iwl_priv *priv)
        wake_up_interruptible(&priv->wait_command_queue);
 
        iwl_power_update_mode(priv, true);
+       IWL_DEBUG_INFO(priv, "Updated power mode\n");
 
-       /* reassociate for ADHOC mode */
-       if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
-               struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
-                                                               priv->vif);
-               if (beacon)
-                       iwl_mac_beacon_update(priv->hw, beacon);
-       }
-
-
-       if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
-               iwl_set_mode(priv, priv->iw_mode);
 
        return;
 
@@ -2183,7 +2404,9 @@ static void __iwl_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl_clear_stations_table(priv);
+       iwl_clear_ucode_stations(priv);
+       iwl_dealloc_bcast_station(priv);
+       iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2231,8 +2454,8 @@ static void __iwl_down(struct iwl_priv *priv)
        /* device going down, Stop using ICT table */
        iwl_disable_ict(priv);
 
-       iwl_txq_ctx_stop(priv);
-       iwl_rxq_stop(priv);
+       iwlagn_txq_ctx_stop(priv);
+       iwlagn_rxq_stop(priv);
 
        /* Power-down device's busmaster DMA clocks */
        iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
@@ -2292,7 +2515,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
 {
        int ret = 0;
 
-       IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+       IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n");
 
        ret = iwl_set_hw_ready(priv);
        if (priv->hw_ready)
@@ -2330,6 +2553,10 @@ static int __iwl_up(struct iwl_priv *priv)
                return -EIO;
        }
 
+       ret = iwl_alloc_bcast_station(priv, true);
+       if (ret)
+               return ret;
+
        iwl_prepare_card_hw(priv);
 
        if (!priv->hw_ready) {
@@ -2353,7 +2580,7 @@ static int __iwl_up(struct iwl_priv *priv)
 
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
-       ret = iwl_hw_nic_init(priv);
+       ret = iwlagn_hw_nic_init(priv);
        if (ret) {
                IWL_ERR(priv, "Unable to init nic\n");
                return ret;
@@ -2380,8 +2607,6 @@ static int __iwl_up(struct iwl_priv *priv)
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-               iwl_clear_stations_table(priv);
-
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
                 * prepare to load the "initialize" uCode */
@@ -2467,7 +2692,6 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        }
 
        mutex_unlock(&priv->mutex);
-       return;
 }
 
 static void iwl_bg_restart(struct work_struct *data)
@@ -2505,34 +2729,28 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
                return;
 
        mutex_lock(&priv->mutex);
-       iwl_rx_replenish(priv);
+       iwlagn_rx_replenish(priv);
        mutex_unlock(&priv->mutex);
 }
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
-void iwl_post_associate(struct iwl_priv *priv)
+void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
-       unsigned long flags;
 
-       if (priv->iw_mode == NL80211_IFTYPE_AP) {
+       if (!vif || !priv->is_open)
+               return;
+
+       if (vif->type == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
                return;
        }
 
-       IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       priv->assoc_id, priv->active_rxon.bssid_addr);
-
-
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-
-       if (!priv->vif || !priv->is_open)
-               return;
-
        iwl_scan_cancel_timeout(priv, 200);
 
        conf = ieee80211_get_hw_conf(priv->hw);
@@ -2540,7 +2758,7 @@ void iwl_post_associate(struct iwl_priv *priv)
        priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        iwlcore_commit_rxon(priv);
 
-       iwl_setup_rxon_timing(priv);
+       iwl_setup_rxon_timing(priv, vif);
        ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                              sizeof(priv->rxon_timing), &priv->rxon_timing);
        if (ret)
@@ -2554,56 +2772,44 @@ void iwl_post_associate(struct iwl_priv *priv)
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
-                       priv->assoc_id, priv->beacon_int);
+                       vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
-       if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+       if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
                priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
                priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               if (vif->bss_conf.assoc_capability &
+                                       WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+               if (vif->type == NL80211_IFTYPE_ADHOC)
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
        }
 
        iwlcore_commit_rxon(priv);
 
-       switch (priv->iw_mode) {
+       IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
+                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
+
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                break;
-
        case NL80211_IFTYPE_ADHOC:
-
-               /* assume default assoc id */
-               priv->assoc_id = 1;
-
-               iwl_rxon_add_station(priv, priv->bssid, 0);
                iwl_send_beacon_cmd(priv);
-
                break;
-
        default:
                IWL_ERR(priv, "%s Should not be called in %d mode\n",
-                         __func__, priv->iw_mode);
+                         __func__, vif->type);
                break;
        }
 
-       if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
-               priv->assoc_station_added = 1;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_activate_qos(priv, 0);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
        /* the chain noise calibration will enabled PM upon completion
         * If chain noise has already been run, then we need to enable
         * power management here */
@@ -2628,7 +2834,8 @@ void iwl_post_associate(struct iwl_priv *priv)
  * Not a mac80211 entry point function, but it fits in with all the
  * other mac80211 functions grouped here.
  */
-static int iwl_mac_setup_register(struct iwl_priv *priv)
+static int iwl_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa)
 {
        int ret;
        struct ieee80211_hw *hw = priv->hw;
@@ -2636,7 +2843,6 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
@@ -2649,6 +2855,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
                             IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 
        hw->sta_data_size = sizeof(struct iwl_station_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
        hw->wiphy->interface_modes =
                BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
@@ -2664,7 +2872,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv)
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
        /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
 
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
@@ -2770,17 +2978,16 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
                     ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
 
-       if (iwl_tx_skb(priv, skb))
+       if (iwlagn_tx_skb(priv, skb))
                dev_kfree_skb_any(skb);
 
        IWL_DEBUG_MACDUMP(priv, "leave\n");
        return NETDEV_TX_OK;
 }
 
-void iwl_config_ap(struct iwl_priv *priv)
+void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int ret = 0;
-       unsigned long flags;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
@@ -2793,7 +3000,7 @@ void iwl_config_ap(struct iwl_priv *priv)
                iwlcore_commit_rxon(priv);
 
                /* RXON Timing */
-               iwl_setup_rxon_timing(priv);
+               iwl_setup_rxon_timing(priv, vif);
                ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                                sizeof(priv->rxon_timing), &priv->rxon_timing);
                if (ret)
@@ -2807,9 +3014,10 @@ void iwl_config_ap(struct iwl_priv *priv)
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
-               /* FIXME: what should be the assoc_id for AP? */
-               priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+               priv->staging_rxon.assoc_id = 0;
+
+               if (vif->bss_conf.assoc_capability &
+                                               WLAN_CAPABILITY_SHORT_PREAMBLE)
                        priv->staging_rxon.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
@@ -2817,26 +3025,21 @@ void iwl_config_ap(struct iwl_priv *priv)
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
                if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-                       if (priv->assoc_capability &
-                               WLAN_CAPABILITY_SHORT_SLOT_TIME)
+                       if (vif->bss_conf.assoc_capability &
+                                               WLAN_CAPABILITY_SHORT_SLOT_TIME)
                                priv->staging_rxon.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
 
-                       if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               iwl_reset_qos(priv);
-               spin_lock_irqsave(&priv->lock, flags);
-               iwl_activate_qos(priv, 1);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               iwl_add_bcast_station(priv);
        }
        iwl_send_beacon_cmd(priv);
 
@@ -2855,8 +3058,7 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
        struct iwl_priv *priv = hw->priv;
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
-       iwl_update_tkip_key(priv, keyconf,
-                           sta ? sta->addr : iwl_bcast_addr,
+       iwl_update_tkip_key(priv, keyconf, sta,
                            iv32, phase1key);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2868,7 +3070,6 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           struct ieee80211_key_conf *key)
 {
        struct iwl_priv *priv = hw->priv;
-       const u8 *addr;
        int ret;
        u8 sta_id;
        bool is_default_wep_key = false;
@@ -2879,25 +3080,29 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
                return -EOPNOTSUPP;
        }
-       addr = sta ? sta->addr : iwl_bcast_addr;
-       sta_id = iwl_find_station(priv, addr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                  addr);
-               return -EINVAL;
 
+       if (sta) {
+               sta_id = iwl_sta_id(sta);
+
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
+                                          sta->addr);
+                       return -EINVAL;
+               }
+       } else {
+               sta_id = priv->hw_params.bcast_sta_id;
        }
 
        mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 100);
-       mutex_unlock(&priv->mutex);
 
-       /* If we are getting WEP group key and we didn't receive any key mapping
+       /*
+        * If we are getting WEP group key and we didn't receive any key mapping
         * so far, we are in legacy wep mode (group key only), otherwise we are
         * in 1X mode.
-        * In legacy wep mode, we use another host command to the uCode */
-       if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
-               priv->iw_mode != NL80211_IFTYPE_AP) {
+        * In legacy wep mode, we use another host command to the uCode.
+        */
+       if (key->alg == ALG_WEP && !sta && vif->type != NL80211_IFTYPE_AP) {
                if (cmd == SET_KEY)
                        is_default_wep_key = !priv->key_mapping_key;
                else
@@ -2926,6 +3131,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                ret = -EINVAL;
        }
 
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
@@ -2933,8 +3139,8 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
                                struct ieee80211_vif *vif,
-                            enum ieee80211_ampdu_mlme_action action,
-                            struct ieee80211_sta *sta, u16 tid, u16 *ssn)
+                               enum ieee80211_ampdu_mlme_action action,
+                               struct ieee80211_sta *sta, u16 tid, u16 *ssn)
 {
        struct iwl_priv *priv = hw->priv;
        int ret;
@@ -2948,20 +3154,31 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
                IWL_DEBUG_HT(priv, "start Rx\n");
-               return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn);
+               return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
        case IEEE80211_AMPDU_RX_STOP:
                IWL_DEBUG_HT(priv, "stop Rx\n");
-               ret = iwl_sta_rx_agg_stop(priv, sta->addr, tid);
+               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                        return 0;
                else
                        return ret;
        case IEEE80211_AMPDU_TX_START:
                IWL_DEBUG_HT(priv, "start Tx\n");
-               return iwl_tx_agg_start(priv, sta->addr, tid, ssn);
+               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
+               if (ret == 0) {
+                       priv->_agn.agg_tids_count++;
+                       IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
+                                    priv->_agn.agg_tids_count);
+               }
+               return ret;
        case IEEE80211_AMPDU_TX_STOP:
                IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwl_tx_agg_stop(priv, sta->addr, tid);
+               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
+               if ((ret == 0) && (priv->_agn.agg_tids_count > 0)) {
+                       priv->_agn.agg_tids_count--;
+                       IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",
+                                    priv->_agn.agg_tids_count);
+               }
                if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                        return 0;
                else
@@ -2977,18 +3194,6 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,
        return 0;
 }
 
-static int iwl_mac_get_stats(struct ieee80211_hw *hw,
-                            struct ieee80211_low_level_stats *stats)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       priv = hw->priv;
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return 0;
-}
-
 static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               enum sta_notify_cmd cmd,
@@ -2998,18 +3203,7 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
        int sta_id;
 
-       /*
-        * TODO: We really should use this callback to
-        *       actually maintain the station table in
-        *       the device.
-        */
-
        switch (cmd) {
-       case STA_NOTIFY_ADD:
-               atomic_set(&sta_priv->pending_frames, 0);
-               if (vif->type == NL80211_IFTYPE_AP)
-                       sta_priv->client = true;
-               break;
        case STA_NOTIFY_SLEEP:
                WARN_ON(!sta_priv->client);
                sta_priv->asleep = true;
@@ -3021,7 +3215,7 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
                if (!sta_priv->asleep)
                        break;
                sta_priv->asleep = false;
-               sta_id = iwl_find_station(priv, sta->addr);
+               sta_id = iwl_sta_id(sta);
                if (sta_id != IWL_INVALID_STATION)
                        iwl_sta_modify_ps_wake(priv, sta_id);
                break;
@@ -3030,6 +3224,44 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
        }
 }
 
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+       int ret;
+       u8 sta_id;
+
+       sta_priv->common.sta_id = IWL_INVALID_STATION;
+
+       IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
+                       sta->addr);
+
+       atomic_set(&sta_priv->pending_frames, 0);
+       if (vif->type == NL80211_IFTYPE_AP)
+               sta_priv->client = true;
+
+       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
+                                    &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               return ret;
+       }
+
+       sta_priv->common.sta_id = sta_id;
+
+       /* Initialize rate scaling */
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
+                      sta->addr);
+       iwl_rs_rate_init(priv, sta, sta_id);
+
+       return 0;
+}
+
 /*****************************************************************************
  *
  * sysfs attributes
@@ -3130,125 +3362,6 @@ static ssize_t store_tx_power(struct device *d,
 
 static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
 
-static ssize_t show_flags(struct device *d,
-                         struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
-}
-
-static ssize_t store_flags(struct device *d,
-                          struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       unsigned long val;
-       u32 flags;
-       int ret = strict_strtoul(buf, 0, &val);
-       if (ret)
-               return ret;
-       flags = (u32)val;
-
-       mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
-               /* Cancel any currently running scans... */
-               if (iwl_scan_cancel_timeout(priv, 100))
-                       IWL_WARN(priv, "Could not cancel scan.\n");
-               else {
-                       IWL_DEBUG_INFO(priv, "Commit rxon.flags = 0x%04X\n", flags);
-                       priv->staging_rxon.flags = cpu_to_le32(flags);
-                       iwlcore_commit_rxon(priv);
-               }
-       }
-       mutex_unlock(&priv->mutex);
-
-       return count;
-}
-
-static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
-
-static ssize_t show_filter_flags(struct device *d,
-                                struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       return sprintf(buf, "0x%04X\n",
-               le32_to_cpu(priv->active_rxon.filter_flags));
-}
-
-static ssize_t store_filter_flags(struct device *d,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       unsigned long val;
-       u32 filter_flags;
-       int ret = strict_strtoul(buf, 0, &val);
-       if (ret)
-               return ret;
-       filter_flags = (u32)val;
-
-       mutex_lock(&priv->mutex);
-       if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
-               /* Cancel any currently running scans... */
-               if (iwl_scan_cancel_timeout(priv, 100))
-                       IWL_WARN(priv, "Could not cancel scan.\n");
-               else {
-                       IWL_DEBUG_INFO(priv, "Committing rxon.filter_flags = "
-                                      "0x%04X\n", filter_flags);
-                       priv->staging_rxon.filter_flags =
-                               cpu_to_le32(filter_flags);
-                       iwlcore_commit_rxon(priv);
-               }
-       }
-       mutex_unlock(&priv->mutex);
-
-       return count;
-}
-
-static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
-                  store_filter_flags);
-
-
-static ssize_t show_statistics(struct device *d,
-                              struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       u32 size = sizeof(struct iwl_notif_statistics);
-       u32 len = 0, ofs = 0;
-       u8 *data = (u8 *)&priv->statistics;
-       int rc = 0;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       mutex_lock(&priv->mutex);
-       rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->mutex);
-
-       if (rc) {
-               len = sprintf(buf,
-                             "Error sending statistics request: 0x%08X\n", rc);
-               return len;
-       }
-
-       while (size && (PAGE_SIZE - len)) {
-               hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
-                                  PAGE_SIZE - len, 1);
-               len = strlen(buf);
-               if (PAGE_SIZE - len)
-                       buf[len++] = '\n';
-
-               ofs += 16;
-               size -= min(size, 16U);
-       }
-
-       return len;
-}
-
-static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
-
 static ssize_t show_rts_ht_protection(struct device *d,
                             struct device_attribute *attr, char *buf)
 {
@@ -3316,6 +3429,13 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
        priv->ucode_trace.data = (unsigned long)priv;
        priv->ucode_trace.function = iwl_bg_ucode_trace;
 
+       if (priv->cfg->ops->lib->recover_from_tx_stall) {
+               init_timer(&priv->monitor_recover);
+               priv->monitor_recover.data = (unsigned long)priv;
+               priv->monitor_recover.function =
+                       priv->cfg->ops->lib->recover_from_tx_stall;
+       }
+
        if (!priv->cfg->use_isr_legacy)
                tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                        iwl_irq_tasklet, (unsigned long)priv);
@@ -3336,6 +3456,8 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
        cancel_work_sync(&priv->beacon_update);
        del_timer_sync(&priv->statistics_periodic);
        del_timer_sync(&priv->ucode_trace);
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
 }
 
 static void iwl_init_hw_rates(struct iwl_priv *priv,
@@ -3373,9 +3495,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
        mutex_init(&priv->mutex);
        mutex_init(&priv->sync_cmd_mutex);
 
-       /* Clear the driver's (not device's) station table */
-       iwl_clear_stations_table(priv);
-
        priv->ieee_channels = NULL;
        priv->ieee_rates = NULL;
        priv->band = IEEE80211_BAND_2GHZ;
@@ -3383,6 +3502,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
        priv->iw_mode = NL80211_IFTYPE_STATION;
        priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
        priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+       priv->_agn.agg_tids_count = 0;
 
        /* initialize force reset */
        priv->force_reset[IWL_RF_RESET].reset_duration =
@@ -3396,16 +3516,10 @@ static int iwl_init_drv(struct iwl_priv *priv)
 
        iwl_init_scan_params(priv);
 
-       iwl_reset_qos(priv);
-
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
-
-       priv->rates_mask = IWL_RATES_MASK;
        /* Set the tx_power_user_lmt to the lowest power level
         * this value will get overwritten by channel max power avg
         * from eeprom */
-       priv->tx_power_user_lmt = IWL_TX_POWER_TARGET_POWER_MIN;
+       priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN;
 
        ret = iwl_init_channel_map(priv);
        if (ret) {
@@ -3433,13 +3547,10 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
        iwl_calib_free_results(priv);
        iwlcore_free_geos(priv);
        iwl_free_channel_map(priv);
-       kfree(priv->scan);
+       kfree(priv->scan_cmd);
 }
 
 static struct attribute *iwl_sysfs_entries[] = {
-       &dev_attr_flags.attr,
-       &dev_attr_filter_flags.attr,
-       &dev_attr_statistics.attr,
        &dev_attr_temperature.attr,
        &dev_attr_tx_power.attr,
        &dev_attr_rts_ht_protection.attr,
@@ -3464,13 +3575,14 @@ static struct ieee80211_ops iwl_hw_ops = {
        .configure_filter = iwl_configure_filter,
        .set_key = iwl_mac_set_key,
        .update_tkip_key = iwl_mac_update_tkip_key,
-       .get_stats = iwl_mac_get_stats,
        .conf_tx = iwl_mac_conf_tx,
        .reset_tsf = iwl_mac_reset_tsf,
        .bss_info_changed = iwl_bss_info_changed,
        .ampdu_action = iwl_mac_ampdu_action,
        .hw_scan = iwl_mac_hw_scan,
        .sta_notify = iwl_mac_sta_notify,
+       .sta_add = iwlagn_mac_sta_add,
+       .sta_remove = iwl_mac_sta_remove,
 };
 
 static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3574,7 +3686,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
        iwl_hw_detect(priv);
-       IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s REV=0x%X\n",
+       IWL_INFO(priv, "Detected %s, REV=0x%X\n",
                priv->cfg->name, priv->hw_rev);
 
        /* We disable the RETRY_TIMEOUT register (0x41) to keep
@@ -3672,6 +3784,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        iwl_power_initialize(priv);
        iwl_tt_initialize(priv);
 
+       init_completion(&priv->_agn.firmware_loading_complete);
+
        err = iwl_request_firmware(priv, true);
        if (err)
                goto out_remove_sysfs;
@@ -3712,6 +3826,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
        if (!priv)
                return;
 
+       wait_for_completion(&priv->_agn.firmware_loading_complete);
+
        IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
 
        iwl_dbgfs_unregister(priv);
@@ -3752,10 +3868,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
        iwl_dealloc_ucode_pci(priv);
 
        if (priv->rxq.bd)
-               iwl_rx_queue_free(priv, &priv->rxq);
-       iwl_hw_txq_ctx_free(priv);
+               iwlagn_rx_queue_free(priv, &priv->rxq);
+       iwlagn_hw_txq_ctx_free(priv);
 
-       iwl_clear_stations_table(priv);
        iwl_eeprom_free(priv);
 
 
@@ -3870,6 +3985,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x4239, 0x1311, iwl6000i_2agn_cfg)},
        {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)},
 
+/* 6x00 Series Gen2a */
+       {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
+
 /* 6x50 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0087, 0x1306, iwl6050_2abg_cfg)},
@@ -3951,3 +4071,38 @@ module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "debug output mask");
 #endif
 
+module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO);
+MODULE_PARM_DESC(swcrypto50,
+                "using crypto in software (default 0 [hardware]) (deprecated)");
+module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO);
+MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
+module_param_named(queues_num50,
+                  iwlagn_mod_params.num_of_queues, int, S_IRUGO);
+MODULE_PARM_DESC(queues_num50,
+                "number of hw queues in 50xx series (deprecated)");
+module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO);
+MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)");
+module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO);
+MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
+module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K,
+                  int, S_IRUGO);
+MODULE_PARM_DESC(amsdu_size_8K50,
+                "enable 8K amsdu size in 50XX series (deprecated)");
+module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K,
+                  int, S_IRUGO);
+MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
+module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO);
+MODULE_PARM_DESC(fw_restart50,
+                "restart firmware in case of error (deprecated)");
+module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
+MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
+module_param_named(
+       disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
+                  S_IRUGO);
+MODULE_PARM_DESC(ucode_alternative,
+                "specify ucode alternative to use from ucode file");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
new file mode 100644 (file)
index 0000000..2d74805
--- /dev/null
@@ -0,0 +1,181 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef __iwl_agn_h__
+#define __iwl_agn_h__
+
+#include "iwl-dev.h"
+
+extern struct iwl_mod_params iwlagn_mod_params;
+extern struct iwl_hcmd_ops iwlagn_hcmd;
+extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
+
+int iwl_reset_ict(struct iwl_priv *priv);
+void iwl_disable_ict(struct iwl_priv *priv);
+int iwl_alloc_isr_ict(struct iwl_priv *priv);
+void iwl_free_isr_ict(struct iwl_priv *priv);
+irqreturn_t iwl_isr_ict(int irq, void *data);
+bool iwl_good_ack_health(struct iwl_priv *priv,
+                        struct iwl_rx_packet *pkt);
+
+/* tx queue */
+void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
+                    int txq_id, u32 index);
+void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
+                            struct iwl_tx_queue *txq,
+                            int tx_fifo_id, int scd_retry);
+void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+                                   struct iwl_tx_queue *txq,
+                                   u16 byte_cnt);
+void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+                                  struct iwl_tx_queue *txq);
+int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
+                         int tx_fifo, int sta_id, int tid, u16 ssn_idx);
+int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+                          u16 ssn_idx, u8 tx_fifo);
+void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
+
+/* uCode */
+int iwlagn_load_ucode(struct iwl_priv *priv);
+void iwlagn_rx_calib_result(struct iwl_priv *priv,
+                        struct iwl_rx_mem_buffer *rxb);
+void iwlagn_rx_calib_complete(struct iwl_priv *priv,
+                          struct iwl_rx_mem_buffer *rxb);
+void iwlagn_init_alive_start(struct iwl_priv *priv);
+int iwlagn_alive_notify(struct iwl_priv *priv);
+
+/* lib */
+void iwl_check_abort_status(struct iwl_priv *priv,
+                           u8 frame_count, u32 status);
+void iwlagn_rx_handler_setup(struct iwl_priv *priv);
+void iwlagn_setup_deferred_work(struct iwl_priv *priv);
+int iwlagn_hw_valid_rtc_data_addr(u32 addr);
+int iwlagn_send_tx_power(struct iwl_priv *priv);
+void iwlagn_temperature(struct iwl_priv *priv);
+u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
+const u8 *iwlagn_eeprom_query_addr(const struct iwl_priv *priv,
+                                  size_t offset);
+void iwlagn_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwlagn_hw_nic_init(struct iwl_priv *priv);
+
+/* rx */
+void iwlagn_rx_queue_restock(struct iwl_priv *priv);
+void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority);
+void iwlagn_rx_replenish(struct iwl_priv *priv);
+void iwlagn_rx_replenish_now(struct iwl_priv *priv);
+void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+int iwlagn_rxq_stop(struct iwl_priv *priv);
+int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
+void iwlagn_rx_reply_rx(struct iwl_priv *priv,
+                    struct iwl_rx_mem_buffer *rxb);
+void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv,
+                        struct iwl_rx_mem_buffer *rxb);
+
+/* tx */
+void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
+                             struct ieee80211_tx_info *info);
+int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
+int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                       struct ieee80211_sta *sta, u16 tid, u16 *ssn);
+int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta, u16 tid);
+int iwlagn_txq_check_empty(struct iwl_priv *priv,
+                          int sta_id, u8 tid, int txq_id);
+void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb);
+int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
+int iwlagn_txq_ctx_alloc(struct iwl_priv *priv);
+void iwlagn_txq_ctx_reset(struct iwl_priv *priv);
+void iwlagn_txq_ctx_stop(struct iwl_priv *priv);
+
+static inline u32 iwl_tx_status_to_mac80211(u32 status)
+{
+       status &= TX_STATUS_MSK;
+
+       switch (status) {
+       case TX_STATUS_SUCCESS:
+       case TX_STATUS_DIRECT_DONE:
+               return IEEE80211_TX_STAT_ACK;
+       case TX_STATUS_FAIL_DEST_PS:
+               return IEEE80211_TX_STAT_TX_FILTERED;
+       default:
+               return 0;
+       }
+}
+
+static inline bool iwl_is_tx_success(u32 status)
+{
+       status &= TX_STATUS_MSK;
+       return (status == TX_STATUS_SUCCESS) ||
+              (status == TX_STATUS_DIRECT_DONE);
+}
+
+/* scan */
+void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
+
+/* station mgmt */
+int iwlagn_manage_ibss_station(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif, bool add);
+
+#endif /* __iwl_agn_h__ */
index 8b516c5ff0bb5f2ba4ad8143aa159968478877bc..7e822777321331cb5f9ae8303e16613247c2c580 100644 (file)
@@ -593,7 +593,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
        IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time);
 
        if (!rx_enable_time) {
-               IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0! \n");
+               IWL_DEBUG_CALIB(priv, "<< RX Enable Time == 0!\n");
                return;
        }
 
@@ -638,8 +638,6 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv,
        iwl_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
        iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
        iwl_sensitivity_write(priv);
-
-       return;
 }
 EXPORT_SYMBOL(iwl_sensitivity_calibration);
 
index f4e59ae07f8e5a70c0d4e39ab57af34b64bf753d..9aab020c474be305dd763f4a088b9c381a71608a 100644 (file)
@@ -106,7 +106,7 @@ enum {
        REPLY_TX = 0x1c,
        REPLY_RATE_SCALE = 0x47,        /* 3945 only */
        REPLY_LEDS_CMD = 0x48,
-       REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+       REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */
 
        /* WiMAX coexistence */
        COEX_PRIORITY_TABLE_CMD = 0x5a, /* for 5000 series and up */
@@ -512,8 +512,9 @@ struct iwl_init_alive_resp {
  *
  *     Entries without timestamps contain only event_id and data.
  *
+ *
  * 2)  error_event_table_ptr indicates base of the error log.  This contains
- *     information about any uCode error that occurs.  For 4965, the format
+ *     information about any uCode error that occurs.  For agn, the format
  *     of the error log is:
  *
  *     __le32 valid;        (nonzero) valid, (0) log is empty
@@ -529,6 +530,30 @@ struct iwl_init_alive_resp {
  *     __le32 bcon_time;    beacon timer
  *     __le32 tsf_low;      network timestamp function timer
  *     __le32 tsf_hi;       network timestamp function timer
+ *     __le32 gp1;          GP1 timer register
+ *     __le32 gp2;          GP2 timer register
+ *     __le32 gp3;          GP3 timer register
+ *     __le32 ucode_ver;    uCode version
+ *     __le32 hw_ver;       HW Silicon version
+ *     __le32 brd_ver;      HW board version
+ *     __le32 log_pc;       log program counter
+ *     __le32 frame_ptr;    frame pointer
+ *     __le32 stack_ptr;    stack pointer
+ *     __le32 hcmd;         last host command
+ *     __le32 isr0;         isr status register LMPM_NIC_ISR0: rxtx_flag
+ *     __le32 isr1;         isr status register LMPM_NIC_ISR1: host_flag
+ *     __le32 isr2;         isr status register LMPM_NIC_ISR2: enc_flag
+ *     __le32 isr3;         isr status register LMPM_NIC_ISR3: time_flag
+ *     __le32 isr4;         isr status register LMPM_NIC_ISR4: wico interrupt
+ *     __le32 isr_pref;     isr status register LMPM_NIC_PREF_STAT
+ *     __le32 wait_event;   wait event() caller address
+ *     __le32 l2p_control;  L2pControlField
+ *     __le32 l2p_duration; L2pDurationField
+ *     __le32 l2p_mhvalid;  L2pMhValidBits
+ *     __le32 l2p_addr_match; L2pAddrMatchStat
+ *     __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL)
+ *     __le32 u_timestamp;  indicate when the date and time of the compilation
+ *     __le32 reserved;
  *
  * The Linux driver can print both logs to the system log when a uCode error
  * occurs.
@@ -1418,7 +1443,7 @@ struct iwl4965_rx_mpdu_res_start {
 
 /* 1: Ignore Bluetooth priority for this frame.
  * 0: Delay Tx until Bluetooth device is done (normal usage). */
-#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12)
+#define TX_CMD_FLG_IGNORE_BT cpu_to_le32(1 << 12)
 
 /* 1: uCode overrides sequence control field in MAC header.
  * 0: Driver provides sequence control field in MAC header.
@@ -1637,7 +1662,7 @@ struct iwl_tx_cmd {
        struct ieee80211_hdr hdr[0];
 } __attribute__ ((packed));
 
-/* TX command response is sent after *all* transmission attempts.
+/* TX command response is sent after *3945* transmission attempts.
  *
  * NOTES:
  *
@@ -1664,25 +1689,66 @@ struct iwl_tx_cmd {
  * command FIFO has been cleared.  The host must then deactivate the TX Abort
  * control line.  Receiving is still allowed in this case.
  */
+enum {
+       TX_3945_STATUS_SUCCESS = 0x01,
+       TX_3945_STATUS_DIRECT_DONE = 0x02,
+       TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82,
+       TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83,
+       TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+       TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85,
+       TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86,
+       TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+       TX_3945_STATUS_FAIL_DEST_PS = 0x88,
+       TX_3945_STATUS_FAIL_ABORTED = 0x89,
+       TX_3945_STATUS_FAIL_BT_RETRY = 0x8a,
+       TX_3945_STATUS_FAIL_STA_INVALID = 0x8b,
+       TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+       TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d,
+       TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+       TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+       TX_3945_STATUS_FAIL_TX_LOCKED = 0x90,
+       TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+/*
+ * TX command response is sent after *agn* transmission attempts.
+ *
+ * both postpone and abort status are expected behavior from uCode. there is
+ * no special operation required from driver; except for RFKILL_FLUSH,
+ * which required tx flush host command to flush all the tx frames in queues
+ */
 enum {
        TX_STATUS_SUCCESS = 0x01,
        TX_STATUS_DIRECT_DONE = 0x02,
+       /* postpone TX */
+       TX_STATUS_POSTPONE_DELAY = 0x40,
+       TX_STATUS_POSTPONE_FEW_BYTES = 0x41,
+       TX_STATUS_POSTPONE_BT_PRIO = 0x42,
+       TX_STATUS_POSTPONE_QUIET_PERIOD = 0x43,
+       TX_STATUS_POSTPONE_CALC_TTAK = 0x44,
+       /* abort TX */
+       TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY = 0x81,
        TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
        TX_STATUS_FAIL_LONG_LIMIT = 0x83,
        TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
-       TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
-       TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+       TX_STATUS_FAIL_DRAIN_FLOW = 0x85,
+       TX_STATUS_FAIL_RFKILL_FLUSH = 0x86,
        TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
        TX_STATUS_FAIL_DEST_PS = 0x88,
-       TX_STATUS_FAIL_ABORTED = 0x89,
+       TX_STATUS_FAIL_HOST_ABORTED = 0x89,
        TX_STATUS_FAIL_BT_RETRY = 0x8a,
        TX_STATUS_FAIL_STA_INVALID = 0x8b,
        TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
        TX_STATUS_FAIL_TID_DISABLE = 0x8d,
-       TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+       TX_STATUS_FAIL_FIFO_FLUSHED = 0x8e,
        TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
-       TX_STATUS_FAIL_TX_LOCKED = 0x90,
-       TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+       /* uCode drop due to FW drop request */
+       TX_STATUS_FAIL_FW_DROP = 0x90,
+       /*
+        * uCode drop due to station color mismatch
+        * between tx command and station table
+        */
+       TX_STATUS_FAIL_STA_COLOR_MISMATCH_DROP = 0x91,
 };
 
 #define        TX_PACKET_MODE_REGULAR          0x0000
@@ -1704,30 +1770,6 @@ enum {
        TX_ABORT_REQUIRED_MSK = 0x80000000,     /* bits 31:31 */
 };
 
-static inline u32 iwl_tx_status_to_mac80211(u32 status)
-{
-       status &= TX_STATUS_MSK;
-
-       switch (status) {
-       case TX_STATUS_SUCCESS:
-       case TX_STATUS_DIRECT_DONE:
-               return IEEE80211_TX_STAT_ACK;
-       case TX_STATUS_FAIL_DEST_PS:
-               return IEEE80211_TX_STAT_TX_FILTERED;
-       default:
-               return 0;
-       }
-}
-
-static inline bool iwl_is_tx_success(u32 status)
-{
-       status &= TX_STATUS_MSK;
-       return (status == TX_STATUS_SUCCESS) ||
-              (status == TX_STATUS_DIRECT_DONE);
-}
-
-
-
 /* *******************************
  * TX aggregation status
  ******************************* */
@@ -2626,7 +2668,6 @@ struct iwl_ssid_ie {
 #define IWL_GOOD_CRC_TH_NEVER          cpu_to_le16(0xffff)
 #define IWL_MAX_SCAN_SIZE 1024
 #define IWL_MAX_CMD_SIZE 4096
-#define IWL_MAX_PROBE_REQUEST          200
 
 /*
  * REPLY_SCAN_CMD = 0x80 (command)
@@ -3086,6 +3127,11 @@ struct statistics_tx {
        __le32 cts_timeout_collision;
        __le32 ack_or_ba_timeout_collision;
        struct statistics_tx_non_phy_agg agg;
+       /*
+        * "tx_power" are optional parameters provided by uCode,
+        * 6000 series is the only device provide the information,
+        * Those are reserved fields for all the other devices
+        */
        struct statistics_tx_power tx_power;
        __le32 reserved1;
 } __attribute__ ((packed));
index 049b652bcb5e61dc2c656248c455d0d2ec559f2a..5a7eca8fb789621f69d15a6b79e5bae143386664 100644 (file)
@@ -66,38 +66,7 @@ MODULE_LICENSE("GPL");
  */
 static bool bt_coex_active = true;
 module_param(bt_coex_active, bool, S_IRUGO);
-MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist\n");
-
-static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
-       {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP,
-        0, COEX_UNASSOC_IDLE_FLAGS},
-       {COEX_CU_UNASSOC_MANUAL_SCAN_RP, COEX_CU_UNASSOC_MANUAL_SCAN_WP,
-        0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
-       {COEX_CU_UNASSOC_AUTO_SCAN_RP, COEX_CU_UNASSOC_AUTO_SCAN_WP,
-        0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
-       {COEX_CU_CALIBRATION_RP, COEX_CU_CALIBRATION_WP,
-        0, COEX_CALIBRATION_FLAGS},
-       {COEX_CU_PERIODIC_CALIBRATION_RP, COEX_CU_PERIODIC_CALIBRATION_WP,
-        0, COEX_PERIODIC_CALIBRATION_FLAGS},
-       {COEX_CU_CONNECTION_ESTAB_RP, COEX_CU_CONNECTION_ESTAB_WP,
-        0, COEX_CONNECTION_ESTAB_FLAGS},
-       {COEX_CU_ASSOCIATED_IDLE_RP, COEX_CU_ASSOCIATED_IDLE_WP,
-        0, COEX_ASSOCIATED_IDLE_FLAGS},
-       {COEX_CU_ASSOC_MANUAL_SCAN_RP, COEX_CU_ASSOC_MANUAL_SCAN_WP,
-        0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
-       {COEX_CU_ASSOC_AUTO_SCAN_RP, COEX_CU_ASSOC_AUTO_SCAN_WP,
-        0, COEX_ASSOC_AUTO_SCAN_FLAGS},
-       {COEX_CU_ASSOC_ACTIVE_LEVEL_RP, COEX_CU_ASSOC_ACTIVE_LEVEL_WP,
-        0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS},
-       {COEX_CU_RF_ON_RP, COEX_CU_RF_ON_WP, 0, COEX_CU_RF_ON_FLAGS},
-       {COEX_CU_RF_OFF_RP, COEX_CU_RF_OFF_WP, 0, COEX_RF_OFF_FLAGS},
-       {COEX_CU_STAND_ALONE_DEBUG_RP, COEX_CU_STAND_ALONE_DEBUG_WP,
-        0, COEX_STAND_ALONE_DEBUG_FLAGS},
-       {COEX_CU_IPAN_ASSOC_LEVEL_RP, COEX_CU_IPAN_ASSOC_LEVEL_WP,
-        0, COEX_IPAN_ASSOC_LEVEL_FLAGS},
-       {COEX_CU_RSRVD1_RP, COEX_CU_RSRVD1_WP, 0, COEX_RSRVD1_FLAGS},
-       {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
-};
+MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist");
 
 #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
        [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
@@ -115,8 +84,6 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
 u32 iwl_debug_level;
 EXPORT_SYMBOL(iwl_debug_level);
 
-static irqreturn_t iwl_isr(int irq, void *data);
-
 /*
  * Parameter order:
  *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
@@ -143,30 +110,6 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
 };
 EXPORT_SYMBOL(iwl_rates);
 
-/**
- * translate ucode response to mac80211 tx status control values
- */
-void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                                 struct ieee80211_tx_info *info)
-{
-       struct ieee80211_tx_rate *r = &info->control.rates[0];
-
-       info->antenna_sel_tx =
-               ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
-       if (rate_n_flags & RATE_MCS_HT_MSK)
-               r->flags |= IEEE80211_TX_RC_MCS;
-       if (rate_n_flags & RATE_MCS_GF_MSK)
-               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
-       if (rate_n_flags & RATE_MCS_HT40_MSK)
-               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
-       if (rate_n_flags & RATE_MCS_DUP_MSK)
-               r->flags |= IEEE80211_TX_RC_DUP_DATA;
-       if (rate_n_flags & RATE_MCS_SGI_MSK)
-               r->flags |= IEEE80211_TX_RC_SHORT_GI;
-       r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band);
-}
-EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
-
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
 {
        int idx = 0;
@@ -198,27 +141,6 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
 }
 EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
 
-int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
-{
-       int idx = 0;
-       int band_offset = 0;
-
-       /* HT rate format: mac80211 wants an MCS number, which is just LSB */
-       if (rate_n_flags & RATE_MCS_HT_MSK) {
-               idx = (rate_n_flags & 0xff);
-               return idx;
-       /* Legacy rate format, search for match in table */
-       } else {
-               if (band == IEEE80211_BAND_5GHZ)
-                       band_offset = IWL_FIRST_OFDM_RATE;
-               for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++)
-                       if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
-                               return idx - band_offset;
-       }
-
-       return -1;
-}
-
 u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
 {
        int i;
@@ -268,74 +190,16 @@ void iwl_hw_detect(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_hw_detect);
 
-int iwl_hw_nic_init(struct iwl_priv *priv)
-{
-       unsigned long flags;
-       struct iwl_rx_queue *rxq = &priv->rxq;
-       int ret;
-
-       /* nic_init */
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->cfg->ops->lib->apm_ops.init(priv);
-
-       /* Set interrupt coalescing calibration timer to default (512 usecs) */
-       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       ret = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
-
-       priv->cfg->ops->lib->apm_ops.config(priv);
-
-       /* Allocate the RX queue, or reset if it is already allocated */
-       if (!rxq->bd) {
-               ret = iwl_rx_queue_alloc(priv);
-               if (ret) {
-                       IWL_ERR(priv, "Unable to initialize Rx queue\n");
-                       return -ENOMEM;
-               }
-       } else
-               iwl_rx_queue_reset(priv, rxq);
-
-       iwl_rx_replenish(priv);
-
-       iwl_rx_init(priv, rxq);
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       rxq->need_update = 1;
-       iwl_rx_queue_update_write_ptr(priv, rxq);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Allocate or reset and init all Tx and Command queues */
-       if (!priv->txq) {
-               ret = iwl_txq_ctx_alloc(priv);
-               if (ret)
-                       return ret;
-       } else
-               iwl_txq_ctx_reset(priv);
-
-       set_bit(STATUS_INIT, &priv->status);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_hw_nic_init);
-
 /*
  * QoS  support
 */
-void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+static void iwl_update_qos(struct iwl_priv *priv)
 {
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
        priv->qos_data.def_qos_parm.qos_flags = 0;
 
-       if (priv->qos_data.qos_cap.q_AP.queue_request &&
-           !priv->qos_data.qos_cap.q_AP.txop_request)
-               priv->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_TXOP_TYPE_MSK;
        if (priv->qos_data.qos_active)
                priv->qos_data.def_qos_parm.qos_flags |=
                        QOS_PARAM_FLG_UPDATE_EDCA_MSK;
@@ -343,118 +207,14 @@ void iwl_activate_qos(struct iwl_priv *priv, u8 force)
        if (priv->current_ht_config.is_ht)
                priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
-       if (force || iwl_is_associated(priv)) {
-               IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-                               priv->qos_data.qos_active,
-                               priv->qos_data.def_qos_parm.qos_flags);
+       IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+                     priv->qos_data.qos_active,
+                     priv->qos_data.def_qos_parm.qos_flags);
 
-               iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
-                                      sizeof(struct iwl_qosparam_cmd),
-                                      &priv->qos_data.def_qos_parm, NULL);
-       }
+       iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+                              sizeof(struct iwl_qosparam_cmd),
+                              &priv->qos_data.def_qos_parm, NULL);
 }
-EXPORT_SYMBOL(iwl_activate_qos);
-
-/*
- * AC        CWmin         CW max      AIFSN      TXOP Limit    TXOP Limit
- *                                              (802.11b)      (802.11a/g)
- * AC_BK      15            1023        7           0               0
- * AC_BE      15            1023        3           0               0
- * AC_VI       7              15        2          6.016ms       3.008ms
- * AC_VO       3               7        2          3.264ms       1.504ms
- */
-void iwl_reset_qos(struct iwl_priv *priv)
-{
-       u16 cw_min = 15;
-       u16 cw_max = 1023;
-       u8 aifs = 2;
-       bool is_legacy = false;
-       unsigned long flags;
-       int i;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       /* QoS always active in AP and ADHOC mode
-        * In STA mode wait for association
-        */
-       if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
-           priv->iw_mode == NL80211_IFTYPE_AP)
-               priv->qos_data.qos_active = 1;
-       else
-               priv->qos_data.qos_active = 0;
-
-       /* check for legacy mode */
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC &&
-           (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) ||
-           (priv->iw_mode == NL80211_IFTYPE_STATION &&
-           (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) {
-               cw_min = 31;
-               is_legacy = 1;
-       }
-
-       if (priv->qos_data.qos_active)
-               aifs = 3;
-
-       /* AC_BE */
-       priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
-       priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
-       priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
-       priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
-       priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
-
-       if (priv->qos_data.qos_active) {
-               /* AC_BK */
-               i = 1;
-               priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
-               priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
-               priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
-               priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
-               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-
-               /* AC_VI */
-               i = 2;
-               priv->qos_data.def_qos_parm.ac[i].cw_min =
-                       cpu_to_le16((cw_min + 1) / 2 - 1);
-               priv->qos_data.def_qos_parm.ac[i].cw_max =
-                       cpu_to_le16(cw_min);
-               priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
-               if (is_legacy)
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(6016);
-               else
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(3008);
-               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-
-               /* AC_VO */
-               i = 3;
-               priv->qos_data.def_qos_parm.ac[i].cw_min =
-                       cpu_to_le16((cw_min + 1) / 4 - 1);
-               priv->qos_data.def_qos_parm.ac[i].cw_max =
-                       cpu_to_le16((cw_min + 1) / 2 - 1);
-               priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
-               priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-               if (is_legacy)
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(3264);
-               else
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop =
-                               cpu_to_le16(1504);
-       } else {
-               for (i = 1; i < 4; i++) {
-                       priv->qos_data.def_qos_parm.ac[i].cw_min =
-                               cpu_to_le16(cw_min);
-                       priv->qos_data.def_qos_parm.ac[i].cw_max =
-                               cpu_to_le16(cw_max);
-                       priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
-                       priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
-                       priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
-               }
-       }
-       IWL_DEBUG_QOS(priv, "set QoS to default \n");
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_reset_qos);
 
 #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
 #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
@@ -721,7 +481,7 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
        return new_val;
 }
 
-void iwl_setup_rxon_timing(struct iwl_priv *priv)
+void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        u64 tsf;
        s32 interval_tm, rem;
@@ -735,15 +495,14 @@ void iwl_setup_rxon_timing(struct iwl_priv *priv)
        priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
        priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
 
-       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-               beacon_int = priv->beacon_int;
-               priv->rxon_timing.atim_window = 0;
-       } else {
-               beacon_int = priv->vif->bss_conf.beacon_int;
+       beacon_int = vif->bss_conf.beacon_int;
 
+       if (vif->type == NL80211_IFTYPE_ADHOC) {
                /* TODO: we need to get atim_window from upper stack
                 * for now we set to 0 */
                priv->rxon_timing.atim_window = 0;
+       } else {
+               priv->rxon_timing.atim_window = 0;
        }
 
        beacon_int = iwl_adjust_beacon_interval(beacon_int,
@@ -903,23 +662,10 @@ EXPORT_SYMBOL(iwl_full_rxon_required);
 
 u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv)
 {
-       int i;
-       int rate_mask;
-
-       /* Set rate mask*/
-       if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
-               rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK;
-       else
-               rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK;
-
-       /* Find lowest valid rate */
-       for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
-                                       i = iwl_rates[i].next_ieee) {
-               if (rate_mask & (1 << i))
-                       return iwl_rates[i].plcp;
-       }
-
-       /* No valid rate was found. Assign the lowest one */
+       /*
+        * Assign the lowest rate -- should really get this from
+        * the beacon skb from mac80211.
+        */
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)
                return IWL_RATE_1M_PLCP;
        else
@@ -991,7 +737,6 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf)
                        "extension channel offset 0x%x\n",
                        le32_to_cpu(rxon->flags), ht_conf->ht_protection,
                        ht_conf->extension_chan_offset);
-       return;
 }
 EXPORT_SYMBOL(iwl_set_rxon_ht);
 
@@ -1050,19 +795,6 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap)
        return res;
 }
 
-/**
- * iwl_is_monitor_mode - Determine if interface in monitor mode
- *
- * priv->iw_mode is set in add_interface, but add_interface is
- * never called for monitor mode. The only way mac80211 informs us about
- * monitor mode is through configuring filters (call to configure_filter).
- */
-bool iwl_is_monitor_mode(struct iwl_priv *priv)
-{
-       return !!(priv->staging_rxon.filter_flags & RXON_FILTER_PROMISC_MSK);
-}
-EXPORT_SYMBOL(iwl_is_monitor_mode);
-
 /**
  * iwl_set_rxon_chain - Set up Rx chain usage in "staging" RXON image
  *
@@ -1106,19 +838,6 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
        rx_chain |= active_rx_cnt << RXON_RX_CHAIN_MIMO_CNT_POS;
        rx_chain |= idle_rx_cnt  << RXON_RX_CHAIN_CNT_POS;
 
-       /* copied from 'iwl_bg_request_scan()' */
-       /* Force use of chains B and C (0x6) for Rx for 4965
-        * Avoid A (0x1) because of its off-channel reception on A-band.
-        * MIMO is not used here, but value is required */
-       if (iwl_is_monitor_mode(priv) &&
-           !(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) &&
-           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)) {
-               rx_chain = ANT_ABC << RXON_RX_CHAIN_VALID_POS;
-               rx_chain |= ANT_BC << RXON_RX_CHAIN_FORCE_SEL_POS;
-               rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
-               rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
-       }
-
        priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
 
        if (!is_single && (active_rx_cnt >= IWL_NUM_RX_CHAINS_SINGLE) && is_cam)
@@ -1174,8 +893,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
 }
 EXPORT_SYMBOL(iwl_set_rxon_channel);
 
-void iwl_set_flags_for_band(struct iwl_priv *priv,
-                           enum ieee80211_band band)
+static void iwl_set_flags_for_band(struct iwl_priv *priv,
+                                  enum ieee80211_band band,
+                                  struct ieee80211_vif *vif)
 {
        if (band == IEEE80211_BAND_5GHZ) {
                priv->staging_rxon.flags &=
@@ -1184,12 +904,12 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
                priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
        } else {
                /* Copied from iwl_post_associate() */
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               if (vif && vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+               if (vif && vif->type == NL80211_IFTYPE_ADHOC)
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
                priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
@@ -1201,13 +921,18 @@ void iwl_set_flags_for_band(struct iwl_priv *priv,
 /*
  * initialize rxon structure with default values from eeprom
  */
-void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif)
 {
        const struct iwl_channel_info *ch_info;
+       enum nl80211_iftype type = NL80211_IFTYPE_STATION;
+
+       if (vif)
+               type = vif->type;
 
        memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
 
-       switch (mode) {
+       switch (type) {
        case NL80211_IFTYPE_AP:
                priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
                break;
@@ -1225,7 +950,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
                break;
 
        default:
-               IWL_ERR(priv, "Unsupported interface type %d\n", mode);
+               IWL_ERR(priv, "Unsupported interface type %d\n", type);
                break;
        }
 
@@ -1244,18 +969,10 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
        if (!ch_info)
                ch_info = &priv->channel_info[0];
 
-       /*
-        * in some case A channels are all non IBSS
-        * in this case force B/G channel
-        */
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
-           !(is_channel_ibss(ch_info)))
-               ch_info = &priv->channel_info[0];
-
        priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
        priv->band = ch_info->band;
 
-       iwl_set_flags_for_band(priv, priv->band);
+       iwl_set_flags_for_band(priv, priv->band, vif);
 
        priv->staging_rxon.ofdm_basic_rates =
            (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
@@ -1286,7 +1003,6 @@ static void iwl_set_rate(struct iwl_priv *priv)
        }
 
        priv->active_rate = 0;
-       priv->active_rate_basic = 0;
 
        for (i = 0; i < hw->n_bitrates; i++) {
                rate = &(hw->bitrates[i]);
@@ -1294,30 +1010,13 @@ static void iwl_set_rate(struct iwl_priv *priv)
                        priv->active_rate |= (1 << rate->hw_value);
        }
 
-       IWL_DEBUG_RATE(priv, "Set active_rate = %0x, active_rate_basic = %0x\n",
-                      priv->active_rate, priv->active_rate_basic);
+       IWL_DEBUG_RATE(priv, "Set active_rate = %0x\n", priv->active_rate);
 
-       /*
-        * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
-        * otherwise set it to the default of all CCK rates and 6, 12, 24 for
-        * OFDM
-        */
-       if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
-               priv->staging_rxon.cck_basic_rates =
-                   ((priv->active_rate_basic &
-                     IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
-       else
-               priv->staging_rxon.cck_basic_rates =
-                   (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
-
-       if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
-               priv->staging_rxon.ofdm_basic_rates =
-                   ((priv->active_rate_basic &
-                     (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
-                     IWL_FIRST_OFDM_RATE) & 0xFF;
-       else
-               priv->staging_rxon.ofdm_basic_rates =
-                  (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+       priv->staging_rxon.cck_basic_rates =
+           (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+       priv->staging_rxon.ofdm_basic_rates =
+          (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
 
 void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
@@ -1374,6 +1073,9 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
        /* Cancel currently queued command. */
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+       IWL_ERR(priv, "Loaded firmware version: %s\n",
+               priv->hw->wiphy->fw_version);
+
        priv->cfg->ops->lib->dump_nic_error_log(priv);
        if (priv->cfg->ops->lib->dump_csr)
                priv->cfg->ops->lib->dump_csr(priv);
@@ -1401,7 +1103,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_irq_handle_error);
 
-int iwl_apm_stop_master(struct iwl_priv *priv)
+static int iwl_apm_stop_master(struct iwl_priv *priv)
 {
        int ret = 0;
 
@@ -1417,7 +1119,6 @@ int iwl_apm_stop_master(struct iwl_priv *priv)
 
        return ret;
 }
-EXPORT_SYMBOL(iwl_apm_stop_master);
 
 void iwl_apm_stop(struct iwl_priv *priv)
 {
@@ -1561,41 +1262,33 @@ void iwl_configure_filter(struct ieee80211_hw *hw,
                          u64 multicast)
 {
        struct iwl_priv *priv = hw->priv;
-       __le32 *filter_flags = &priv->staging_rxon.filter_flags;
+       __le32 filter_or = 0, filter_nand = 0;
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
 
        IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
                        changed_flags, *total_flags);
 
-       if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) {
-               if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS))
-                       *filter_flags |= RXON_FILTER_PROMISC_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_PROMISC_MSK;
-       }
-       if (changed_flags & FIF_ALLMULTI) {
-               if (*total_flags & FIF_ALLMULTI)
-                       *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK;
-       }
-       if (changed_flags & FIF_CONTROL) {
-               if (*total_flags & FIF_CONTROL)
-                       *filter_flags |= RXON_FILTER_CTL2HOST_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK;
-       }
-       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-               if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
-                       *filter_flags |= RXON_FILTER_BCON_AWARE_MSK;
-               else
-                       *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK;
-       }
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK);
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
 
-       /* We avoid iwl_commit_rxon here to commit the new filter flags
-        * since mac80211 will call ieee80211_hw_config immediately.
-        * (mc_list is not supported at this time). Otherwise, we need to
-        * queue a background iwl_commit_rxon work.
-        */
+#undef CHK
+
+       mutex_lock(&priv->mutex);
+
+       priv->staging_rxon.filter_flags &= ~filter_nand;
+       priv->staging_rxon.filter_flags |= filter_or;
+
+       iwlcore_commit_rxon(priv);
+
+       mutex_unlock(&priv->mutex);
 
        *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
@@ -1626,10 +1319,11 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        int ret = 0;
        s8 prev_tx_power = priv->tx_power_user_lmt;
 
-       if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) {
-               IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
+       if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
+               IWL_WARN(priv,
+                        "Requested user TXPOWER %d below lower limit %d.\n",
                         tx_power,
-                        IWL_TX_POWER_TARGET_POWER_MIN);
+                        IWLAGN_TX_POWER_TARGET_POWER_MIN);
                return -EINVAL;
        }
 
@@ -1668,286 +1362,16 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 }
 EXPORT_SYMBOL(iwl_set_tx_power);
 
-#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
-
-/* Free dram table */
-void iwl_free_isr_ict(struct iwl_priv *priv)
-{
-       if (priv->ict_tbl_vir) {
-               dma_free_coherent(&priv->pci_dev->dev,
-                                 (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
-                                 priv->ict_tbl_vir, priv->ict_tbl_dma);
-               priv->ict_tbl_vir = NULL;
-       }
-}
-EXPORT_SYMBOL(iwl_free_isr_ict);
-
-
-/* allocate dram shared table it is a PAGE_SIZE aligned
- * also reset all data related to ICT table interrupt.
- */
-int iwl_alloc_isr_ict(struct iwl_priv *priv)
-{
-
-       if (priv->cfg->use_isr_legacy)
-               return 0;
-       /* allocate shrared data table */
-       priv->ict_tbl_vir = dma_alloc_coherent(&priv->pci_dev->dev,
-                                       (sizeof(u32) * ICT_COUNT) + PAGE_SIZE,
-                                       &priv->ict_tbl_dma, GFP_KERNEL);
-       if (!priv->ict_tbl_vir)
-               return -ENOMEM;
-
-       /* align table to PAGE_SIZE boundry */
-       priv->aligned_ict_tbl_dma = ALIGN(priv->ict_tbl_dma, PAGE_SIZE);
-
-       IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n",
-                            (unsigned long long)priv->ict_tbl_dma,
-                            (unsigned long long)priv->aligned_ict_tbl_dma,
-                       (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
-
-       priv->ict_tbl =  priv->ict_tbl_vir +
-                         (priv->aligned_ict_tbl_dma - priv->ict_tbl_dma);
-
-       IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n",
-                            priv->ict_tbl, priv->ict_tbl_vir,
-                       (int)(priv->aligned_ict_tbl_dma - priv->ict_tbl_dma));
-
-       /* reset table and index to all 0 */
-       memset(priv->ict_tbl_vir,0, (sizeof(u32) * ICT_COUNT) + PAGE_SIZE);
-       priv->ict_index = 0;
-
-       /* add periodic RX interrupt */
-       priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
-       return 0;
-}
-EXPORT_SYMBOL(iwl_alloc_isr_ict);
-
-/* Device is going up inform it about using ICT interrupt table,
- * also we need to tell the driver to start using ICT interrupt.
- */
-int iwl_reset_ict(struct iwl_priv *priv)
-{
-       u32 val;
-       unsigned long flags;
-
-       if (!priv->ict_tbl_vir)
-               return 0;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_disable_interrupts(priv);
-
-       memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT);
-
-       val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT;
-
-       val |= CSR_DRAM_INT_TBL_ENABLE;
-       val |= CSR_DRAM_INIT_TBL_WRAP_CHECK;
-
-       IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X "
-                       "aligned dma address %Lx\n",
-                       val, (unsigned long long)priv->aligned_ict_tbl_dma);
-
-       iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val);
-       priv->use_ict = true;
-       priv->ict_index = 0;
-       iwl_write32(priv, CSR_INT, priv->inta_mask);
-       iwl_enable_interrupts(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_reset_ict);
-
-/* Device is going down disable ict interrupt usage */
-void iwl_disable_ict(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->use_ict = false;
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_disable_ict);
-
-/* interrupt handler using ict table, with this interrupt driver will
- * stop using INTA register to get device's interrupt, reading this register
- * is expensive, device will write interrupts in ICT dram table, increment
- * index then will fire interrupt to driver, driver will OR all ICT table
- * entries from current index up to table entry with 0 value. the result is
- * the interrupt we need to service, driver will set the entries back to 0 and
- * set index.
- */
-irqreturn_t iwl_isr_ict(int irq, void *data)
-{
-       struct iwl_priv *priv = data;
-       u32 inta, inta_mask;
-       u32 val = 0;
-
-       if (!priv)
-               return IRQ_NONE;
-
-       /* dram interrupt table not set yet,
-        * use legacy interrupt.
-        */
-       if (!priv->use_ict)
-               return iwl_isr(irq, data);
-
-       spin_lock(&priv->lock);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        * back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here.
-        */
-       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!priv->ict_tbl[priv->ict_index]) {
-               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
-               goto none;
-       }
-
-       /* read all entries that not 0 start with ict_index */
-       while (priv->ict_tbl[priv->ict_index]) {
-
-               val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]);
-               IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n",
-                               priv->ict_index,
-                               le32_to_cpu(priv->ict_tbl[priv->ict_index]));
-               priv->ict_tbl[priv->ict_index] = 0;
-               priv->ict_index = iwl_queue_inc_wrap(priv->ict_index,
-                                                    ICT_COUNT);
-
-       }
-
-       /* We should not get this value, just ignore it. */
-       if (val == 0xffffffff)
-               val = 0;
-
-       /*
-        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
-        * (bit 15 before shifting it to 31) to clear when using interrupt
-        * coalescing. fortunately, bits 18 and 19 stay set when this happens
-        * so we use them to decide on the real state of the Rx bit.
-        * In order words, bit 15 is set if bit 18 or bit 19 are set.
-        */
-       if (val & 0xC0000)
-               val |= 0x8000;
-
-       inta = (0xff & val) | ((0xff00 & val) << 16);
-       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n",
-                       inta, inta_mask, val);
-
-       inta &= priv->inta_mask;
-       priv->inta |= inta;
-
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
-       if (likely(inta))
-               tasklet_schedule(&priv->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) {
-               /* Allow interrupt if was disabled by this handler and
-                * no tasklet was schedules, We should not enable interrupt,
-                * tasklet will enable it.
-                */
-               iwl_enable_interrupts(priv);
-       }
-
-       spin_unlock(&priv->lock);
-       return IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service.
-        * only Re-enable if disabled by irq.
-        */
-       if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
-               iwl_enable_interrupts(priv);
-
-       spin_unlock(&priv->lock);
-       return IRQ_NONE;
-}
-EXPORT_SYMBOL(iwl_isr_ict);
-
-
-static irqreturn_t iwl_isr(int irq, void *data)
-{
-       struct iwl_priv *priv = data;
-       u32 inta, inta_mask;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       u32 inta_fh;
-#endif
-       if (!priv)
-               return IRQ_NONE;
-
-       spin_lock(&priv->lock);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-       /* Discover which interrupts are active/pending */
-       inta = iwl_read32(priv, CSR_INT);
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!inta) {
-               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n");
-               goto none;
-       }
-
-       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-               /* Hardware disappeared. It might have already raised
-                * an interrupt */
-               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-               goto unplugged;
-       }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
-               inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-               IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
-                             "fh 0x%08x\n", inta, inta_mask, inta_fh);
-       }
-#endif
-
-       priv->inta |= inta;
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
-       if (likely(inta))
-               tasklet_schedule(&priv->irq_tasklet);
-       else if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
-               iwl_enable_interrupts(priv);
-
- unplugged:
-       spin_unlock(&priv->lock);
-       return IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service. */
-       /* only Re-enable if diabled by irq  and no schedules tasklet. */
-       if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta)
-               iwl_enable_interrupts(priv);
-
-       spin_unlock(&priv->lock);
-       return IRQ_NONE;
-}
-
 irqreturn_t iwl_isr_legacy(int irq, void *data)
 {
        struct iwl_priv *priv = data;
        u32 inta, inta_mask;
        u32 inta_fh;
+       unsigned long flags;
        if (!priv)
                return IRQ_NONE;
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* Disable (but don't clear!) interrupts here to avoid
         *    back-to-back ISRs and sporadic interrupts from our NIC.
@@ -1985,7 +1409,7 @@ irqreturn_t iwl_isr_legacy(int irq, void *data)
                tasklet_schedule(&priv->irq_tasklet);
 
  unplugged:
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_HANDLED;
 
  none:
@@ -1993,12 +1417,12 @@ irqreturn_t iwl_isr_legacy(int irq, void *data)
        /* only Re-enable if diabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
                iwl_enable_interrupts(priv);
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        return IRQ_NONE;
 }
 EXPORT_SYMBOL(iwl_isr_legacy);
 
-int iwl_send_bt_config(struct iwl_priv *priv)
+void iwl_send_bt_config(struct iwl_priv *priv)
 {
        struct iwl_bt_cmd bt_cmd = {
                .lead_time = BT_LEAD_TIME_DEF,
@@ -2015,8 +1439,9 @@ int iwl_send_bt_config(struct iwl_priv *priv)
        IWL_DEBUG_INFO(priv, "BT coex %s\n",
                (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active");
 
-       return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
-                               sizeof(struct iwl_bt_cmd), &bt_cmd);
+       if (iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+                            sizeof(struct iwl_bt_cmd), &bt_cmd))
+               IWL_ERR(priv, "failed to send BT Coex Config\n");
 }
 EXPORT_SYMBOL(iwl_send_bt_config);
 
@@ -2306,12 +1731,6 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                        cpu_to_le16((params->txop * 32));
 
        priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-       priv->qos_data.qos_active = 1;
-
-       if (priv->iw_mode == NL80211_IFTYPE_AP)
-               iwl_activate_qos(priv, 1);
-       else if (priv->assoc_id && iwl_is_associated(priv))
-               iwl_activate_qos(priv, 0);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -2321,12 +1740,13 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 EXPORT_SYMBOL(iwl_mac_conf_tx);
 
 static void iwl_ht_conf(struct iwl_priv *priv,
-                       struct ieee80211_bss_conf *bss_conf)
+                       struct ieee80211_vif *vif)
 {
        struct iwl_ht_config *ht_conf = &priv->current_ht_config;
        struct ieee80211_sta *sta;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 
-       IWL_DEBUG_MAC80211(priv, "enter: \n");
+       IWL_DEBUG_MAC80211(priv, "enter:\n");
 
        if (!ht_conf->is_ht)
                return;
@@ -2338,10 +1758,10 @@ static void iwl_ht_conf(struct iwl_priv *priv,
 
        ht_conf->single_chain_sufficient = false;
 
-       switch (priv->iw_mode) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                rcu_read_lock();
-               sta = ieee80211_find_sta(priv->vif, priv->bssid);
+               sta = ieee80211_find_sta(vif, bss_conf->bssid);
                if (sta) {
                        struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
                        int maxstreams;
@@ -2379,7 +1799,6 @@ static void iwl_ht_conf(struct iwl_priv *priv,
 
 static inline void iwl_set_no_assoc(struct iwl_priv *priv)
 {
-       priv->assoc_id = 0;
        iwl_led_disassociate(priv);
        /*
         * inform the ucode that there is no longer an
@@ -2392,7 +1811,6 @@ static inline void iwl_set_no_assoc(struct iwl_priv *priv)
        iwlcore_commit_rxon(priv);
 }
 
-#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6)
 void iwl_bss_info_changed(struct ieee80211_hw *hw,
                          struct ieee80211_vif *vif,
                          struct ieee80211_bss_conf *bss_conf,
@@ -2408,14 +1826,12 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
-       if (changes & BSS_CHANGED_BEACON &&
-           priv->iw_mode == NL80211_IFTYPE_AP) {
+       if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) {
                dev_kfree_skb(priv->ibss_beacon);
                priv->ibss_beacon = ieee80211_beacon_get(hw, vif);
        }
 
        if (changes & BSS_CHANGED_BEACON_INT) {
-               priv->beacon_int = bss_conf->beacon_int;
                /* TODO: in AP mode, do something to make this take effect */
        }
 
@@ -2435,8 +1851,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                }
 
                /* mac80211 only sets assoc when in STATION mode */
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC ||
-                   bss_conf->assoc) {
+               if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) {
                        memcpy(priv->staging_rxon.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
 
@@ -2454,7 +1869,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
         * mac80211 decides to do both changes at once because
         * it will invoke post_associate.
         */
-       if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
            changes & BSS_CHANGED_BEACON) {
                struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 
@@ -2497,7 +1912,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changes & BSS_CHANGED_HT) {
-               iwl_ht_conf(priv, bss_conf);
+               iwl_ht_conf(priv, vif);
 
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv);
@@ -2506,28 +1921,17 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
        if (changes & BSS_CHANGED_ASSOC) {
                IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc);
                if (bss_conf->assoc) {
-                       priv->assoc_id = bss_conf->aid;
-                       priv->beacon_int = bss_conf->beacon_int;
                        priv->timestamp = bss_conf->timestamp;
-                       priv->assoc_capability = bss_conf->assoc_capability;
 
                        iwl_led_associate(priv);
 
-                       /*
-                        * We have just associated, don't start scan too early
-                        * leave time for EAPOL exchange to complete.
-                        *
-                        * XXX: do this in mac80211
-                        */
-                       priv->next_scan_jiffies = jiffies +
-                                       IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
                        if (!iwl_is_rfkill(priv))
-                               priv->cfg->ops->lib->post_associate(priv);
+                               priv->cfg->ops->lib->post_associate(priv, vif);
                } else
                        iwl_set_no_assoc(priv);
        }
 
-       if (changes && iwl_is_associated(priv) && priv->assoc_id) {
+       if (changes && iwl_is_associated(priv) && bss_conf->aid) {
                IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n",
                                   changes);
                ret = iwl_send_rxon_assoc(priv);
@@ -2544,11 +1948,20 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw,
                        memcpy(priv->staging_rxon.bssid_addr,
                               bss_conf->bssid, ETH_ALEN);
                        memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN);
-                       iwlcore_config_ap(priv);
+                       iwlcore_config_ap(priv, vif);
                } else
                        iwl_set_no_assoc(priv);
        }
 
+       if (changes & BSS_CHANGED_IBSS) {
+               ret = priv->cfg->ops->lib->manage_ibss_station(priv, vif,
+                                                       bss_conf->ibss_joined);
+               if (ret)
+                       IWL_ERR(priv, "failed to %s IBSS station %pM\n",
+                               bss_conf->ibss_joined ? "add" : "remove",
+                               bss_conf->bssid);
+       }
+
        mutex_unlock(&priv->mutex);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -2568,11 +1981,6 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
                return -EIO;
        }
 
-       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-               IWL_DEBUG_MAC80211(priv, "leave - not IBSS\n");
-               return -EIO;
-       }
-
        spin_lock_irqsave(&priv->lock, flags);
 
        if (priv->ibss_beacon)
@@ -2580,59 +1988,31 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        priv->ibss_beacon = skb;
 
-       priv->assoc_id = 0;
        timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
        priv->timestamp = le64_to_cpu(timestamp);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl_reset_qos(priv);
-
-       priv->cfg->ops->lib->post_associate(priv);
-
+       priv->cfg->ops->lib->post_associate(priv, priv->vif);
 
        return 0;
 }
 EXPORT_SYMBOL(iwl_mac_beacon_update);
 
-int iwl_set_mode(struct iwl_priv *priv, int mode)
+static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
-       if (mode == NL80211_IFTYPE_ADHOC) {
-               const struct iwl_channel_info *ch_info;
-
-               ch_info = iwl_get_channel_info(priv,
-                       priv->band,
-                       le16_to_cpu(priv->staging_rxon.channel));
-
-               if (!ch_info || !is_channel_ibss(ch_info)) {
-                       IWL_ERR(priv, "channel %d not IBSS channel\n",
-                                 le16_to_cpu(priv->staging_rxon.channel));
-                       return -EINVAL;
-               }
-       }
-
-       iwl_connection_init_rx_config(priv, mode);
+       iwl_connection_init_rx_config(priv, vif);
 
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv);
 
        memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
 
-       iwl_clear_stations_table(priv);
-
-       /* dont commit rxon if rf-kill is on*/
-       if (!iwl_is_ready_rf(priv))
-               return -EAGAIN;
-
-       iwlcore_commit_rxon(priv);
-
-       return 0;
+       return iwlcore_commit_rxon(priv);
 }
-EXPORT_SYMBOL(iwl_set_mode);
 
-int iwl_mac_add_interface(struct ieee80211_hw *hw,
-                                struct ieee80211_vif *vif)
+int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
        int err = 0;
@@ -2641,6 +2021,11 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
+       if (WARN_ON(!iwl_is_ready_rf(priv))) {
+               err = -EINVAL;
+               goto out;
+       }
+
        if (priv->vif) {
                IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n");
                err = -EOPNOTSUPP;
@@ -2650,15 +2035,18 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw,
        priv->vif = vif;
        priv->iw_mode = vif->type;
 
-       if (vif->addr) {
-               IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
-               memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
-       }
+       IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
+       memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
+
+       err = iwl_set_mode(priv, vif);
+       if (err)
+               goto out_err;
 
-       if (iwl_set_mode(priv, vif->type) == -EAGAIN)
-               /* we are not ready, will run again when ready */
-               set_bit(STATUS_MODE_PENDING, &priv->status);
+       goto out;
 
+ out_err:
+       priv->vif = NULL;
+       priv->iw_mode = NL80211_IFTYPE_STATION;
  out:
        mutex_unlock(&priv->mutex);
 
@@ -2668,7 +2056,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_vif *vif)
+                             struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
 
@@ -2694,10 +2082,6 @@ EXPORT_SYMBOL(iwl_mac_remove_interface);
 
 /**
  * iwl_mac_config - mac80211 config callback
- *
- * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
- * be set inappropriately and the driver currently sets the hardware up to
- * use it whenever needed.
  */
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
 {
@@ -2752,15 +2136,6 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                        goto set_ch_out;
                }
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
-                       !is_channel_ibss(ch_info)) {
-                       IWL_ERR(priv, "channel %d in band %d not "
-                               "IBSS channel\n",
-                               conf->channel->hw_value, conf->channel->band);
-                       ret = -EINVAL;
-                       goto set_ch_out;
-               }
-
                spin_lock_irqsave(&priv->lock, flags);
 
                /* Configure HT40 channels */
@@ -2794,7 +2169,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_rxon_channel(priv, conf->channel);
                iwl_set_rxon_ht(priv, ht_conf);
 
-               iwl_set_flags_for_band(priv, conf->channel->band);
+               iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
                spin_unlock_irqrestore(&priv->lock, flags);
                if (iwl_is_associated(priv) &&
                    (le16_to_cpu(priv->active_rxon.channel) != ch) &&
@@ -2833,6 +2208,15 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                iwl_set_tx_power(priv, conf->power_level, false);
        }
 
+       if (changed & IEEE80211_CONF_CHANGE_QOS) {
+               bool qos_active = !!(conf->flags & IEEE80211_CONF_QOS);
+
+               spin_lock_irqsave(&priv->lock, flags);
+               priv->qos_data.qos_active = qos_active;
+               iwl_update_qos(priv);
+               spin_unlock_irqrestore(&priv->lock, flags);
+       }
+
        if (!iwl_is_ready(priv)) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                goto out;
@@ -2867,12 +2251,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
        memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config));
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       iwl_reset_qos(priv);
-
        spin_lock_irqsave(&priv->lock, flags);
-       priv->assoc_id = 0;
-       priv->assoc_capability = 0;
-       priv->assoc_station_added = 0;
 
        /* new association get rid of ibss beacon skb */
        if (priv->ibss_beacon)
@@ -2880,10 +2259,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
 
        priv->ibss_beacon = NULL;
 
-       priv->beacon_int = priv->vif->bss_conf.beacon_int;
        priv->timestamp = 0;
-       if ((priv->iw_mode == NL80211_IFTYPE_STATION))
-               priv->beacon_int = 0;
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -2896,17 +2272,9 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
        /* we are restarting association process
         * clear RXON_FILTER_ASSOC_MSK bit
         */
-       if (priv->iw_mode != NL80211_IFTYPE_AP) {
-               iwl_scan_cancel_timeout(priv, 100);
-               priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-               iwlcore_commit_rxon(priv);
-       }
-
-       if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-               IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
-               mutex_unlock(&priv->mutex);
-               return;
-       }
+       iwl_scan_cancel_timeout(priv, 100);
+       priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       iwlcore_commit_rxon(priv);
 
        iwl_set_rate(priv);
 
@@ -2923,7 +2291,7 @@ int iwl_alloc_txq_mem(struct iwl_priv *priv)
                        sizeof(struct iwl_tx_queue) * priv->cfg->num_of_queues,
                        GFP_KERNEL);
        if (!priv->txq) {
-               IWL_ERR(priv, "Not enough memory for txq \n");
+               IWL_ERR(priv, "Not enough memory for txq\n");
                return -ENOMEM;
        }
        return 0;
@@ -2937,34 +2305,6 @@ void iwl_free_txq_mem(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_free_txq_mem);
 
-int iwl_send_wimax_coex(struct iwl_priv *priv)
-{
-       struct iwl_wimax_coex_cmd uninitialized_var(coex_cmd);
-
-       if (priv->cfg->support_wimax_coexist) {
-               /* UnMask wake up src at associated sleep */
-               coex_cmd.flags |= COEX_FLAGS_ASSOC_WA_UNMASK_MSK;
-
-               /* UnMask wake up src at unassociated sleep */
-               coex_cmd.flags |= COEX_FLAGS_UNASSOC_WA_UNMASK_MSK;
-               memcpy(coex_cmd.sta_prio, cu_priorities,
-                       sizeof(struct iwl_wimax_coex_event_entry) *
-                        COEX_NUM_OF_EVENTS);
-
-               /* enabling the coexistence feature */
-               coex_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK;
-
-               /* enabling the priorities tables */
-               coex_cmd.flags |= COEX_FLAGS_STA_TABLE_VALID_MSK;
-       } else {
-               /* coexistence is disabled */
-               memset(&coex_cmd, 0, sizeof(coex_cmd));
-       }
-       return iwl_send_cmd_pdu(priv, COEX_PRIORITY_TABLE_CMD,
-                               sizeof(coex_cmd), &coex_cmd);
-}
-EXPORT_SYMBOL(iwl_send_wimax_coex);
-
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 
 #define IWL_TRAFFIC_DUMP_SIZE  (IWL_TRAFFIC_ENTRY_SIZE * IWL_TRAFFIC_ENTRIES)
@@ -3403,6 +2743,99 @@ int iwl_force_reset(struct iwl_priv *priv, int mode)
        }
        return 0;
 }
+EXPORT_SYMBOL(iwl_force_reset);
+
+/**
+ * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover
+ *
+ * During normal condition (no queue is stuck), the timer is continually set to
+ * execute every monitor_recover_period milliseconds after the last timer
+ * expired.  When the queue read_ptr is at the same place, the timer is
+ * shorten to 100mSecs.  This is
+ *      1) to reduce the chance that the read_ptr may wrap around (not stuck)
+ *      2) to detect the stuck queues quicker before the station and AP can
+ *      disassociate each other.
+ *
+ * This function monitors all the tx queues and recover from it if any
+ * of the queues are stuck.
+ * 1. It first check the cmd queue for stuck conditions.  If it is stuck,
+ *      it will recover by resetting the firmware and return.
+ * 2. Then, it checks for station association.  If it associates it will check
+ *      other queues.  If any queue is stuck, it will recover by resetting
+ *      the firmware.
+ * Note: It the number of times the queue read_ptr to be at the same place to
+ *      be MAX_REPEAT+1 in order to consider to be stuck.
+ */
+/*
+ * The maximum number of times the read pointer of the tx queue at the
+ * same place without considering to be stuck.
+ */
+#define MAX_REPEAT      (2)
+static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt)
+{
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+
+       txq = &priv->txq[cnt];
+       q = &txq->q;
+       /* queue is empty, skip */
+       if (q->read_ptr != q->write_ptr) {
+               if (q->read_ptr == q->last_read_ptr) {
+                       /* a queue has not been read from last time */
+                       if (q->repeat_same_read_ptr > MAX_REPEAT) {
+                               IWL_ERR(priv,
+                                       "queue %d stuck %d time. Fw reload.\n",
+                                       q->id, q->repeat_same_read_ptr);
+                               q->repeat_same_read_ptr = 0;
+                               iwl_force_reset(priv, IWL_FW_RESET);
+                       } else {
+                               q->repeat_same_read_ptr++;
+                               IWL_DEBUG_RADIO(priv,
+                                               "queue %d, not read %d time\n",
+                                               q->id,
+                                               q->repeat_same_read_ptr);
+                               mod_timer(&priv->monitor_recover, jiffies +
+                                       msecs_to_jiffies(IWL_ONE_HUNDRED_MSECS));
+                       }
+                       return 1;
+               } else {
+                       q->last_read_ptr = q->read_ptr;
+                       q->repeat_same_read_ptr = 0;
+               }
+       }
+       return 0;
+}
+
+void iwl_bg_monitor_recover(unsigned long data)
+{
+       struct iwl_priv *priv = (struct iwl_priv *)data;
+       int cnt;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       /* monitor and check for stuck cmd queue */
+       if (iwl_check_stuck_queue(priv, IWL_CMD_QUEUE_NUM))
+               return;
+
+       /* monitor and check for other stuck queues */
+       if (iwl_is_associated(priv)) {
+               for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) {
+                       /* skip as we already checked the command queue */
+                       if (cnt == IWL_CMD_QUEUE_NUM)
+                               continue;
+                       if (iwl_check_stuck_queue(priv, cnt))
+                               return;
+               }
+       }
+       /*
+        * Reschedule the timer to occur in
+        * priv->cfg->monitor_recover_period
+        */
+       mod_timer(&priv->monitor_recover,
+               jiffies + msecs_to_jiffies(priv->cfg->monitor_recover_period));
+}
+EXPORT_SYMBOL(iwl_bg_monitor_recover);
 
 #ifdef CONFIG_PM
 
@@ -3432,6 +2865,12 @@ int iwl_pci_resume(struct pci_dev *pdev)
        struct iwl_priv *priv = pci_get_drvdata(pdev);
        int ret;
 
+       /*
+        * We disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state.
+        */
+       pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
+
        pci_set_power_state(pdev, PCI_D0);
        ret = pci_enable_device(pdev);
        if (ret)
index 36940a9ec6b93442021af5b2f1053a607b5bd50f..7e5a5ba41fd210e492655a5248d39bd7d4c7beb1 100644 (file)
@@ -90,6 +90,7 @@ struct iwl_hcmd_ops {
        int (*commit_rxon)(struct iwl_priv *priv);
        void (*set_rxon_chain)(struct iwl_priv *priv);
        int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
+       void (*send_bt_config)(struct iwl_priv *priv);
 };
 
 struct iwl_hcmd_utils_ops {
@@ -105,6 +106,7 @@ struct iwl_hcmd_utils_ops {
                        __le32 *tx_flags);
        int  (*calc_rssi)(struct iwl_priv *priv,
                          struct iwl_rx_phy_res *rx_resp);
+       void (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
 };
 
 struct iwl_apm_ops {
@@ -114,23 +116,21 @@ struct iwl_apm_ops {
        int (*set_pwr_src)(struct iwl_priv *priv, enum iwl_pwr_src src);
 };
 
+struct iwl_debugfs_ops {
+       ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos);
+       ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf,
+                                size_t count, loff_t *ppos);
+       ssize_t (*general_stats_read)(struct file *file, char __user *user_buf,
+                                     size_t count, loff_t *ppos);
+};
+
 struct iwl_temp_ops {
        void (*temperature)(struct iwl_priv *priv);
        void (*set_ct_kill)(struct iwl_priv *priv);
        void (*set_calib_version)(struct iwl_priv *priv);
 };
 
-struct iwl_ucode_ops {
-       u32 (*get_header_size)(u32);
-       u32 (*get_build)(const struct iwl_ucode_header *, u32);
-       u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
-       u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
-       u8 * (*get_data)(const struct iwl_ucode_header *, u32);
-};
-
 struct iwl_lib_ops {
        /* set hw dependent parameters */
        int (*set_hw_params)(struct iwl_priv *priv);
@@ -180,8 +180,9 @@ struct iwl_lib_ops {
        /* power */
        int (*send_tx_power) (struct iwl_priv *priv);
        void (*update_chain_flags)(struct iwl_priv *priv);
-       void (*post_associate) (struct iwl_priv *priv);
-       void (*config_ap) (struct iwl_priv *priv);
+       void (*post_associate)(struct iwl_priv *priv,
+                              struct ieee80211_vif *vif);
+       void (*config_ap)(struct iwl_priv *priv, struct ieee80211_vif *vif);
        irqreturn_t (*isr) (int irq, void *data);
 
        /* eeprom operations (as defined in iwl-eeprom.h) */
@@ -190,7 +191,17 @@ struct iwl_lib_ops {
        /* temperature */
        struct iwl_temp_ops temp_ops;
        /* station management */
-       void (*add_bcast_station)(struct iwl_priv *priv);
+       int (*manage_ibss_station)(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif, bool add);
+       /* recover from tx queue stall */
+       void (*recover_from_tx_stall)(unsigned long data);
+       /* check for plcp health */
+       bool (*check_plcp_health)(struct iwl_priv *priv,
+                                       struct iwl_rx_packet *pkt);
+       /* check for ack health */
+       bool (*check_ack_health)(struct iwl_priv *priv,
+                                       struct iwl_rx_packet *pkt);
+       struct iwl_debugfs_ops debugfs_ops;
 };
 
 struct iwl_led_ops {
@@ -200,7 +211,6 @@ struct iwl_led_ops {
 };
 
 struct iwl_ops {
-       const struct iwl_ucode_ops *ucode;
        const struct iwl_lib_ops *lib;
        const struct iwl_hcmd_ops *hcmd;
        const struct iwl_hcmd_utils_ops *utils;
@@ -237,6 +247,18 @@ struct iwl_mod_params {
  * @support_wimax_coexist: support wimax/wifi co-exist
  * @plcp_delta_threshold: plcp error rate threshold used to trigger
  *     radio tuning when there is a high receiving plcp error rate
+ * @chain_noise_scale: default chain noise scale used for gain computation
+ * @monitor_recover_period: default timer used to check stuck queues
+ * @temperature_kelvin: temperature report by uCode in kelvin
+ * @max_event_log_size: size of event log buffer size for ucode event logging
+ * @tx_power_by_driver: tx power calibration performed by driver
+ *     instead of uCode
+ * @ucode_tracing: support ucode continuous tracing
+ * @sensitivity_calib_by_driver: driver has the capability to perform
+ *     sensitivity calibration operation
+ * @chain_noise_calib_by_driver: driver has the capability to perform
+ *     chain noise calibration operation
+ * @scan_antennas: available antenna for scan operation
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -295,6 +317,15 @@ struct iwl_cfg {
        const bool support_wimax_coexist;
        u8 plcp_delta_threshold;
        s32 chain_noise_scale;
+       /* timer period for monitor the driver queues */
+       u32 monitor_recover_period;
+       bool temperature_kelvin;
+       u32 max_event_log_size;
+       const bool tx_power_by_driver;
+       const bool ucode_tracing;
+       const bool sensitivity_calib_by_driver;
+       const bool chain_noise_calib_by_driver;
+       u8 scan_antennas[IEEE80211_NUM_BANDS];
 };
 
 /***************************
@@ -304,8 +335,7 @@ struct iwl_cfg {
 struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
                struct ieee80211_ops *hw_ops);
 void iwl_hw_detect(struct iwl_priv *priv);
-void iwl_reset_qos(struct iwl_priv *priv);
-void iwl_activate_qos(struct iwl_priv *priv, u8 force);
+void iwl_activate_qos(struct iwl_priv *priv);
 int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
                    const struct ieee80211_tx_queue_params *params);
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
@@ -316,8 +346,8 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
 void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
 u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
                         struct ieee80211_sta_ht_cap *sta_ht_inf);
-void iwl_set_flags_for_band(struct iwl_priv *priv, enum ieee80211_band band);
-void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode);
+void iwl_connection_init_rx_config(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif);
 int iwl_set_decrypted_flag(struct iwl_priv *priv,
                           struct ieee80211_hdr *hdr,
                           u32 decrypt_res,
@@ -326,29 +356,25 @@ void iwl_irq_handle_error(struct iwl_priv *priv);
 void iwl_configure_filter(struct ieee80211_hw *hw,
                          unsigned int changed_flags,
                          unsigned int *total_flags, u64 multicast);
-int iwl_hw_nic_init(struct iwl_priv *priv);
 int iwl_set_hw_params(struct iwl_priv *priv);
-bool iwl_is_monitor_mode(struct iwl_priv *priv);
-void iwl_post_associate(struct iwl_priv *priv);
+void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
                                     u32 changes);
 int iwl_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_vif *vif);
 void iwl_mac_remove_interface(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif);
 int iwl_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwl_config_ap(struct iwl_priv *priv);
+void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwl_mac_reset_tsf(struct ieee80211_hw *hw);
 int iwl_alloc_txq_mem(struct iwl_priv *priv);
 void iwl_free_txq_mem(struct iwl_priv *priv);
 void iwlcore_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
                                __le32 *tx_flags);
-int iwl_send_wimax_coex(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
 void iwl_free_traffic_mem(struct iwl_priv *priv);
@@ -411,26 +437,24 @@ void iwl_rx_reply_error(struct iwl_priv *priv,
 /*****************************************************
 * RX
 ******************************************************/
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
 void iwl_cmd_queue_free(struct iwl_priv *priv);
 int iwl_rx_queue_alloc(struct iwl_priv *priv);
 void iwl_rx_handle(struct iwl_priv *priv);
 void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
                                  struct iwl_rx_queue *q);
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-void iwl_rx_replenish(struct iwl_priv *priv);
-void iwl_rx_replenish_now(struct iwl_priv *priv);
-int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
-void iwl_rx_queue_restock(struct iwl_priv *priv);
 int iwl_rx_queue_space(const struct iwl_rx_queue *q);
-void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
 void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
-int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
 /* Handlers */
 void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb);
 void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
                                          struct iwl_rx_mem_buffer *rxb);
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+                                struct iwl_rx_packet *pkt);
+bool iwl_good_ack_health(struct iwl_priv *priv,
+                                struct iwl_rx_packet *pkt);
+void iwl_recover_from_statistics(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt);
 void iwl_rx_statistics(struct iwl_priv *priv,
                              struct iwl_rx_mem_buffer *rxb);
 void iwl_reply_statistics(struct iwl_priv *priv,
@@ -442,14 +466,10 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 /*****************************************************
 * TX
 ******************************************************/
-int iwl_txq_ctx_alloc(struct iwl_priv *priv);
-void iwl_txq_ctx_reset(struct iwl_priv *priv);
 void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
 int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
                                 struct iwl_tx_queue *txq,
                                 dma_addr_t addr, u16 len, u8 reset, u8 pad);
-int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
 int iwl_hw_tx_queue_init(struct iwl_priv *priv,
                         struct iwl_tx_queue *txq);
 void iwl_free_tfds_in_queue(struct iwl_priv *priv,
@@ -460,9 +480,6 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                        int slots_num, u32 txq_id);
 void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
-int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
-int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
-int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id);
 /*****************************************************
  * TX power
  ****************************************************/
@@ -472,10 +489,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
  * Rate
  ******************************************************************************/
 
-void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                             struct ieee80211_tx_info *info);
 int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
-int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
 
 u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
 
@@ -505,7 +519,10 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
 void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
+int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req);
+void iwl_bg_start_internal_scan(struct work_struct *work);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
@@ -515,7 +532,8 @@ u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
                              enum ieee80211_band band,
                              u8 n_probes);
 u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                              enum ieee80211_band band);
+                              enum ieee80211_band band,
+                              struct ieee80211_vif *vif);
 void iwl_bg_scan_check(struct work_struct *data);
 void iwl_bg_abort_scan(struct work_struct *work);
 void iwl_bg_scan_completed(struct work_struct *work);
@@ -530,6 +548,7 @@ void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
 #define IWL_ACTIVE_QUIET_TIME       cpu_to_le16(10)  /* msec */
 #define IWL_PLCP_QUIET_THRESH       cpu_to_le16(1)  /* packets */
 
+#define IWL_SCAN_CHECK_WATCHDOG                (HZ * 7)
 
 /*******************************************************************************
  * Calibrations - implemented in iwl-calib.c
@@ -563,11 +582,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
  * PCI                                              *
  *****************************************************/
 irqreturn_t iwl_isr_legacy(int irq, void *data);
-int iwl_reset_ict(struct iwl_priv *priv);
-void iwl_disable_ict(struct iwl_priv *priv);
-int iwl_alloc_isr_ict(struct iwl_priv *priv);
-void iwl_free_isr_ict(struct iwl_priv *priv);
-irqreturn_t iwl_isr_ict(int irq, void *data);
 
 static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
 {
@@ -577,6 +591,9 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
        pci_read_config_word(priv->pci_dev, pos + PCI_EXP_LNKCTL, &pci_lnk_ctl);
        return pci_lnk_ctl;
 }
+
+void iwl_bg_monitor_recover(unsigned long data);
+
 #ifdef CONFIG_PM
 int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
 int iwl_pci_resume(struct pci_dev *pdev);
@@ -625,7 +642,6 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_SCAN_HW         15
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
-#define STATUS_MODE_PENDING    18
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -672,23 +688,16 @@ static inline int iwl_is_ready_rf(struct iwl_priv *priv)
 }
 
 extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
-extern int iwl_send_bt_config(struct iwl_priv *priv);
+extern void iwl_send_bt_config(struct iwl_priv *priv);
 extern int iwl_send_statistics_request(struct iwl_priv *priv,
                                       u8 flags, bool clear);
 extern int iwl_verify_ucode(struct iwl_priv *priv);
 extern int iwl_send_lq_cmd(struct iwl_priv *priv,
-               struct iwl_link_quality_cmd *lq, u8 flags);
-extern void iwl_rx_reply_rx(struct iwl_priv *priv,
-               struct iwl_rx_mem_buffer *rxb);
-extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb);
-void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                          struct iwl_rx_mem_buffer *rxb);
+               struct iwl_link_quality_cmd *lq, u8 flags, bool init);
 void iwl_apm_stop(struct iwl_priv *priv);
-int iwl_apm_stop_master(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
-void iwl_setup_rxon_timing(struct iwl_priv *priv);
+void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif);
 static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
 {
        return priv->cfg->ops->hcmd->rxon_assoc(priv);
@@ -697,9 +706,10 @@ static inline int iwlcore_commit_rxon(struct iwl_priv *priv)
 {
        return priv->cfg->ops->hcmd->commit_rxon(priv);
 }
-static inline void iwlcore_config_ap(struct iwl_priv *priv)
+static inline void iwlcore_config_ap(struct iwl_priv *priv,
+                                    struct ieee80211_vif *vif)
 {
-       priv->cfg->ops->lib->config_ap(priv);
+       priv->cfg->ops->lib->config_ap(priv, vif);
 }
 static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
                        struct iwl_priv *priv, enum ieee80211_band band)
index 808b7146bead98d1cfc15e83051450d561261a37..254c35ae8b38b583472df5254a3b50c36e83825c 100644 (file)
 #define CSR_HW_REV_TYPE_1000           (0x0000060)
 #define CSR_HW_REV_TYPE_6x00           (0x0000070)
 #define CSR_HW_REV_TYPE_6x50           (0x0000080)
+#define CSR_HW_REV_TYPE_6x00g2         (0x00000B0)
 #define CSR_HW_REV_TYPE_NONE           (0x00000F0)
 
 /* EEPROM REG */
index 1c7b53d511c7eefe9bec3fca6fc143ab8d994f46..5c2bcef5df0cdca8a328f2fc35b38b7c6aa71f2b 100644 (file)
@@ -78,6 +78,8 @@ static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_dbgfs_register(struct iwl_priv *priv, const char *name);
 void iwl_dbgfs_unregister(struct iwl_priv *priv);
+extern int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
+                                    int bufsz);
 #else
 static inline int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
 {
index b6e1b0ebe230075292d5c2f4676f7bd9685e086d..9659c5d01df9331b87d4e458bb19769a87bef8d8 100644 (file)
@@ -106,6 +106,26 @@ static const struct file_operations iwl_dbgfs_##name##_ops = {          \
        .open = iwl_dbgfs_open_file_generic,                            \
 };
 
+int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+       int p = 0;
+
+       p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
+                      le32_to_cpu(priv->statistics.flag));
+       if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
+               p += scnprintf(buf + p, bufsz - p,
+                              "\tStatistics have been cleared\n");
+       p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+                      (le32_to_cpu(priv->statistics.flag) &
+                       UCODE_STATISTICS_FREQUENCY_MSK)
+                       ? "2.4 GHz" : "5.2 GHz");
+       p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+                      (le32_to_cpu(priv->statistics.flag) &
+                       UCODE_STATISTICS_NARROW_BAND_MSK)
+                       ? "enabled" : "disabled");
+       return p;
+}
+EXPORT_SYMBOL(iwl_dbgfs_statistics_flag);
 
 static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
                                                char __user *user_buf,
@@ -561,8 +581,6 @@ static ssize_t iwl_dbgfs_status_read(struct file *file,
                test_bit(STATUS_POWER_PMI, &priv->status));
        pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n",
                test_bit(STATUS_FW_ERROR, &priv->status));
-       pos += scnprintf(buf + pos, bufsz - pos, "STATUS_MODE_PENDING:\t %d\n",
-               test_bit(STATUS_MODE_PENDING, &priv->status));
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
@@ -661,7 +679,6 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
        int pos = 0, i;
        char buf[256];
        const size_t bufsz = sizeof(buf);
-       ssize_t ret;
 
        for (i = 0; i < AC_NUM; i++) {
                pos += scnprintf(buf + pos, bufsz - pos,
@@ -673,8 +690,7 @@ static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
                                priv->qos_data.def_qos_parm.ac[i].aifsn,
                                priv->qos_data.def_qos_parm.ac[i].edca_txop);
        }
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       return ret;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
@@ -684,7 +700,6 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
        int pos = 0;
        char buf[256];
        const size_t bufsz = sizeof(buf);
-       ssize_t ret;
 
        pos += scnprintf(buf + pos, bufsz - pos,
                         "allow blinking: %s\n",
@@ -698,8 +713,7 @@ static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
                                 priv->last_blink_time);
        }
 
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       return ret;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
@@ -712,7 +726,6 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
        char buf[100];
        int pos = 0;
        const size_t bufsz = sizeof(buf);
-       ssize_t ret;
 
        pos += scnprintf(buf + pos, bufsz - pos,
                        "Thermal Throttling Mode: %s\n",
@@ -732,8 +745,7 @@ static ssize_t iwl_dbgfs_thermal_throttling_read(struct file *file,
                                "HT mode: %d\n",
                                restriction->is_ht);
        }
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       return ret;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_disable_ht40_write(struct file *file,
@@ -770,13 +782,11 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
        char buf[100];
        int pos = 0;
        const size_t bufsz = sizeof(buf);
-       ssize_t ret;
 
        pos += scnprintf(buf + pos, bufsz - pos,
                        "11n 40MHz Mode: %s\n",
                        priv->disable_ht40 ? "Disabled" : "Enabled");
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       return ret;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
@@ -1044,474 +1054,13 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
-static int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf,
-                                    int bufsz)
-{
-       int p = 0;
-
-       p += scnprintf(buf + p, bufsz - p,
-               "Statistics Flag(0x%X):\n",
-               le32_to_cpu(priv->statistics.flag));
-       if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
-               p += scnprintf(buf + p, bufsz - p,
-               "\tStatistics have been cleared\n");
-       p += scnprintf(buf + p, bufsz - p,
-               "\tOperational Frequency: %s\n",
-               (le32_to_cpu(priv->statistics.flag) &
-               UCODE_STATISTICS_FREQUENCY_MSK)
-                ? "2.4 GHz" : "5.2 GHz");
-       p += scnprintf(buf + p, bufsz - p,
-               "\tTGj Narrow Band: %s\n",
-               (le32_to_cpu(priv->statistics.flag) &
-               UCODE_STATISTICS_NARROW_BAND_MSK)
-                ? "enabled" : "disabled");
-       return p;
-}
-
-static const char ucode_stats_header[] =
-       "%-32s     current  acumulative       delta         max\n";
-static const char ucode_stats_short_format[] =
-       "  %-30s %10u\n";
-static const char ucode_stats_format[] =
-       "  %-30s %10u  %10u  %10u  %10u\n";
-
 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 = file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = sizeof(struct statistics_rx_phy) * 40 +
-               sizeof(struct statistics_rx_non_phy) * 40 +
-               sizeof(struct statistics_rx_ht_phy) * 40 + 400;
-       ssize_t ret;
-       struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
-       struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
-       struct statistics_rx_non_phy *general, *accum_general;
-       struct statistics_rx_non_phy *delta_general, *max_general;
-       struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf) {
-               IWL_ERR(priv, "Can not allocate Buffer\n");
-               return -ENOMEM;
-       }
-
-       /* the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-       ofdm = &priv->statistics.rx.ofdm;
-       cck = &priv->statistics.rx.cck;
-       general = &priv->statistics.rx.general;
-       ht = &priv->statistics.rx.ofdm_ht;
-       accum_ofdm = &priv->accum_statistics.rx.ofdm;
-       accum_cck = &priv->accum_statistics.rx.cck;
-       accum_general = &priv->accum_statistics.rx.general;
-       accum_ht = &priv->accum_statistics.rx.ofdm_ht;
-       delta_ofdm = &priv->delta_statistics.rx.ofdm;
-       delta_cck = &priv->delta_statistics.rx.cck;
-       delta_general = &priv->delta_statistics.rx.general;
-       delta_ht = &priv->delta_statistics.rx.ofdm_ht;
-       max_ofdm = &priv->max_delta.rx.ofdm;
-       max_cck = &priv->max_delta.rx.cck;
-       max_general = &priv->max_delta.rx.general;
-       max_ht = &priv->max_delta.rx.ofdm_ht;
-
-       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
-                        "Statistics_Rx - OFDM:");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "ina_cnt:", le32_to_cpu(ofdm->ina_cnt),
-                        accum_ofdm->ina_cnt,
-                        delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "fina_cnt:",
-                        le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
-                        delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "plcp_err:",
-                        le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
-                        delta_ofdm->plcp_err, max_ofdm->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "crc32_err:",
-                        le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
-                        delta_ofdm->crc32_err, max_ofdm->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "overrun_err:",
-                        le32_to_cpu(ofdm->overrun_err),
-                        accum_ofdm->overrun_err,
-                        delta_ofdm->overrun_err, max_ofdm->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "early_overrun_err:",
-                        le32_to_cpu(ofdm->early_overrun_err),
-                        accum_ofdm->early_overrun_err,
-                        delta_ofdm->early_overrun_err,
-                        max_ofdm->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "crc32_good:",
-                        le32_to_cpu(ofdm->crc32_good),
-                        accum_ofdm->crc32_good,
-                        delta_ofdm->crc32_good, max_ofdm->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "false_alarm_cnt:",
-                        le32_to_cpu(ofdm->false_alarm_cnt),
-                        accum_ofdm->false_alarm_cnt,
-                        delta_ofdm->false_alarm_cnt,
-                        max_ofdm->false_alarm_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "fina_sync_err_cnt:",
-                        le32_to_cpu(ofdm->fina_sync_err_cnt),
-                        accum_ofdm->fina_sync_err_cnt,
-                        delta_ofdm->fina_sync_err_cnt,
-                        max_ofdm->fina_sync_err_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sfd_timeout:",
-                        le32_to_cpu(ofdm->sfd_timeout),
-                        accum_ofdm->sfd_timeout,
-                        delta_ofdm->sfd_timeout,
-                        max_ofdm->sfd_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "fina_timeout:",
-                        le32_to_cpu(ofdm->fina_timeout),
-                        accum_ofdm->fina_timeout,
-                        delta_ofdm->fina_timeout,
-                        max_ofdm->fina_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "unresponded_rts:",
-                        le32_to_cpu(ofdm->unresponded_rts),
-                        accum_ofdm->unresponded_rts,
-                        delta_ofdm->unresponded_rts,
-                        max_ofdm->unresponded_rts);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "rxe_frame_lmt_ovrun:",
-                        le32_to_cpu(ofdm->rxe_frame_limit_overrun),
-                        accum_ofdm->rxe_frame_limit_overrun,
-                        delta_ofdm->rxe_frame_limit_overrun,
-                        max_ofdm->rxe_frame_limit_overrun);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sent_ack_cnt:",
-                        le32_to_cpu(ofdm->sent_ack_cnt),
-                        accum_ofdm->sent_ack_cnt,
-                        delta_ofdm->sent_ack_cnt,
-                        max_ofdm->sent_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sent_cts_cnt:",
-                        le32_to_cpu(ofdm->sent_cts_cnt),
-                        accum_ofdm->sent_cts_cnt,
-                        delta_ofdm->sent_cts_cnt, max_ofdm->sent_cts_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sent_ba_rsp_cnt:",
-                        le32_to_cpu(ofdm->sent_ba_rsp_cnt),
-                        accum_ofdm->sent_ba_rsp_cnt,
-                        delta_ofdm->sent_ba_rsp_cnt,
-                        max_ofdm->sent_ba_rsp_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "dsp_self_kill:",
-                        le32_to_cpu(ofdm->dsp_self_kill),
-                        accum_ofdm->dsp_self_kill,
-                        delta_ofdm->dsp_self_kill,
-                        max_ofdm->dsp_self_kill);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "mh_format_err:",
-                        le32_to_cpu(ofdm->mh_format_err),
-                        accum_ofdm->mh_format_err,
-                        delta_ofdm->mh_format_err,
-                        max_ofdm->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "re_acq_main_rssi_sum:",
-                        le32_to_cpu(ofdm->re_acq_main_rssi_sum),
-                        accum_ofdm->re_acq_main_rssi_sum,
-                        delta_ofdm->re_acq_main_rssi_sum,
-                       max_ofdm->re_acq_main_rssi_sum);
-
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
-                        "Statistics_Rx - CCK:");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "ina_cnt:",
-                        le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
-                        delta_cck->ina_cnt, max_cck->ina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "fina_cnt:",
-                        le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
-                        delta_cck->fina_cnt, max_cck->fina_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "plcp_err:",
-                        le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
-                        delta_cck->plcp_err, max_cck->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "crc32_err:",
-                        le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
-                        delta_cck->crc32_err, max_cck->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "overrun_err:",
-                        le32_to_cpu(cck->overrun_err),
-                        accum_cck->overrun_err,
-                        delta_cck->overrun_err, max_cck->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "early_overrun_err:",
-                        le32_to_cpu(cck->early_overrun_err),
-                        accum_cck->early_overrun_err,
-                        delta_cck->early_overrun_err,
-                        max_cck->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "crc32_good:",
-                        le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
-                        delta_cck->crc32_good,
-                        max_cck->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "false_alarm_cnt:",
-                        le32_to_cpu(cck->false_alarm_cnt),
-                        accum_cck->false_alarm_cnt,
-                        delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "fina_sync_err_cnt:",
-                        le32_to_cpu(cck->fina_sync_err_cnt),
-                        accum_cck->fina_sync_err_cnt,
-                        delta_cck->fina_sync_err_cnt,
-                        max_cck->fina_sync_err_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sfd_timeout:",
-                        le32_to_cpu(cck->sfd_timeout),
-                        accum_cck->sfd_timeout,
-                        delta_cck->sfd_timeout, max_cck->sfd_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "fina_timeout:",
-                        le32_to_cpu(cck->fina_timeout),
-                        accum_cck->fina_timeout,
-                        delta_cck->fina_timeout, max_cck->fina_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "unresponded_rts:",
-                        le32_to_cpu(cck->unresponded_rts),
-                        accum_cck->unresponded_rts,
-                        delta_cck->unresponded_rts,
-                        max_cck->unresponded_rts);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "rxe_frame_lmt_ovrun:",
-                        le32_to_cpu(cck->rxe_frame_limit_overrun),
-                        accum_cck->rxe_frame_limit_overrun,
-                        delta_cck->rxe_frame_limit_overrun,
-                        max_cck->rxe_frame_limit_overrun);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sent_ack_cnt:",
-                        le32_to_cpu(cck->sent_ack_cnt),
-                        accum_cck->sent_ack_cnt,
-                        delta_cck->sent_ack_cnt,
-                        max_cck->sent_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sent_cts_cnt:",
-                        le32_to_cpu(cck->sent_cts_cnt),
-                        accum_cck->sent_cts_cnt,
-                        delta_cck->sent_cts_cnt,
-                        max_cck->sent_cts_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sent_ba_rsp_cnt:",
-                        le32_to_cpu(cck->sent_ba_rsp_cnt),
-                        accum_cck->sent_ba_rsp_cnt,
-                        delta_cck->sent_ba_rsp_cnt,
-                        max_cck->sent_ba_rsp_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "dsp_self_kill:",
-                        le32_to_cpu(cck->dsp_self_kill),
-                        accum_cck->dsp_self_kill,
-                        delta_cck->dsp_self_kill,
-                        max_cck->dsp_self_kill);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "mh_format_err:",
-                        le32_to_cpu(cck->mh_format_err),
-                        accum_cck->mh_format_err,
-                        delta_cck->mh_format_err, max_cck->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "re_acq_main_rssi_sum:",
-                        le32_to_cpu(cck->re_acq_main_rssi_sum),
-                        accum_cck->re_acq_main_rssi_sum,
-                        delta_cck->re_acq_main_rssi_sum,
-                        max_cck->re_acq_main_rssi_sum);
-
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
-                       "Statistics_Rx - GENERAL:");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "bogus_cts:",
-                        le32_to_cpu(general->bogus_cts),
-                        accum_general->bogus_cts,
-                        delta_general->bogus_cts, max_general->bogus_cts);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "bogus_ack:",
-                        le32_to_cpu(general->bogus_ack),
-                        accum_general->bogus_ack,
-                        delta_general->bogus_ack, max_general->bogus_ack);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "non_bssid_frames:",
-                        le32_to_cpu(general->non_bssid_frames),
-                        accum_general->non_bssid_frames,
-                        delta_general->non_bssid_frames,
-                        max_general->non_bssid_frames);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "filtered_frames:",
-                        le32_to_cpu(general->filtered_frames),
-                        accum_general->filtered_frames,
-                        delta_general->filtered_frames,
-                        max_general->filtered_frames);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "non_channel_beacons:",
-                        le32_to_cpu(general->non_channel_beacons),
-                        accum_general->non_channel_beacons,
-                        delta_general->non_channel_beacons,
-                        max_general->non_channel_beacons);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "channel_beacons:",
-                        le32_to_cpu(general->channel_beacons),
-                        accum_general->channel_beacons,
-                        delta_general->channel_beacons,
-                        max_general->channel_beacons);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "num_missed_bcon:",
-                        le32_to_cpu(general->num_missed_bcon),
-                        accum_general->num_missed_bcon,
-                        delta_general->num_missed_bcon,
-                        max_general->num_missed_bcon);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "adc_rx_saturation_time:",
-                        le32_to_cpu(general->adc_rx_saturation_time),
-                        accum_general->adc_rx_saturation_time,
-                        delta_general->adc_rx_saturation_time,
-                        max_general->adc_rx_saturation_time);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "ina_detect_search_tm:",
-                        le32_to_cpu(general->ina_detection_search_time),
-                        accum_general->ina_detection_search_time,
-                        delta_general->ina_detection_search_time,
-                        max_general->ina_detection_search_time);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_silence_rssi_a:",
-                        le32_to_cpu(general->beacon_silence_rssi_a),
-                        accum_general->beacon_silence_rssi_a,
-                        delta_general->beacon_silence_rssi_a,
-                        max_general->beacon_silence_rssi_a);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_silence_rssi_b:",
-                        le32_to_cpu(general->beacon_silence_rssi_b),
-                        accum_general->beacon_silence_rssi_b,
-                        delta_general->beacon_silence_rssi_b,
-                        max_general->beacon_silence_rssi_b);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_silence_rssi_c:",
-                        le32_to_cpu(general->beacon_silence_rssi_c),
-                        accum_general->beacon_silence_rssi_c,
-                        delta_general->beacon_silence_rssi_c,
-                        max_general->beacon_silence_rssi_c);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "interference_data_flag:",
-                        le32_to_cpu(general->interference_data_flag),
-                        accum_general->interference_data_flag,
-                        delta_general->interference_data_flag,
-                        max_general->interference_data_flag);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "channel_load:",
-                        le32_to_cpu(general->channel_load),
-                        accum_general->channel_load,
-                        delta_general->channel_load,
-                        max_general->channel_load);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "dsp_false_alarms:",
-                        le32_to_cpu(general->dsp_false_alarms),
-                        accum_general->dsp_false_alarms,
-                        delta_general->dsp_false_alarms,
-                        max_general->dsp_false_alarms);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_rssi_a:",
-                        le32_to_cpu(general->beacon_rssi_a),
-                        accum_general->beacon_rssi_a,
-                        delta_general->beacon_rssi_a,
-                        max_general->beacon_rssi_a);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_rssi_b:",
-                        le32_to_cpu(general->beacon_rssi_b),
-                        accum_general->beacon_rssi_b,
-                        delta_general->beacon_rssi_b,
-                        max_general->beacon_rssi_b);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_rssi_c:",
-                        le32_to_cpu(general->beacon_rssi_c),
-                        accum_general->beacon_rssi_c,
-                        delta_general->beacon_rssi_c,
-                        max_general->beacon_rssi_c);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_energy_a:",
-                        le32_to_cpu(general->beacon_energy_a),
-                        accum_general->beacon_energy_a,
-                        delta_general->beacon_energy_a,
-                        max_general->beacon_energy_a);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_energy_b:",
-                        le32_to_cpu(general->beacon_energy_b),
-                        accum_general->beacon_energy_b,
-                        delta_general->beacon_energy_b,
-                        max_general->beacon_energy_b);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "beacon_energy_c:",
-                        le32_to_cpu(general->beacon_energy_c),
-                        accum_general->beacon_energy_c,
-                        delta_general->beacon_energy_c,
-                        max_general->beacon_energy_c);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Statistics_Rx - OFDM_HT:\n");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
-                       "Statistics_Rx - OFDM_HT:");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "plcp_err:",
-                        le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
-                        delta_ht->plcp_err, max_ht->plcp_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "overrun_err:",
-                        le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
-                        delta_ht->overrun_err, max_ht->overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "early_overrun_err:",
-                        le32_to_cpu(ht->early_overrun_err),
-                        accum_ht->early_overrun_err,
-                        delta_ht->early_overrun_err,
-                        max_ht->early_overrun_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "crc32_good:",
-                        le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
-                        delta_ht->crc32_good, max_ht->crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "crc32_err:",
-                        le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
-                        delta_ht->crc32_err, max_ht->crc32_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "mh_format_err:",
-                        le32_to_cpu(ht->mh_format_err),
-                        accum_ht->mh_format_err,
-                        delta_ht->mh_format_err, max_ht->mh_format_err);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg_crc32_good:",
-                        le32_to_cpu(ht->agg_crc32_good),
-                        accum_ht->agg_crc32_good,
-                        delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg_mpdu_cnt:",
-                        le32_to_cpu(ht->agg_mpdu_cnt),
-                        accum_ht->agg_mpdu_cnt,
-                        delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg_cnt:",
-                        le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
-                        delta_ht->agg_cnt, max_ht->agg_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "unsupport_mcs:",
-                        le32_to_cpu(ht->unsupport_mcs),
-                        accum_ht->unsupport_mcs,
-                        delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
+                       user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
@@ -1519,173 +1068,8 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
                                        size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
-       ssize_t ret;
-       struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf) {
-               IWL_ERR(priv, "Can not allocate Buffer\n");
-               return -ENOMEM;
-       }
-
-       /* the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-       tx = &priv->statistics.tx;
-       accum_tx = &priv->accum_statistics.tx;
-       delta_tx = &priv->delta_statistics.tx;
-       max_tx = &priv->max_delta.tx;
-       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos,  ucode_stats_header,
-                       "Statistics_Tx:");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "preamble:",
-                        le32_to_cpu(tx->preamble_cnt),
-                        accum_tx->preamble_cnt,
-                        delta_tx->preamble_cnt, max_tx->preamble_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "rx_detected_cnt:",
-                        le32_to_cpu(tx->rx_detected_cnt),
-                        accum_tx->rx_detected_cnt,
-                        delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "bt_prio_defer_cnt:",
-                        le32_to_cpu(tx->bt_prio_defer_cnt),
-                        accum_tx->bt_prio_defer_cnt,
-                        delta_tx->bt_prio_defer_cnt,
-                        max_tx->bt_prio_defer_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "bt_prio_kill_cnt:",
-                        le32_to_cpu(tx->bt_prio_kill_cnt),
-                        accum_tx->bt_prio_kill_cnt,
-                        delta_tx->bt_prio_kill_cnt,
-                        max_tx->bt_prio_kill_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "few_bytes_cnt:",
-                        le32_to_cpu(tx->few_bytes_cnt),
-                        accum_tx->few_bytes_cnt,
-                        delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "cts_timeout:",
-                        le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
-                        delta_tx->cts_timeout, max_tx->cts_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "ack_timeout:",
-                        le32_to_cpu(tx->ack_timeout),
-                        accum_tx->ack_timeout,
-                        delta_tx->ack_timeout, max_tx->ack_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "expected_ack_cnt:",
-                        le32_to_cpu(tx->expected_ack_cnt),
-                        accum_tx->expected_ack_cnt,
-                        delta_tx->expected_ack_cnt,
-                        max_tx->expected_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "actual_ack_cnt:",
-                        le32_to_cpu(tx->actual_ack_cnt),
-                        accum_tx->actual_ack_cnt,
-                        delta_tx->actual_ack_cnt,
-                        max_tx->actual_ack_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "dump_msdu_cnt:",
-                        le32_to_cpu(tx->dump_msdu_cnt),
-                        accum_tx->dump_msdu_cnt,
-                        delta_tx->dump_msdu_cnt,
-                        max_tx->dump_msdu_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "abort_nxt_frame_mismatch:",
-                        le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
-                        accum_tx->burst_abort_next_frame_mismatch_cnt,
-                        delta_tx->burst_abort_next_frame_mismatch_cnt,
-                        max_tx->burst_abort_next_frame_mismatch_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "abort_missing_nxt_frame:",
-                        le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
-                        accum_tx->burst_abort_missing_next_frame_cnt,
-                        delta_tx->burst_abort_missing_next_frame_cnt,
-                        max_tx->burst_abort_missing_next_frame_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "cts_timeout_collision:",
-                        le32_to_cpu(tx->cts_timeout_collision),
-                        accum_tx->cts_timeout_collision,
-                        delta_tx->cts_timeout_collision,
-                        max_tx->cts_timeout_collision);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "ack_ba_timeout_collision:",
-                        le32_to_cpu(tx->ack_or_ba_timeout_collision),
-                        accum_tx->ack_or_ba_timeout_collision,
-                        delta_tx->ack_or_ba_timeout_collision,
-                        max_tx->ack_or_ba_timeout_collision);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg ba_timeout:",
-                        le32_to_cpu(tx->agg.ba_timeout),
-                        accum_tx->agg.ba_timeout,
-                        delta_tx->agg.ba_timeout,
-                        max_tx->agg.ba_timeout);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "agg ba_resched_frames:",
-                        le32_to_cpu(tx->agg.ba_reschedule_frames),
-                        accum_tx->agg.ba_reschedule_frames,
-                        delta_tx->agg.ba_reschedule_frames,
-                        max_tx->agg.ba_reschedule_frames);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "agg scd_query_agg_frame:",
-                        le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
-                        accum_tx->agg.scd_query_agg_frame_cnt,
-                        delta_tx->agg.scd_query_agg_frame_cnt,
-                        max_tx->agg.scd_query_agg_frame_cnt);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg scd_query_no_agg:",
-                        le32_to_cpu(tx->agg.scd_query_no_agg),
-                        accum_tx->agg.scd_query_no_agg,
-                        delta_tx->agg.scd_query_no_agg,
-                        max_tx->agg.scd_query_no_agg);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg scd_query_agg:",
-                        le32_to_cpu(tx->agg.scd_query_agg),
-                        accum_tx->agg.scd_query_agg,
-                        delta_tx->agg.scd_query_agg,
-                        max_tx->agg.scd_query_agg);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                       "agg scd_query_mismatch:",
-                        le32_to_cpu(tx->agg.scd_query_mismatch),
-                        accum_tx->agg.scd_query_mismatch,
-                        delta_tx->agg.scd_query_mismatch,
-                        max_tx->agg.scd_query_mismatch);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg frame_not_ready:",
-                        le32_to_cpu(tx->agg.frame_not_ready),
-                        accum_tx->agg.frame_not_ready,
-                        delta_tx->agg.frame_not_ready,
-                        max_tx->agg.frame_not_ready);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg underrun:",
-                        le32_to_cpu(tx->agg.underrun),
-                        accum_tx->agg.underrun,
-                        delta_tx->agg.underrun, max_tx->agg.underrun);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg bt_prio_kill:",
-                        le32_to_cpu(tx->agg.bt_prio_kill),
-                        accum_tx->agg.bt_prio_kill,
-                        delta_tx->agg.bt_prio_kill,
-                        max_tx->agg.bt_prio_kill);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "agg rx_ba_rsp_cnt:",
-                        le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
-                        accum_tx->agg.rx_ba_rsp_cnt,
-                        delta_tx->agg.rx_ba_rsp_cnt,
-                        max_tx->agg.rx_ba_rsp_cnt);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
+                       user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
@@ -1693,107 +1077,8 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
                                        size_t count, loff_t *ppos)
 {
        struct iwl_priv *priv = file->private_data;
-       int pos = 0;
-       char *buf;
-       int bufsz = sizeof(struct statistics_general) * 10 + 300;
-       ssize_t ret;
-       struct statistics_general *general, *accum_general;
-       struct statistics_general *delta_general, *max_general;
-       struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg;
-       struct statistics_div *div, *accum_div, *delta_div, *max_div;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf) {
-               IWL_ERR(priv, "Can not allocate Buffer\n");
-               return -ENOMEM;
-       }
-
-       /* the statistic information display here is based on
-        * the last statistics notification from uCode
-        * might not reflect the current uCode activity
-        */
-       general = &priv->statistics.general;
-       dbg = &priv->statistics.general.dbg;
-       div = &priv->statistics.general.div;
-       accum_general = &priv->accum_statistics.general;
-       delta_general = &priv->delta_statistics.general;
-       max_general = &priv->max_delta.general;
-       accum_dbg = &priv->accum_statistics.general.dbg;
-       delta_dbg = &priv->delta_statistics.general.dbg;
-       max_dbg = &priv->max_delta.general.dbg;
-       accum_div = &priv->accum_statistics.general.div;
-       delta_div = &priv->delta_statistics.general.div;
-       max_div = &priv->max_delta.general.div;
-       pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_header,
-                       "Statistics_General:");
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format,
-                        "temperature:",
-                        le32_to_cpu(general->temperature));
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_short_format,
-                        "temperature_m:",
-                        le32_to_cpu(general->temperature_m));
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "burst_check:",
-                        le32_to_cpu(dbg->burst_check),
-                        accum_dbg->burst_check,
-                        delta_dbg->burst_check, max_dbg->burst_check);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "burst_count:",
-                        le32_to_cpu(dbg->burst_count),
-                        accum_dbg->burst_count,
-                        delta_dbg->burst_count, max_dbg->burst_count);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "sleep_time:",
-                        le32_to_cpu(general->sleep_time),
-                        accum_general->sleep_time,
-                        delta_general->sleep_time, max_general->sleep_time);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "slots_out:",
-                        le32_to_cpu(general->slots_out),
-                        accum_general->slots_out,
-                        delta_general->slots_out, max_general->slots_out);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "slots_idle:",
-                        le32_to_cpu(general->slots_idle),
-                        accum_general->slots_idle,
-                        delta_general->slots_idle, max_general->slots_idle);
-       pos += scnprintf(buf + pos, bufsz - pos, "ttl_timestamp:\t\t\t%u\n",
-                        le32_to_cpu(general->ttl_timestamp));
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "tx_on_a:",
-                        le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
-                        delta_div->tx_on_a, max_div->tx_on_a);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "tx_on_b:",
-                        le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
-                        delta_div->tx_on_b, max_div->tx_on_b);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "exec_time:",
-                        le32_to_cpu(div->exec_time), accum_div->exec_time,
-                        delta_div->exec_time, max_div->exec_time);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "probe_time:",
-                        le32_to_cpu(div->probe_time), accum_div->probe_time,
-                        delta_div->probe_time, max_div->probe_time);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "rx_enable_counter:",
-                        le32_to_cpu(general->rx_enable_counter),
-                        accum_general->rx_enable_counter,
-                        delta_general->rx_enable_counter,
-                        max_general->rx_enable_counter);
-       pos += scnprintf(buf + pos, bufsz - pos, ucode_stats_format,
-                        "num_of_sos_states:",
-                        le32_to_cpu(general->num_of_sos_states),
-                        accum_general->num_of_sos_states,
-                        delta_general->num_of_sos_states,
-                        max_general->num_of_sos_states);
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
+                       user_buf, count, ppos);
 }
 
 static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
@@ -1935,46 +1220,6 @@ static ssize_t iwl_dbgfs_chain_noise_read(struct file *file,
        return ret;
 }
 
-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 = file->private_data;
-       char buf[128];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-       struct statistics_tx *tx;
-
-       if (!iwl_is_alive(priv))
-               pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
-       else {
-               tx = &priv->statistics.tx;
-               if (tx->tx_power.ant_a ||
-                   tx->tx_power.ant_b ||
-                   tx->tx_power.ant_c) {
-                       pos += scnprintf(buf + pos, bufsz - pos,
-                               "tx power: (1/2 dB step)\n");
-                       if ((priv->cfg->valid_tx_ant & ANT_A) &&
-                           tx->tx_power.ant_a)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                               "\tantenna A: 0x%X\n",
-                                               tx->tx_power.ant_a);
-                       if ((priv->cfg->valid_tx_ant & ANT_B) &&
-                           tx->tx_power.ant_b)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                               "\tantenna B: 0x%X\n",
-                                               tx->tx_power.ant_b);
-                       if ((priv->cfg->valid_tx_ant & ANT_C) &&
-                           tx->tx_power.ant_c)
-                               pos += scnprintf(buf + pos, bufsz - pos,
-                                               "\tantenna C: 0x%X\n",
-                                               tx->tx_power.ant_c);
-               } else
-                       pos += scnprintf(buf + pos, bufsz - pos, "N/A\n");
-       }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
 static ssize_t iwl_dbgfs_power_save_status_read(struct file *file,
                                                    char __user *user_buf,
                                                    size_t count, loff_t *ppos)
@@ -2052,7 +1297,6 @@ static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
        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");
@@ -2063,8 +1307,7 @@ static ssize_t iwl_dbgfs_ucode_tracing_read(struct file *file,
        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;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
@@ -2096,6 +1339,31 @@ static ssize_t iwl_dbgfs_ucode_tracing_write(struct file *file,
        return count;
 }
 
+static ssize_t iwl_dbgfs_rxon_flags_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 len = 0;
+       char buf[20];
+
+       len = sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.flags));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_rxon_filter_flags_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 len = 0;
+       char buf[20];
+
+       len = sprintf(buf, "0x%04X\n",
+                     le32_to_cpu(priv->active_rxon.filter_flags));
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
 static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
                                         char __user *user_buf,
                                         size_t count, loff_t *ppos)
@@ -2125,13 +1393,11 @@ static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file,
        int pos = 0;
        char buf[12];
        const size_t bufsz = sizeof(buf);
-       ssize_t ret;
 
        pos += scnprintf(buf + pos, bufsz - pos, "%d\n",
                        priv->missed_beacon_threshold);
 
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       return ret;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
@@ -2160,27 +1426,6 @@ static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
        return count;
 }
 
-static ssize_t iwl_dbgfs_internal_scan_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 scan;
-
-       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", &scan) != 1)
-               return -EINVAL;
-
-       iwl_internal_short_hw_scan(priv);
-
-       return count;
-}
-
 static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
                                        char __user *user_buf,
                                        size_t count, loff_t *ppos) {
@@ -2189,13 +1434,11 @@ static ssize_t iwl_dbgfs_plcp_delta_read(struct file *file,
        int pos = 0;
        char buf[12];
        const size_t bufsz = sizeof(buf);
-       ssize_t ret;
 
        pos += scnprintf(buf + pos, bufsz - pos, "%u\n",
                        priv->cfg->plcp_delta_threshold);
 
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       return ret;
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
 static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
@@ -2288,7 +1531,6 @@ DEBUGFS_READ_FILE_OPS(ucode_tx_stats);
 DEBUGFS_READ_FILE_OPS(ucode_general_stats);
 DEBUGFS_READ_FILE_OPS(sensitivity);
 DEBUGFS_READ_FILE_OPS(chain_noise);
-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);
@@ -2296,9 +1538,10 @@ DEBUGFS_WRITE_FILE_OPS(csr);
 DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
 DEBUGFS_READ_FILE_OPS(fh_reg);
 DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
-DEBUGFS_WRITE_FILE_OPS(internal_scan);
 DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta);
 DEBUGFS_READ_WRITE_FILE_OPS(force_reset);
+DEBUGFS_READ_FILE_OPS(rxon_flags);
+DEBUGFS_READ_FILE_OPS(rxon_filter_flags);
 
 /*
  * Create the debugfs files and directories
@@ -2334,8 +1577,11 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(led, dir_data, S_IRUSR);
-       DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+       if (!priv->cfg->broken_powersave) {
+               DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
+                                S_IWUSR | S_IRUSR);
+               DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
+       }
        DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
@@ -2343,29 +1589,33 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_power, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR);
-       DEBUGFS_ADD_FILE(internal_scan, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR);
        DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR);
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
-               DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
-               DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR);
+       DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
+
+       if (priv->cfg->sensitivity_calib_by_driver)
                DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+       if (priv->cfg->chain_noise_calib_by_driver)
                DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+       if (priv->cfg->ucode_tracing)
                DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
-       }
-       DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal);
-       DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
-                        &priv->disable_chain_noise_cal);
-       if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
-           ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+       DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
+       DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
+       if (priv->cfg->sensitivity_calib_by_driver)
+               DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
+                                &priv->disable_sens_cal);
+       if (priv->cfg->chain_noise_calib_by_driver)
+               DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
+                                &priv->disable_chain_noise_cal);
+       if (priv->cfg->tx_power_by_driver)
                DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
                                &priv->disable_tx_power_cal);
        return 0;
index ef1720a852e9954a2f42b32b5e1704115e68ce7e..f3f3473c5c7ec852bf73657596354fe99d473e6c 100644 (file)
@@ -43,6 +43,7 @@
 #include "iwl-debug.h"
 #include "iwl-4965-hw.h"
 #include "iwl-3945-hw.h"
+#include "iwl-agn-hw.h"
 #include "iwl-led.h"
 #include "iwl-power.h"
 #include "iwl-agn-rs.h"
@@ -56,6 +57,7 @@ extern struct iwl_cfg iwl5100_bgn_cfg;
 extern struct iwl_cfg iwl5100_abg_cfg;
 extern struct iwl_cfg iwl5150_agn_cfg;
 extern struct iwl_cfg iwl5150_abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2agn_cfg;
 extern struct iwl_cfg iwl6000i_2agn_cfg;
 extern struct iwl_cfg iwl6000i_2abg_cfg;
 extern struct iwl_cfg iwl6000i_2bg_cfg;
@@ -67,45 +69,6 @@ extern struct iwl_cfg iwl1000_bg_cfg;
 
 struct iwl_tx_queue;
 
-/* shared structures from iwl-5000.c */
-extern struct iwl_mod_params iwl50_mod_params;
-extern struct iwl_ucode_ops iwl5000_ucode;
-extern struct iwl_lib_ops iwl5000_lib;
-extern struct iwl_hcmd_ops iwl5000_hcmd;
-extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
-
-/* shared functions from iwl-5000.c */
-extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len);
-extern u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd,
-                                    u8 *data);
-extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
-                                   __le32 *tx_flags);
-extern int iwl5000_calc_rssi(struct iwl_priv *priv,
-                            struct iwl_rx_phy_res *rx_resp);
-extern void iwl5000_nic_config(struct iwl_priv *priv);
-extern u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv);
-extern const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
-                                   size_t offset);
-extern void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
-                                           struct iwl_tx_queue *txq,
-                                           u16 byte_cnt);
-extern void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
-                                   struct iwl_tx_queue *txq);
-extern int iwl5000_load_ucode(struct iwl_priv *priv);
-extern void iwl5000_init_alive_start(struct iwl_priv *priv);
-extern int iwl5000_alive_notify(struct iwl_priv *priv);
-extern int iwl5000_hw_set_hw_params(struct iwl_priv *priv);
-extern int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id,
-                          int tx_fifo, int sta_id, int tid, u16 ssn_idx);
-extern int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
-                           u16 ssn_idx, u8 tx_fifo);
-extern void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask);
-extern void iwl5000_setup_deferred_work(struct iwl_priv *priv);
-extern void iwl5000_rx_handler_setup(struct iwl_priv *priv);
-extern int iwl5000_hw_valid_rtc_data_addr(u32 addr);
-extern int iwl5000_send_tx_power(struct iwl_priv *priv);
-extern void iwl5000_temperature(struct iwl_priv *priv);
-
 /* CT-KILL constants */
 #define CT_KILL_THRESHOLD_LEGACY   110 /* in Celsius */
 #define CT_KILL_THRESHOLD         114 /* in Celsius */
@@ -183,6 +146,10 @@ struct iwl_queue {
        int n_bd;              /* number of BDs in this queue */
        int write_ptr;       /* 1-st empty entry (index) host_w*/
        int read_ptr;         /* last used entry (index) host_r*/
+       /* use for monitoring and recovering the stuck queue */
+       int last_read_ptr;      /* storing the last read_ptr */
+       /* number of time read_ptr and last_read_ptr are the same */
+       u8 repeat_same_read_ptr;
        dma_addr_t dma_addr;   /* physical addr for BD's */
        int n_window;          /* safe queue window */
        u32 id;
@@ -304,13 +271,11 @@ struct iwl_channel_info {
        struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
 };
 
-#define IWL_TX_FIFO_AC0        0
-#define IWL_TX_FIFO_AC1        1
-#define IWL_TX_FIFO_AC2        2
-#define IWL_TX_FIFO_AC3        3
-#define IWL_TX_FIFO_HCCA_1     5
-#define IWL_TX_FIFO_HCCA_2     6
-#define IWL_TX_FIFO_NONE       7
+#define IWL_TX_FIFO_BK         0
+#define IWL_TX_FIFO_BE         1
+#define IWL_TX_FIFO_VI         2
+#define IWL_TX_FIFO_VO         3
+#define IWL_TX_FIFO_UNUSED     -1
 
 /* Minimum number of queues. MAX_NUM is defined in hw specific files.
  * Set the minimum to accommodate the 4 standard TX queues, 1 command
@@ -361,13 +326,6 @@ enum {
 
 #define DEF_CMD_PAYLOAD_SIZE 320
 
-/*
- * IWL_LINK_HDR_MAX should include ieee80211_hdr, radiotap header,
- * SNAP header and alignment. It should also be big enough for 802.11
- * control frames.
- */
-#define IWL_LINK_HDR_MAX 64
-
 /**
  * struct iwl_device_cmd
  *
@@ -519,38 +477,28 @@ struct iwl_ht_config {
        u8 non_GF_STA_present;
 };
 
-union iwl_qos_capabity {
-       struct {
-               u8 edca_count:4;        /* bit 0-3 */
-               u8 q_ack:1;             /* bit 4 */
-               u8 queue_request:1;     /* bit 5 */
-               u8 txop_request:1;      /* bit 6 */
-               u8 reserved:1;          /* bit 7 */
-       } q_AP;
-       struct {
-               u8 acvo_APSD:1;         /* bit 0 */
-               u8 acvi_APSD:1;         /* bit 1 */
-               u8 ac_bk_APSD:1;        /* bit 2 */
-               u8 ac_be_APSD:1;        /* bit 3 */
-               u8 q_ack:1;             /* bit 4 */
-               u8 max_len:2;           /* bit 5-6 */
-               u8 more_data_ack:1;     /* bit 7 */
-       } q_STA;
-       u8 val;
-};
-
 /* QoS structures */
 struct iwl_qos_info {
        int qos_active;
-       union iwl_qos_capabity qos_cap;
        struct iwl_qosparam_cmd def_qos_parm;
 };
 
+/*
+ * Structure should be accessed with sta_lock held. When station addition
+ * is in progress (IWL_STA_UCODE_INPROGRESS) it is possible to access only
+ * the commands (iwl_addsta_cmd and iwl_link_quality_cmd) without sta_lock
+ * held.
+ */
 struct iwl_station_entry {
        struct iwl_addsta_cmd sta;
        struct iwl_tid_data tid[MAX_TID_COUNT];
        u8 used;
        struct iwl_hw_key keyinfo;
+       struct iwl_link_quality_cmd *lq;
+};
+
+struct iwl_station_priv_common {
+       u8 sta_id;
 };
 
 /*
@@ -559,14 +507,28 @@ struct iwl_station_entry {
  * When mac80211 creates a station it reserves some space (hw->sta_data_size)
  * in the structure for use by driver. This structure is places in that
  * space.
+ *
+ * The common struct MUST be first because it is shared between
+ * 3945 and agn!
  */
 struct iwl_station_priv {
+       struct iwl_station_priv_common common;
        struct iwl_lq_sta lq_sta;
        atomic_t pending_frames;
        bool client;
        bool asleep;
 };
 
+/**
+ * struct iwl_vif_priv - driver's private per-interface information
+ *
+ * When mac80211 allocates a virtual interface, it can allocate
+ * space for us to put data into.
+ */
+struct iwl_vif_priv {
+       u8 ibss_bssid_sta_id;
+};
+
 /* one for each uCode image (inst/data, boot/init/runtime) */
 struct fw_desc {
        void *v_addr;           /* access by driver */
@@ -574,7 +536,7 @@ struct fw_desc {
        u32 len;                /* bytes */
 };
 
-/* uCode file layout */
+/* v1/v2 uCode file layout */
 struct iwl_ucode_header {
        __le32 ver;     /* major/minor/API/serial */
        union {
@@ -597,7 +559,62 @@ struct iwl_ucode_header {
                } v2;
        } u;
 };
-#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
+
+/*
+ * new TLV uCode file layout
+ *
+ * The new TLV file format contains TLVs, that each specify
+ * some piece of data. To facilitate "groups", for example
+ * different instruction image with different capabilities,
+ * bundled with the same init image, an alternative mechanism
+ * is provided:
+ * When the alternative field is 0, that means that the item
+ * is always valid. When it is non-zero, then it is only
+ * valid in conjunction with items of the same alternative,
+ * in which case the driver (user) selects one alternative
+ * to use.
+ */
+
+enum iwl_ucode_tlv_type {
+       IWL_UCODE_TLV_INVALID           = 0, /* unused */
+       IWL_UCODE_TLV_INST              = 1,
+       IWL_UCODE_TLV_DATA              = 2,
+       IWL_UCODE_TLV_INIT              = 3,
+       IWL_UCODE_TLV_INIT_DATA         = 4,
+       IWL_UCODE_TLV_BOOT              = 5,
+       IWL_UCODE_TLV_PROBE_MAX_LEN     = 6, /* a u32 value */
+};
+
+struct iwl_ucode_tlv {
+       __le16 type;            /* see above */
+       __le16 alternative;     /* see comment */
+       __le32 length;          /* not including type/length fields */
+       u8 data[0];
+} __attribute__ ((packed));
+
+#define IWL_TLV_UCODE_MAGIC    0x0a4c5749
+
+struct iwl_tlv_ucode_header {
+       /*
+        * The TLV style ucode header is distinguished from
+        * the v1/v2 style header by first four bytes being
+        * zero, as such is an invalid combination of
+        * major/minor/API/serial versions.
+        */
+       __le32 zero;
+       __le32 magic;
+       u8 human_readable[64];
+       __le32 ver;             /* major/minor/API/serial */
+       __le32 build;
+       __le64 alternatives;    /* bitmask of valid alternatives */
+       /*
+        * The data contained herein has a TLV layout,
+        * see above for the TLV header and types.
+        * Note that each TLV is padded to a length
+        * that is a multiple of 4 for alignment.
+        */
+       u8 data[0];
+};
 
 struct iwl4965_ibss_seq {
        u8 mac[ETH_ALEN];
@@ -1039,6 +1056,11 @@ struct iwl_event_log {
 #define IWL_DELAY_NEXT_FORCE_RF_RESET  (HZ*3)
 #define IWL_DELAY_NEXT_FORCE_FW_RELOAD (HZ*5)
 
+/* timer constants use to monitor and recover stuck tx queues in mSecs */
+#define IWL_MONITORING_PERIOD  (1000)
+#define IWL_ONE_HUNDRED_MSECS   (100)
+#define IWL_SIXTY_SECS          (60000)
+
 enum iwl_reset {
        IWL_RF_RESET = 0,
        IWL_FW_RESET,
@@ -1092,10 +1114,6 @@ struct iwl_priv {
        struct iwl_channel_info *channel_info;  /* channel info array */
        u8 channel_count;       /* # of channels */
 
-       /* each calibration channel group in the EEPROM has a derived
-        * clip setting for each rate. 3945 only.*/
-       const struct iwl3945_clip_group clip39_groups[5];
-
        /* thermal calibration */
        s32 temperature;        /* degrees Kelvin */
        s32 last_temperature;
@@ -1104,12 +1122,10 @@ struct iwl_priv {
        struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
        /* Scan related variables */
-       unsigned long next_scan_jiffies;
        unsigned long scan_start;
-       unsigned long scan_pass_start;
        unsigned long scan_start_tsf;
-       void *scan;
-       int scan_bands;
+       void *scan_cmd;
+       enum ieee80211_band scan_band;
        struct cfg80211_scan_request *scan_request;
        bool is_internal_short_scan;
        u8 scan_tx_ant[IEEE80211_NUM_BANDS];
@@ -1168,16 +1184,13 @@ struct iwl_priv {
        u64 led_tpt;
 
        u16 active_rate;
-       u16 active_rate_basic;
 
-       u8 assoc_station_added;
        u8 start_calib;
        struct iwl_sensitivity_data sensitivity_data;
        struct iwl_chain_noise_data chain_noise_data;
        __le16 sensitivity_tbl[HD_TABLE_SIZE];
 
        struct iwl_ht_config current_ht_config;
-       u8 last_phy_res[100];
 
        /* Rate scaling data */
        u8 retry_rate;
@@ -1197,9 +1210,6 @@ struct iwl_priv {
 
        unsigned long status;
 
-       int last_rx_rssi;       /* From Rx packet statistics */
-       int last_rx_noise;      /* From beacon statistics */
-
        /* counts mgmt, ctl, and data packets */
        struct traffic_stats tx_stats;
        struct traffic_stats rx_stats;
@@ -1218,18 +1228,14 @@ struct iwl_priv {
 #endif
 
        /* context information */
-       u16 rates_mask;
-
-       u8 bssid[ETH_ALEN];
-       u16 rts_threshold;
+       u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
        u8 mac_addr[ETH_ALEN];
 
        /*station table variables */
        spinlock_t sta_lock;
        int num_stations;
        struct iwl_station_entry stations[IWL_STATION_COUNT];
-       struct iwl_wep_key wep_keys[WEP_KEYS_MAX];
-       u8 default_wep_key;
+       struct iwl_wep_key wep_keys[WEP_KEYS_MAX]; /* protected by mutex */
        u8 key_mapping_key;
        unsigned long ucode_key_table;
 
@@ -1244,10 +1250,6 @@ struct iwl_priv {
 
        u8 mac80211_registered;
 
-       /* Rx'd packet timing information */
-       u32 last_beacon_time;
-       u64 last_tsf;
-
        /* eeprom -- this is in the card's little endian byte order */
        u8 *eeprom;
        int    nvm_device_type;
@@ -1259,29 +1261,67 @@ struct iwl_priv {
 
        /* Last Rx'd beacon timestamp */
        u64 timestamp;
-       u16 beacon_int;
        struct ieee80211_vif *vif;
 
-       /*Added for 3945 */
-       void *shared_virt;
-       dma_addr_t shared_phys;
-       /*End*/
-       struct iwl_hw_params hw_params;
+       union {
+#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE)
+               struct {
+                       void *shared_virt;
+                       dma_addr_t shared_phys;
 
-       /* INT ICT Table */
-       __le32 *ict_tbl;
-       dma_addr_t ict_tbl_dma;
-       dma_addr_t aligned_ict_tbl_dma;
-       int ict_index;
-       void *ict_tbl_vir;
-       u32 inta;
-       bool use_ict;
+                       struct delayed_work thermal_periodic;
+                       struct delayed_work rfkill_poll;
+
+                       struct iwl3945_notif_statistics statistics;
+#ifdef CONFIG_IWLWIFI_DEBUG
+                       struct iwl3945_notif_statistics accum_statistics;
+                       struct iwl3945_notif_statistics delta_statistics;
+                       struct iwl3945_notif_statistics max_delta;
+#endif
+
+                       u32 sta_supp_rates;
+                       int last_rx_rssi;       /* From Rx packet statistics */
+
+                       /* Rx'd packet timing information */
+                       u32 last_beacon_time;
+                       u64 last_tsf;
+
+                       /*
+                        * each calibration channel group in the
+                        * EEPROM has a derived clip setting for
+                        * each rate.
+                        */
+                       const struct iwl3945_clip_group clip_groups[5];
+
+               } _3945;
+#endif
+#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE)
+               struct {
+                       /* INT ICT Table */
+                       __le32 *ict_tbl;
+                       void *ict_tbl_vir;
+                       dma_addr_t ict_tbl_dma;
+                       dma_addr_t aligned_ict_tbl_dma;
+                       int ict_index;
+                       u32 inta;
+                       bool use_ict;
+                       /*
+                        * reporting the number of tids has AGG on. 0 means
+                        * no AGGREGATION
+                        */
+                       u8 agg_tids_count;
+
+                       struct iwl_rx_phy_res last_phy_res;
+                       bool last_phy_res_valid;
+
+                       struct completion firmware_loading_complete;
+               } _agn;
+#endif
+       };
+
+       struct iwl_hw_params hw_params;
 
        u32 inta_mask;
-       /* Current association information needed to configure the
-        * hardware */
-       u16 assoc_id;
-       u16 assoc_capability;
 
        struct iwl_qos_info qos_data;
 
@@ -1291,7 +1331,6 @@ struct iwl_priv {
        struct work_struct scan_completed;
        struct work_struct rx_replenish;
        struct work_struct abort_scan;
-       struct work_struct request_scan;
        struct work_struct beacon_update;
        struct work_struct tt_work;
        struct work_struct ct_enter;
@@ -1304,10 +1343,6 @@ struct iwl_priv {
        struct delayed_work alive_start;
        struct delayed_work scan_check;
 
-       /*For 3945 only*/
-       struct delayed_work thermal_periodic;
-       struct delayed_work rfkill_poll;
-
        /* TX Power */
        s8 tx_power_user_lmt;
        s8 tx_power_device_lmt;
@@ -1339,13 +1374,8 @@ struct iwl_priv {
        struct work_struct run_time_calib_work;
        struct timer_list statistics_periodic;
        struct timer_list ucode_trace;
+       struct timer_list monitor_recover;
        bool hw_ready;
-       /*For 3945*/
-#define IWL_DEFAULT_TX_POWER 0x0F
-
-       struct iwl3945_notif_statistics statistics_39;
-
-       u32 sta_supp_rates;
 
        struct iwl_event_log event_log;
 }; /*iwl_priv */
index 2ffc2edbf4f08c0e189a09802f62080e31281aca..4a487639d932c3086d471104d98aab4df8b5bf1b 100644 (file)
@@ -37,6 +37,7 @@ EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite8);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ioread32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_iowrite32);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_rx);
+EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_tx);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_event);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_error);
 EXPORT_TRACEPOINT_SYMBOL(iwlwifi_dev_ucode_cont_event);
index fb5bb487f3bc9991bbfd63ecb645454fae161202..ee11452519e6490a52b8176e445e40edede91e27 100644 (file)
@@ -590,9 +590,16 @@ int iwl_eeprom_init(struct iwl_priv *priv)
                        e[addr / 2] = cpu_to_le16(r >> 16);
                }
        }
+
+       IWL_DEBUG_INFO(priv, "NVM Type: %s, version: 0x%x\n",
+                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                      ? "OTP" : "EEPROM",
+                      iwl_eeprom_query16(priv, EEPROM_VERSION));
+
        ret = 0;
 done:
        priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
+
 err:
        if (ret)
                iwl_eeprom_free(priv);
index 8171c701e4e15e53610a0068e8d79bfeb72c0ec2..95aa202c85e315a1737301863ebb880c40150c88 100644 (file)
@@ -172,35 +172,35 @@ struct iwl_eeprom_enhanced_txpwr {
 #define EEPROM_5000_TX_POWER_VERSION    (4)
 #define EEPROM_5000_EEPROM_VERSION     (0x11A)
 
-/*5000 calibrations */
-#define EEPROM_5000_CALIB_ALL  (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
-#define EEPROM_5000_XTAL       ((2*0x128) | EEPROM_5000_CALIB_ALL)
-#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_5000_CALIB_ALL)
-
-/* 5000 links */
-#define EEPROM_5000_LINK_HOST             (2*0x64)
-#define EEPROM_5000_LINK_GENERAL          (2*0x65)
-#define EEPROM_5000_LINK_REGULATORY       (2*0x66)
-#define EEPROM_5000_LINK_CALIBRATION      (2*0x67)
-#define EEPROM_5000_LINK_PROCESS_ADJST    (2*0x68)
-#define EEPROM_5000_LINK_OTHERS           (2*0x69)
-
-/* 5000 regulatory - indirect access */
-#define EEPROM_5000_REG_SKU_ID ((0x02)\
-               | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 4  bytes */
-#define EEPROM_5000_REG_BAND_1_CHANNELS       ((0x08)\
+/* 5000 and up calibration */
+#define EEPROM_CALIB_ALL       (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
+#define EEPROM_XTAL            ((2*0x128) | EEPROM_CALIB_ALL)
+
+/* 5000 temperature */
+#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL)
+
+/* agn links */
+#define EEPROM_LINK_HOST             (2*0x64)
+#define EEPROM_LINK_GENERAL          (2*0x65)
+#define EEPROM_LINK_REGULATORY       (2*0x66)
+#define EEPROM_LINK_CALIBRATION      (2*0x67)
+#define EEPROM_LINK_PROCESS_ADJST    (2*0x68)
+#define EEPROM_LINK_OTHERS           (2*0x69)
+
+/* agn regulatory - indirect access */
+#define EEPROM_REG_BAND_1_CHANNELS       ((0x08)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 28 bytes */
-#define EEPROM_5000_REG_BAND_2_CHANNELS       ((0x26)\
+#define EEPROM_REG_BAND_2_CHANNELS       ((0x26)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 26 bytes */
-#define EEPROM_5000_REG_BAND_3_CHANNELS       ((0x42)\
+#define EEPROM_REG_BAND_3_CHANNELS       ((0x42)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 24 bytes */
-#define EEPROM_5000_REG_BAND_4_CHANNELS       ((0x5C)\
+#define EEPROM_REG_BAND_4_CHANNELS       ((0x5C)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22 bytes */
-#define EEPROM_5000_REG_BAND_5_CHANNELS       ((0x74)\
+#define EEPROM_REG_BAND_5_CHANNELS       ((0x74)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 12 bytes */
-#define EEPROM_5000_REG_BAND_24_HT40_CHANNELS  ((0x82)\
+#define EEPROM_REG_BAND_24_HT40_CHANNELS  ((0x82)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 14  bytes */
-#define EEPROM_5000_REG_BAND_52_HT40_CHANNELS  ((0x92)\
+#define EEPROM_REG_BAND_52_HT40_CHANNELS  ((0x92)\
                | INDIRECT_ADDRESS | INDIRECT_REGULATORY)   /* 22  bytes */
 
 /* 6000 regulatory - indirect access */
@@ -265,14 +265,21 @@ struct iwl_eeprom_enhanced_txpwr {
 #define EEPROM_5050_EEPROM_VERSION     (0x21E)
 
 /* 1000 Specific */
+#define EEPROM_1000_TX_POWER_VERSION    (4)
 #define EEPROM_1000_EEPROM_VERSION     (0x15C)
 
 /* 6x00 Specific */
+#define EEPROM_6000_TX_POWER_VERSION    (4)
 #define EEPROM_6000_EEPROM_VERSION     (0x434)
 
 /* 6x50 Specific */
+#define EEPROM_6050_TX_POWER_VERSION    (4)
 #define EEPROM_6050_EEPROM_VERSION     (0x532)
 
+/* 6x00g2 Specific */
+#define EEPROM_6000G2_TX_POWER_VERSION    (6)
+#define EEPROM_6000G2_EEPROM_VERSION   (0x709)
+
 /* OTP */
 /* lower blocks contain EEPROM image and calibration data */
 #define OTP_LOW_IMAGE_SIZE             (2 * 512 * sizeof(u16)) /* 2 KB */
index 73681c4fefe718232eeb96163c5c5a33e137a871..51f89e7ba6814b26e95f128d39315dc637dc5651 100644 (file)
@@ -169,7 +169,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        mutex_lock(&priv->sync_cmd_mutex);
 
        set_bit(STATUS_HCMD_ACTIVE, &priv->status);
-       IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s \n",
+       IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
                        get_cmd_string(cmd->id));
 
        cmd_idx = iwl_enqueue_hcmd(priv, cmd);
@@ -191,7 +191,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
                        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-                       IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+                       IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                                       get_cmd_string(cmd->id));
                        ret = -ETIMEDOUT;
                        goto cancel;
index 51a67fb2e185ea60777121f6c9d388c4280ba424..3ff6b9d25a10665397c5b87285207d5591293993 100644 (file)
@@ -31,6 +31,9 @@
 #define __iwl_helpers_h__
 
 #include <linux/ctype.h>
+#include <net/mac80211.h>
+
+#include "iwl-io.h"
 
 #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo))))
 
index 16eb3ced9b30c1f9301f0327b31487322c2248c3..0203a3bbf872e2f05086c242993e182c618f9e31 100644 (file)
@@ -298,7 +298,7 @@ static inline u32 __iwl_read_direct32(const char *f, u32 l,
                                        struct iwl_priv *priv, u32 reg)
 {
        u32 value = _iwl_read_direct32(priv, reg);
-       IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value,
+       IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value,
                     f, l);
        return value;
 }
index a6f9c918aabcd0507c3ec10de7550da58fc4ebe5..db5bfcb036ca274a2f1183e4f5e7ff963568998d 100644 (file)
@@ -46,7 +46,7 @@
 static int led_mode;
 module_param(led_mode, int, S_IRUGO);
 MODULE_PARM_DESC(led_mode, "led mode: 0=blinking, 1=On(RF On)/Off(RF Off), "
-                          "(default 0)\n");
+                          "(default 0)");
 
 
 static const struct {
index 548dac2f6a960363b5046f1df0e8f5cf034941ae..cda6a94d6cc92234f901470fb3c8fe93650c61e6 100644 (file)
@@ -318,10 +318,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
        update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
                        priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
 
-       if (priv->vif)
-               dtimper = priv->hw->conf.ps_dtim_period;
-       else
-               dtimper = 1;
+       dtimper = priv->hw->conf.ps_dtim_period ?: 1;
 
        if (priv->cfg->broken_powersave)
                iwl_power_sleep_cam_cmd(priv, &cmd);
@@ -384,10 +381,10 @@ EXPORT_SYMBOL(iwl_ht_enabled);
 
 bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
 {
-       s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
        bool within_margin = false;
 
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+       if (priv->cfg->temperature_kelvin)
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -840,12 +837,12 @@ EXPORT_SYMBOL(iwl_tt_exit_ct_kill);
 static void iwl_bg_tt_work(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work);
-       s32 temp = priv->temperature; /* degrees CELSIUS except 4965 */
+       s32 temp = priv->temperature; /* degrees CELSIUS except specified */
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
+       if (priv->cfg->temperature_kelvin)
                temp = KELVIN_TO_CELSIUS(priv->temperature);
 
        if (!priv->thermal_throttle.advanced_tt)
@@ -875,7 +872,7 @@ void iwl_tt_initialize(struct iwl_priv *priv)
        int size = sizeof(struct iwl_tt_trans) * (IWL_TI_STATE_MAX - 1);
        struct iwl_tt_trans *transaction;
 
-       IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling \n");
+       IWL_DEBUG_POWER(priv, "Initialize Thermal Throttling\n");
 
        memset(tt, 0, sizeof(struct iwl_tt_mgmt));
 
index d2d2a9174900e7d84ecfa97acbae6c20206bad77..b1f101caf19d2f063386453c7cd1f8e045e7b10d 100644 (file)
  * device.  A queue maps to only one (selectable by driver) Tx DMA channel,
  * but one DMA channel may take input from several queues.
  *
- * Tx DMA channels have dedicated purposes.  For 4965, they are used as follows
+ * Tx DMA FIFOs have dedicated purposes.  For 4965, they are used as follows
  * (cf. default_queue_to_tx_fifo in iwl-4965.c):
  *
  * 0 -- EDCA BK (background) frames, lowest priority
  * 2 -- EDCA VI (video) frames, higher priority
  * 3 -- EDCA VO (voice) and management frames, highest priority
  * 4 -- Commands (e.g. RXON, etc.)
- * 5 -- HCCA short frames
- * 6 -- HCCA long frames
+ * 5 -- unused (HCCA)
+ * 6 -- unused (HCCA)
  * 7 -- not used by driver (device-internal only)
  *
- * For 5000 series and up, they are used slightly differently
+ * For 5000 series and up, they are used differently
  * (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c):
  *
  * 0 -- EDCA BK (background) frames, lowest priority
  * 1 -- EDCA BE (best effort) frames, normal priority
  * 2 -- EDCA VI (video) frames, higher priority
  * 3 -- EDCA VO (voice) and management frames, highest priority
- * 4 -- (TBD)
- * 5 -- HCCA short frames
- * 6 -- HCCA long frames
+ * 4 -- unused
+ * 5 -- unused
+ * 6 -- unused
  * 7 -- Commands
  *
  * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6.
 #define IWL_SCD_TXFIFO_POS_RA                  (4)
 #define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK     (0x01FF)
 
-/* 5000 SCD */
-#define IWL50_SCD_QUEUE_STTS_REG_POS_TXF       (0)
-#define IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE    (3)
-#define IWL50_SCD_QUEUE_STTS_REG_POS_WSL       (4)
-#define IWL50_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
-#define IWL50_SCD_QUEUE_STTS_REG_MSK           (0x00FF0000)
-
-#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_POS            (8)
-#define IWL50_SCD_QUEUE_CTX_REG1_CREDIT_MSK            (0x00FFFF00)
-#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS      (24)
-#define IWL50_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK      (0xFF000000)
-#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS          (0)
-#define IWL50_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK          (0x0000007F)
-#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS       (16)
-#define IWL50_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK       (0x007F0000)
-
-#define IWL50_SCD_CONTEXT_DATA_OFFSET          (0x600)
-#define IWL50_SCD_TX_STTS_BITMAP_OFFSET                (0x7B1)
-#define IWL50_SCD_TRANSLATE_TBL_OFFSET         (0x7E0)
-
-#define IWL50_SCD_CONTEXT_QUEUE_OFFSET(x)\
-       (IWL50_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
-
-#define IWL50_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
-       ((IWL50_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
-
-#define IWL50_SCD_QUEUECHAIN_SEL_ALL(x)                (((1<<(x)) - 1) &\
+/* agn SCD */
+#define IWLAGN_SCD_QUEUE_STTS_REG_POS_TXF      (0)
+#define IWLAGN_SCD_QUEUE_STTS_REG_POS_ACTIVE   (3)
+#define IWLAGN_SCD_QUEUE_STTS_REG_POS_WSL      (4)
+#define IWLAGN_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (19)
+#define IWLAGN_SCD_QUEUE_STTS_REG_MSK          (0x00FF0000)
+
+#define IWLAGN_SCD_QUEUE_CTX_REG1_CREDIT_POS           (8)
+#define IWLAGN_SCD_QUEUE_CTX_REG1_CREDIT_MSK           (0x00FFFF00)
+#define IWLAGN_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS     (24)
+#define IWLAGN_SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK     (0xFF000000)
+#define IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS         (0)
+#define IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK         (0x0000007F)
+#define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS      (16)
+#define IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK      (0x007F0000)
+
+#define IWLAGN_SCD_CONTEXT_DATA_OFFSET         (0x600)
+#define IWLAGN_SCD_TX_STTS_BITMAP_OFFSET               (0x7B1)
+#define IWLAGN_SCD_TRANSLATE_TBL_OFFSET                (0x7E0)
+
+#define IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(x)\
+       (IWLAGN_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+
+#define IWLAGN_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+       ((IWLAGN_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffc)
+
+#define IWLAGN_SCD_QUEUECHAIN_SEL_ALL(x)               (((1<<(x)) - 1) &\
        (~(1<<IWL_CMD_QUEUE_NUM)))
 
-#define IWL50_SCD_BASE                 (PRPH_BASE + 0xa02c00)
-
-#define IWL50_SCD_SRAM_BASE_ADDR         (IWL50_SCD_BASE + 0x0)
-#define IWL50_SCD_DRAM_BASE_ADDR        (IWL50_SCD_BASE + 0x8)
-#define IWL50_SCD_AIT                    (IWL50_SCD_BASE + 0x0c)
-#define IWL50_SCD_TXFACT                 (IWL50_SCD_BASE + 0x10)
-#define IWL50_SCD_ACTIVE                (IWL50_SCD_BASE + 0x14)
-#define IWL50_SCD_QUEUE_WRPTR(x)         (IWL50_SCD_BASE + 0x18 + (x) * 4)
-#define IWL50_SCD_QUEUE_RDPTR(x)         (IWL50_SCD_BASE + 0x68 + (x) * 4)
-#define IWL50_SCD_QUEUECHAIN_SEL         (IWL50_SCD_BASE + 0xe8)
-#define IWL50_SCD_AGGR_SEL              (IWL50_SCD_BASE + 0x248)
-#define IWL50_SCD_INTERRUPT_MASK         (IWL50_SCD_BASE + 0x108)
-#define IWL50_SCD_QUEUE_STATUS_BITS(x)   (IWL50_SCD_BASE + 0x10c + (x) * 4)
+#define IWLAGN_SCD_BASE                        (PRPH_BASE + 0xa02c00)
+
+#define IWLAGN_SCD_SRAM_BASE_ADDR      (IWLAGN_SCD_BASE + 0x0)
+#define IWLAGN_SCD_DRAM_BASE_ADDR      (IWLAGN_SCD_BASE + 0x8)
+#define IWLAGN_SCD_AIT                 (IWLAGN_SCD_BASE + 0x0c)
+#define IWLAGN_SCD_TXFACT              (IWLAGN_SCD_BASE + 0x10)
+#define IWLAGN_SCD_ACTIVE              (IWLAGN_SCD_BASE + 0x14)
+#define IWLAGN_SCD_QUEUE_WRPTR(x)      (IWLAGN_SCD_BASE + 0x18 + (x) * 4)
+#define IWLAGN_SCD_QUEUE_RDPTR(x)      (IWLAGN_SCD_BASE + 0x68 + (x) * 4)
+#define IWLAGN_SCD_QUEUECHAIN_SEL      (IWLAGN_SCD_BASE + 0xe8)
+#define IWLAGN_SCD_AGGR_SEL            (IWLAGN_SCD_BASE + 0x248)
+#define IWLAGN_SCD_INTERRUPT_MASK      (IWLAGN_SCD_BASE + 0x108)
+#define IWLAGN_SCD_QUEUE_STATUS_BITS(x)        (IWLAGN_SCD_BASE + 0x10c + (x) * 4)
 
 /*********************** END TX SCHEDULER *************************************/
 
index e5eb339107ddfd6ef65c838a14a9d2cbf9b2ae49..0a5d7cf25196031d635c55f8d5ab23a8ca16e0cf 100644 (file)
@@ -163,197 +163,6 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q
        spin_unlock_irqrestore(&q->lock, flags);
 }
 EXPORT_SYMBOL(iwl_rx_queue_update_write_ptr);
-/**
- * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
-                                         dma_addr_t dma_addr)
-{
-       return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-/**
- * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
- *
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can, pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-void iwl_rx_queue_restock(struct iwl_priv *priv)
-{
-       struct iwl_rx_queue *rxq = &priv->rxq;
-       struct list_head *element;
-       struct iwl_rx_mem_buffer *rxb;
-       unsigned long flags;
-       int write;
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       write = rxq->write & ~0x7;
-       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
-               /* Get next free Rx buffer, remove from free list */
-               element = rxq->rx_free.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
-               /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->page_dma);
-               rxq->queue[rxq->write] = rxb;
-               rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
-               rxq->free_count--;
-       }
-       spin_unlock_irqrestore(&rxq->lock, flags);
-       /* If the pre-allocated buffer pool is dropping low, schedule to
-        * refill it */
-       if (rxq->free_count <= RX_LOW_WATERMARK)
-               queue_work(priv->workqueue, &priv->rx_replenish);
-
-
-       /* If we've added more space for the firmware to place data, tell it.
-        * Increment device's write pointer in multiples of 8. */
-       if (rxq->write_actual != (rxq->write & ~0x7)) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               rxq->need_update = 1;
-               spin_unlock_irqrestore(&rxq->lock, flags);
-               iwl_rx_queue_update_write_ptr(priv, rxq);
-       }
-}
-EXPORT_SYMBOL(iwl_rx_queue_restock);
-
-
-/**
- * iwl_rx_replenish - Move all used packet from rx_used to rx_free
- *
- * When moving to rx_free an SKB is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_rx_queue_restock.
- * This is called as a scheduled work item (except for during initialization)
- */
-void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
-{
-       struct iwl_rx_queue *rxq = &priv->rxq;
-       struct list_head *element;
-       struct iwl_rx_mem_buffer *rxb;
-       struct page *page;
-       unsigned long flags;
-       gfp_t gfp_mask = priority;
-
-       while (1) {
-               spin_lock_irqsave(&rxq->lock, flags);
-               if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
-                       return;
-               }
-               spin_unlock_irqrestore(&rxq->lock, flags);
-
-               if (rxq->free_count > RX_LOW_WATERMARK)
-                       gfp_mask |= __GFP_NOWARN;
-
-               if (priv->hw_params.rx_page_order > 0)
-                       gfp_mask |= __GFP_COMP;
-
-               /* Alloc a new receive buffer */
-               page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order);
-               if (!page) {
-                       if (net_ratelimit())
-                               IWL_DEBUG_INFO(priv, "alloc_pages failed, "
-                                              "order: %d\n",
-                                              priv->hw_params.rx_page_order);
-
-                       if ((rxq->free_count <= RX_LOW_WATERMARK) &&
-                           net_ratelimit())
-                               IWL_CRIT(priv, "Failed to alloc_pages with %s. Only %u free buffers remaining.\n",
-                                        priority == GFP_ATOMIC ?  "GFP_ATOMIC" : "GFP_KERNEL",
-                                        rxq->free_count);
-                       /* We don't reschedule replenish work here -- we will
-                        * call the restock method and if it still needs
-                        * more buffers it will schedule replenish */
-                       return;
-               }
-
-               spin_lock_irqsave(&rxq->lock, flags);
-
-               if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
-                       __free_pages(page, priv->hw_params.rx_page_order);
-                       return;
-               }
-               element = rxq->rx_used.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
-
-               rxb->page = page;
-               /* Get physical address of the RB */
-               rxb->page_dma = pci_map_page(priv->pci_dev, page, 0,
-                               PAGE_SIZE << priv->hw_params.rx_page_order,
-                               PCI_DMA_FROMDEVICE);
-               /* dma address must be no more than 36 bits */
-               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-               /* and also 256 byte aligned! */
-               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
-
-               spin_lock_irqsave(&rxq->lock, flags);
-
-               list_add_tail(&rxb->list, &rxq->rx_free);
-               rxq->free_count++;
-               priv->alloc_rxb_page++;
-
-               spin_unlock_irqrestore(&rxq->lock, flags);
-       }
-}
-
-void iwl_rx_replenish(struct iwl_priv *priv)
-{
-       unsigned long flags;
-
-       iwl_rx_allocate(priv, GFP_KERNEL);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_rx_queue_restock(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_rx_replenish);
-
-void iwl_rx_replenish_now(struct iwl_priv *priv)
-{
-       iwl_rx_allocate(priv, GFP_ATOMIC);
-
-       iwl_rx_queue_restock(priv);
-}
-EXPORT_SYMBOL(iwl_rx_replenish_now);
-
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-       int i;
-       for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
-               if (rxq->pool[i].page != NULL) {
-                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
-                               PAGE_SIZE << priv->hw_params.rx_page_order,
-                               PCI_DMA_FROMDEVICE);
-                       __iwl_free_pages(priv, rxq->pool[i].page);
-                       rxq->pool[i].page = NULL;
-               }
-       }
-
-       dma_free_coherent(&priv->pci_dev->dev, 4 * RX_QUEUE_SIZE, rxq->bd,
-                         rxq->dma_addr);
-       dma_free_coherent(&priv->pci_dev->dev, sizeof(struct iwl_rb_status),
-                         rxq->rb_stts, rxq->rb_stts_dma);
-       rxq->bd = NULL;
-       rxq->rb_stts  = NULL;
-}
-EXPORT_SYMBOL(iwl_rx_queue_free);
 
 int iwl_rx_queue_alloc(struct iwl_priv *priv)
 {
@@ -396,98 +205,6 @@ err_bd:
 }
 EXPORT_SYMBOL(iwl_rx_queue_alloc);
 
-void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-       unsigned long flags;
-       int i;
-       spin_lock_irqsave(&rxq->lock, flags);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-               /* In the reset function, these buffers may have been allocated
-                * to an SKB, so we need to unmap and free potential storage */
-               if (rxq->pool[i].page != NULL) {
-                       pci_unmap_page(priv->pci_dev, rxq->pool[i].page_dma,
-                               PAGE_SIZE << priv->hw_params.rx_page_order,
-                               PCI_DMA_FROMDEVICE);
-                       __iwl_free_pages(priv, rxq->pool[i].page);
-                       rxq->pool[i].page = NULL;
-               }
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-       }
-
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->write_actual = 0;
-       rxq->free_count = 0;
-       spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
-{
-       u32 rb_size;
-       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-       u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
-       if (!priv->cfg->use_isr_legacy)
-               rb_timeout = RX_RB_TIMEOUT;
-
-       if (priv->cfg->mod_params->amsdu_size_8K)
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-       /* Stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-       /* Reset driver's Rx queue write index */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-       /* Tell device where to find RBD circular buffer in DRAM */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-                          (u32)(rxq->dma_addr >> 8));
-
-       /* Tell device where in DRAM to update its Rx status */
-       iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-                          rxq->rb_stts_dma >> 4);
-
-       /* Enable Rx DMA
-        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
-        *      the credit mechanism in 5000 HW RX FIFO
-        * Direct rx interrupts to hosts
-        * Rx buffer size 4 or 8k
-        * RB timeout 0x10
-        * 256 RBDs
-        */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
-                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
-                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
-                          rb_size|
-                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
-                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
-       /* Set interrupt coalescing timer to default (2048 usecs) */
-       iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-
-       return 0;
-}
-
-int iwl_rxq_stop(struct iwl_priv *priv)
-{
-
-       /* stop Rx DMA */
-       iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
-                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_rxq_stop);
-
 void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                                struct iwl_rx_mem_buffer *rxb)
 
@@ -543,6 +260,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
                le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
        int bcn_silence_c =
                le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+       int last_rx_noise;
 
        if (bcn_silence_a) {
                total_silence += bcn_silence_a;
@@ -559,13 +277,13 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
 
        /* Average among active antennas */
        if (num_active_rx)
-               priv->last_rx_noise = (total_silence / num_active_rx) - 107;
+               last_rx_noise = (total_silence / num_active_rx) - 107;
        else
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+               last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
 
        IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",
                        bcn_silence_a, bcn_silence_b, bcn_silence_c,
-                       priv->last_rx_noise);
+                       last_rx_noise);
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -617,29 +335,20 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv,
 
 #define REG_RECALIB_PERIOD (60)
 
-#define PLCP_MSG "plcp_err exceeded %u, %u, %u, %u, %u, %d, %u mSecs\n"
-void iwl_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
+/**
+ * iwl_good_plcp_health - checks for plcp error.
+ *
+ * When the plcp error is exceeding the thresholds, reset the radio
+ * to improve the throughput.
+ */
+bool iwl_good_plcp_health(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
 {
-       int change;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       bool rc = true;
        int combined_plcp_delta;
        unsigned int plcp_msec;
        unsigned long plcp_received_jiffies;
 
-       IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
-                    (int)sizeof(priv->statistics),
-                    le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-
-       change = ((priv->statistics.general.temperature !=
-                  pkt->u.stats.general.temperature) ||
-                 ((priv->statistics.flag &
-                   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
-                  (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
-#endif
        /*
         * check for plcp_err and trigger radio reset if it exceeds
         * the plcp error threshold plcp_delta.
@@ -660,11 +369,11 @@ void iwl_rx_statistics(struct iwl_priv *priv,
                        le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));
 
                if ((combined_plcp_delta > 0) &&
-                       ((combined_plcp_delta * 100) / plcp_msec) >
+                   ((combined_plcp_delta * 100) / plcp_msec) >
                        priv->cfg->plcp_delta_threshold) {
                        /*
-                        * if plcp_err exceed the threshold, the following
-                        * data is printed in csv format:
+                        * if plcp_err exceed the threshold,
+                        * the following data is printed in csv format:
                         *    Text: plcp_err exceeded %d,
                         *    Received ofdm.plcp_err,
                         *    Current ofdm.plcp_err,
@@ -673,22 +382,76 @@ void iwl_rx_statistics(struct iwl_priv *priv,
                         *    combined_plcp_delta,
                         *    plcp_msec
                         */
-                       IWL_DEBUG_RADIO(priv, PLCP_MSG,
+                       IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "
+                               "%u, %u, %u, %u, %d, %u mSecs\n",
                                priv->cfg->plcp_delta_threshold,
                                le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),
                                le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),
                                le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),
                                le32_to_cpu(
-                                       priv->statistics.rx.ofdm_ht.plcp_err),
+                                 priv->statistics.rx.ofdm_ht.plcp_err),
                                combined_plcp_delta, plcp_msec);
+                       rc = false;
+               }
+       }
+       return rc;
+}
+EXPORT_SYMBOL(iwl_good_plcp_health);
 
-                       /*
-                        * Reset the RF radio due to the high plcp
-                        * error rate
-                        */
-                       iwl_force_reset(priv, IWL_RF_RESET);
+void iwl_recover_from_statistics(struct iwl_priv *priv,
+                               struct iwl_rx_packet *pkt)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+       if (iwl_is_associated(priv)) {
+               if (priv->cfg->ops->lib->check_ack_health) {
+                       if (!priv->cfg->ops->lib->check_ack_health(
+                           priv, pkt)) {
+                               /*
+                                * low ack count detected
+                                * restart Firmware
+                                */
+                               IWL_ERR(priv, "low ack count detected, "
+                                       "restart firmware\n");
+                               if (!iwl_force_reset(priv, IWL_FW_RESET))
+                                       return;
+                       }
+               }
+               if (priv->cfg->ops->lib->check_plcp_health) {
+                       if (!priv->cfg->ops->lib->check_plcp_health(
+                           priv, pkt)) {
+                               /*
+                                * high plcp error detected
+                                * reset Radio
+                                */
+                               iwl_force_reset(priv, IWL_RF_RESET);
+                       }
                }
        }
+}
+EXPORT_SYMBOL(iwl_recover_from_statistics);
+
+void iwl_rx_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb)
+{
+       int change;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+
+
+       IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
+                    (int)sizeof(priv->statistics),
+                    le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
+
+       change = ((priv->statistics.general.temperature !=
+                  pkt->u.stats.general.temperature) ||
+                 ((priv->statistics.flag &
+                   STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+                  (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+#endif
+       iwl_recover_from_statistics(priv, pkt);
 
        memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
 
@@ -731,139 +494,6 @@ void iwl_reply_statistics(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_reply_statistics);
 
-/* Calc max signal level (dBm) among 3 possible receivers */
-static inline int iwl_calc_rssi(struct iwl_priv *priv,
-                               struct iwl_rx_phy_res *rx_resp)
-{
-       return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-/**
- * iwl_dbg_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good data frames.
- *    All beacon and probe response frames are printed.
- */
-static void iwl_dbg_report_frame(struct iwl_priv *priv,
-                     struct iwl_rx_phy_res *phy_res, u16 length,
-                     struct ieee80211_hdr *header, int group100)
-{
-       u32 to_us;
-       u32 print_summary = 0;
-       u32 print_dump = 0;     /* set to 1 to dump all frames' contents */
-       u32 hundred = 0;
-       u32 dataframe = 0;
-       __le16 fc;
-       u16 seq_ctl;
-       u16 channel;
-       u16 phy_flags;
-       u32 rate_n_flags;
-       u32 tsf_low;
-       int rssi;
-
-       if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
-               return;
-
-       /* MAC header */
-       fc = header->frame_control;
-       seq_ctl = le16_to_cpu(header->seq_ctrl);
-
-       /* metadata */
-       channel = le16_to_cpu(phy_res->channel);
-       phy_flags = le16_to_cpu(phy_res->phy_flags);
-       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
-       /* signal statistics */
-       rssi = iwl_calc_rssi(priv, phy_res);
-       tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
-
-       to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
-       /* if data frame is to us and all is good,
-        *   (optionally) print summary for only 1 out of every 100 */
-       if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
-           cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
-               dataframe = 1;
-               if (!group100)
-                       print_summary = 1;      /* print each frame */
-               else if (priv->framecnt_to_us < 100) {
-                       priv->framecnt_to_us++;
-                       print_summary = 0;
-               } else {
-                       priv->framecnt_to_us = 0;
-                       print_summary = 1;
-                       hundred = 1;
-               }
-       } else {
-               /* print summary for all other frames */
-               print_summary = 1;
-       }
-
-       if (print_summary) {
-               char *title;
-               int rate_idx;
-               u32 bitrate;
-
-               if (hundred)
-                       title = "100Frames";
-               else if (ieee80211_has_retry(fc))
-                       title = "Retry";
-               else if (ieee80211_is_assoc_resp(fc))
-                       title = "AscRsp";
-               else if (ieee80211_is_reassoc_resp(fc))
-                       title = "RasRsp";
-               else if (ieee80211_is_probe_resp(fc)) {
-                       title = "PrbRsp";
-                       print_dump = 1; /* dump frame contents */
-               } else if (ieee80211_is_beacon(fc)) {
-                       title = "Beacon";
-                       print_dump = 1; /* dump frame contents */
-               } else if (ieee80211_is_atim(fc))
-                       title = "ATIM";
-               else if (ieee80211_is_auth(fc))
-                       title = "Auth";
-               else if (ieee80211_is_deauth(fc))
-                       title = "DeAuth";
-               else if (ieee80211_is_disassoc(fc))
-                       title = "DisAssoc";
-               else
-                       title = "Frame";
-
-               rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
-               if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
-                       bitrate = 0;
-                       WARN_ON_ONCE(1);
-               } else {
-                       bitrate = iwl_rates[rate_idx].ieee / 2;
-               }
-
-               /* print frame summary.
-                * MAC addresses show just the last byte (for brevity),
-                *    but you can hack it to show more, if you'd like to. */
-               if (dataframe)
-                       IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
-                                    "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
-                                    title, le16_to_cpu(fc), header->addr1[5],
-                                    length, rssi, channel, bitrate);
-               else {
-                       /* src/dst addresses assume managed mode */
-                       IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
-                                    "len=%u, rssi=%d, tim=%lu usec, "
-                                    "phy=0x%02x, chnl=%d\n",
-                                    title, le16_to_cpu(fc), header->addr1[5],
-                                    header->addr3[5], length, rssi,
-                                    tsf_low - priv->scan_start_tsf,
-                                    phy_flags, channel);
-               }
-       }
-       if (print_dump)
-               iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
-}
-#endif
-
 /*
  * returns non-zero if packet should be dropped
  */
@@ -911,305 +541,3 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv,
        return 0;
 }
 EXPORT_SYMBOL(iwl_set_decrypted_flag);
-
-static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
-{
-       u32 decrypt_out = 0;
-
-       if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
-                                       RX_RES_STATUS_STATION_FOUND)
-               decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
-                               RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
-
-       decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
-
-       /* packet was not encrypted */
-       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-                                       RX_RES_STATUS_SEC_TYPE_NONE)
-               return decrypt_out;
-
-       /* packet was encrypted with unknown alg */
-       if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
-                                       RX_RES_STATUS_SEC_TYPE_ERR)
-               return decrypt_out;
-
-       /* decryption was not done in HW */
-       if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
-                                       RX_MPDU_RES_STATUS_DEC_DONE_MSK)
-               return decrypt_out;
-
-       switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
-
-       case RX_RES_STATUS_SEC_TYPE_CCMP:
-               /* alg is CCM: check MIC only */
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
-                       /* Bad MIC */
-                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-               else
-                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-
-               break;
-
-       case RX_RES_STATUS_SEC_TYPE_TKIP:
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
-                       /* Bad TTAK */
-                       decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
-                       break;
-               }
-               /* fall through if TTAK OK */
-       default:
-               if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
-                       decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
-               else
-                       decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-               break;
-       };
-
-       IWL_DEBUG_RX(priv, "decrypt_in:0x%x  decrypt_out = 0x%x\n",
-                                       decrypt_in, decrypt_out);
-
-       return decrypt_out;
-}
-
-static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
-                                       struct ieee80211_hdr *hdr,
-                                       u16 len,
-                                       u32 ampdu_status,
-                                       struct iwl_rx_mem_buffer *rxb,
-                                       struct ieee80211_rx_status *stats)
-{
-       struct sk_buff *skb;
-       int ret = 0;
-       __le16 fc = hdr->frame_control;
-
-       /* We only process data packets if the interface is open */
-       if (unlikely(!priv->is_open)) {
-               IWL_DEBUG_DROP_LIMIT(priv,
-                   "Dropping packet while interface is not open.\n");
-               return;
-       }
-
-       /* In case of HW accelerated crypto and bad decryption, drop */
-       if (!priv->cfg->mod_params->sw_crypto &&
-           iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
-               return;
-
-       skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC);
-       if (!skb) {
-               IWL_ERR(priv, "alloc_skb failed\n");
-               return;
-       }
-
-       skb_reserve(skb, IWL_LINK_HDR_MAX);
-       skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
-
-       /* mac80211 currently doesn't support paged SKB. Convert it to
-        * linear SKB for management frame and data frame requires
-        * software decryption or software defragementation. */
-       if (ieee80211_is_mgmt(fc) ||
-           ieee80211_has_protected(fc) ||
-           ieee80211_has_morefrags(fc) ||
-           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG ||
-           (ieee80211_is_data_qos(fc) &&
-            *ieee80211_get_qos_ctl(hdr) &
-            IEEE80211_QOS_CONTROL_A_MSDU_PRESENT))
-               ret = skb_linearize(skb);
-       else
-               ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
-                        0 : -ENOMEM;
-
-       if (ret) {
-               kfree_skb(skb);
-               goto out;
-       }
-
-       /*
-        * XXX: We cannot touch the page and its virtual memory (hdr) after
-        * here. It might have already been freed by the above skb change.
-        */
-
-       iwl_update_stats(priv, false, fc, len);
-       memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
-
-       ieee80211_rx(priv->hw, skb);
- out:
-       priv->alloc_rxb_page--;
-       rxb->page = NULL;
-}
-
-/* This is necessary only for a number of statistics, see the caller. */
-static int iwl_is_network_packet(struct iwl_priv *priv,
-               struct ieee80211_hdr *header)
-{
-       /* Filter incoming packets to determine if they are targeted toward
-        * this network, discarding packets coming from ourselves */
-       switch (priv->iw_mode) {
-       case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source    | BSSID */
-               /* packets to our IBSS update information */
-               return !compare_ether_addr(header->addr3, priv->bssid);
-       case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */
-               /* packets to our IBSS update information */
-               return !compare_ether_addr(header->addr2, priv->bssid);
-       default:
-               return 1;
-       }
-}
-
-/* Called for REPLY_RX (legacy ABG frames), or
- * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-void iwl_rx_reply_rx(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
-{
-       struct ieee80211_hdr *header;
-       struct ieee80211_rx_status rx_status;
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_rx_phy_res *phy_res;
-       __le32 rx_pkt_status;
-       struct iwl4965_rx_mpdu_res_start *amsdu;
-       u32 len;
-       u32 ampdu_status;
-       u32 rate_n_flags;
-
-       /**
-        * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently.
-        *      REPLY_RX: physical layer info is in this buffer
-        *      REPLY_RX_MPDU_CMD: physical layer info was sent in separate
-        *              command and cached in priv->last_phy_res
-        *
-        * Here we set up local variables depending on which command is
-        * received.
-        */
-       if (pkt->hdr.cmd == REPLY_RX) {
-               phy_res = (struct iwl_rx_phy_res *)pkt->u.raw;
-               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res)
-                               + phy_res->cfg_phy_cnt);
-
-               len = le16_to_cpu(phy_res->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) +
-                               phy_res->cfg_phy_cnt + len);
-               ampdu_status = le32_to_cpu(rx_pkt_status);
-       } else {
-               if (!priv->last_phy_res[0]) {
-                       IWL_ERR(priv, "MPDU frame without cached PHY data\n");
-                       return;
-               }
-               phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1];
-               amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
-               header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu));
-               len = le16_to_cpu(amsdu->byte_count);
-               rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len);
-               ampdu_status = iwl_translate_rx_status(priv,
-                               le32_to_cpu(rx_pkt_status));
-       }
-
-       if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
-               IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
-                               phy_res->cfg_phy_cnt);
-               return;
-       }
-
-       if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
-           !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
-               IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
-                               le32_to_cpu(rx_pkt_status));
-               return;
-       }
-
-       /* This will be used in several places later */
-       rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
-       /* rx_status carries information about the packet to mac80211 */
-       rx_status.mactime = le64_to_cpu(phy_res->timestamp);
-       rx_status.freq =
-               ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel));
-       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
-                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
-       rx_status.rate_idx =
-               iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
-       rx_status.flag = 0;
-
-       /* TSF isn't reliable. In order to allow smooth user experience,
-        * this W/A doesn't propagate it to the mac80211 */
-       /*rx_status.flag |= RX_FLAG_TSFT;*/
-
-       priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
-
-       /* Find max signal strength (dBm) among 3 antenna/receiver chains */
-       rx_status.signal = iwl_calc_rssi(priv, phy_res);
-
-       /* Meaningful noise values are available only from beacon statistics,
-        *   which are gathered only when associated, and indicate noise
-        *   only for the associated network channel ...
-        * Ignore these noise values while scanning (other channels) */
-       if (iwl_is_associated(priv) &&
-           !test_bit(STATUS_SCANNING, &priv->status)) {
-               rx_status.noise = priv->last_rx_noise;
-       } else {
-               rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-       }
-
-       /* Reset beacon noise level if not associated. */
-       if (!iwl_is_associated(priv))
-               priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       /* Set "1" to report good data frames in groups of 100 */
-       if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
-               iwl_dbg_report_frame(priv, phy_res, len, header, 1);
-#endif
-       iwl_dbg_log_rx_data_frame(priv, len, header);
-       IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n",
-               rx_status.signal, rx_status.noise,
-               (unsigned long long)rx_status.mactime);
-
-       /*
-        * "antenna number"
-        *
-        * It seems that the antenna field in the phy flags value
-        * is actually a bit field. This is undefined by radiotap,
-        * it wants an actual antenna number but I always get "7"
-        * for most legacy frames I receive indicating that the
-        * same frame was received on all three RX chains.
-        *
-        * I think this field should be removed in favor of a
-        * new 802.11n radiotap field "RX chains" that is defined
-        * as a bitmask.
-        */
-       rx_status.antenna =
-               (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
-               >> RX_RES_PHY_FLAGS_ANTENNA_POS;
-
-       /* set the preamble flag if appropriate */
-       if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
-               rx_status.flag |= RX_FLAG_SHORTPRE;
-
-       /* Set up the HT phy flags */
-       if (rate_n_flags & RATE_MCS_HT_MSK)
-               rx_status.flag |= RX_FLAG_HT;
-       if (rate_n_flags & RATE_MCS_HT40_MSK)
-               rx_status.flag |= RX_FLAG_40MHZ;
-       if (rate_n_flags & RATE_MCS_SGI_MSK)
-               rx_status.flag |= RX_FLAG_SHORT_GI;
-
-       if (iwl_is_network_packet(priv, header)) {
-               priv->last_rx_rssi = rx_status.signal;
-               priv->last_beacon_time =  priv->ucode_beacon_time;
-               priv->last_tsf = le64_to_cpu(phy_res->timestamp);
-       }
-
-       iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
-                                   rxb, &rx_status);
-}
-EXPORT_SYMBOL(iwl_rx_reply_rx);
-
-/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
- * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       priv->last_phy_res[0] = 1;
-       memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
-              sizeof(struct iwl_rx_phy_res));
-}
-EXPORT_SYMBOL(iwl_rx_reply_rx_phy);
index 741e65ec8301dce638b5952378d832a0ef7457c0..107e173112f65ab9a2b1b66d22108edc148d5fc6 100644 (file)
@@ -69,9 +69,8 @@ int iwl_scan_cancel(struct iwl_priv *priv)
        }
 
        if (test_bit(STATUS_SCANNING, &priv->status)) {
-               if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+               if (!test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
                        IWL_DEBUG_SCAN(priv, "Queuing scan abort.\n");
-                       set_bit(STATUS_SCAN_ABORTING, &priv->status);
                        queue_work(priv->workqueue, &priv->abort_scan);
 
                } else
@@ -201,9 +200,6 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
                       le32_to_cpu(notif->statistics[0]),
                       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
 #endif
-
-       if (!priv->is_internal_short_scan)
-               priv->next_scan_jiffies = 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
@@ -223,49 +219,24 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
        /* The HW is no longer scanning */
        clear_bit(STATUS_SCAN_HW, &priv->status);
 
-       IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n",
-                      (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
-                                               "2.4" : "5.2",
+       IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n",
+                      (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
                       jiffies_to_msecs(elapsed_jiffies
-                                       (priv->scan_pass_start, jiffies)));
+                                       (priv->scan_start, jiffies)));
 
-       /* Remove this scanned band from the list of pending
-        * bands to scan, band G precedes A in order of scanning
-        * as seen in iwl_bg_request_scan */
-       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
-               priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
-       else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
-               priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
-
-       /* If a request to abort was given, or the scan did not succeed
+       /*
+        * If a request to abort was given, or the scan did not succeed
         * then we reset the scan state machine and terminate,
-        * re-queuing another scan if one has been requested */
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+        * re-queuing another scan if one has been requested
+        */
+       if (test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status))
                IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");
-               clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-       } else {
-               /* If there are more bands on this scan pass reschedule */
-               if (priv->scan_bands)
-                       goto reschedule;
-       }
-
-       if (!priv->is_internal_short_scan)
-               priv->next_scan_jiffies = 0;
 
        IWL_DEBUG_INFO(priv, "Setting scan to off\n");
 
        clear_bit(STATUS_SCANNING, &priv->status);
 
-       IWL_DEBUG_INFO(priv, "Scan took %dms\n",
-               jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
-
        queue_work(priv->workqueue, &priv->scan_completed);
-
-       return;
-
-reschedule:
-       priv->scan_pass_start = jiffies;
-       queue_work(priv->workqueue, &priv->request_scan);
 }
 
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
@@ -294,7 +265,8 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_get_active_dwell_time);
 
 u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                              enum ieee80211_band band)
+                              enum ieee80211_band band,
+                              struct ieee80211_vif *vif)
 {
        u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
@@ -304,7 +276,7 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                /* If we're associated, we clamp the maximum passive
                 * dwell time to be 98% of the beacon interval (minus
                 * 2 * channel tune time) */
-               passive = priv->beacon_int;
+               passive = vif ? vif->bss_conf.beacon_int : 0;
                if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
                        passive = IWL_PASSIVE_DWELL_BASE;
                passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
@@ -314,150 +286,6 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
 }
 EXPORT_SYMBOL(iwl_get_passive_dwell_time);
 
-static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
-                                    enum ieee80211_band band,
-                                    struct iwl_scan_channel *scan_ch)
-{
-       const struct ieee80211_supported_band *sband;
-       const struct iwl_channel_info *ch_info;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int i, added = 0;
-       u16 channel = 0;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband) {
-               IWL_ERR(priv, "invalid band\n");
-               return added;
-       }
-
-       active_dwell = iwl_get_active_dwell_time(priv, band, 0);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-       if (passive_dwell <= active_dwell)
-               passive_dwell = active_dwell + 1;
-
-       /* only scan single channel, good enough to reset the RF */
-       /* pick the first valid not in-use channel */
-       if (band == IEEE80211_BAND_5GHZ) {
-               for (i = 14; i < priv->channel_count; i++) {
-                       if (priv->channel_info[i].channel !=
-                           le16_to_cpu(priv->staging_rxon.channel)) {
-                               channel = priv->channel_info[i].channel;
-                               ch_info = iwl_get_channel_info(priv,
-                                       band, channel);
-                               if (is_channel_valid(ch_info))
-                                       break;
-                       }
-               }
-       } else {
-               for (i = 0; i < 14; i++) {
-                       if (priv->channel_info[i].channel !=
-                           le16_to_cpu(priv->staging_rxon.channel)) {
-                                       channel =
-                                               priv->channel_info[i].channel;
-                                       ch_info = iwl_get_channel_info(priv,
-                                               band, channel);
-                                       if (is_channel_valid(ch_info))
-                                               break;
-                       }
-               }
-       }
-       if (channel) {
-               scan_ch->channel = cpu_to_le16(channel);
-               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-               added++;
-       } else
-               IWL_ERR(priv, "no valid channel found\n");
-       return added;
-}
-
-static int iwl_get_channels_for_scan(struct iwl_priv *priv,
-                                    enum ieee80211_band band,
-                                    u8 is_active, u8 n_probes,
-                                    struct iwl_scan_channel *scan_ch)
-{
-       struct ieee80211_channel *chan;
-       const struct ieee80211_supported_band *sband;
-       const struct iwl_channel_info *ch_info;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int added, i;
-       u16 channel;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband)
-               return 0;
-
-       active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
-
-       if (passive_dwell <= active_dwell)
-               passive_dwell = active_dwell + 1;
-
-       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
-               chan = priv->scan_request->channels[i];
-
-               if (chan->band != band)
-                       continue;
-
-               channel = ieee80211_frequency_to_channel(chan->center_freq);
-               scan_ch->channel = cpu_to_le16(channel);
-
-               ch_info = iwl_get_channel_info(priv, band, channel);
-               if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n",
-                                       channel);
-                       continue;
-               }
-
-               if (!is_active || is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
-                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
-
-               if (n_probes)
-                       scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
-
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-
-               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                * power level:
-                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                */
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
-               IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
-                              channel, le32_to_cpu(scan_ch->type),
-                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-                               "ACTIVE" : "PASSIVE",
-                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-                              active_dwell : passive_dwell);
-
-               scan_ch++;
-               added++;
-       }
-
-       IWL_DEBUG_SCAN(priv, "total channels to scan %d \n", added);
-       return added;
-}
-
 void iwl_init_scan_params(struct iwl_priv *priv)
 {
        u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
@@ -468,7 +296,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_init_scan_params);
 
-static int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        WARN_ON(!mutex_is_locked(&priv->mutex));
 
@@ -476,26 +304,28 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
        set_bit(STATUS_SCANNING, &priv->status);
        priv->is_internal_short_scan = false;
        priv->scan_start = jiffies;
-       priv->scan_pass_start = priv->scan_start;
 
-       queue_work(priv->workqueue, &priv->request_scan);
+       if (WARN_ON(!priv->cfg->ops->utils->request_scan))
+               return -EOPNOTSUPP;
+
+       priv->cfg->ops->utils->request_scan(priv, vif);
 
        return 0;
 }
 
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
-
 int iwl_mac_hw_scan(struct ieee80211_hw *hw,
-                    struct cfg80211_scan_request *req)
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req)
 {
-       unsigned long flags;
        struct iwl_priv *priv = hw->priv;
-       int ret, i;
+       int ret;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
+       if (req->n_channels == 0)
+               return -EINVAL;
+
        mutex_lock(&priv->mutex);
-       spin_lock_irqsave(&priv->lock, flags);
 
        if (!iwl_is_ready_rf(priv)) {
                ret = -EIO;
@@ -515,30 +345,15 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       /* We don't schedule scan within next_scan_jiffies period.
-        * Avoid scanning during possible EAPOL exchange, return
-        * success immediately.
-        */
-       if (priv->next_scan_jiffies &&
-           time_after(priv->next_scan_jiffies, jiffies)) {
-               IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n");
-               queue_work(priv->workqueue, &priv->scan_completed);
-               ret = 0;
-               goto out_unlock;
-       }
-
-       priv->scan_bands = 0;
-       for (i = 0; i < req->n_channels; i++)
-               priv->scan_bands |= BIT(req->channels[i]->band);
-
+       /* mac80211 will only ask for one band at a time */
+       priv->scan_band = req->channels[0]->band;
        priv->scan_request = req;
 
-       ret = iwl_scan_initiate(priv);
+       ret = iwl_scan_initiate(priv, vif);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
 out_unlock:
-       spin_unlock_irqrestore(&priv->lock, flags);
        mutex_unlock(&priv->mutex);
 
        return ret;
@@ -554,7 +369,7 @@ void iwl_internal_short_hw_scan(struct iwl_priv *priv)
        queue_work(priv->workqueue, &priv->start_internal_scan);
 }
 
-static void iwl_bg_start_internal_scan(struct work_struct *work)
+void iwl_bg_start_internal_scan(struct work_struct *work)
 {
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, start_internal_scan);
@@ -576,22 +391,20 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
                goto unlock;
        }
 
-       priv->scan_bands = 0;
-       if (priv->band == IEEE80211_BAND_5GHZ)
-               priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
-       else
-               priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+       priv->scan_band = priv->band;
 
        IWL_DEBUG_SCAN(priv, "Start internal short scan...\n");
        set_bit(STATUS_SCANNING, &priv->status);
        priv->is_internal_short_scan = true;
-       queue_work(priv->workqueue, &priv->request_scan);
+
+       if (WARN_ON(!priv->cfg->ops->utils->request_scan))
+               goto unlock;
+
+       priv->cfg->ops->utils->request_scan(priv, NULL);
  unlock:
        mutex_unlock(&priv->mutex);
 }
-EXPORT_SYMBOL(iwl_internal_short_hw_scan);
-
-#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+EXPORT_SYMBOL(iwl_bg_start_internal_scan);
 
 void iwl_bg_scan_check(struct work_struct *data)
 {
@@ -654,289 +467,15 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
        if (WARN_ON(left < ie_len))
                return len;
 
-       if (ies)
+       if (ies && ie_len) {
                memcpy(pos, ies, ie_len);
-       len += ie_len;
-       left -= ie_len;
+               len += ie_len;
+       }
 
        return (u16)len;
 }
 EXPORT_SYMBOL(iwl_fill_probe_req);
 
-static void iwl_bg_request_scan(struct work_struct *data)
-{
-       struct iwl_priv *priv =
-           container_of(data, struct iwl_priv, request_scan);
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_SCAN_CMD,
-               .len = sizeof(struct iwl_scan_cmd),
-               .flags = CMD_SIZE_HUGE,
-       };
-       struct iwl_scan_cmd *scan;
-       struct ieee80211_conf *conf = NULL;
-       int ret = 0;
-       u32 rate_flags = 0;
-       u16 cmd_len;
-       u16 rx_chain = 0;
-       enum ieee80211_band band;
-       u8 n_probes = 0;
-       u8 rx_ant = priv->hw_params.valid_rx_ant;
-       u8 rate;
-       bool is_active = false;
-       int  chan_mod;
-       u8 active_chains;
-
-       conf = ieee80211_get_hw_conf(priv->hw);
-
-       mutex_lock(&priv->mutex);
-
-       cancel_delayed_work(&priv->scan_check);
-
-       if (!iwl_is_ready(priv)) {
-               IWL_WARN(priv, "request scan called when driver not ready.\n");
-               goto done;
-       }
-
-       /* Make sure the scan wasn't canceled before this queued work
-        * was given the chance to run... */
-       if (!test_bit(STATUS_SCANNING, &priv->status))
-               goto done;
-
-       /* This should never be called or scheduled if there is currently
-        * a scan active in the hardware. */
-       if (test_bit(STATUS_SCAN_HW, &priv->status)) {
-               IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests in parallel. "
-                              "Ignoring second request.\n");
-               ret = -EIO;
-               goto done;
-       }
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
-               goto done;
-       }
-
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_HC(priv, "Scan request while abort pending.  Queuing.\n");
-               goto done;
-       }
-
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
-               goto done;
-       }
-
-       if (!test_bit(STATUS_READY, &priv->status)) {
-               IWL_DEBUG_HC(priv, "Scan request while uninitialized.  Queuing.\n");
-               goto done;
-       }
-
-       if (!priv->scan_bands) {
-               IWL_DEBUG_HC(priv, "Aborting scan due to no requested bands\n");
-               goto done;
-       }
-
-       if (!priv->scan) {
-               priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
-                                    IWL_MAX_SCAN_SIZE, GFP_KERNEL);
-               if (!priv->scan) {
-                       ret = -ENOMEM;
-                       goto done;
-               }
-       }
-       scan = priv->scan;
-       memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
-
-       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
-       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
-
-       if (iwl_is_associated(priv)) {
-               u16 interval = 0;
-               u32 extra;
-               u32 suspend_time = 100;
-               u32 scan_suspend_time = 100;
-               unsigned long flags;
-
-               IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
-               spin_lock_irqsave(&priv->lock, flags);
-               interval = priv->beacon_int;
-               spin_unlock_irqrestore(&priv->lock, flags);
-
-               scan->suspend_time = 0;
-               scan->max_out_time = cpu_to_le32(200 * 1024);
-               if (!interval)
-                       interval = suspend_time;
-
-               extra = (suspend_time / interval) << 22;
-               scan_suspend_time = (extra |
-                   ((suspend_time % interval) * 1024));
-               scan->suspend_time = cpu_to_le32(scan_suspend_time);
-               IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
-                              scan_suspend_time, interval);
-       }
-
-       if (priv->is_internal_short_scan) {
-               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
-       } else if (priv->scan_request->n_ssids) {
-               int i, p = 0;
-               IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
-               for (i = 0; i < priv->scan_request->n_ssids; i++) {
-                       /* always does wildcard anyway */
-                       if (!priv->scan_request->ssids[i].ssid_len)
-                               continue;
-                       scan->direct_scan[p].id = WLAN_EID_SSID;
-                       scan->direct_scan[p].len =
-                               priv->scan_request->ssids[i].ssid_len;
-                       memcpy(scan->direct_scan[p].ssid,
-                              priv->scan_request->ssids[i].ssid,
-                              priv->scan_request->ssids[i].ssid_len);
-                       n_probes++;
-                       p++;
-               }
-               is_active = true;
-       } else
-               IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
-
-       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
-       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-
-       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
-               band = IEEE80211_BAND_2GHZ;
-               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-               chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK)
-                                      >> RXON_FLG_CHANNEL_MODE_POS;
-               if (chan_mod == CHANNEL_MODE_PURE_40) {
-                       rate = IWL_RATE_6M_PLCP;
-               } else {
-                       rate = IWL_RATE_1M_PLCP;
-                       rate_flags = RATE_MCS_CCK_MSK;
-               }
-               scan->good_CRC_th = IWL_GOOD_CRC_TH_DISABLED;
-       } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
-               band = IEEE80211_BAND_5GHZ;
-               rate = IWL_RATE_6M_PLCP;
-               /*
-                * If active scanning is requested but a certain channel is
-                * marked passive, we can do active scanning if we detect
-                * transmissions.
-                *
-                * There is an issue with some firmware versions that triggers
-                * a sysassert on a "good CRC threshold" of zero (== disabled),
-                * on a radar channel even though this means that we should NOT
-                * send probes.
-                *
-                * The "good CRC threshold" is the number of frames that we
-                * need to receive during our dwell time on a channel before
-                * sending out probes -- setting this to a huge value will
-                * mean we never reach it, but at the same time work around
-                * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
-                * here instead of IWL_GOOD_CRC_TH_DISABLED.
-                */
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-                                               IWL_GOOD_CRC_TH_NEVER;
-
-               /* Force use of chains B and C (0x6) for scan Rx for 4965
-                * Avoid A (0x1) because of its off-channel reception on A-band.
-                */
-               if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
-                       rx_ant = ANT_BC;
-       } else {
-               IWL_WARN(priv, "Invalid scan band count\n");
-               goto done;
-       }
-
-       priv->scan_tx_ant[band] =
-                        iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
-       rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
-       scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
-
-       /* In power save mode use one chain, otherwise use all chains */
-       if (test_bit(STATUS_POWER_PMI, &priv->status)) {
-               /* rx_ant has been set to all valid chains previously */
-               active_chains = rx_ant &
-                               ((u8)(priv->chain_noise_data.active_chains));
-               if (!active_chains)
-                       active_chains = rx_ant;
-
-               IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
-                               priv->chain_noise_data.active_chains);
-
-               rx_ant = first_antenna(active_chains);
-       }
-       /* MIMO is not used here, but value is required */
-       rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
-       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
-       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
-       rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
-       scan->rx_chain = cpu_to_le16(rx_chain);
-       if (!priv->is_internal_short_scan) {
-               cmd_len = iwl_fill_probe_req(priv,
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       priv->scan_request->ie,
-                                       priv->scan_request->ie_len,
-                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
-       } else {
-               cmd_len = iwl_fill_probe_req(priv,
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       NULL, 0,
-                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
-
-       }
-       scan->tx_cmd.len = cpu_to_le16(cmd_len);
-       if (iwl_is_monitor_mode(priv))
-               scan->filter_flags = RXON_FILTER_PROMISC_MSK;
-
-       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
-                              RXON_FILTER_BCON_AWARE_MSK);
-
-       if (priv->is_internal_short_scan) {
-               scan->channel_count =
-                       iwl_get_single_channel_for_scan(priv, band,
-                               (void *)&scan->data[le16_to_cpu(
-                               scan->tx_cmd.len)]);
-       } else {
-               scan->channel_count =
-                       iwl_get_channels_for_scan(priv, band,
-                               is_active, n_probes,
-                               (void *)&scan->data[le16_to_cpu(
-                               scan->tx_cmd.len)]);
-       }
-       if (scan->channel_count == 0) {
-               IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
-               goto done;
-       }
-
-       cmd.len += le16_to_cpu(scan->tx_cmd.len) +
-           scan->channel_count * sizeof(struct iwl_scan_channel);
-       cmd.data = scan;
-       scan->len = cpu_to_le16(cmd.len);
-
-       set_bit(STATUS_SCAN_HW, &priv->status);
-       ret = iwl_send_cmd_sync(priv, &cmd);
-       if (ret)
-               goto done;
-
-       queue_delayed_work(priv->workqueue, &priv->scan_check,
-                          IWL_SCAN_CHECK_WATCHDOG);
-
-       mutex_unlock(&priv->mutex);
-       return;
-
- done:
-       /* Cannot perform scan. Make sure we clear scanning
-       * bits from status so next scan request can be performed.
-       * If we don't clear scanning status bit here all next scan
-       * will fail
-       */
-       clear_bit(STATUS_SCAN_HW, &priv->status);
-       clear_bit(STATUS_SCANNING, &priv->status);
-       /* inform mac80211 scan aborted */
-       queue_work(priv->workqueue, &priv->scan_completed);
-       mutex_unlock(&priv->mutex);
-}
-
 void iwl_bg_abort_scan(struct work_struct *work)
 {
        struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
@@ -984,7 +523,6 @@ EXPORT_SYMBOL(iwl_bg_scan_completed);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
 {
        INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-       INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
        INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
        INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
        INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
index 4a6686fa6b3649971c218bd060836ef0ba64084a..85ed235ac901c446f9efdb924d6f02009b81f706 100644 (file)
 
 #include <net/mac80211.h>
 #include <linux/etherdevice.h>
+#include <linux/sched.h>
 
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-sta.h"
 
-#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
-#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
-
-u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr)
-{
-       int i;
-       int start = 0;
-       int ret = IWL_INVALID_STATION;
-       unsigned long flags;
-
-       if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
-           (priv->iw_mode == NL80211_IFTYPE_AP))
-               start = IWL_STA_ID;
-
-       if (is_broadcast_ether_addr(addr))
-               return priv->hw_params.bcast_sta_id;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       for (i = start; i < priv->hw_params.max_stations; i++)
-               if (priv->stations[i].used &&
-                   (!compare_ether_addr(priv->stations[i].sta.sta.addr,
-                                        addr))) {
-                       ret = i;
-                       goto out;
-               }
-
-       IWL_DEBUG_ASSOC_LIMIT(priv, "can not find STA %pM total %d\n",
-                             addr, priv->num_stations);
-
- out:
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
-}
-EXPORT_SYMBOL(iwl_find_station);
-
-int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
-{
-       if (priv->iw_mode == NL80211_IFTYPE_STATION) {
-               return IWL_AP_ID;
-       } else {
-               u8 *da = ieee80211_get_DA(hdr);
-               return iwl_find_station(priv, da);
-       }
-}
-EXPORT_SYMBOL(iwl_get_ra_sta_id);
-
 /* priv->sta_lock must be held */
 static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 {
@@ -132,7 +87,7 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
                        sta_id);
                break;
        case ADD_STA_MODIFY_NON_EXIST_STA:
-               IWL_ERR(priv, "Attempting to modify non-existing station %d \n",
+               IWL_ERR(priv, "Attempting to modify non-existing station %d\n",
                        sta_id);
                break;
        default:
@@ -158,13 +113,6 @@ static void iwl_process_add_sta_resp(struct iwl_priv *priv,
                       priv->stations[sta_id].sta.mode ==
                       STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",
                       addsta->sta.addr);
-
-       /*
-        * Determine if we wanted to modify or add a station,
-        * if adding a station succeeded we have some more initialization
-        * to do when using station notification. TODO
-        */
-
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 
@@ -190,6 +138,10 @@ int iwl_send_add_sta(struct iwl_priv *priv,
                .flags = flags,
                .data = data,
        };
+       u8 sta_id __maybe_unused = sta->sta.sta_id;
+
+       IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
+                      sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
 
        if (flags & CMD_ASYNC)
                cmd.callback = iwl_add_sta_callback;
@@ -263,18 +215,19 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
 }
 
 /**
- * iwl_add_station - Add station to tables in driver and device
+ * iwl_prep_station - Prepare station information for addition
+ *
+ * should be called with sta_lock held
  */
-u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
-               struct ieee80211_sta_ht_cap *ht_info)
+static u8 iwl_prep_station(struct iwl_priv *priv, const u8 *addr,
+                          bool is_ap,
+                          struct ieee80211_sta_ht_cap *ht_info)
 {
        struct iwl_station_entry *station;
-       unsigned long flags_spin;
        int i;
-       int sta_id = IWL_INVALID_STATION;
+       u8 sta_id = IWL_INVALID_STATION;
        u16 rate;
 
-       spin_lock_irqsave(&priv->sta_lock, flags_spin);
        if (is_ap)
                sta_id = IWL_AP_ID;
        else if (is_broadcast_ether_addr(addr))
@@ -292,20 +245,32 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
                                sta_id = i;
                }
 
-       /* These two conditions have the same outcome, but keep them separate
-          since they have different meanings */
-       if (unlikely(sta_id == IWL_INVALID_STATION)) {
-               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+       /*
+        * These two conditions have the same outcome, but keep them
+        * separate
+        */
+       if (unlikely(sta_id == IWL_INVALID_STATION))
+               return sta_id;
+
+       /*
+        * uCode is not able to deal with multiple requests to add a
+        * station. Keep track if one is in progress so that we do not send
+        * another.
+        */
+       if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
+               IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n",
+                               sta_id);
                return sta_id;
        }
 
-       if (priv->stations[sta_id].used &&
+       if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+           (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) &&
            !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) {
-               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n",
+                               sta_id, addr);
                return sta_id;
        }
 
-
        station = &priv->stations[sta_id];
        station->used = IWL_STA_DRIVER_ACTIVE;
        IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n",
@@ -319,10 +284,12 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
        station->sta.sta.sta_id = sta_id;
        station->sta.station_flags = 0;
 
-       /* BCAST station and IBSS stations do not work in HT mode */
-       if (sta_id != priv->hw_params.bcast_sta_id &&
-           priv->iw_mode != NL80211_IFTYPE_ADHOC)
-               iwl_set_ht_add_station(priv, sta_id, ht_info);
+       /*
+        * OK to call unconditionally, since local stations (IBSS BSSID
+        * STA and broadcast STA) pass in a NULL ht_info, and mac80211
+        * doesn't allow HT IBSS.
+        */
+       iwl_set_ht_add_station(priv, sta_id, ht_info);
 
        /* 3945 only */
        rate = (priv->band == IEEE80211_BAND_5GHZ) ?
@@ -330,86 +297,221 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
        /* Turn on both antennas for the station... */
        station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
 
+       return sta_id;
+
+}
+
+#define STA_WAIT_TIMEOUT (HZ/2)
+
+/**
+ * iwl_add_station_common -
+ */
+int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
+                                 bool is_ap,
+                                 struct ieee80211_sta_ht_cap *ht_info,
+                                 u8 *sta_id_r)
+{
+       struct iwl_station_entry *station;
+       unsigned long flags_spin;
+       int ret = 0;
+       u8 sta_id;
+
+       *sta_id_r = 0;
+       spin_lock_irqsave(&priv->sta_lock, flags_spin);
+       sta_id = iwl_prep_station(priv, addr, is_ap, ht_info);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Unable to prepare station %pM for addition\n",
+                       addr);
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               return -EINVAL;
+       }
+
+       /*
+        * uCode is not able to deal with multiple requests to add a
+        * station. Keep track if one is in progress so that we do not send
+        * another.
+        */
+       if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) {
+               IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n",
+                              sta_id);
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               return -EEXIST;
+       }
+
+       if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
+           (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
+               IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n",
+                               sta_id, addr);
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+               return -EEXIST;
+       }
+
+       priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
+       station = &priv->stations[sta_id];
        spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
 
        /* Add station to device's station table */
-       iwl_send_add_sta(priv, &station->sta, flags);
-       return sta_id;
+       ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC);
+       if (ret) {
+               IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr);
+               spin_lock_irqsave(&priv->sta_lock, flags_spin);
+               priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+               priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+       }
+       *sta_id_r = sta_id;
+       return ret;
+}
+EXPORT_SYMBOL(iwl_add_station_common);
+
+static struct iwl_link_quality_cmd *iwl_sta_alloc_lq(struct iwl_priv *priv,
+                                                    u8 sta_id)
+{
+       int i, r;
+       struct iwl_link_quality_cmd *link_cmd;
+       u32 rate_flags;
+
+       link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL);
+       if (!link_cmd) {
+               IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n");
+               return NULL;
+       }
+       /* Set up the rate scaling to start at selected rate, fall back
+        * all the way down to 1M in IEEE order, and then spin on 1M */
+       if (priv->band == IEEE80211_BAND_5GHZ)
+               r = IWL_RATE_6M_INDEX;
+       else
+               r = IWL_RATE_1M_INDEX;
 
+       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+               rate_flags = 0;
+               if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+                       rate_flags |= RATE_MCS_CCK_MSK;
+
+               rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
+                               RATE_MCS_ANT_POS;
+
+               link_cmd->rs_table[i].rate_n_flags =
+                       iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+               r = iwl_get_prev_ieee_rate(r);
+       }
+
+       link_cmd->general_params.single_stream_ant_msk =
+                               first_antenna(priv->hw_params.valid_tx_ant);
+
+       link_cmd->general_params.dual_stream_ant_msk =
+               priv->hw_params.valid_tx_ant &
+               ~first_antenna(priv->hw_params.valid_tx_ant);
+       if (!link_cmd->general_params.dual_stream_ant_msk) {
+               link_cmd->general_params.dual_stream_ant_msk = ANT_AB;
+       } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) {
+               link_cmd->general_params.dual_stream_ant_msk =
+                       priv->hw_params.valid_tx_ant;
+       }
+
+       link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+       link_cmd->agg_params.agg_time_limit =
+               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+
+       link_cmd->sta_id = sta_id;
+
+       return link_cmd;
 }
-EXPORT_SYMBOL(iwl_add_station);
 
-static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const u8 *addr)
+/*
+ * iwl_add_bssid_station - Add the special IBSS BSSID station
+ *
+ * Function sleeps.
+ */
+int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
+                         u8 *sta_id_r)
 {
+       int ret;
+       u8 sta_id;
+       struct iwl_link_quality_cmd *link_cmd;
        unsigned long flags;
-       u8 sta_id = iwl_find_station(priv, addr);
 
-       BUG_ON(sta_id == IWL_INVALID_STATION);
+       if (*sta_id_r)
+               *sta_id_r = IWL_INVALID_STATION;
 
-       IWL_DEBUG_ASSOC(priv, "Removed STA from Ucode: %pM\n", addr);
+       ret = iwl_add_station_common(priv, addr, 0, NULL, &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM\n", addr);
+               return ret;
+       }
+
+       if (sta_id_r)
+               *sta_id_r = sta_id;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
+       priv->stations[sta_id].used |= IWL_STA_LOCAL;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       /* Ucode must be active and driver must be non active */
-       if (priv->stations[sta_id].used != IWL_STA_UCODE_ACTIVE)
-               IWL_ERR(priv, "removed non active STA %d\n", sta_id);
+       if (init_rs) {
+               /* Set up default rate scaling table in device's station table */
+               link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+               if (!link_cmd) {
+                       IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n",
+                               addr);
+                       return -ENOMEM;
+               }
 
-       priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
+               ret = iwl_send_lq_cmd(priv, link_cmd, CMD_SYNC, true);
+               if (ret)
+                       IWL_ERR(priv, "Link quality command failed (%d)\n", ret);
 
-       memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
+               spin_lock_irqsave(&priv->sta_lock, flags);
+               priv->stations[sta_id].lq = link_cmd;
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+       }
+
+       return 0;
 }
+EXPORT_SYMBOL(iwl_add_bssid_station);
 
-static void iwl_remove_sta_callback(struct iwl_priv *priv,
-                                   struct iwl_device_cmd *cmd,
-                                   struct iwl_rx_packet *pkt)
+/**
+ * iwl_sta_ucode_deactivate - deactivate ucode status for a station
+ *
+ * priv->sta_lock must be held
+ */
+static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
 {
-       struct iwl_rem_sta_cmd *rm_sta =
-                       (struct iwl_rem_sta_cmd *)cmd->cmd.payload;
-       const u8 *addr = rm_sta->addr;
+       /* Ucode must be active and driver must be non active */
+       if ((priv->stations[sta_id].used &
+            (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != IWL_STA_UCODE_ACTIVE)
+               IWL_ERR(priv, "removed non active STA %u\n", sta_id);
 
-       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n",
-               pkt->hdr.flags);
-               return;
-       }
+       priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE;
 
-       switch (pkt->u.rem_sta.status) {
-       case REM_STA_SUCCESS_MSK:
-               iwl_sta_ucode_deactivate(priv, addr);
-               break;
-       default:
-               IWL_ERR(priv, "REPLY_REMOVE_STA failed\n");
-               break;
-       }
+       memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry));
+       IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id);
 }
 
-static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
-                                  u8 flags)
+static int iwl_send_remove_station(struct iwl_priv *priv,
+                                  struct iwl_station_entry *station)
 {
        struct iwl_rx_packet *pkt;
        int ret;
 
+       unsigned long flags_spin;
        struct iwl_rem_sta_cmd rm_sta_cmd;
 
        struct iwl_host_cmd cmd = {
                .id = REPLY_REMOVE_STA,
                .len = sizeof(struct iwl_rem_sta_cmd),
-               .flags = flags,
+               .flags = CMD_SYNC,
                .data = &rm_sta_cmd,
        };
 
        memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
        rm_sta_cmd.num_sta = 1;
-       memcpy(&rm_sta_cmd.addr, addr , ETH_ALEN);
+       memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN);
+
+       cmd.flags |= CMD_WANT_SKB;
 
-       if (flags & CMD_ASYNC)
-               cmd.callback = iwl_remove_sta_callback;
-       else
-               cmd.flags |= CMD_WANT_SKB;
        ret = iwl_send_cmd(priv, &cmd);
 
-       if (ret || (flags & CMD_ASYNC))
+       if (ret)
                return ret;
 
        pkt = (struct iwl_rx_packet *)cmd.reply_page;
@@ -422,7 +524,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
        if (!ret) {
                switch (pkt->u.rem_sta.status) {
                case REM_STA_SUCCESS_MSK:
-                       iwl_sta_ucode_deactivate(priv, addr);
+                       spin_lock_irqsave(&priv->sta_lock, flags_spin);
+                       iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id);
+                       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
                        IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
                        break;
                default:
@@ -439,45 +543,48 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
 /**
  * iwl_remove_station - Remove driver's knowledge of station.
  */
-int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+                      const u8 *addr)
 {
-       int sta_id = IWL_INVALID_STATION;
-       int i, ret = -EINVAL;
+       struct iwl_station_entry *station;
        unsigned long flags;
 
-       spin_lock_irqsave(&priv->sta_lock, flags);
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_INFO(priv,
+                       "Unable to remove station %pM, device not ready.\n",
+                       addr);
+               /*
+                * It is typical for stations to be removed when we are
+                * going down. Return success since device will be down
+                * soon anyway
+                */
+               return 0;
+       }
 
-       if (is_ap)
-               sta_id = IWL_AP_ID;
-       else if (is_broadcast_ether_addr(addr))
-               sta_id = priv->hw_params.bcast_sta_id;
-       else
-               for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
-                       if (priv->stations[i].used &&
-                           !compare_ether_addr(priv->stations[i].sta.sta.addr,
-                                               addr)) {
-                               sta_id = i;
-                               break;
-                       }
+       IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
+                       sta_id, addr);
 
-       if (unlikely(sta_id == IWL_INVALID_STATION))
-               goto out;
+       if (WARN_ON(sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
 
-       IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d  %pM\n",
-               sta_id, addr);
+       spin_lock_irqsave(&priv->sta_lock, flags);
 
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
-               IWL_ERR(priv, "Removing %pM but non DRIVER active\n",
+               IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n",
                                addr);
-               goto out;
+               goto out_err;
        }
 
        if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) {
-               IWL_ERR(priv, "Removing %pM but non UCODE active\n",
+               IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n",
                                addr);
-               goto out;
+               goto out_err;
        }
 
+       if (priv->stations[sta_id].used & IWL_STA_LOCAL) {
+               kfree(priv->stations[sta_id].lq);
+               priv->stations[sta_id].lq = NULL;
+       }
 
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
 
@@ -485,47 +592,112 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
 
        BUG_ON(priv->num_stations < 0);
 
+       station = &priv->stations[sta_id];
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       ret = iwl_send_remove_station(priv, addr, CMD_ASYNC);
-       return ret;
-out:
+       return iwl_send_remove_station(priv, station);
+out_err:
        spin_unlock_irqrestore(&priv->sta_lock, flags);
-       return ret;
+       return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(iwl_remove_station);
 
 /**
- * iwl_clear_stations_table - Clear the driver's station table
+ * iwl_clear_ucode_stations - clear ucode station table bits
  *
- * NOTE:  This does not clear or otherwise alter the device's station table.
+ * This function clears all the bits in the driver indicating
+ * which stations are active in the ucode. Call when something
+ * other than explicit station management would cause this in
+ * the ucode, e.g. unassociated RXON.
  */
-void iwl_clear_stations_table(struct iwl_priv *priv)
+void iwl_clear_ucode_stations(struct iwl_priv *priv)
 {
-       unsigned long flags;
        int i;
+       unsigned long flags_spin;
+       bool cleared = false;
 
-       spin_lock_irqsave(&priv->sta_lock, flags);
+       IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n");
 
-       if (iwl_is_alive(priv) &&
-          !test_bit(STATUS_EXIT_PENDING, &priv->status) &&
-          iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL))
-               IWL_ERR(priv, "Couldn't clear the station table\n");
+       spin_lock_irqsave(&priv->sta_lock, flags_spin);
+       for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) {
+                       IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i);
+                       priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+                       cleared = true;
+               }
+       }
+       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+       if (!cleared)
+               IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n");
+}
+EXPORT_SYMBOL(iwl_clear_ucode_stations);
+
+/**
+ * iwl_restore_stations() - Restore driver known stations to device
+ *
+ * All stations considered active by driver, but not present in ucode, is
+ * restored.
+ *
+ * Function sleeps.
+ */
+void iwl_restore_stations(struct iwl_priv *priv)
+{
+       struct iwl_station_entry *station;
+       unsigned long flags_spin;
+       int i;
+       bool found = false;
+       int ret;
 
-       priv->num_stations = 0;
-       memset(priv->stations, 0, sizeof(priv->stations));
+       if (!iwl_is_ready(priv)) {
+               IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n");
+               return;
+       }
 
-       /* clean ucode key table bit map */
-       priv->ucode_key_table = 0;
+       IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n");
+       spin_lock_irqsave(&priv->sta_lock, flags_spin);
+       for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) &&
+                           !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) {
+                       IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n",
+                                       priv->stations[i].sta.sta.addr);
+                       priv->stations[i].sta.mode = 0;
+                       priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS;
+                       found = true;
+               }
+       }
 
-       /* keep track of static keys */
-       for (i = 0; i < WEP_KEYS_MAX ; i++) {
-               if (priv->wep_keys[i].key_size)
-                       set_bit(i, &priv->ucode_key_table);
+       for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+                       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+                       station = &priv->stations[i];
+                       ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC);
+                       if (ret) {
+                               IWL_ERR(priv, "Adding station %pM failed.\n",
+                                       station->sta.sta.addr);
+                               spin_lock_irqsave(&priv->sta_lock, flags_spin);
+                               priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE;
+                               priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
+                               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+                       }
+                       /*
+                        * Rate scaling has already been initialized, send
+                        * current LQ command
+                        */
+                       if (station->lq)
+                               iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true);
+                       spin_lock_irqsave(&priv->sta_lock, flags_spin);
+                       priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
+               }
        }
 
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
+       spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+       if (!found)
+               IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n");
+       else
+               IWL_DEBUG_INFO(priv, "Restoring all known stations .... complete.\n");
 }
-EXPORT_SYMBOL(iwl_clear_stations_table);
+EXPORT_SYMBOL(iwl_restore_stations);
 
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
@@ -539,7 +711,7 @@ int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
 
-int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
+static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 {
        int i, not_empty = 0;
        u8 buff[sizeof(struct iwl_wep_cmd) +
@@ -549,9 +721,11 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        struct iwl_host_cmd cmd = {
                .id = REPLY_WEPKEY,
                .data = wep_cmd,
-               .flags = CMD_ASYNC,
+               .flags = CMD_SYNC,
        };
 
+       might_sleep();
+
        memset(wep_cmd, 0, cmd_size +
                        (sizeof(struct iwl_wep_key) * WEP_KEYS_MAX));
 
@@ -581,33 +755,34 @@ int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
        else
                return 0;
 }
-EXPORT_SYMBOL(iwl_send_static_wepkey_cmd);
+
+int iwl_restore_default_wep_keys(struct iwl_priv *priv)
+{
+       WARN_ON(!mutex_is_locked(&priv->mutex));
+
+       return iwl_send_static_wepkey_cmd(priv, 0);
+}
+EXPORT_SYMBOL(iwl_restore_default_wep_keys);
 
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
                               struct ieee80211_key_conf *keyconf)
 {
        int ret;
-       unsigned long flags;
 
-       spin_lock_irqsave(&priv->sta_lock, flags);
+       WARN_ON(!mutex_is_locked(&priv->mutex));
+
        IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
                      keyconf->keyidx);
 
-       if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
-               IWL_ERR(priv, "index %d not used in uCode key table.\n",
-                         keyconf->keyidx);
-
-       priv->default_wep_key--;
        memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
        if (iwl_is_rfkill(priv)) {
                IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
-               spin_unlock_irqrestore(&priv->sta_lock, flags);
+               /* but keys in device are clear anyway so return success */
                return 0;
        }
        ret = iwl_send_static_wepkey_cmd(priv, 1);
        IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
                      keyconf->keyidx, ret);
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        return ret;
 }
@@ -617,7 +792,8 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
                            struct ieee80211_key_conf *keyconf)
 {
        int ret;
-       unsigned long flags;
+
+       WARN_ON(!mutex_is_locked(&priv->mutex));
 
        if (keyconf->keylen != WEP_KEY_LEN_128 &&
            keyconf->keylen != WEP_KEY_LEN_64) {
@@ -629,13 +805,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
        keyconf->hw_key_idx = HW_KEY_DEFAULT;
        priv->stations[IWL_AP_ID].keyinfo.alg = ALG_WEP;
 
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->default_wep_key++;
-
-       if (test_and_set_bit(keyconf->keyidx, &priv->ucode_key_table))
-               IWL_ERR(priv, "index %d already used in uCode key table.\n",
-                       keyconf->keyidx);
-
        priv->wep_keys[keyconf->keyidx].key_size = keyconf->keylen;
        memcpy(&priv->wep_keys[keyconf->keyidx].key, &keyconf->key,
                                                        keyconf->keylen);
@@ -643,7 +812,6 @@ int iwl_set_default_wep_key(struct iwl_priv *priv,
        ret = iwl_send_static_wepkey_cmd(priv, 0);
        IWL_DEBUG_WEP(priv, "Set default WEP key: len=%d idx=%d ret=%d\n",
                keyconf->keylen, keyconf->keyidx, ret);
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        return ret;
 }
@@ -798,18 +966,23 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,
 
 void iwl_update_tkip_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *keyconf,
-                       const u8 *addr, u32 iv32, u16 *phase1key)
+                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key)
 {
-       u8 sta_id = IWL_INVALID_STATION;
+       u8 sta_id;
        unsigned long flags;
        int i;
 
-       sta_id = iwl_find_station(priv, addr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                  addr);
-               return;
-       }
+       if (sta) {
+               sta_id = iwl_sta_id(sta);
+
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n",
+                                          sta->addr);
+                       return;
+               }
+       } else
+               sta_id = priv->hw_params.bcast_sta_id;
+
 
        if (iwl_scan_cancel(priv)) {
                /* cancel scan failed, just live w/ bad key and rely
@@ -885,7 +1058,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
        priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
        if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
+               IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled.\n");
                spin_unlock_irqrestore(&priv->sta_lock, flags);
                return 0;
        }
@@ -948,253 +1121,149 @@ static inline void iwl_dump_lq_cmd(struct iwl_priv *priv,
 }
 #endif
 
-int iwl_send_lq_cmd(struct iwl_priv *priv,
-                   struct iwl_link_quality_cmd *lq, u8 flags)
-{
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_TX_LINK_QUALITY_CMD,
-               .len = sizeof(struct iwl_link_quality_cmd),
-               .flags = flags,
-               .data = lq,
-       };
-
-       if ((lq->sta_id == 0xFF) &&
-           (priv->iw_mode == NL80211_IFTYPE_ADHOC))
-               return -EINVAL;
-
-       if (lq->sta_id == 0xFF)
-               lq->sta_id = IWL_AP_ID;
-
-       iwl_dump_lq_cmd(priv, lq);
-
-       if (iwl_is_associated(priv) && priv->assoc_station_added)
-               return  iwl_send_cmd(priv, &cmd);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_send_lq_cmd);
-
 /**
- * iwl_sta_init_lq - Initialize a station's hardware rate table
- *
- * The uCode's station table contains a table of fallback rates
- * for automatic fallback during transmission.
- *
- * NOTE: This sets up a default set of values.  These will be replaced later
- *       if the driver's iwl-agn-rs rate scaling algorithm is used, instead of
- *       rc80211_simple.
+ * is_lq_table_valid() - Test one aspect of LQ cmd for validity
  *
- * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
- *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
- *       which requires station table entry to exist).
+ * It sometimes happens when a HT rate has been in use and we
+ * loose connectivity with AP then mac80211 will first tell us that the
+ * current channel is not HT anymore before removing the station. In such a
+ * scenario the RXON flags will be updated to indicate we are not
+ * communicating HT anymore, but the LQ command may still contain HT rates.
+ * Test for this to prevent driver from sending LQ command between the time
+ * RXON flags are updated and when LQ command is updated.
  */
-static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
+static bool is_lq_table_valid(struct iwl_priv *priv,
+                             struct iwl_link_quality_cmd *lq)
 {
-       int i, r;
-       struct iwl_link_quality_cmd link_cmd = {
-               .reserved1 = 0,
-       };
-       u32 rate_flags;
+       int i;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
 
-       /* Set up the rate scaling to start at selected rate, fall back
-        * all the way down to 1M in IEEE order, and then spin on 1M */
-       if (is_ap)
-               r = IWL_RATE_54M_INDEX;
-       else if (priv->band == IEEE80211_BAND_5GHZ)
-               r = IWL_RATE_6M_INDEX;
-       else
-               r = IWL_RATE_1M_INDEX;
+       if (ht_conf->is_ht)
+               return true;
 
+       IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n",
+                      priv->active_rxon.channel);
        for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-               rate_flags = 0;
-               if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
-                       rate_flags |= RATE_MCS_CCK_MSK;
-
-               rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
-                               RATE_MCS_ANT_POS;
-
-               link_cmd.rs_table[i].rate_n_flags =
-                       iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-               r = iwl_get_prev_ieee_rate(r);
+               if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) {
+                       IWL_DEBUG_INFO(priv,
+                                      "index %d of LQ expects HT channel\n",
+                                      i);
+                       return false;
+               }
        }
-
-       link_cmd.general_params.single_stream_ant_msk =
-                               first_antenna(priv->hw_params.valid_tx_ant);
-       link_cmd.general_params.dual_stream_ant_msk = 3;
-       link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
-       link_cmd.agg_params.agg_time_limit =
-               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
-
-       /* Update the rate scaling for control frame Tx to AP */
-       link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
-
-       iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
-                              sizeof(link_cmd), &link_cmd, NULL);
+       return true;
 }
 
 /**
- * iwl_rxon_add_station - add station into station table.
+ * iwl_send_lq_cmd() - Send link quality command
+ * @init: This command is sent as part of station initialization right
+ *        after station has been added.
  *
- * there is only one AP station with id= IWL_AP_ID
- * NOTE: mutex must be held before calling this function
+ * The link quality command is sent as the last step of station creation.
+ * This is the special case in which init is set and we call a callback in
+ * this case to clear the state indicating that station creation is in
+ * progress.
  */
-int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
+int iwl_send_lq_cmd(struct iwl_priv *priv,
+                   struct iwl_link_quality_cmd *lq, u8 flags, bool init)
 {
-       struct ieee80211_sta *sta;
-       struct ieee80211_sta_ht_cap ht_config;
-       struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
-       u8 sta_id;
+       int ret = 0;
+       unsigned long flags_spin;
 
-       /*
-        * Set HT capabilities. It is ok to set this struct even if not using
-        * HT config: the priv->current_ht_config.is_ht flag will just be false
-        */
-       rcu_read_lock();
-       sta = ieee80211_find_sta(priv->vif, addr);
-       if (sta) {
-               memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
-               cur_ht_config = &ht_config;
-       }
-       rcu_read_unlock();
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_TX_LINK_QUALITY_CMD,
+               .len = sizeof(struct iwl_link_quality_cmd),
+               .flags = flags,
+               .data = lq,
+       };
 
-       /* Add station to device's station table */
-       sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
+       if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
+               return -EINVAL;
 
-       /* Set up default rate scaling table in device's station table */
-       iwl_sta_init_lq(priv, addr, is_ap);
+       iwl_dump_lq_cmd(priv, lq);
+       BUG_ON(init && (cmd.flags & CMD_ASYNC));
 
-       return sta_id;
+       if (is_lq_table_valid(priv, lq))
+               ret = iwl_send_cmd(priv, &cmd);
+       else
+               ret = -EINVAL;
+
+       if (cmd.flags & CMD_ASYNC)
+               return ret;
+
+       if (init) {
+               IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d\n",
+                              lq->sta_id);
+               spin_lock_irqsave(&priv->sta_lock, flags_spin);
+               priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
+               spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+       }
+       return ret;
 }
-EXPORT_SYMBOL(iwl_rxon_add_station);
+EXPORT_SYMBOL(iwl_send_lq_cmd);
 
 /**
- * iwl_sta_init_bcast_lq - Initialize a bcast station's hardware rate table
+ * iwl_alloc_bcast_station - add broadcast station into driver's station table.
  *
- * NOTE: Run REPLY_ADD_STA command to set up station table entry, before
- *       calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
- *       which requires station table entry to exist).
+ * This adds the broadcast station into the driver's station table
+ * and marks it driver active, so that it will be restored to the
+ * device at the next best time.
  */
-static void iwl_sta_init_bcast_lq(struct iwl_priv *priv)
+int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq)
 {
-       int i, r;
-       struct iwl_link_quality_cmd link_cmd = {
-               .reserved1 = 0,
-       };
-       u32 rate_flags;
-
-       /* Set up the rate scaling to start at selected rate, fall back
-        * all the way down to 1M in IEEE order, and then spin on 1M */
-       if (priv->band == IEEE80211_BAND_5GHZ)
-               r = IWL_RATE_6M_INDEX;
-       else
-               r = IWL_RATE_1M_INDEX;
-
-       for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
-               rate_flags = 0;
-               if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
-                       rate_flags |= RATE_MCS_CCK_MSK;
+       struct iwl_link_quality_cmd *link_cmd;
+       unsigned long flags;
+       u8 sta_id;
 
-               rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) <<
-                               RATE_MCS_ANT_POS;
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       sta_id = iwl_prep_station(priv, iwl_bcast_addr, false, NULL);
+       if (sta_id == IWL_INVALID_STATION) {
+               IWL_ERR(priv, "Unable to prepare broadcast station\n");
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-               link_cmd.rs_table[i].rate_n_flags =
-                       iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
-               r = iwl_get_prev_ieee_rate(r);
+               return -EINVAL;
        }
 
-       link_cmd.general_params.single_stream_ant_msk =
-                               first_antenna(priv->hw_params.valid_tx_ant);
-       link_cmd.general_params.dual_stream_ant_msk = 3;
-       link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
-       link_cmd.agg_params.agg_time_limit =
-               cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
-
-       /* Update the rate scaling for control frame Tx to AP */
-       link_cmd.sta_id = priv->hw_params.bcast_sta_id;
-
-       iwl_send_cmd_pdu_async(priv, REPLY_TX_LINK_QUALITY_CMD,
-                              sizeof(link_cmd), &link_cmd, NULL);
-}
-
+       priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE;
+       priv->stations[sta_id].used |= IWL_STA_BCAST;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-/**
- * iwl_add_bcast_station - add broadcast station into station table.
- */
-void iwl_add_bcast_station(struct iwl_priv *priv)
-{
-       IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
-       iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL);
+       if (init_lq) {
+               link_cmd = iwl_sta_alloc_lq(priv, sta_id);
+               if (!link_cmd) {
+                       IWL_ERR(priv,
+                               "Unable to initialize rate scaling for bcast station.\n");
+                       return -ENOMEM;
+               }
 
-       /* Set up default rate scaling table in device's station table */
-       iwl_sta_init_bcast_lq(priv);
-}
-EXPORT_SYMBOL(iwl_add_bcast_station);
+               spin_lock_irqsave(&priv->sta_lock, flags);
+               priv->stations[sta_id].lq = link_cmd;
+               spin_unlock_irqrestore(&priv->sta_lock, flags);
+       }
 
-/**
- * iwl3945_add_bcast_station - add broadcast station into station table.
- */
-void iwl3945_add_bcast_station(struct iwl_priv *priv)
-{
-       IWL_DEBUG_INFO(priv, "Adding broadcast station to station table\n");
-       iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL);
+       return 0;
 }
-EXPORT_SYMBOL(iwl3945_add_bcast_station);
+EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);
 
-/**
- * iwl_get_sta_id - Find station's index within station table
- *
- * If new IBSS station, create new entry in station table
- */
-int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+void iwl_dealloc_bcast_station(struct iwl_priv *priv)
 {
-       int sta_id;
-       __le16 fc = hdr->frame_control;
-
-       /* If this frame is broadcast or management, use broadcast station id */
-       if (!ieee80211_is_data(fc) ||  is_multicast_ether_addr(hdr->addr1))
-               return priv->hw_params.bcast_sta_id;
-
-       switch (priv->iw_mode) {
-
-       /* If we are a client station in a BSS network, use the special
-        * AP station entry (that's the only station we communicate with) */
-       case NL80211_IFTYPE_STATION:
-               return IWL_AP_ID;
-
-       /* If we are an AP, then find the station, or use BCAST */
-       case NL80211_IFTYPE_AP:
-               sta_id = iwl_find_station(priv, hdr->addr1);
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-               return priv->hw_params.bcast_sta_id;
-
-       /* If this frame is going out to an IBSS network, find the station,
-        * or create a new station table entry */
-       case NL80211_IFTYPE_ADHOC:
-               sta_id = iwl_find_station(priv, hdr->addr1);
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-
-               /* Create new station table entry */
-               sta_id = iwl_add_station(priv, hdr->addr1, false,
-                                       CMD_ASYNC, NULL);
-
-               if (sta_id != IWL_INVALID_STATION)
-                       return sta_id;
-
-               IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
-                              "Defaulting to broadcast...\n",
-                              hdr->addr1);
-               iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
-               return priv->hw_params.bcast_sta_id;
+       unsigned long flags;
+       int i;
 
-       default:
-               IWL_WARN(priv, "Unknown mode of operation: %d\n",
-                       priv->iw_mode);
-               return priv->hw_params.bcast_sta_id;
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       for (i = 0; i < priv->hw_params.max_stations; i++) {
+               if (!(priv->stations[i].used & IWL_STA_BCAST))
+                       continue;
+
+               priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
+               priv->num_stations--;
+               BUG_ON(priv->num_stations < 0);
+               kfree(priv->stations[i].lq);
+               priv->stations[i].lq = NULL;
        }
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
-EXPORT_SYMBOL(iwl_get_sta_id);
+EXPORT_SYMBOL_GPL(iwl_dealloc_bcast_station);
 
 /**
  * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table
@@ -1214,13 +1283,13 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
 }
 EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
 
-int iwl_sta_rx_agg_start(struct iwl_priv *priv,
-                        const u8 *addr, int tid, u16 ssn)
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                        int tid, u16 ssn)
 {
        unsigned long flags;
        int sta_id;
 
-       sta_id = iwl_find_station(priv, addr);
+       sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION)
                return -ENXIO;
 
@@ -1233,16 +1302,17 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv,
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
        return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
-                                       CMD_ASYNC);
+                               CMD_ASYNC);
 }
 EXPORT_SYMBOL(iwl_sta_rx_agg_start);
 
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                       int tid)
 {
        unsigned long flags;
        int sta_id;
 
-       sta_id = iwl_find_station(priv, addr);
+       sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
                return -ENXIO;
@@ -1291,3 +1361,22 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 
        iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
 }
+EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
+
+int iwl_mac_sta_remove(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv_common *sta_common = (void *)sta->drv_priv;
+       int ret;
+
+       IWL_DEBUG_INFO(priv, "received request to remove station %pM\n",
+                       sta->addr);
+       ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr);
+       if (ret)
+               IWL_ERR(priv, "Error removing station %pM\n",
+                       sta->addr);
+       return ret;
+}
+EXPORT_SYMBOL(iwl_mac_sta_remove);
index 2dc35fe28f56420e9a3fcaef2a57d6105bc54cb9..c2a453a1a9917e4e6bb9124b4af0318416ff0f34 100644 (file)
 #ifndef __iwl_sta_h__
 #define __iwl_sta_h__
 
+#include "iwl-dev.h"
+
 #define HW_KEY_DYNAMIC 0
 #define HW_KEY_DEFAULT 1
 
-/**
- * iwl_find_station - Find station id for a given BSSID
- * @bssid: MAC address of station ID to find
- */
-u8 iwl_find_station(struct iwl_priv *priv, const u8 *bssid);
+#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */
+#define IWL_STA_UCODE_ACTIVE  BIT(1) /* ucode entry is active */
+#define IWL_STA_UCODE_INPROGRESS  BIT(2) /* ucode entry is in process of
+                                           being activated */
+#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211;
+                               (this is for the IBSS BSSID stations) */
+#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */
+
 
-int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty);
 int iwl_remove_default_wep_key(struct iwl_priv *priv,
                               struct ieee80211_key_conf *key);
 int iwl_set_default_wep_key(struct iwl_priv *priv,
                            struct ieee80211_key_conf *key);
+int iwl_restore_default_wep_keys(struct iwl_priv *priv);
 int iwl_set_dynamic_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *key, u8 sta_id);
 int iwl_remove_dynamic_key(struct iwl_priv *priv,
                           struct ieee80211_key_conf *key, u8 sta_id);
 void iwl_update_tkip_key(struct iwl_priv *priv,
                        struct ieee80211_key_conf *keyconf,
-                       const u8 *addr, u32 iv32, u16 *phase1key);
+                       struct ieee80211_sta *sta, u32 iv32, u16 *phase1key);
 
-int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
-void iwl_add_bcast_station(struct iwl_priv *priv);
-void iwl3945_add_bcast_station(struct iwl_priv *priv);
-int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
-void iwl_clear_stations_table(struct iwl_priv *priv);
+void iwl_restore_stations(struct iwl_priv *priv);
+void iwl_clear_ucode_stations(struct iwl_priv *priv);
+int iwl_alloc_bcast_station(struct iwl_priv *priv, bool init_lq);
+void iwl_dealloc_bcast_station(struct iwl_priv *priv);
 int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
-int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
-int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags);
-u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
-                       struct ieee80211_sta_ht_cap *ht_info);
+int iwl_add_bssid_station(struct iwl_priv *priv, const u8 *addr, bool init_rs,
+                         u8 *sta_id_r);
+int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
+                                 bool is_ap,
+                                 struct ieee80211_sta_ht_cap *ht_info,
+                                 u8 *sta_id_r);
+int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
+                      const u8 *addr);
+int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta);
 void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
-int iwl_sta_rx_agg_start(struct iwl_priv *priv,
-                        const u8 *addr, int tid, u16 ssn);
-int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid);
+int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                        int tid, u16 ssn);
+int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
+                       int tid);
 void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id);
 void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
+
+/**
+ * iwl_clear_driver_stations - clear knowledge of all stations from driver
+ * @priv: iwl priv struct
+ *
+ * This is called during iwl_down() to make sure that in the case
+ * we're coming there from a hardware restart mac80211 will be
+ * able to reconfigure stations -- if we're getting there in the
+ * normal down flow then the stations will already be cleared.
+ */
+static inline void iwl_clear_driver_stations(struct iwl_priv *priv)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sta_lock, flags);
+       memset(priv->stations, 0, sizeof(priv->stations));
+       priv->num_stations = 0;
+       spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+static inline int iwl_sta_id(struct ieee80211_sta *sta)
+{
+       if (WARN_ON(!sta))
+               return IWL_INVALID_STATION;
+
+       return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id;
+}
 #endif /* __iwl_sta_h__ */
index 8dd0c036d547d4abca46d9bd80eeaea4c5334e12..1ece2ea09773567145a5acde6bf997749856e107 100644 (file)
 #include "iwl-io.h"
 #include "iwl-helpers.h"
 
-static const u16 default_tid_to_tx_fifo[] = {
-       IWL_TX_FIFO_AC1,
-       IWL_TX_FIFO_AC0,
-       IWL_TX_FIFO_AC0,
-       IWL_TX_FIFO_AC1,
-       IWL_TX_FIFO_AC2,
-       IWL_TX_FIFO_AC2,
-       IWL_TX_FIFO_AC3,
-       IWL_TX_FIFO_AC3,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_NONE,
-       IWL_TX_FIFO_AC3
-};
-
-static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv,
-                                   struct iwl_dma_ptr *ptr, size_t size)
-{
-       ptr->addr = dma_alloc_coherent(&priv->pci_dev->dev, size, &ptr->dma,
-                                      GFP_KERNEL);
-       if (!ptr->addr)
-               return -ENOMEM;
-       ptr->size = size;
-       return 0;
-}
-
-static inline void iwl_free_dma_ptr(struct iwl_priv *priv,
-                                   struct iwl_dma_ptr *ptr)
-{
-       if (unlikely(!ptr->addr))
-               return;
-
-       dma_free_coherent(&priv->pci_dev->dev, ptr->size, ptr->addr, ptr->dma);
-       memset(ptr, 0, sizeof(*ptr));
-}
-
 /**
  * iwl_txq_update_write_ptr - Send new write index to hardware
  */
@@ -310,6 +269,8 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
                q->high_mark = 2;
 
        q->write_ptr = q->read_ptr = 0;
+       q->last_read_ptr = 0;
+       q->repeat_same_read_ptr = 0;
 
        return 0;
 }
@@ -454,611 +415,6 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
 }
 EXPORT_SYMBOL(iwl_tx_queue_reset);
 
-/**
- * iwl_hw_txq_ctx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
-{
-       int txq_id;
-
-       /* Tx queues */
-       if (priv->txq) {
-               for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-                       if (txq_id == IWL_CMD_QUEUE_NUM)
-                               iwl_cmd_queue_free(priv);
-                       else
-                               iwl_tx_queue_free(priv, txq_id);
-       }
-       iwl_free_dma_ptr(priv, &priv->kw);
-
-       iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
-
-       /* free tx queue structure */
-       iwl_free_txq_mem(priv);
-}
-EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
-
-/**
- * iwl_txq_ctx_alloc - allocate TX queue context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-int iwl_txq_ctx_alloc(struct iwl_priv *priv)
-{
-       int ret;
-       int txq_id, slots_num;
-       unsigned long flags;
-
-       /* Free all tx/cmd queues and keep-warm buffer */
-       iwl_hw_txq_ctx_free(priv);
-
-       ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls,
-                               priv->hw_params.scd_bc_tbls_size);
-       if (ret) {
-               IWL_ERR(priv, "Scheduler BC Table allocation failed\n");
-               goto error_bc_tbls;
-       }
-       /* Alloc keep-warm buffer */
-       ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE);
-       if (ret) {
-               IWL_ERR(priv, "Keep Warm allocation failed\n");
-               goto error_kw;
-       }
-
-       /* allocate tx queue structure */
-       ret = iwl_alloc_txq_mem(priv);
-       if (ret)
-               goto error;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4) */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
-                                      txq_id);
-               if (ret) {
-                       IWL_ERR(priv, "Tx %d queue init failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return ret;
-
- error:
-       iwl_hw_txq_ctx_free(priv);
-       iwl_free_dma_ptr(priv, &priv->kw);
- error_kw:
-       iwl_free_dma_ptr(priv, &priv->scd_bc_tbls);
- error_bc_tbls:
-       return ret;
-}
-
-void iwl_txq_ctx_reset(struct iwl_priv *priv)
-{
-       int txq_id, slots_num;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4) */
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
-               slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
-                           TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
-       }
-}
-
-/**
- * iwl_txq_ctx_stop - Stop all Tx DMA channels
- */
-void iwl_txq_ctx_stop(struct iwl_priv *priv)
-{
-       int ch;
-       unsigned long flags;
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&priv->lock, flags);
-
-       priv->cfg->ops->lib->txq_set_sched(priv, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
-               iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
-                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-                                   1000);
-       }
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-EXPORT_SYMBOL(iwl_txq_ctx_stop);
-
-/*
- * handle build REPLY_TX command notification.
- */
-static void iwl_tx_cmd_build_basic(struct iwl_priv *priv,
-                                 struct iwl_tx_cmd *tx_cmd,
-                                 struct ieee80211_tx_info *info,
-                                 struct ieee80211_hdr *hdr,
-                                 u8 std_id)
-{
-       __le16 fc = hdr->frame_control;
-       __le32 tx_flags = tx_cmd->tx_flags;
-
-       tx_cmd->stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-               tx_flags |= TX_CMD_FLG_ACK_MSK;
-               if (ieee80211_is_mgmt(fc))
-                       tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-               if (ieee80211_is_probe_resp(fc) &&
-                   !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
-                       tx_flags |= TX_CMD_FLG_TSF_MSK;
-       } else {
-               tx_flags &= (~TX_CMD_FLG_ACK_MSK);
-               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-       }
-
-       if (ieee80211_is_back_req(fc))
-               tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK;
-
-
-       tx_cmd->sta_id = std_id;
-       if (ieee80211_has_morefrags(fc))
-               tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
-
-       if (ieee80211_is_data_qos(fc)) {
-               u8 *qc = ieee80211_get_qos_ctl(hdr);
-               tx_cmd->tid_tspec = qc[0] & 0xf;
-               tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
-       } else {
-               tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
-       }
-
-       priv->cfg->ops->utils->rts_tx_cmd_flag(info, &tx_flags);
-
-       if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
-               tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
-
-       tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
-       if (ieee80211_is_mgmt(fc)) {
-               if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc))
-                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(3);
-               else
-                       tx_cmd->timeout.pm_frame_timeout = cpu_to_le16(2);
-       } else {
-               tx_cmd->timeout.pm_frame_timeout = 0;
-       }
-
-       tx_cmd->driver_txop = 0;
-       tx_cmd->tx_flags = tx_flags;
-       tx_cmd->next_frame_len = 0;
-}
-
-#define RTS_HCCA_RETRY_LIMIT           3
-#define RTS_DFAULT_RETRY_LIMIT         60
-
-static void iwl_tx_cmd_build_rate(struct iwl_priv *priv,
-                             struct iwl_tx_cmd *tx_cmd,
-                             struct ieee80211_tx_info *info,
-                             __le16 fc, int is_hcca)
-{
-       u32 rate_flags;
-       int rate_idx;
-       u8 rts_retry_limit;
-       u8 data_retry_limit;
-       u8 rate_plcp;
-
-       /* Set retry limit on DATA packets and Probe Responses*/
-       if (ieee80211_is_probe_resp(fc))
-               data_retry_limit = 3;
-       else
-               data_retry_limit = IWL_DEFAULT_TX_RETRY;
-       tx_cmd->data_retry_limit = data_retry_limit;
-
-       /* Set retry limit on RTS packets */
-       rts_retry_limit = (is_hcca) ?  RTS_HCCA_RETRY_LIMIT :
-               RTS_DFAULT_RETRY_LIMIT;
-       if (data_retry_limit < rts_retry_limit)
-               rts_retry_limit = data_retry_limit;
-       tx_cmd->rts_retry_limit = rts_retry_limit;
-
-       /* DATA packets will use the uCode station table for rate/antenna
-        * selection */
-       if (ieee80211_is_data(fc)) {
-               tx_cmd->initial_rate_index = 0;
-               tx_cmd->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
-               return;
-       }
-
-       /**
-        * If the current TX rate stored in mac80211 has the MCS bit set, it's
-        * not really a TX rate.  Thus, we use the lowest supported rate for
-        * this band.  Also use the lowest supported rate if the stored rate
-        * index is invalid.
-        */
-       rate_idx = info->control.rates[0].idx;
-       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS ||
-                       (rate_idx < 0) || (rate_idx > IWL_RATE_COUNT_LEGACY))
-               rate_idx = rate_lowest_index(&priv->bands[info->band],
-                               info->control.sta);
-       /* For 5 GHZ band, remap mac80211 rate indices into driver indices */
-       if (info->band == IEEE80211_BAND_5GHZ)
-               rate_idx += IWL_FIRST_OFDM_RATE;
-       /* Get PLCP rate for tx_cmd->rate_n_flags */
-       rate_plcp = iwl_rates[rate_idx].plcp;
-       /* Zero out flags for this packet */
-       rate_flags = 0;
-
-       /* Set CCK flag as needed */
-       if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE))
-               rate_flags |= RATE_MCS_CCK_MSK;
-
-       /* Set up RTS and CTS flags for certain packets */
-       switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) {
-       case cpu_to_le16(IEEE80211_STYPE_AUTH):
-       case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
-       case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ):
-       case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ):
-               if (tx_cmd->tx_flags & TX_CMD_FLG_RTS_MSK) {
-                       tx_cmd->tx_flags &= ~TX_CMD_FLG_RTS_MSK;
-                       tx_cmd->tx_flags |= TX_CMD_FLG_CTS_MSK;
-               }
-               break;
-       default:
-               break;
-       }
-
-       /* Set up antennas */
-       priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
-       rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
-
-       /* Set the rate in the TX cmd */
-       tx_cmd->rate_n_flags = iwl_hw_set_rate_n_flags(rate_plcp, rate_flags);
-}
-
-static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
-                                     struct ieee80211_tx_info *info,
-                                     struct iwl_tx_cmd *tx_cmd,
-                                     struct sk_buff *skb_frag,
-                                     int sta_id)
-{
-       struct ieee80211_key_conf *keyconf = info->control.hw_key;
-
-       switch (keyconf->alg) {
-       case ALG_CCMP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_CCM;
-               memcpy(tx_cmd->key, keyconf->key, keyconf->keylen);
-               if (info->flags & IEEE80211_TX_CTL_AMPDU)
-                       tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK;
-               IWL_DEBUG_TX(priv, "tx_cmd with AES hwcrypto\n");
-               break;
-
-       case ALG_TKIP:
-               tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
-               ieee80211_get_tkip_key(keyconf, skb_frag,
-                       IEEE80211_TKIP_P2_KEY, tx_cmd->key);
-               IWL_DEBUG_TX(priv, "tx_cmd with tkip hwcrypto\n");
-               break;
-
-       case ALG_WEP:
-               tx_cmd->sec_ctl |= (TX_CMD_SEC_WEP |
-                       (keyconf->keyidx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT);
-
-               if (keyconf->keylen == WEP_KEY_LEN_128)
-                       tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128;
-
-               memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen);
-
-               IWL_DEBUG_TX(priv, "Configuring packet for WEP encryption "
-                            "with key %d\n", keyconf->keyidx);
-               break;
-
-       default:
-               IWL_ERR(priv, "Unknown encode alg %d\n", keyconf->alg);
-               break;
-       }
-}
-
-/*
- * start REPLY_TX command process
- */
-int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_sta *sta = info->control.sta;
-       struct iwl_station_priv *sta_priv = NULL;
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       struct iwl_device_cmd *out_cmd;
-       struct iwl_cmd_meta *out_meta;
-       struct iwl_tx_cmd *tx_cmd;
-       int swq_id, txq_id;
-       dma_addr_t phys_addr;
-       dma_addr_t txcmd_phys;
-       dma_addr_t scratch_phys;
-       u16 len, len_org, firstlen, secondlen;
-       u16 seq_number = 0;
-       __le16 fc;
-       u8 hdr_len;
-       u8 sta_id;
-       u8 wait_write_ptr = 0;
-       u8 tid = 0;
-       u8 *qc = NULL;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       if (iwl_is_rfkill(priv)) {
-               IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
-               goto drop_unlock;
-       }
-
-       fc = hdr->frame_control;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (ieee80211_is_auth(fc))
-               IWL_DEBUG_TX(priv, "Sending AUTH frame\n");
-       else if (ieee80211_is_assoc_req(fc))
-               IWL_DEBUG_TX(priv, "Sending ASSOC frame\n");
-       else if (ieee80211_is_reassoc_req(fc))
-               IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
-#endif
-
-       /* drop all non-injected data frame if we are not associated */
-       if (ieee80211_is_data(fc) &&
-           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
-           (!iwl_is_associated(priv) ||
-            ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id) ||
-            !priv->assoc_station_added)) {
-               IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
-               goto drop_unlock;
-       }
-
-       hdr_len = ieee80211_hdrlen(fc);
-
-       /* Find (or create) index into station table for destination station */
-       if (info->flags & IEEE80211_TX_CTL_INJECTED)
-               sta_id = priv->hw_params.bcast_sta_id;
-       else
-               sta_id = iwl_get_sta_id(priv, hdr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
-                              hdr->addr1);
-               goto drop_unlock;
-       }
-
-       IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
-
-       if (sta)
-               sta_priv = (void *)sta->drv_priv;
-
-       if (sta_priv && sta_id != priv->hw_params.bcast_sta_id &&
-           sta_priv->asleep) {
-               WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
-               /*
-                * This sends an asynchronous command to the device,
-                * but we can rely on it being processed before the
-                * next frame is processed -- and the next frame to
-                * this station is the one that will consume this
-                * counter.
-                * For now set the counter to just 1 since we do not
-                * support uAPSD yet.
-                */
-               iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
-       }
-
-       txq_id = skb_get_queue_mapping(skb);
-       if (ieee80211_is_data_qos(fc)) {
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               if (unlikely(tid >= MAX_TID_COUNT))
-                       goto drop_unlock;
-               seq_number = priv->stations[sta_id].tid[tid].seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl = hdr->seq_ctrl &
-                               cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(seq_number);
-               seq_number += 0x10;
-               /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
-                   priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
-                       txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
-               }
-       }
-
-       txq = &priv->txq[txq_id];
-       swq_id = txq->swq_id;
-       q = &txq->q;
-
-       if (unlikely(iwl_queue_space(q) < q->high_mark))
-               goto drop_unlock;
-
-       if (ieee80211_is_data_qos(fc))
-               priv->stations[sta_id].tid[tid].tfds_in_queue++;
-
-       /* Set up driver data for this TFD */
-       memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
-       txq->txb[q->write_ptr].skb[0] = skb;
-
-       /* Set up first empty entry in queue's array of Tx/cmd buffers */
-       out_cmd = txq->cmd[q->write_ptr];
-       out_meta = &txq->meta[q->write_ptr];
-       tx_cmd = &out_cmd->cmd.tx;
-       memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
-       memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd));
-
-       /*
-        * Set up the Tx-command (not MAC!) header.
-        * Store the chosen Tx queue and TFD index within the sequence field;
-        * after Tx, uCode's Tx response will return this value so driver can
-        * locate the frame within the tx queue and do post-tx processing.
-        */
-       out_cmd->hdr.cmd = REPLY_TX;
-       out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-                               INDEX_TO_SEQ(q->write_ptr)));
-
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
-
-
-       /* Total # bytes to be transmitted */
-       len = (u16)skb->len;
-       tx_cmd->len = cpu_to_le16(len);
-
-       if (info->control.hw_key)
-               iwl_tx_cmd_build_hwcrypto(priv, info, tx_cmd, skb, sta_id);
-
-       /* TODO need this for burst mode later on */
-       iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id);
-       iwl_dbg_log_tx_data_frame(priv, len, hdr);
-
-       /* set is_hcca to 0; it probably will never be implemented */
-       iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, 0);
-
-       iwl_update_stats(priv, true, fc, len);
-       /*
-        * Use the first empty entry in this queue's command buffer array
-        * to contain the Tx command and MAC header concatenated together
-        * (payload data will be in another buffer).
-        * Size of this varies, due to varying MAC header length.
-        * If end is not dword aligned, we'll have 2 extra bytes at the end
-        * of the MAC header (device reads on dword boundaries).
-        * We'll tell device about this padding later.
-        */
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-
-       len_org = len;
-       firstlen = len = (len + 3) & ~3;
-
-       if (len_org != len)
-               len_org = 1;
-       else
-               len_org = 0;
-
-       /* Tell NIC about any 2-byte padding after MAC header */
-       if (len_org)
-               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-       /* Physical address of this Tx command's header (not MAC header!),
-        * within command buffer array. */
-       txcmd_phys = pci_map_single(priv->pci_dev,
-                                   &out_cmd->hdr, len,
-                                   PCI_DMA_BIDIRECTIONAL);
-       pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       pci_unmap_len_set(out_meta, len, len);
-       /* Add buffer containing Tx command and MAC(!) header to TFD's
-        * first entry */
-       priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                  txcmd_phys, len, 1, 0);
-
-       if (!ieee80211_has_morefrags(hdr->frame_control)) {
-               txq->need_update = 1;
-               if (qc)
-                       priv->stations[sta_id].tid[tid].seq_number = seq_number;
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
-
-       /* Set up TFD's 2nd entry to point directly to remainder of skb,
-        * if any (802.11 null frames have no payload). */
-       secondlen = len = skb->len - hdr_len;
-       if (len) {
-               phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
-                                          len, PCI_DMA_TODEVICE);
-               priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
-                                                          phys_addr, len,
-                                                          0, 0);
-       }
-
-       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-                               offsetof(struct iwl_tx_cmd, scratch);
-
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-       /* take back ownership of DMA buffer to enable update */
-       pci_dma_sync_single_for_cpu(priv->pci_dev, txcmd_phys,
-                                   len, PCI_DMA_BIDIRECTIONAL);
-       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
-       IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
-                    le16_to_cpu(out_cmd->hdr.sequence));
-       IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
-       iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
-
-       /* Set up entry for this TFD in Tx byte-count array */
-       if (info->flags & IEEE80211_TX_CTL_AMPDU)
-               priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
-                                                    le16_to_cpu(tx_cmd->len));
-
-       pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
-                                      len, PCI_DMA_BIDIRECTIONAL);
-
-       trace_iwlwifi_dev_tx(priv,
-                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
-                            sizeof(struct iwl_tfd),
-                            &out_cmd->hdr, firstlen,
-                            skb->data + hdr_len, secondlen);
-
-       /* Tell device the write index *just past* this latest filled TFD */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(priv, txq);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /*
-        * At this point the frame is "transmitted" successfully
-        * and we will get a TX status notification eventually,
-        * regardless of the value of ret. "ret" only indicates
-        * whether or not we should update the write pointer.
-        */
-
-       /* avoid atomic ops if it isn't an associated client */
-       if (sta_priv && sta_priv->client)
-               atomic_inc(&sta_priv->pending_frames);
-
-       if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
-               if (wait_write_ptr) {
-                       spin_lock_irqsave(&priv->lock, flags);
-                       txq->need_update = 1;
-                       iwl_txq_update_write_ptr(priv, txq);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-               } else {
-                       iwl_stop_queue(priv, txq->swq_id);
-               }
-       }
-
-       return 0;
-
-drop_unlock:
-       spin_unlock_irqrestore(&priv->lock, flags);
-       return -1;
-}
-EXPORT_SYMBOL(iwl_tx_skb);
-
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 
 /**
@@ -1192,61 +548,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        return idx;
 }
 
-static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_sta *sta;
-       struct iwl_station_priv *sta_priv;
-
-       sta = ieee80211_find_sta(priv->vif, hdr->addr1);
-       if (sta) {
-               sta_priv = (void *)sta->drv_priv;
-               /* avoid atomic ops if this isn't a client */
-               if (sta_priv->client &&
-                   atomic_dec_return(&sta_priv->pending_frames) == 0)
-                       ieee80211_sta_block_awake(priv->hw, sta, false);
-       }
-
-       ieee80211_tx_status_irqsafe(priv->hw, skb);
-}
-
-int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
-{
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       struct iwl_tx_info *tx_info;
-       int nfreed = 0;
-       struct ieee80211_hdr *hdr;
-
-       if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
-                         "is out of range [0-%d] %d %d.\n", txq_id,
-                         index, q->n_bd, q->write_ptr, q->read_ptr);
-               return 0;
-       }
-
-       for (index = iwl_queue_inc_wrap(index, q->n_bd);
-            q->read_ptr != index;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-               tx_info = &txq->txb[txq->q.read_ptr];
-               iwl_tx_status(priv, tx_info->skb[0]);
-
-               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
-               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
-                       nfreed++;
-               tx_info->skb[0] = NULL;
-
-               if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
-                       priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
-
-               priv->cfg->ops->lib->txq_free_tfd(priv, txq);
-       }
-       return nfreed;
-}
-EXPORT_SYMBOL(iwl_tx_queue_reclaim);
-
-
 /**
  * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
  *
@@ -1340,7 +641,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        if (!(meta->flags & CMD_ASYNC)) {
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-               IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s \n",
+               IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                               get_cmd_string(cmd->hdr.cmd));
                wake_up_interruptible(&priv->wait_command_queue);
        }
@@ -1348,358 +649,37 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 }
 EXPORT_SYMBOL(iwl_tx_cmd_complete);
 
-/*
- * Find first available (lowest unused) Tx Queue, mark it "active".
- * Called only when finding queue for aggregation.
- * Should never return anything < 7, because they should already
- * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6).
- */
-static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
-{
-       int txq_id;
-
-       for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
-               if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
-                       return txq_id;
-       return -1;
-}
-
-int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
-{
-       int sta_id;
-       int tx_fifo;
-       int txq_id;
-       int ret;
-       unsigned long flags;
-       struct iwl_tid_data *tid_data;
-
-       if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
-               tx_fifo = default_tid_to_tx_fifo[tid];
-       else
-               return -EINVAL;
-
-       IWL_WARN(priv, "%s on ra = %pM tid = %d\n",
-                       __func__, ra, tid);
-
-       sta_id = iwl_find_station(priv, ra);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Start AGG on invalid station\n");
-               return -ENXIO;
-       }
-       if (unlikely(tid >= MAX_TID_COUNT))
-               return -EINVAL;
-
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
-               IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
-               return -ENXIO;
-       }
-
-       txq_id = iwl_txq_ctx_activate_free(priv);
-       if (txq_id == -1) {
-               IWL_ERR(priv, "No free aggregation queue available\n");
-               return -ENXIO;
-       }
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       tid_data = &priv->stations[sta_id].tid[tid];
-       *ssn = SEQ_TO_SN(tid_data->seq_number);
-       tid_data->agg.txq_id = txq_id;
-       priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-       ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
-                                                 sta_id, tid, *ssn);
-       if (ret)
-               return ret;
-
-       if (tid_data->tfds_in_queue == 0) {
-               IWL_DEBUG_HT(priv, "HW queue is empty\n");
-               tid_data->agg.state = IWL_AGG_ON;
-               ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid);
-       } else {
-               IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n",
-                            tid_data->tfds_in_queue);
-               tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
-       }
-       return ret;
-}
-EXPORT_SYMBOL(iwl_tx_agg_start);
-
-int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
-{
-       int tx_fifo_id, txq_id, sta_id, ssn = -1;
-       struct iwl_tid_data *tid_data;
-       int write_ptr, read_ptr;
-       unsigned long flags;
-
-       if (!ra) {
-               IWL_ERR(priv, "ra = NULL\n");
-               return -EINVAL;
-       }
-
-       if (unlikely(tid >= MAX_TID_COUNT))
-               return -EINVAL;
-
-       if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
-               tx_fifo_id = default_tid_to_tx_fifo[tid];
-       else
-               return -EINVAL;
-
-       sta_id = iwl_find_station(priv, ra);
-
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
-               return -ENXIO;
-       }
-
-       if (priv->stations[sta_id].tid[tid].agg.state ==
-                               IWL_EMPTYING_HW_QUEUE_ADDBA) {
-               IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
-               ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
-               priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-               return 0;
-       }
-
-       if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
-               IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
-
-       tid_data = &priv->stations[sta_id].tid[tid];
-       ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
-       txq_id = tid_data->agg.txq_id;
-       write_ptr = priv->txq[txq_id].q.write_ptr;
-       read_ptr = priv->txq[txq_id].q.read_ptr;
-
-       /* The queue is not empty */
-       if (write_ptr != read_ptr) {
-               IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
-               priv->stations[sta_id].tid[tid].agg.state =
-                               IWL_EMPTYING_HW_QUEUE_DELBA;
-               return 0;
-       }
-
-       IWL_DEBUG_HT(priv, "HW queue is empty\n");
-       priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       /*
-        * the only reason this call can fail is queue number out of range,
-        * which can happen if uCode is reloaded and all the station
-        * information are lost. if it is outside the range, there is no need
-        * to deactivate the uCode queue, just return "success" to allow
-        *  mac80211 to clean up it own data.
-        */
-       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
-                                                  tx_fifo_id);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid);
-
-       return 0;
-}
-EXPORT_SYMBOL(iwl_tx_agg_stop);
-
-int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
-{
-       struct iwl_queue *q = &priv->txq[txq_id].q;
-       u8 *addr = priv->stations[sta_id].sta.sta.addr;
-       struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
-
-       switch (priv->stations[sta_id].tid[tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* We are reclaiming the last packet of the */
-               /* aggregated HW queue */
-               if ((txq_id  == tid_data->agg.txq_id) &&
-                   (q->read_ptr == q->write_ptr)) {
-                       u16 ssn = SEQ_TO_SN(tid_data->seq_number);
-                       int tx_fifo = default_tid_to_tx_fifo[tid];
-                       IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
-                       priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
-                                                            ssn, tx_fifo);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid);
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* We are reclaiming the last packet of the queue */
-               if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n");
-                       tid_data->agg.state = IWL_AGG_ON;
-                       ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid);
-               }
-               break;
-       }
-       return 0;
-}
-EXPORT_SYMBOL(iwl_txq_check_empty);
-
-/**
- * iwl_tx_status_reply_compressed_ba - Update tx status from block-ack
- *
- * Go through block-ack's bitmap of ACK'd frames, update driver's record of
- * ACK vs. not.  This gets sent to mac80211, then to rate scaling algo.
- */
-static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
-                                struct iwl_ht_agg *agg,
-                                struct iwl_compressed_ba_resp *ba_resp)
-
-{
-       int i, sh, ack;
-       u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
-       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-       u64 bitmap;
-       int successes = 0;
-       struct ieee80211_tx_info *info;
-
-       if (unlikely(!agg->wait_for_ba))  {
-               IWL_ERR(priv, "Received BA when not expected\n");
-               return -EINVAL;
-       }
-
-       /* Mark that the expected block-ack response arrived */
-       agg->wait_for_ba = 0;
-       IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
-
-       /* Calculate shift to align block-ack bits with our Tx window bits */
-       sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
-       if (sh < 0) /* tbw something is wrong with indices */
-               sh += 0x100;
-
-       /* don't use 64-bit values for now */
-       bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
-
-       if (agg->frame_count > (64 - sh)) {
-               IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
-               return -1;
-       }
-
-       /* check for success or failure according to the
-        * transmitted bitmap and block-ack bitmap */
-       bitmap &= agg->bitmap;
-
-       /* For each frame attempted in aggregation,
-        * update driver's record of tx frame's status. */
-       for (i = 0; i < agg->frame_count ; i++) {
-               ack = bitmap & (1ULL << i);
-               successes += !!ack;
-               IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
-                       ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
-                       agg->start_idx + i);
-       }
-
-       info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
-       memset(&info->status, 0, sizeof(info->status));
-       info->flags |= IEEE80211_TX_STAT_ACK;
-       info->flags |= IEEE80211_TX_STAT_AMPDU;
-       info->status.ampdu_ack_map = successes;
-       info->status.ampdu_ack_len = agg->frame_count;
-       iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
-
-       IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap);
-
-       return 0;
-}
-
-/**
- * iwl_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
- *
- * Handles block-acknowledge notification from device, which reports success
- * of frames sent via aggregation.
- */
-void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                          struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
-       struct iwl_tx_queue *txq = NULL;
-       struct iwl_ht_agg *agg;
-       int index;
-       int sta_id;
-       int tid;
-
-       /* "flow" corresponds to Tx queue */
-       u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
-
-       /* "ssn" is start of block-ack Tx window, corresponds to index
-        * (in Tx queue's circular buffer) of first TFD/frame in window */
-       u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
-
-       if (scd_flow >= priv->hw_params.max_txq_num) {
-               IWL_ERR(priv,
-                       "BUG_ON scd_flow is bigger than number of queues\n");
-               return;
-       }
-
-       txq = &priv->txq[scd_flow];
-       sta_id = ba_resp->sta_id;
-       tid = ba_resp->tid;
-       agg = &priv->stations[sta_id].tid[tid].agg;
-
-       /* Find index just before block-ack window */
-       index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
-
-       /* TODO: Need to get this copy more safely - now good for debug */
-
-       IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
-                          "sta_id = %d\n",
-                          agg->wait_for_ba,
-                          (u8 *) &ba_resp->sta_addr_lo32,
-                          ba_resp->sta_id);
-       IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
-                          "%d, scd_ssn = %d\n",
-                          ba_resp->tid,
-                          ba_resp->seq_ctl,
-                          (unsigned long long)le64_to_cpu(ba_resp->bitmap),
-                          ba_resp->scd_flow,
-                          ba_resp->scd_ssn);
-       IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx \n",
-                          agg->start_idx,
-                          (unsigned long long)agg->bitmap);
-
-       /* Update driver's record of ACK vs. not for each frame in window */
-       iwl_tx_status_reply_compressed_ba(priv, agg, ba_resp);
-
-       /* Release all TFDs before the SSN, i.e. all TFDs in front of
-        * block-ack window (we assume that they've been successfully
-        * transmitted ... if not, it's too late anyway). */
-       if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
-               /* calculate mac80211 ampdu sw queue to wake */
-               int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
-               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
-
-               if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
-                   priv->mac80211_registered &&
-                   (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA))
-                       iwl_wake_queue(priv, txq->swq_id);
-
-               iwl_txq_check_empty(priv, sta_id, tid, scd_flow);
-       }
-}
-EXPORT_SYMBOL(iwl_rx_reply_compressed_ba);
-
 #ifdef CONFIG_IWLWIFI_DEBUG
-#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x
+#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x
 
 const char *iwl_get_tx_fail_reason(u32 status)
 {
        switch (status & TX_STATUS_MSK) {
        case TX_STATUS_SUCCESS:
                return "SUCCESS";
-               TX_STATUS_ENTRY(SHORT_LIMIT);
-               TX_STATUS_ENTRY(LONG_LIMIT);
-               TX_STATUS_ENTRY(FIFO_UNDERRUN);
-               TX_STATUS_ENTRY(MGMNT_ABORT);
-               TX_STATUS_ENTRY(NEXT_FRAG);
-               TX_STATUS_ENTRY(LIFE_EXPIRE);
-               TX_STATUS_ENTRY(DEST_PS);
-               TX_STATUS_ENTRY(ABORTED);
-               TX_STATUS_ENTRY(BT_RETRY);
-               TX_STATUS_ENTRY(STA_INVALID);
-               TX_STATUS_ENTRY(FRAG_DROPPED);
-               TX_STATUS_ENTRY(TID_DISABLE);
-               TX_STATUS_ENTRY(FRAME_FLUSHED);
-               TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
-               TX_STATUS_ENTRY(TX_LOCKED);
-               TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+               TX_STATUS_POSTPONE(DELAY);
+               TX_STATUS_POSTPONE(FEW_BYTES);
+               TX_STATUS_POSTPONE(BT_PRIO);
+               TX_STATUS_POSTPONE(QUIET_PERIOD);
+               TX_STATUS_POSTPONE(CALC_TTAK);
+               TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY);
+               TX_STATUS_FAIL(SHORT_LIMIT);
+               TX_STATUS_FAIL(LONG_LIMIT);
+               TX_STATUS_FAIL(FIFO_UNDERRUN);
+               TX_STATUS_FAIL(DRAIN_FLOW);
+               TX_STATUS_FAIL(RFKILL_FLUSH);
+               TX_STATUS_FAIL(LIFE_EXPIRE);
+               TX_STATUS_FAIL(DEST_PS);
+               TX_STATUS_FAIL(HOST_ABORTED);
+               TX_STATUS_FAIL(BT_RETRY);
+               TX_STATUS_FAIL(STA_INVALID);
+               TX_STATUS_FAIL(FRAG_DROPPED);
+               TX_STATUS_FAIL(TID_DISABLE);
+               TX_STATUS_FAIL(FIFO_FLUSHED);
+               TX_STATUS_FAIL(INSUFFICIENT_CF_POLL);
+               TX_STATUS_FAIL(FW_DROP);
+               TX_STATUS_FAIL(STA_COLOR_MISMATCH_DROP);
        }
 
        return "UNKNOWN";
index b74a56c48d2698eeda2007afa0db58b9383526fd..3e5bffb6034f47bad2d69ed89b7b38ae0f25be30 100644 (file)
@@ -352,11 +352,11 @@ static int iwl3945_send_beacon_cmd(struct iwl_priv *priv)
 
 static void iwl3945_unset_hw_params(struct iwl_priv *priv)
 {
-       if (priv->shared_virt)
+       if (priv->_3945.shared_virt)
                dma_free_coherent(&priv->pci_dev->dev,
                                  sizeof(struct iwl3945_shared),
-                                 priv->shared_virt,
-                                 priv->shared_phys);
+                                 priv->_3945.shared_virt,
+                                 priv->_3945.shared_phys);
 }
 
 static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
@@ -505,24 +505,15 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
 #endif
 
-       /* drop all non-injected data frame if we are not associated */
-       if (ieee80211_is_data(fc) &&
-           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
-           (!iwl_is_associated(priv) ||
-            ((priv->iw_mode == NL80211_IFTYPE_STATION) && !priv->assoc_id))) {
-               IWL_DEBUG_DROP(priv, "Dropping - !iwl_is_associated\n");
-               goto drop_unlock;
-       }
-
        spin_unlock_irqrestore(&priv->lock, flags);
 
        hdr_len = ieee80211_hdrlen(fc);
 
-       /* Find (or create) index into station table for destination station */
-       if (info->flags & IEEE80211_TX_CTL_INJECTED)
+       /* Find index into station table for destination station */
+       if (!info->control.sta)
                sta_id = priv->hw_params.bcast_sta_id;
        else
-               sta_id = iwl_get_sta_id(priv, hdr);
+               sta_id = iwl_sta_id(info->control.sta);
        if (sta_id == IWL_INVALID_STATION) {
                IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
                               hdr->addr1);
@@ -607,9 +598,9 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                txq->need_update = 0;
        }
 
-       IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
+       IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n",
                     le16_to_cpu(out_cmd->hdr.sequence));
-       IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
+       IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
        iwl_print_hex_dump(priv, IWL_DL_TX, tx_cmd, sizeof(*tx_cmd));
        iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr,
                           ieee80211_hdrlen(fc));
@@ -754,7 +745,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
        if (iwl_is_associated(priv))
                add_time =
                    iwl3945_usecs_to_beacons(
-                       le64_to_cpu(params->start_time) - priv->last_tsf,
+                       le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
                        le16_to_cpu(priv->rxon_timing.beacon_interval));
 
        memset(&spectrum, 0, sizeof(spectrum));
@@ -768,7 +759,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
 
        if (iwl_is_associated(priv))
                spectrum.start_time =
-                   iwl3945_add_beacon_time(priv->last_beacon_time,
+                   iwl3945_add_beacon_time(priv->_3945.last_beacon_time,
                                add_time,
                                le16_to_cpu(priv->rxon_timing.beacon_interval));
        else
@@ -857,7 +848,6 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv,
 #endif
 
        IWL_DEBUG_RX(priv, "Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
-       return;
 }
 
 static void iwl3945_bg_beacon_update(struct work_struct *work)
@@ -966,7 +956,7 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
         * statistics request from the host as well as for the periodic
         * statistics notifications (after received beacons) from the uCode.
         */
-       priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
+       priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_reply_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
        iwl_setup_rx_scan_handlers(priv);
@@ -1613,9 +1603,6 @@ static int iwl3945_print_last_event_logs(struct iwl_priv *priv, u32 capacity,
        return pos;
 }
 
-/* For sanity check only.  Actual size is determined by uCode, typ. 512 */
-#define IWL3945_MAX_EVENT_LOG_SIZE (512)
-
 #define DEFAULT_IWL3945_DUMP_EVENT_LOG_ENTRIES (20)
 
 int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
@@ -1642,16 +1629,16 @@ int iwl3945_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
        num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
        next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
-       if (capacity > IWL3945_MAX_EVENT_LOG_SIZE) {
+       if (capacity > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
-                       capacity, IWL3945_MAX_EVENT_LOG_SIZE);
-               capacity = IWL3945_MAX_EVENT_LOG_SIZE;
+                       capacity, priv->cfg->max_event_log_size);
+               capacity = priv->cfg->max_event_log_size;
        }
 
-       if (next_entry > IWL3945_MAX_EVENT_LOG_SIZE) {
+       if (next_entry > priv->cfg->max_event_log_size) {
                IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
-                       next_entry, IWL3945_MAX_EVENT_LOG_SIZE);
-               next_entry = IWL3945_MAX_EVENT_LOG_SIZE;
+                       next_entry, priv->cfg->max_event_log_size);
+               next_entry = priv->cfg->max_event_log_size;
        }
 
        size = num_wraps ? capacity : next_entry;
@@ -1860,7 +1847,8 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
 static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                                         enum ieee80211_band band,
                                     u8 is_active, u8 n_probes,
-                                    struct iwl3945_scan_channel *scan_ch)
+                                    struct iwl3945_scan_channel *scan_ch,
+                                    struct ieee80211_vif *vif)
 {
        struct ieee80211_channel *chan;
        const struct ieee80211_supported_band *sband;
@@ -1874,7 +1862,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                return 0;
 
        active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
 
        if (passive_dwell <= active_dwell)
                passive_dwell = active_dwell + 1;
@@ -1947,7 +1935,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                added++;
        }
 
-       IWL_DEBUG_SCAN(priv, "total channels to scan %d \n", added);
+       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
        return added;
 }
 
@@ -2122,6 +2110,28 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
        iwl_write32(priv, CSR_RESET, 0);
 }
 
+#define IWL3945_UCODE_GET(item)                                                \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode)\
+{                                                                      \
+       return le32_to_cpu(ucode->u.v1.item);                           \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+       return 24;
+}
+
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode)
+{
+       return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
 /**
  * iwl3945_read_ucode - Read uCode images from disk file.
  *
@@ -2170,7 +2180,7 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
                goto error;
 
        /* Make sure that we got at least our header! */
-       if (ucode_raw->size <  priv->cfg->ops->ucode->get_header_size(1)) {
+       if (ucode_raw->size <  iwl3945_ucode_get_header_size(1)) {
                IWL_ERR(priv, "File size way too small!\n");
                ret = -EINVAL;
                goto err_release;
@@ -2181,13 +2191,12 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
 
        priv->ucode_ver = le32_to_cpu(ucode->ver);
        api_ver = IWL_UCODE_API(priv->ucode_ver);
-       inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
-       data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
-       init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
-       init_data_size =
-               priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
-       boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
-       src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
+       inst_size = iwl3945_ucode_get_inst_size(ucode);
+       data_size = iwl3945_ucode_get_data_size(ucode);
+       init_size = iwl3945_ucode_get_init_size(ucode);
+       init_data_size = iwl3945_ucode_get_init_data_size(ucode);
+       boot_size = iwl3945_ucode_get_boot_size(ucode);
+       src = iwl3945_ucode_get_data(ucode);
 
        /* api_ver should match the api version forming part of the
         * firmware filename ... but we don't check for that and only rely
@@ -2236,7 +2245,7 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
 
 
        /* Verify size of file vs. image size info in file's header */
-       if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
+       if (ucode_raw->size != iwl3945_ucode_get_header_size(api_ver) +
                inst_size + data_size + init_size +
                init_data_size + boot_size) {
 
@@ -2490,8 +2499,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                goto restart;
        }
 
-       iwl_clear_stations_table(priv);
-
        rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
        IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
 
@@ -2513,13 +2520,19 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        /* After the ALIVE response, we can send commands to 3945 uCode */
        set_bit(STATUS_ALIVE, &priv->status);
 
+       if (priv->cfg->ops->lib->recover_from_tx_stall) {
+               /* Enable timer to monitor the driver queues */
+               mod_timer(&priv->monitor_recover,
+                       jiffies +
+                       msecs_to_jiffies(priv->cfg->monitor_recover_period));
+       }
+
        if (iwl_is_rfkill(priv))
                return;
 
        ieee80211_wake_queues(priv->hw);
 
-       priv->active_rate = priv->rates_mask;
-       priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+       priv->active_rate = IWL_RATES_MASK;
 
        iwl_power_update_mode(priv, true);
 
@@ -2531,11 +2544,11 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
        } else {
                /* Initialize our rx_config data */
-               iwl_connection_init_rx_config(priv, priv->iw_mode);
+               iwl_connection_init_rx_config(priv, NULL);
        }
 
        /* Configure Bluetooth device coexistence support */
-       iwl_send_bt_config(priv);
+       priv->cfg->ops->hcmd->send_bt_config(priv);
 
        /* Configure the adapter for unassociated operation */
        iwlcore_commit_rxon(priv);
@@ -2548,17 +2561,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        set_bit(STATUS_READY, &priv->status);
        wake_up_interruptible(&priv->wait_command_queue);
 
-       /* reassociate for ADHOC mode */
-       if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
-               struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
-                                                               priv->vif);
-               if (beacon)
-                       iwl_mac_beacon_update(priv->hw, beacon);
-       }
-
-       if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status))
-               iwl_set_mode(priv, priv->iw_mode);
-
        return;
 
  restart:
@@ -2580,7 +2582,10 @@ static void __iwl3945_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
-       iwl_clear_stations_table(priv);
+       /* Station information will now be cleared in device */
+       iwl_clear_ucode_stations(priv);
+       iwl_dealloc_bcast_station(priv);
+       iwl_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
        wake_up_interruptible_all(&priv->wait_command_queue);
@@ -2661,6 +2666,10 @@ static int __iwl3945_up(struct iwl_priv *priv)
 {
        int rc, i;
 
+       rc = iwl_alloc_bcast_station(priv, false);
+       if (rc)
+               return rc;
+
        if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
                IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
                return -EIO;
@@ -2714,12 +2723,10 @@ static int __iwl3945_up(struct iwl_priv *priv)
 
        for (i = 0; i < MAX_HW_RESTARTS; i++) {
 
-               iwl_clear_stations_table(priv);
-
                /* load bootstrap state machine,
                 * load bootstrap program into processor's memory,
                 * prepare to load the "initialize" uCode */
-               priv->cfg->ops->lib->load_ucode(priv);
+               rc = priv->cfg->ops->lib->load_ucode(priv);
 
                if (rc) {
                        IWL_ERR(priv,
@@ -2787,7 +2794,7 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
 static void iwl3945_rfkill_poll(struct work_struct *data)
 {
        struct iwl_priv *priv =
-           container_of(data, struct iwl_priv, rfkill_poll.work);
+           container_of(data, struct iwl_priv, _3945.rfkill_poll.work);
        bool old_rfkill = test_bit(STATUS_RF_KILL_HW, &priv->status);
        bool new_rfkill = !(iwl_read32(priv, CSR_GP_CNTRL)
                        & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
@@ -2806,22 +2813,18 @@ static void iwl3945_rfkill_poll(struct work_struct *data)
 
        /* Keep this running, even if radio now enabled.  This will be
         * cancelled in mac_start() if system decides to start again */
-       queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
+       queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll,
                           round_jiffies_relative(2 * HZ));
 
 }
 
-#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
-static void iwl3945_bg_request_scan(struct work_struct *data)
+void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
-       struct iwl_priv *priv =
-           container_of(data, struct iwl_priv, request_scan);
        struct iwl_host_cmd cmd = {
                .id = REPLY_SCAN_CMD,
                .len = sizeof(struct iwl3945_scan_cmd),
                .flags = CMD_SIZE_HUGE,
        };
-       int rc = 0;
        struct iwl3945_scan_cmd *scan;
        struct ieee80211_conf *conf = NULL;
        u8 n_probes = 0;
@@ -2830,8 +2833,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 
        conf = ieee80211_get_hw_conf(priv->hw);
 
-       mutex_lock(&priv->mutex);
-
        cancel_delayed_work(&priv->scan_check);
 
        if (!iwl_is_ready(priv)) {
@@ -2849,7 +2850,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        if (test_bit(STATUS_SCAN_HW, &priv->status)) {
                IWL_DEBUG_INFO(priv, "Multiple concurrent scan requests  "
                                "Ignoring second request.\n");
-               rc = -EIO;
                goto done;
        }
 
@@ -2875,20 +2875,15 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                goto done;
        }
 
-       if (!priv->scan_bands) {
-               IWL_DEBUG_HC(priv, "Aborting scan due to no requested bands\n");
-               goto done;
-       }
-
-       if (!priv->scan) {
-               priv->scan = kmalloc(sizeof(struct iwl3945_scan_cmd) +
-                                    IWL_MAX_SCAN_SIZE, GFP_KERNEL);
-               if (!priv->scan) {
-                       rc = -ENOMEM;
+       if (!priv->scan_cmd) {
+               priv->scan_cmd = kmalloc(sizeof(struct iwl3945_scan_cmd) +
+                                        IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+               if (!priv->scan_cmd) {
+                       IWL_DEBUG_SCAN(priv, "Fail to allocate scan memory\n");
                        goto done;
                }
        }
-       scan = priv->scan;
+       scan = priv->scan_cmd;
        memset(scan, 0, sizeof(struct iwl3945_scan_cmd) + IWL_MAX_SCAN_SIZE);
 
        scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
@@ -2904,7 +2899,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
 
                spin_lock_irqsave(&priv->lock, flags);
-               interval = priv->beacon_int;
+               interval = vif ? vif->bss_conf.beacon_int : 0;
                spin_unlock_irqrestore(&priv->lock, flags);
 
                scan->suspend_time = 0;
@@ -2927,7 +2922,9 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                               scan_suspend_time, interval);
        }
 
-       if (priv->scan_request->n_ssids) {
+       if (priv->is_internal_short_scan) {
+               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+       } else if (priv->scan_request->n_ssids) {
                int i, p = 0;
                IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
                for (i = 0; i < priv->scan_request->n_ssids; i++) {
@@ -2955,12 +2952,14 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 
        /* flags + rate selection */
 
-       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
+       switch (priv->scan_band) {
+       case IEEE80211_BAND_2GHZ:
                scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
                scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
                scan->good_CRC_th = 0;
                band = IEEE80211_BAND_2GHZ;
-       } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
+               break;
+       case IEEE80211_BAND_5GHZ:
                scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
                /*
                 * If active scaning is requested but a certain channel
@@ -2970,27 +2969,32 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
                scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
                                                IWL_GOOD_CRC_TH_DISABLED;
                band = IEEE80211_BAND_5GHZ;
-       } else {
-               IWL_WARN(priv, "Invalid scan band count\n");
+               break;
+       default:
+               IWL_WARN(priv, "Invalid scan band\n");
                goto done;
        }
 
-       scan->tx_cmd.len = cpu_to_le16(
+       if (!priv->is_internal_short_scan) {
+               scan->tx_cmd.len = cpu_to_le16(
                        iwl_fill_probe_req(priv,
                                (struct ieee80211_mgmt *)scan->data,
                                priv->scan_request->ie,
                                priv->scan_request->ie_len,
                                IWL_MAX_SCAN_SIZE - sizeof(*scan)));
-
+       } else {
+               scan->tx_cmd.len = cpu_to_le16(
+                       iwl_fill_probe_req(priv,
+                               (struct ieee80211_mgmt *)scan->data,
+                               NULL, 0,
+                               IWL_MAX_SCAN_SIZE - sizeof(*scan)));
+       }
        /* select Rx antennas */
        scan->flags |= iwl3945_get_antenna_flags(priv);
 
-       if (iwl_is_monitor_mode(priv))
-               scan->filter_flags = RXON_FILTER_PROMISC_MSK;
-
        scan->channel_count =
                iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
-                       (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+                       (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif);
 
        if (scan->channel_count == 0) {
                IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
@@ -3003,14 +3007,12 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
        scan->len = cpu_to_le16(cmd.len);
 
        set_bit(STATUS_SCAN_HW, &priv->status);
-       rc = iwl_send_cmd_sync(priv, &cmd);
-       if (rc)
+       if (iwl_send_cmd_sync(priv, &cmd))
                goto done;
 
        queue_delayed_work(priv->workqueue, &priv->scan_check,
                           IWL_SCAN_CHECK_WATCHDOG);
 
-       mutex_unlock(&priv->mutex);
        return;
 
  done:
@@ -3024,7 +3026,6 @@ static void iwl3945_bg_request_scan(struct work_struct *data)
 
        /* inform mac80211 scan aborted */
        queue_work(priv->workqueue, &priv->scan_completed);
-       mutex_unlock(&priv->mutex);
 }
 
 static void iwl3945_bg_restart(struct work_struct *data)
@@ -3066,28 +3067,25 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
        mutex_unlock(&priv->mutex);
 }
 
-#define IWL_DELAY_NEXT_SCAN (HZ*2)
-
-void iwl3945_post_associate(struct iwl_priv *priv)
+void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
        struct ieee80211_conf *conf = NULL;
 
-       if (priv->iw_mode == NL80211_IFTYPE_AP) {
+       if (!vif || !priv->is_open)
+               return;
+
+       if (vif->type == NL80211_IFTYPE_AP) {
                IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__);
                return;
        }
 
-
        IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n",
-                       priv->assoc_id, priv->active_rxon.bssid_addr);
+                       vif->bss_conf.aid, priv->active_rxon.bssid_addr);
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (!priv->vif || !priv->is_open)
-               return;
-
        iwl_scan_cancel_timeout(priv, 200);
 
        conf = ieee80211_get_hw_conf(priv->hw);
@@ -3096,7 +3094,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
        iwlcore_commit_rxon(priv);
 
        memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-       iwl_setup_rxon_timing(priv);
+       iwl_setup_rxon_timing(priv, vif);
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                              sizeof(priv->rxon_timing), &priv->rxon_timing);
        if (rc)
@@ -3105,57 +3103,40 @@ void iwl3945_post_associate(struct iwl_priv *priv)
 
        priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
 
-       priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+       priv->staging_rxon.assoc_id = cpu_to_le16(vif->bss_conf.aid);
 
        IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
-                       priv->assoc_id, priv->beacon_int);
+                       vif->bss_conf.aid, vif->bss_conf.beacon_int);
 
-       if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+       if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
                priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
        else
                priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
        if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
 
-               if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+               if (vif->type == NL80211_IFTYPE_ADHOC)
                        priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
        }
 
        iwlcore_commit_rxon(priv);
 
-       switch (priv->iw_mode) {
+       switch (vif->type) {
        case NL80211_IFTYPE_STATION:
                iwl3945_rate_scale_init(priv->hw, IWL_AP_ID);
                break;
-
        case NL80211_IFTYPE_ADHOC:
-
-               priv->assoc_id = 1;
-               iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL);
-               iwl3945_sync_sta(priv, IWL_STA_ID,
-                                (priv->band == IEEE80211_BAND_5GHZ) ?
-                                IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
-                                CMD_ASYNC);
-               iwl3945_rate_scale_init(priv->hw, IWL_STA_ID);
                iwl3945_send_beacon_cmd(priv);
-
                break;
-
        default:
-                IWL_ERR(priv, "%s Should not be called in %d mode\n",
-                          __func__, priv->iw_mode);
+               IWL_ERR(priv, "%s Should not be called in %d mode\n",
+                       __func__, vif->type);
                break;
        }
-
-       iwl_activate_qos(priv, 0);
-
-       /* we have just associated, don't start scan too early */
-       priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
 }
 
 /*****************************************************************************
@@ -3214,7 +3195,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
 
        /* ucode is running and will send rfkill notifications,
         * no need to poll the killswitch state anymore */
-       cancel_delayed_work(&priv->rfkill_poll);
+       cancel_delayed_work(&priv->_3945.rfkill_poll);
 
        iwl_led_start(priv);
 
@@ -3255,7 +3236,7 @@ static void iwl3945_mac_stop(struct ieee80211_hw *hw)
        flush_workqueue(priv->workqueue);
 
        /* start polling the killswitch state again */
-       queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
+       queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll,
                           round_jiffies_relative(2 * HZ));
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3277,7 +3258,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return NETDEV_TX_OK;
 }
 
-void iwl3945_config_ap(struct iwl_priv *priv)
+void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        int rc = 0;
 
@@ -3293,7 +3274,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
 
                /* RXON Timing */
                memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
-               iwl_setup_rxon_timing(priv);
+               iwl_setup_rxon_timing(priv, vif);
                rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
                                      sizeof(priv->rxon_timing),
                                      &priv->rxon_timing);
@@ -3301,9 +3282,10 @@ void iwl3945_config_ap(struct iwl_priv *priv)
                        IWL_WARN(priv, "REPLY_RXON_TIMING failed - "
                                        "Attempting to continue.\n");
 
-               /* FIXME: what should be the assoc_id for AP? */
-               priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
-               if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+               priv->staging_rxon.assoc_id = 0;
+
+               if (vif->bss_conf.assoc_capability &
+                                       WLAN_CAPABILITY_SHORT_PREAMBLE)
                        priv->staging_rxon.flags |=
                                RXON_FLG_SHORT_PREAMBLE_MSK;
                else
@@ -3311,22 +3293,21 @@ void iwl3945_config_ap(struct iwl_priv *priv)
                                ~RXON_FLG_SHORT_PREAMBLE_MSK;
 
                if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
-                       if (priv->assoc_capability &
-                               WLAN_CAPABILITY_SHORT_SLOT_TIME)
+                       if (vif->bss_conf.assoc_capability &
+                                       WLAN_CAPABILITY_SHORT_SLOT_TIME)
                                priv->staging_rxon.flags |=
                                        RXON_FLG_SHORT_SLOT_MSK;
                        else
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
 
-                       if (priv->iw_mode == NL80211_IFTYPE_ADHOC)
+                       if (vif->type == NL80211_IFTYPE_ADHOC)
                                priv->staging_rxon.flags &=
                                        ~RXON_FLG_SHORT_SLOT_MSK;
                }
                /* restore RXON assoc */
                priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
                iwlcore_commit_rxon(priv);
-               iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL);
        }
        iwl3945_send_beacon_cmd(priv);
 
@@ -3341,7 +3322,6 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                               struct ieee80211_key_conf *key)
 {
        struct iwl_priv *priv = hw->priv;
-       const u8 *addr;
        int ret = 0;
        u8 sta_id = IWL_INVALID_STATION;
        u8 static_key;
@@ -3353,21 +3333,24 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                return -EOPNOTSUPP;
        }
 
-       addr = sta ? sta->addr : iwl_bcast_addr;
        static_key = !iwl_is_associated(priv);
 
        if (!static_key) {
-               sta_id = iwl_find_station(priv, addr);
-               if (sta_id == IWL_INVALID_STATION) {
-                       IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                           addr);
-                       return -EINVAL;
+               if (!sta) {
+                       sta_id = priv->hw_params.bcast_sta_id;
+               } else {
+                       sta_id = iwl_sta_id(sta);
+                       if (sta_id == IWL_INVALID_STATION) {
+                               IWL_DEBUG_MAC80211(priv,
+                                                  "leave - %pM not in station map.\n",
+                                                  sta->addr);
+                               return -EINVAL;
+                       }
                }
        }
 
        mutex_lock(&priv->mutex);
        iwl_scan_cancel_timeout(priv, 100);
-       mutex_unlock(&priv->mutex);
 
        switch (cmd) {
        case SET_KEY:
@@ -3388,11 +3371,45 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                ret = -EINVAL;
        }
 
+       mutex_unlock(&priv->mutex);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
        return ret;
 }
 
+static int iwl3945_mac_sta_add(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl3945_sta_priv *sta_priv = (void *)sta->drv_priv;
+       int ret;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+       u8 sta_id;
+
+       sta_priv->common.sta_id = IWL_INVALID_STATION;
+
+       IWL_DEBUG_INFO(priv, "received request to add station %pM\n",
+                       sta->addr);
+
+       ret = iwl_add_station_common(priv, sta->addr, is_ap, &sta->ht_cap,
+                                    &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               return ret;
+       }
+
+       sta_priv->common.sta_id = sta_id;
+
+       /* Initialize rate scaling */
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
+                      sta->addr);
+       iwl3945_rs_rate_init(priv, sta, sta_id);
+
+       return 0;
+}
 /*****************************************************************************
  *
  * sysfs attributes
@@ -3592,7 +3609,7 @@ static ssize_t store_measurement(struct device *d,
        struct iwl_priv *priv = dev_get_drvdata(d);
        struct ieee80211_measurement_params params = {
                .channel = le16_to_cpu(priv->active_rxon.channel),
-               .start_time = cpu_to_le64(priv->last_tsf),
+               .start_time = cpu_to_le64(priv->_3945.last_tsf),
                .duration = cpu_to_le16(1),
        };
        u8 type = IWL_MEASURE_BASIC;
@@ -3656,44 +3673,6 @@ static ssize_t show_channels(struct device *d,
 
 static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
 
-static ssize_t show_statistics(struct device *d,
-                              struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       u32 size = sizeof(struct iwl3945_notif_statistics);
-       u32 len = 0, ofs = 0;
-       u8 *data = (u8 *)&priv->statistics_39;
-       int rc = 0;
-
-       if (!iwl_is_alive(priv))
-               return -EAGAIN;
-
-       mutex_lock(&priv->mutex);
-       rc = iwl_send_statistics_request(priv, CMD_SYNC, false);
-       mutex_unlock(&priv->mutex);
-
-       if (rc) {
-               len = sprintf(buf,
-                             "Error sending statistics request: 0x%08X\n", rc);
-               return len;
-       }
-
-       while (size && (PAGE_SIZE - len)) {
-               hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
-                                  PAGE_SIZE - len, 1);
-               len = strlen(buf);
-               if (PAGE_SIZE - len)
-                       buf[len++] = '\n';
-
-               ofs += 16;
-               size -= min(size, 16U);
-       }
-
-       return len;
-}
-
-static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
-
 static ssize_t show_antenna(struct device *d,
                            struct device_attribute *attr, char *buf)
 {
@@ -3775,14 +3754,21 @@ static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
        INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update);
        INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start);
        INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start);
-       INIT_DELAYED_WORK(&priv->rfkill_poll, iwl3945_rfkill_poll);
+       INIT_DELAYED_WORK(&priv->_3945.rfkill_poll, iwl3945_rfkill_poll);
        INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
-       INIT_WORK(&priv->request_scan, iwl3945_bg_request_scan);
        INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+       INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
        INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
 
        iwl3945_hw_setup_deferred_work(priv);
 
+       if (priv->cfg->ops->lib->recover_from_tx_stall) {
+               init_timer(&priv->monitor_recover);
+               priv->monitor_recover.data = (unsigned long)priv;
+               priv->monitor_recover.function =
+                       priv->cfg->ops->lib->recover_from_tx_stall;
+       }
+
        tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
                     iwl3945_irq_tasklet, (unsigned long)priv);
 }
@@ -3794,7 +3780,10 @@ static void iwl3945_cancel_deferred_work(struct iwl_priv *priv)
        cancel_delayed_work_sync(&priv->init_alive_start);
        cancel_delayed_work(&priv->scan_check);
        cancel_delayed_work(&priv->alive_start);
+       cancel_work_sync(&priv->start_internal_scan);
        cancel_work_sync(&priv->beacon_update);
+       if (priv->cfg->ops->lib->recover_from_tx_stall)
+               del_timer_sync(&priv->monitor_recover);
 }
 
 static struct attribute *iwl3945_sysfs_entries[] = {
@@ -3805,7 +3794,6 @@ static struct attribute *iwl3945_sysfs_entries[] = {
        &dev_attr_filter_flags.attr,
        &dev_attr_measurement.attr,
        &dev_attr_retry_rate.attr,
-       &dev_attr_statistics.attr,
        &dev_attr_status.attr,
        &dev_attr_temperature.attr,
        &dev_attr_tx_power.attr,
@@ -3832,7 +3820,9 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .conf_tx = iwl_mac_conf_tx,
        .reset_tsf = iwl_mac_reset_tsf,
        .bss_info_changed = iwl_bss_info_changed,
-       .hw_scan = iwl_mac_hw_scan
+       .hw_scan = iwl_mac_hw_scan,
+       .sta_add = iwl3945_mac_sta_add,
+       .sta_remove = iwl_mac_sta_remove,
 };
 
 static int iwl3945_init_drv(struct iwl_priv *priv)
@@ -3851,9 +3841,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        mutex_init(&priv->mutex);
        mutex_init(&priv->sync_cmd_mutex);
 
-       /* Clear the driver's (not device's) station table */
-       iwl_clear_stations_table(priv);
-
        priv->ieee_channels = NULL;
        priv->ieee_rates = NULL;
        priv->band = IEEE80211_BAND_2GHZ;
@@ -3861,12 +3848,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        priv->iw_mode = NL80211_IFTYPE_STATION;
        priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
 
-       iwl_reset_qos(priv);
-
-       priv->qos_data.qos_active = 0;
-       priv->qos_data.qos_cap.val = 0;
-
-       priv->rates_mask = IWL_RATES_MASK;
        priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER;
 
        if (eeprom->version < EEPROM_3945_EEPROM_VERSION) {
@@ -3902,6 +3883,8 @@ err:
        return ret;
 }
 
+#define IWL3945_MAX_PROBE_REQUEST      200
+
 static int iwl3945_setup_mac(struct iwl_priv *priv)
 {
        int ret;
@@ -3909,10 +3892,10 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
        hw->rate_control_algorithm = "iwl-3945-rs";
        hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM |
                    IEEE80211_HW_SPECTRUM_MGMT;
 
        if (!priv->cfg->broken_powersave)
@@ -3928,7 +3911,7 @@ static int iwl3945_setup_mac(struct iwl_priv *priv)
 
        hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX_3945;
        /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = IWL_MAX_PROBE_REQUEST - 24 - 2;
+       hw->wiphy->max_scan_ie_len = IWL3945_MAX_PROBE_REQUEST - 24 - 2;
 
        /* Default value; 4 EDCA QOS priorities */
        hw->queues = 4;
@@ -4131,7 +4114,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
 
        /* Start monitoring the killswitch */
-       queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
+       queue_delayed_work(priv->workqueue, &priv->_3945.rfkill_poll,
                           2 * HZ);
 
        return 0;
@@ -4205,7 +4188,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
 
-       cancel_delayed_work_sync(&priv->rfkill_poll);
+       cancel_delayed_work_sync(&priv->_3945.rfkill_poll);
 
        iwl3945_dealloc_ucode_pci(priv);
 
@@ -4214,7 +4197,6 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
        iwl3945_hw_txq_ctx_free(priv);
 
        iwl3945_unset_hw_params(priv);
-       iwl_clear_stations_table(priv);
 
        /*netif_stop_queue(dev); */
        flush_workqueue(priv->workqueue);
@@ -4236,7 +4218,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
 
        iwl_free_channel_map(priv);
        iwlcore_free_geos(priv);
-       kfree(priv->scan);
+       kfree(priv->scan_cmd);
        if (priv->ibss_beacon)
                dev_kfree_skb(priv->ibss_beacon);
 
index b9d34a76696448efa65920cc2923f1d0c9d260b2..03f998d098c59b60edbcf91d971c1d66e28f1d16 100644 (file)
@@ -17,7 +17,7 @@ config IWM
 config IWM_DEBUG
        bool "Enable full debugging output in iwmc3200wifi"
        depends on IWM && DEBUG_FS
-       ---help---
+       help
          This option will enable debug tracing and setting for iwm
 
          You can set the debug level and module through debugfs. By
@@ -30,3 +30,10 @@ config IWM_DEBUG
          Or, if you want the full debug, for all modules:
          echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level
          echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules
+
+config IWM_TRACING
+       bool "Enable event tracing for iwmc3200wifi"
+       depends on IWM && EVENT_TRACING
+       help
+         Say Y here to trace all the commands and responses between
+         the driver and firmware (including TX/RX frames) with ftrace.
index d34291b652d31e38c1c426839ae144435fc18867..cdc7e07ba113b02b60bb383fcd3bccecbfa9560d 100644 (file)
@@ -3,3 +3,8 @@ iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
 iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o
 
 iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
+iwmc3200wifi-$(CONFIG_IWM_TRACING) += trace.o
+
+CFLAGS_trace.o := -I$(src)
+
+ccflags-y += -D__CHECK_ENDIAN__
index 836663eec257c61e0ee8a0041e0c7723f2b56313..62edd5888a7b34fa6dc2353d4adef8ad7dc14eda 100644 (file)
@@ -31,7 +31,7 @@ struct iwm_if_ops {
        int (*disable)(struct iwm_priv *iwm);
        int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count);
 
-       int (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir);
+       void (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir);
        void (*debugfs_exit)(struct iwm_priv *iwm);
 
        const char *umac_name;
index a1d45cce0ebcab1f7b92568cafacf0dea4537014..902e95f70f6e7695445d2a3d23d04316bccea1a8 100644 (file)
@@ -264,7 +264,7 @@ static int iwm_cfg80211_get_station(struct wiphy *wiphy,
 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
 {
        struct wiphy *wiphy = iwm_to_wiphy(iwm);
-       struct iwm_bss_info *bss, *next;
+       struct iwm_bss_info *bss;
        struct iwm_umac_notif_bss_info *umac_bss;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_channel *channel;
@@ -272,7 +272,7 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
        s32 signal;
        int freq;
 
-       list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
+       list_for_each_entry(bss, &iwm->bss_list, node) {
                umac_bss = bss->bss;
                mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
 
@@ -726,23 +726,26 @@ static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
                                       CFG_POWER_INDEX, iwm->conf.power_index);
 }
 
-int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
-                          struct cfg80211_pmksa *pmksa)
+static int iwm_cfg80211_set_pmksa(struct wiphy *wiphy,
+                                 struct net_device *netdev,
+                                 struct cfg80211_pmksa *pmksa)
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
 
        return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD);
 }
 
-int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
-                          struct cfg80211_pmksa *pmksa)
+static int iwm_cfg80211_del_pmksa(struct wiphy *wiphy,
+                                 struct net_device *netdev,
+                                 struct cfg80211_pmksa *pmksa)
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
 
        return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL);
 }
 
-int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+static int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy,
+                                   struct net_device *netdev)
 {
        struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
        struct cfg80211_pmksa pmksa;
index 42df7262f9f7391d1c71faed6193ea3066052428..330c7d9cf101733bd70ef40476a592592068c641 100644 (file)
@@ -507,7 +507,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
                return ret;
        }
 
-       /* When succeding, the send_target routine returns the seq number */
+       /* When succeeding, the send_target routine returns the seq number */
        seq_num = ret;
 
        ret = wait_event_interruptible_timeout(iwm->nonwifi_queue,
@@ -782,10 +782,9 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
        return 0;
 }
 
-int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
+int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 {
        struct iwm_umac_invalidate_profile invalid;
-       int ret;
 
        invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
        invalid.hdr.buf_size =
@@ -794,7 +793,14 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
 
        invalid.reason = WLAN_REASON_UNSPECIFIED;
 
-       ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
+       return iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
+}
+
+int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
+{
+       int ret;
+
+       ret = __iwm_invalidate_mlme_profile(iwm);
        if (ret)
                return ret;
 
index 3dfd9f0e90035ba3043268cc1a53110454e20621..7e16bcf59978a99c6a78f38b4913484447072b0f 100644 (file)
@@ -488,6 +488,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
                            void *payload, u16 payload_size);
 int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags);
 int iwm_send_mlme_profile(struct iwm_priv *iwm);
+int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
 int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
 int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
 int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
index e35c9b693d1fde1a06a5dcf4eaa3aa7c7ac016b2..a0c13a49ab3ca095be4a042963fb52776bcce1f7 100644 (file)
@@ -113,13 +113,10 @@ struct iwm_debugfs {
 };
 
 #ifdef CONFIG_IWM_DEBUG
-int iwm_debugfs_init(struct iwm_priv *iwm);
+void iwm_debugfs_init(struct iwm_priv *iwm);
 void iwm_debugfs_exit(struct iwm_priv *iwm);
 #else
-static inline int iwm_debugfs_init(struct iwm_priv *iwm)
-{
-       return 0;
-}
+static inline void iwm_debugfs_init(struct iwm_priv *iwm) {}
 static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {}
 #endif
 
index cbb81befdb5596ed85eb3af77fd84a095d777bbb..53b0b7711f02a4c595d95fd0a92ef62753b33f65 100644 (file)
@@ -48,12 +48,11 @@ static struct {
 
 #define add_dbg_module(dbg, name, id, initlevel)       \
 do {                                                   \
-       struct dentry *d;                               \
        dbg.dbg_module[id] = (initlevel);               \
-       d = debugfs_create_x8(name, 0600, dbg.dbgdir,   \
-                            &(dbg.dbg_module[id]));    \
-       if (!IS_ERR(d))                                 \
-               dbg.dbg_module_dentries[id] = d;        \
+       dbg.dbg_module_dentries[id] =                   \
+               debugfs_create_x8(name, 0600,           \
+                               dbg.dbgdir,             \
+                               &(dbg.dbg_module[id])); \
 } while (0)
 
 static int iwm_debugfs_u32_read(void *data, u64 *val)
@@ -266,7 +265,7 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
                                          size_t count, loff_t *ppos)
 {
        struct iwm_priv *iwm = filp->private_data;
-       struct iwm_rx_ticket_node *ticket, *next;
+       struct iwm_rx_ticket_node *ticket;
        char *buf;
        int buf_len = 4096, i;
        size_t len = 0;
@@ -281,7 +280,8 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
        if (!buf)
                return -ENOMEM;
 
-       list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) {
+       spin_lock(&iwm->ticket_lock);
+       list_for_each_entry(ticket, &iwm->rx_tickets, node) {
                len += snprintf(buf + len, buf_len - len, "Ticket #%d\n",
                                ticket->ticket->id);
                len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n",
@@ -289,14 +289,17 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
                len += snprintf(buf + len, buf_len - len, "\tflags:  0x%x\n",
                                ticket->ticket->flags);
        }
+       spin_unlock(&iwm->ticket_lock);
 
        for (i = 0; i < IWM_RX_ID_HASH; i++) {
-               struct iwm_rx_packet *packet, *nxt;
+               struct iwm_rx_packet *packet;
                struct list_head *pkt_list = &iwm->rx_packets[i];
+
                if (!list_empty(pkt_list)) {
                        len += snprintf(buf + len, buf_len - len,
                                        "Packet hash #%d\n", i);
-                       list_for_each_entry_safe(packet, nxt, pkt_list, node) {
+                       spin_lock(&iwm->packet_lock[i]);
+                       list_for_each_entry(packet, pkt_list, node) {
                                len += snprintf(buf + len, buf_len - len,
                                                "\tPacket id:     %d\n",
                                                packet->id);
@@ -304,6 +307,7 @@ static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp,
                                                "\tPacket length: %lu\n",
                                                packet->pkt_size);
                        }
+                       spin_unlock(&iwm->packet_lock[i]);
                }
        }
 
@@ -418,89 +422,29 @@ static const struct file_operations iwm_debugfs_fw_err_fops = {
        .read =         iwm_debugfs_fw_err_read,
 };
 
-int iwm_debugfs_init(struct iwm_priv *iwm)
+void iwm_debugfs_init(struct iwm_priv *iwm)
 {
-       int i, result;
-       char devdir[16];
+       int i;
 
        iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       result = PTR_ERR(iwm->dbg.rootdir);
-       if (!result || IS_ERR(iwm->dbg.rootdir)) {
-               if (result == -ENODEV) {
-                       IWM_ERR(iwm, "DebugFS (CONFIG_DEBUG_FS) not "
-                               "enabled in kernel config\n");
-                       result = 0;     /* No debugfs support */
-               }
-               IWM_ERR(iwm, "Couldn't create rootdir: %d\n", result);
-               goto error;
-       }
-
-       snprintf(devdir, sizeof(devdir), "%s", wiphy_name(iwm_to_wiphy(iwm)));
-
-       iwm->dbg.devdir = debugfs_create_dir(devdir, iwm->dbg.rootdir);
-       result = PTR_ERR(iwm->dbg.devdir);
-       if (IS_ERR(iwm->dbg.devdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create devdir: %d\n", result);
-               goto error;
-       }
-
+       iwm->dbg.devdir = debugfs_create_dir(wiphy_name(iwm_to_wiphy(iwm)),
+                                            iwm->dbg.rootdir);
        iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.dbgdir);
-       if (IS_ERR(iwm->dbg.dbgdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create dbgdir: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.rxdir);
-       if (IS_ERR(iwm->dbg.rxdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create rx dir: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.txdir);
-       if (IS_ERR(iwm->dbg.txdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create tx dir: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir);
-       result = PTR_ERR(iwm->dbg.busdir);
-       if (IS_ERR(iwm->dbg.busdir) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create bus dir: %d\n", result);
-               goto error;
-       }
-
-       if (iwm->bus_ops->debugfs_init) {
-               result = iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
-               if (result < 0) {
-                       IWM_ERR(iwm, "Couldn't create bus entry: %d\n", result);
-                       goto error;
-               }
-       }
-
+       if (iwm->bus_ops->debugfs_init)
+               iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir);
 
        iwm->dbg.dbg_level = IWM_DL_NONE;
        iwm->dbg.dbg_level_dentry =
                debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm,
                                    &fops_iwm_dbg_level);
-       result = PTR_ERR(iwm->dbg.dbg_level_dentry);
-       if (IS_ERR(iwm->dbg.dbg_level_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create dbg_level: %d\n", result);
-               goto error;
-       }
-
 
        iwm->dbg.dbg_modules = IWM_DM_DEFAULT;
        iwm->dbg.dbg_modules_dentry =
                debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm,
                                    &fops_iwm_dbg_modules);
-       result = PTR_ERR(iwm->dbg.dbg_modules_dentry);
-       if (IS_ERR(iwm->dbg.dbg_modules_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create dbg_modules: %d\n", result);
-               goto error;
-       }
 
        for (i = 0; i < __IWM_DM_NR; i++)
                add_dbg_module(iwm->dbg, iwm_debug_module[i].name,
@@ -509,44 +453,15 @@ int iwm_debugfs_init(struct iwm_priv *iwm)
        iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200,
                                                  iwm->dbg.txdir, iwm,
                                                  &iwm_debugfs_txq_fops);
-       result = PTR_ERR(iwm->dbg.txq_dentry);
-       if (IS_ERR(iwm->dbg.txq_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create tx queue: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200,
                                                   iwm->dbg.txdir, iwm,
                                                   &iwm_debugfs_tx_credit_fops);
-       result = PTR_ERR(iwm->dbg.tx_credit_dentry);
-       if (IS_ERR(iwm->dbg.tx_credit_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create tx credit: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200,
                                                  iwm->dbg.rxdir, iwm,
                                                  &iwm_debugfs_rx_ticket_fops);
-       result = PTR_ERR(iwm->dbg.rx_ticket_dentry);
-       if (IS_ERR(iwm->dbg.rx_ticket_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create rx ticket: %d\n", result);
-               goto error;
-       }
-
        iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200,
                                                     iwm->dbg.dbgdir, iwm,
                                                     &iwm_debugfs_fw_err_fops);
-       result = PTR_ERR(iwm->dbg.fw_err_dentry);
-       if (IS_ERR(iwm->dbg.fw_err_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create last FW err: %d\n", result);
-               goto error;
-       }
-
-
-       return 0;
-
- error:
-       return result;
 }
 
 void iwm_debugfs_exit(struct iwm_priv *iwm)
index 229de990379c151b5b1a31c2434b92a7b488bc31..9531b18cf72a1f8163c3e89b265f70346a4922aa 100644 (file)
 #include "hal.h"
 #include "umac.h"
 #include "debug.h"
+#include "trace.h"
 
 static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
                                struct iwm_nonwifi_cmd *cmd,
@@ -207,9 +208,9 @@ void iwm_cmd_flush(struct iwm_priv *iwm)
 
 struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
 {
-       struct iwm_wifi_cmd *cmd, *next;
+       struct iwm_wifi_cmd *cmd;
 
-       list_for_each_entry_safe(cmd, next, &iwm->wifi_pending_cmd, pending)
+       list_for_each_entry(cmd, &iwm->wifi_pending_cmd, pending)
                if (cmd->seq_num == seq_num) {
                        list_del(&cmd->pending);
                        return cmd;
@@ -218,12 +219,12 @@ struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num)
        return NULL;
 }
 
-struct iwm_nonwifi_cmd *
-iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, u8 seq_num, u8 cmd_opcode)
+struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm,
+                                                   u8 seq_num, u8 cmd_opcode)
 {
-       struct iwm_nonwifi_cmd *cmd, *next;
+       struct iwm_nonwifi_cmd *cmd;
 
-       list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending)
+       list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending)
                if ((cmd->seq_num == seq_num) &&
                    (cmd->udma_cmd.opcode == cmd_opcode) &&
                    (cmd->resp_received)) {
@@ -277,6 +278,7 @@ static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm,
                    udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr,
                    udma_cmd->op1_sz, udma_cmd->op2);
 
+       trace_iwm_tx_nonwifi_cmd(iwm, udma_hdr);
        return iwm_bus_send_chunk(iwm, buf->start, buf->len);
 }
 
@@ -363,6 +365,7 @@ static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm,
                return ret;
        }
 
+       trace_iwm_tx_wifi_cmd(iwm, umac_hdr);
        return iwm_bus_send_chunk(iwm, buf->start, buf->len);
 }
 
index 0adfdc85765db8c80a47ebe47304c7ba545ed0a5..c20936d9b6b783003708c34ba1cdff94eaf860ec 100644 (file)
@@ -75,7 +75,8 @@ do {                                                                    \
 
 
 /* UDMA IN OP CODE -- cmd bits [3:0] */
-#define UDMA_IN_OPCODE_MASK                    0xF
+#define UDMA_HDI_IN_NW_CMD_OPCODE_POS          0
+#define UDMA_HDI_IN_NW_CMD_OPCODE_SEED         0xF
 
 #define UDMA_IN_OPCODE_GENERAL_RESP            0x0
 #define UDMA_IN_OPCODE_READ_RESP               0x1
@@ -130,7 +131,7 @@ do {                                                                          \
 #define IWM_MAX_WIFI_CMD_BUFF_SIZE     (IWM_SDIO_FW_MAX_CHUNK_SIZE - \
                                         IWM_MAX_WIFI_HEADERS_SIZE)
 
-#define IWM_HAL_CONCATENATE_BUF_SIZE   8192
+#define IWM_HAL_CONCATENATE_BUF_SIZE   (32 * 1024)
 
 struct iwm_wifi_cmd_buff {
        u16 len;
index 79ffa3b98d73c687c968e2b815272a1843f6e0ba..13266c3842f864b072d9f64e61bf9aedee9af70c 100644 (file)
@@ -48,6 +48,7 @@
 #include "umac.h"
 #include "lmac.h"
 #include "eeprom.h"
+#include "trace.h"
 
 #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
 #define IWM_AUTHOR "<ilw@linux.intel.com>"
@@ -268,7 +269,9 @@ struct iwm_priv {
 
        struct sk_buff_head rx_list;
        struct list_head rx_tickets;
+       spinlock_t ticket_lock;
        struct list_head rx_packets[IWM_RX_ID_HASH];
+       spinlock_t packet_lock[IWM_RX_ID_HASH];
        struct workqueue_struct *rx_wq;
        struct work_struct rx_worker;
 
index 23856d359e123b40ce080a2f6f7511c3fcc258bd..362002735b12f63694366c433f1e3f2fbd8b3b8e 100644 (file)
@@ -277,8 +277,11 @@ int iwm_priv_init(struct iwm_priv *iwm)
 
        skb_queue_head_init(&iwm->rx_list);
        INIT_LIST_HEAD(&iwm->rx_tickets);
-       for (i = 0; i < IWM_RX_ID_HASH; i++)
+       spin_lock_init(&iwm->ticket_lock);
+       for (i = 0; i < IWM_RX_ID_HASH; i++) {
                INIT_LIST_HEAD(&iwm->rx_packets[i]);
+               spin_lock_init(&iwm->packet_lock[i]);
+       }
 
        INIT_WORK(&iwm->rx_worker, iwm_rx_worker);
 
@@ -424,9 +427,9 @@ int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd,
 static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd,
                                        u8 source)
 {
-       struct iwm_notif *notif, *next;
+       struct iwm_notif *notif;
 
-       list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) {
+       list_for_each_entry(notif, &iwm->pending_notif, pending) {
                if ((notif->cmd_id == cmd) && (notif->src == source)) {
                        list_del(&notif->pending);
                        return notif;
index 3257d4fad835a03c3cd45e01abca00b60f453142..e1184deca55900636257525f1b24e4bf0f20be1c 100644 (file)
@@ -343,15 +343,17 @@ static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node)
 static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id)
 {
        u8 id_hash = IWM_RX_ID_GET_HASH(id);
-       struct list_head *packet_list;
-       struct iwm_rx_packet *packet, *next;
-
-       packet_list = &iwm->rx_packets[id_hash];
+       struct iwm_rx_packet *packet;
 
-       list_for_each_entry_safe(packet, next, packet_list, node)
-               if (packet->id == id)
+       spin_lock(&iwm->packet_lock[id_hash]);
+       list_for_each_entry(packet, &iwm->rx_packets[id_hash], node)
+               if (packet->id == id) {
+                       list_del(&packet->node);
+                       spin_unlock(&iwm->packet_lock[id_hash]);
                        return packet;
+               }
 
+       spin_unlock(&iwm->packet_lock[id_hash]);
        return NULL;
 }
 
@@ -389,18 +391,22 @@ void iwm_rx_free(struct iwm_priv *iwm)
        struct iwm_rx_packet *packet, *np;
        int i;
 
+       spin_lock(&iwm->ticket_lock);
        list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) {
                list_del(&ticket->node);
                iwm_rx_ticket_node_free(ticket);
        }
+       spin_unlock(&iwm->ticket_lock);
 
        for (i = 0; i < IWM_RX_ID_HASH; i++) {
+               spin_lock(&iwm->packet_lock[i]);
                list_for_each_entry_safe(packet, np, &iwm->rx_packets[i],
                                         node) {
                        list_del(&packet->node);
                        kfree_skb(packet->skb);
                        kfree(packet);
                }
+               spin_unlock(&iwm->packet_lock[i]);
        }
 }
 
@@ -425,10 +431,13 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
                                return PTR_ERR(ticket_node);
 
                        IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n",
-                                  ticket->action ==  IWM_RX_TICKET_RELEASE ?
+                                  __le16_to_cpu(ticket->action) ==
+                                                       IWM_RX_TICKET_RELEASE ?
                                   "RELEASE" : "DROP",
                                   ticket->id);
+                       spin_lock(&iwm->ticket_lock);
                        list_add_tail(&ticket_node->node, &iwm->rx_tickets);
+                       spin_unlock(&iwm->ticket_lock);
 
                        /*
                         * We received an Rx ticket, most likely there's
@@ -461,6 +470,7 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
        struct iwm_rx_packet *packet;
        u16 id, buf_offset;
        u32 packet_size;
+       u8 id_hash;
 
        IWM_DBG_RX(iwm, DBG, "\n");
 
@@ -478,7 +488,10 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
        if (IS_ERR(packet))
                return PTR_ERR(packet);
 
-       list_add_tail(&packet->node, &iwm->rx_packets[IWM_RX_ID_GET_HASH(id)]);
+       id_hash = IWM_RX_ID_GET_HASH(id);
+       spin_lock(&iwm->packet_lock[id_hash]);
+       list_add_tail(&packet->node, &iwm->rx_packets[id_hash]);
+       spin_unlock(&iwm->packet_lock[id_hash]);
 
        /* We might (unlikely) have received the packet _after_ the ticket */
        queue_work(iwm->rx_wq, &iwm->rx_worker);
@@ -519,6 +532,8 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                   unsigned long buf_size,
                                   struct iwm_wifi_cmd *cmd)
 {
+       struct wiphy *wiphy = iwm_to_wiphy(iwm);
+       struct ieee80211_channel *chan;
        struct iwm_umac_notif_assoc_complete *complete =
                (struct iwm_umac_notif_assoc_complete *)buf;
 
@@ -527,6 +542,18 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
 
        switch (le32_to_cpu(complete->status)) {
        case UMAC_ASSOC_COMPLETE_SUCCESS:
+               chan = ieee80211_get_channel(wiphy,
+                       ieee80211_channel_to_frequency(complete->channel));
+               if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+                       /* Associated to a unallowed channel, disassociate. */
+                       __iwm_invalidate_mlme_profile(iwm);
+                       IWM_WARN(iwm, "Couldn't associate with %pM due to "
+                                "channel %d is disabled. Check your local "
+                                "regulatory setting.\n",
+                                complete->bssid, complete->channel);
+                       goto failure;
+               }
+
                set_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
                memcpy(iwm->bssid, complete->bssid, ETH_ALEN);
                iwm->channel = complete->channel;
@@ -563,6 +590,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
                                        GFP_KERNEL);
                break;
        case UMAC_ASSOC_COMPLETE_FAILURE:
+ failure:
                clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
                memset(iwm->bssid, 0, ETH_ALEN);
                iwm->channel = 0;
@@ -757,7 +785,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
                        (struct iwm_umac_notif_bss_info *)buf;
        struct ieee80211_channel *channel;
        struct ieee80211_supported_band *band;
-       struct iwm_bss_info *bss, *next;
+       struct iwm_bss_info *bss;
        s32 signal;
        int freq;
        u16 frame_len = le16_to_cpu(umac_bss->frame_len);
@@ -776,7 +804,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
        IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi);
        IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len);
 
-       list_for_each_entry_safe(bss, next, &iwm->bss_list, node)
+       list_for_each_entry(bss, &iwm->bss_list, node)
                if (bss->bss->table_idx == umac_bss->table_idx)
                        break;
 
@@ -843,16 +871,15 @@ static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf,
        int i;
 
        for (i = 0; i < le32_to_cpu(bss_rm->count); i++) {
-               table_idx = (le16_to_cpu(bss_rm->entries[i])
-                            & IWM_BSS_REMOVE_INDEX_MSK);
+               table_idx = le16_to_cpu(bss_rm->entries[i]) &
+                           IWM_BSS_REMOVE_INDEX_MSK;
                list_for_each_entry_safe(bss, next, &iwm->bss_list, node)
                        if (bss->bss->table_idx == cpu_to_le16(table_idx)) {
                                struct ieee80211_mgmt *mgmt;
 
                                mgmt = (struct ieee80211_mgmt *)
                                        (bss->bss->frame_buf);
-                               IWM_DBG_MLME(iwm, ERR,
-                                            "BSS removed: %pM\n",
+                               IWM_DBG_MLME(iwm, ERR, "BSS removed: %pM\n",
                                             mgmt->bssid);
                                list_del(&bss->node);
                                kfree(bss->bss);
@@ -1224,18 +1251,24 @@ static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf,
        u8 source, cmd_id;
        u16 seq_num;
        u32 count;
-       u8 resp;
 
        wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
        cmd_id = wifi_hdr->sw_hdr.cmd.cmd;
-
        source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
        if (source >= IWM_SRC_NUM) {
                IWM_CRIT(iwm, "invalid source %d\n", source);
                return -EINVAL;
        }
 
-       count = (GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT));
+       if (cmd_id == REPLY_RX_MPDU_CMD)
+               trace_iwm_rx_packet(iwm, buf, buf_size);
+       else if ((cmd_id == UMAC_NOTIFY_OPCODE_RX_TICKET) &&
+                (source == UMAC_HDI_IN_SOURCE_FW))
+               trace_iwm_rx_ticket(iwm, buf, buf_size);
+       else
+               trace_iwm_rx_wifi_cmd(iwm, wifi_hdr);
+
+       count = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT);
        count += sizeof(struct iwm_umac_wifi_in_hdr) -
                 sizeof(struct iwm_dev_cmd_hdr);
        if (count > buf_size) {
@@ -1243,8 +1276,6 @@ static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf,
                return -EINVAL;
        }
 
-       resp = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_STATUS);
-
        seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
 
        IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n",
@@ -1317,8 +1348,9 @@ static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf,
 {
        u8 seq_num;
        struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf;
-       struct iwm_nonwifi_cmd *cmd, *next;
+       struct iwm_nonwifi_cmd *cmd;
 
+       trace_iwm_rx_nonwifi_cmd(iwm, buf, buf_size);
        seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM);
 
        /*
@@ -1329,7 +1361,7 @@ static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf,
         * That means we only support synchronised non wifi command response
         * schemes.
         */
-       list_for_each_entry_safe(cmd, next, &iwm->nonwifi_pending_cmd, pending)
+       list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending)
                if (cmd->seq_num == seq_num) {
                        cmd->resp_received = 1;
                        cmd->buf.len = buf_size;
@@ -1648,6 +1680,7 @@ void iwm_rx_worker(struct work_struct *work)
         * We stop whenever a ticket is missing its packet, as we're
         * supposed to send the packets in order.
         */
+       spin_lock(&iwm->ticket_lock);
        list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) {
                struct iwm_rx_packet *packet =
                        iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id));
@@ -1656,12 +1689,12 @@ void iwm_rx_worker(struct work_struct *work)
                        IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d "
                                   "to be handled first\n",
                                   le16_to_cpu(ticket->ticket->id));
-                       return;
+                       break;
                }
 
                list_del(&ticket->node);
-               list_del(&packet->node);
                iwm_rx_process_packet(iwm, packet, ticket);
        }
+       spin_unlock(&iwm->ticket_lock);
 }
 
index 1eafd6dec3fd1536766983f8c5a67ef994cbb0a2..edcb52330cf5ebbfca816cf6975b49221a1a0a4d 100644 (file)
@@ -366,21 +366,13 @@ static const struct file_operations iwm_debugfs_sdio_fops = {
        .read =         iwm_debugfs_sdio_read,
 };
 
-static int if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir)
+static void if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir)
 {
-       int result;
        struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm);
 
        hw->cccr_dentry = debugfs_create_file("cccr", 0200,
                                              parent_dir, iwm,
                                              &iwm_debugfs_sdio_fops);
-       result = PTR_ERR(hw->cccr_dentry);
-       if (IS_ERR(hw->cccr_dentry) && (result != -ENODEV)) {
-               IWM_ERR(iwm, "Couldn't create CCCR entry: %d\n", result);
-               return result;
-       }
-
-       return 0;
 }
 
 static void if_sdio_debugfs_exit(struct iwm_priv *iwm)
@@ -440,11 +432,7 @@ static int iwm_sdio_probe(struct sdio_func *func,
        hw = iwm_private(iwm);
        hw->iwm = iwm;
 
-       ret = iwm_debugfs_init(iwm);
-       if (ret < 0) {
-               IWM_ERR(iwm, "Debugfs registration failed\n");
-               goto if_free;
-       }
+       iwm_debugfs_init(iwm);
 
        sdio_set_drvdata(func, hw);
 
@@ -473,7 +461,6 @@ static int iwm_sdio_probe(struct sdio_func *func,
        destroy_workqueue(hw->isr_wq);
  debugfs_exit:
        iwm_debugfs_exit(iwm);
- if_free:
        iwm_if_free(iwm);
        return ret;
 }
@@ -492,8 +479,6 @@ static void iwm_sdio_remove(struct sdio_func *func)
        sdio_set_drvdata(func, NULL);
 
        dev_info(dev, "IWM SDIO remove\n");
-
-       return;
 }
 
 static const struct sdio_device_id iwm_sdio_ids[] = {
diff --git a/drivers/net/wireless/iwmc3200wifi/trace.c b/drivers/net/wireless/iwmc3200wifi/trace.c
new file mode 100644 (file)
index 0000000..904d36f
--- /dev/null
@@ -0,0 +1,3 @@
+#include "iwm.h"
+#define CREATE_TRACE_POINTS
+#include "trace.h"
diff --git a/drivers/net/wireless/iwmc3200wifi/trace.h b/drivers/net/wireless/iwmc3200wifi/trace.h
new file mode 100644 (file)
index 0000000..abb4805
--- /dev/null
@@ -0,0 +1,283 @@
+#if !defined(__IWM_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ)
+#define __IWM_TRACE_H__
+
+#include <linux/tracepoint.h>
+
+#if !defined(CONFIG_IWM_TRACING)
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM iwm
+
+#define IWM_ENTRY      __array(char, ndev_name, 16)
+#define IWM_ASSIGN     strlcpy(__entry->ndev_name, iwm_to_ndev(iwm)->name, 16)
+#define IWM_PR_FMT     "%s"
+#define IWM_PR_ARG     __entry->ndev_name
+
+TRACE_EVENT(iwm_tx_nonwifi_cmd,
+       TP_PROTO(struct iwm_priv *iwm, struct iwm_udma_out_nonwifi_hdr *hdr),
+
+       TP_ARGS(iwm, hdr),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, opcode)
+               __field(u8, resp)
+               __field(u8, eot)
+               __field(u8, hw)
+               __field(u16, seq)
+               __field(u32, addr)
+               __field(u32, op1)
+               __field(u32, op2)
+       ),
+
+       TP_fast_assign(
+               IWM_ASSIGN;
+               __entry->opcode = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE);
+               __entry->resp = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP);
+               __entry->eot = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT);
+               __entry->hw = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW);
+               __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM);
+               __entry->addr = le32_to_cpu(hdr->addr);
+               __entry->op1 = le32_to_cpu(hdr->op1_sz);
+               __entry->op2 = le32_to_cpu(hdr->op2);
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Tx TARGET CMD: opcode 0x%x, resp %d, eot %d, "
+               "hw %d, seq 0x%x, addr 0x%x, op1 0x%x, op2 0x%x",
+               IWM_PR_ARG, __entry->opcode, __entry->resp, __entry->eot,
+               __entry->hw, __entry->seq, __entry->addr, __entry->op1,
+               __entry->op2
+       )
+);
+
+TRACE_EVENT(iwm_tx_wifi_cmd,
+       TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_out_hdr *hdr),
+
+       TP_ARGS(iwm, hdr),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, opcode)
+               __field(u8, lmac)
+               __field(u8, resp)
+               __field(u8, eot)
+               __field(u8, ra_tid)
+               __field(u8, credit_group)
+               __field(u8, color)
+               __field(u16, seq)
+       ),
+
+       TP_fast_assign(
+               IWM_ASSIGN;
+               __entry->opcode = hdr->sw_hdr.cmd.cmd;
+               __entry->lmac = 0;
+               __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
+               __entry->resp = GET_VAL8(hdr->sw_hdr.cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ);
+               __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR);
+               __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT);
+               __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID);
+               __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP);
+               if (__entry->opcode == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH ||
+                   __entry->opcode == UMAC_CMD_OPCODE_WIFI_IF_WRAPPER) {
+                       __entry->lmac = 1;
+                       __entry->opcode = ((struct iwm_lmac_hdr *)(hdr + 1))->id;
+               }
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Tx %cMAC CMD: opcode 0x%x, resp %d, eot %d, "
+               "seq 0x%x, sta_color 0x%x, ra_tid 0x%x, credit_group 0x%x",
+               IWM_PR_ARG, __entry->lmac ? 'L' : 'U', __entry->opcode,
+               __entry->resp, __entry->eot, __entry->seq, __entry->color,
+               __entry->ra_tid, __entry->credit_group
+       )
+);
+
+TRACE_EVENT(iwm_tx_packets,
+       TP_PROTO(struct iwm_priv *iwm, u8 *buf, int len),
+
+       TP_ARGS(iwm, buf, len),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, eot)
+               __field(u8, ra_tid)
+               __field(u8, credit_group)
+               __field(u8, color)
+               __field(u16, seq)
+               __field(u8, npkt)
+               __field(u32, bytes)
+       ),
+
+       TP_fast_assign(
+               struct iwm_umac_wifi_out_hdr *hdr =
+                       (struct iwm_umac_wifi_out_hdr *)buf;
+
+               IWM_ASSIGN;
+               __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT);
+               __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID);
+               __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP);
+               __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR);
+               __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
+               __entry->npkt = 1;
+               __entry->bytes = len;
+
+               if (!__entry->eot) {
+                       int count;
+                       u8 *ptr = buf;
+
+                       __entry->npkt = 0;
+                       while (ptr < buf + len) {
+                               count = GET_VAL32(hdr->sw_hdr.meta_data,
+                                                 UMAC_FW_CMD_BYTE_COUNT);
+                               ptr += ALIGN(sizeof(*hdr) + count, 16);
+                               hdr = (struct iwm_umac_wifi_out_hdr *)ptr;
+                               __entry->npkt++;
+                       }
+               }
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Tx %spacket: eot %d, seq 0x%x, sta_color 0x%x, "
+               "ra_tid 0x%x, credit_group 0x%x, embeded_packets %d, %d bytes",
+               IWM_PR_ARG, !__entry->eot ? "concatenated " : "",
+               __entry->eot, __entry->seq, __entry->color, __entry->ra_tid,
+               __entry->credit_group, __entry->npkt, __entry->bytes
+       )
+);
+
+TRACE_EVENT(iwm_rx_nonwifi_cmd,
+       TP_PROTO(struct iwm_priv *iwm, void *buf, int len),
+
+       TP_ARGS(iwm, buf, len),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, opcode)
+               __field(u16, seq)
+               __field(u32, len)
+       ),
+
+       TP_fast_assign(
+               struct iwm_udma_in_hdr *hdr = buf;
+
+               IWM_ASSIGN;
+               __entry->opcode = GET_VAL32(hdr->cmd, UDMA_HDI_IN_NW_CMD_OPCODE);
+               __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM);
+               __entry->len = len;
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Rx TARGET RESP: opcode 0x%x, seq 0x%x, len 0x%x",
+               IWM_PR_ARG, __entry->opcode, __entry->seq, __entry->len
+       )
+);
+
+TRACE_EVENT(iwm_rx_wifi_cmd,
+       TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_in_hdr *hdr),
+
+       TP_ARGS(iwm, hdr),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, cmd)
+               __field(u8, source)
+               __field(u16, seq)
+               __field(u32, count)
+       ),
+
+       TP_fast_assign(
+               IWM_ASSIGN;
+               __entry->cmd = hdr->sw_hdr.cmd.cmd;
+               __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
+               __entry->count = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT);
+               __entry->seq = le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Rx %s RESP: cmd 0x%x, seq 0x%x, count 0x%x",
+               IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ? "LMAC" :
+               __entry->source == UMAC_HDI_IN_SOURCE_FW ? "UMAC" : "UDMA",
+               __entry->cmd, __entry->seq, __entry->count
+       )
+);
+
+#define iwm_ticket_action_symbol               \
+       { IWM_RX_TICKET_DROP, "DROP" },         \
+       { IWM_RX_TICKET_RELEASE, "RELEASE" },   \
+       { IWM_RX_TICKET_SNIFFER, "SNIFFER" },   \
+       { IWM_RX_TICKET_ENQUEUE, "ENQUEUE" }
+
+TRACE_EVENT(iwm_rx_ticket,
+       TP_PROTO(struct iwm_priv *iwm, void *buf, int len),
+
+       TP_ARGS(iwm, buf, len),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, action)
+               __field(u8, reason)
+               __field(u16, id)
+               __field(u16, flags)
+       ),
+
+       TP_fast_assign(
+               struct iwm_rx_ticket *ticket =
+                       ((struct iwm_umac_notif_rx_ticket *)buf)->tickets;
+
+               IWM_ASSIGN;
+               __entry->id = le16_to_cpu(ticket->id);
+               __entry->action = le16_to_cpu(ticket->action);
+               __entry->flags = le16_to_cpu(ticket->flags);
+               __entry->reason = (__entry->flags & IWM_RX_TICKET_DROP_REASON_MSK) >> IWM_RX_TICKET_DROP_REASON_POS;
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Rx ticket: id 0x%x, action %s, %s 0x%x%s",
+               IWM_PR_ARG, __entry->id,
+               __print_symbolic(__entry->action, iwm_ticket_action_symbol),
+               __entry->reason ? "reason" : "flags",
+               __entry->reason ? __entry->reason : __entry->flags,
+               __entry->flags & IWM_RX_TICKET_AMSDU_MSK ? ", AMSDU frame" : ""
+       )
+);
+
+TRACE_EVENT(iwm_rx_packet,
+       TP_PROTO(struct iwm_priv *iwm, void *buf, int len),
+
+       TP_ARGS(iwm, buf, len),
+
+       TP_STRUCT__entry(
+               IWM_ENTRY
+               __field(u8, source)
+               __field(u16, id)
+               __field(u32, len)
+       ),
+
+       TP_fast_assign(
+               struct iwm_umac_wifi_in_hdr *hdr = buf;
+
+               IWM_ASSIGN;
+               __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE);
+               __entry->id = le16_to_cpu(hdr->sw_hdr.cmd.seq_num);
+               __entry->len = len - sizeof(*hdr);
+       ),
+
+       TP_printk(
+               IWM_PR_FMT " Rx %s packet: id 0x%x, %d bytes",
+               IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ?
+               "LMAC" : "UMAC", __entry->id, __entry->len
+       )
+);
+#endif
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
index f6a02f123f31b182927b2071627eb7de274e372e..3216621fc55a020ecd081362d1633a30067a75bb 100644 (file)
@@ -302,8 +302,8 @@ void iwm_tx_credit_init_pools(struct iwm_priv *iwm,
 
 #define IWM_UDMA_HDR_LEN       sizeof(struct iwm_umac_wifi_out_hdr)
 
-static int iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
-                              int pool_id, u8 *buf)
+static __le16 iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb,
+                                 int pool_id, u8 *buf)
 {
        struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf;
        struct iwm_udma_wifi_cmd udma_cmd;
@@ -347,6 +347,7 @@ static int iwm_tx_send_concat_packets(struct iwm_priv *iwm,
        /* mark EOP for the last packet */
        iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1);
 
+       trace_iwm_tx_packets(iwm, txq->concat_buf, txq->concat_count);
        ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count);
 
        txq->concat_count = 0;
@@ -451,7 +452,6 @@ void iwm_tx_worker(struct work_struct *work)
 int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct iwm_priv *iwm = ndev_to_iwm(netdev);
-       struct net_device *ndev = iwm_to_ndev(iwm);
        struct wireless_dev *wdev = iwm_to_wdev(iwm);
        struct iwm_tx_info *tx_info;
        struct iwm_tx_queue *txq;
@@ -518,12 +518,12 @@ int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker);
 
-       ndev->stats.tx_packets++;
-       ndev->stats.tx_bytes += skb->len;
+       netdev->stats.tx_packets++;
+       netdev->stats.tx_bytes += skb->len;
        return NETDEV_TX_OK;
 
  drop:
-       ndev->stats.tx_dropped++;
+       netdev->stats.tx_dropped++;
        dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
index 7f54a145ca65ee276917b90e5c3b71ca2a3adb3e..0cbba3ecc813c717b9fda3d8aea66dab1ff19f70 100644 (file)
@@ -362,7 +362,7 @@ struct iwm_udma_out_wifi_hdr {
 #define IWM_RX_TICKET_SPECIAL_SNAP_MSK    0x4
 #define IWM_RX_TICKET_AMSDU_MSK           0x8
 #define IWM_RX_TICKET_DROP_REASON_POS       4
-#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << RX_TICKET_FLAGS_DROP_REASON_POS)
+#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << IWM_RX_TICKET_DROP_REASON_POS)
 
 #define IWM_RX_DROP_NO_DROP                          0x0
 #define IWM_RX_DROP_BAD_CRC                          0x1
index 12a2ef9dacea9aca87c59f0cd8d41b2d8732d6c1..aa06070e5eabc248ea029e9fbc88c53eed90918e 100644 (file)
@@ -32,6 +32,9 @@ u8 lbs_bg_rates[MAX_RATES] =
 0x00, 0x00 };
 
 
+static int assoc_helper_wep_keys(struct lbs_private *priv,
+               struct assoc_request *assoc_req);
+
 /**
  *  @brief This function finds common rates between rates and card rates.
  *
@@ -611,7 +614,7 @@ static int lbs_assoc_post(struct lbs_private *priv,
 
        if (status_code) {
                lbs_mac_event_disconnected(priv);
-               ret = -1;
+               ret = status_code;
                goto done;
        }
 
@@ -814,7 +817,24 @@ static int lbs_try_associate(struct lbs_private *priv,
                goto out;
 
        ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
+       /* If the association fails with current auth mode, let's
+        * try by changing the auth mode
+        */
+       if ((priv->authtype_auto) &&
+                       (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) &&
+                       (assoc_req->secinfo.wep_enabled) &&
+                       (priv->connect_status != LBS_CONNECTED)) {
+               if (priv->secinfo.auth_mode == IW_AUTH_ALG_OPEN_SYSTEM)
+                       priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
+               else
+                       priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+               if (!assoc_helper_wep_keys(priv, assoc_req))
+                       ret = lbs_associate(priv, assoc_req,
+                                               CMD_802_11_ASSOCIATE);
+       }
 
+       if (ret)
+               ret = -1;
 out:
        lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
        return ret;
index ce7bec402a33bbc885647b733d0e00dff50c6022..9d5d3ccf08c854376e9a22d3364019b37512baf5 100644 (file)
@@ -79,6 +79,7 @@ static const u32 cipher_suites[] = {
 
 
 static int lbs_cfg_set_channel(struct wiphy *wiphy,
+       struct net_device *netdev,
        struct ieee80211_channel *chan,
        enum nl80211_channel_type channel_type)
 {
index a48ccaffb288a785c78c944953943cf5296eed9b..de2caac11dd61a37cc9d0ee591db84616f825f33 100644 (file)
@@ -75,7 +75,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf,
                return -ENOMEM;
 
        pos += snprintf(buf+pos, len-pos,
-               "# | ch  | rssi |       bssid       |   cap    | Qual | SSID \n");
+               "# | ch  | rssi |       bssid       |   cap    | Qual | SSID\n");
 
        mutex_lock(&priv->lock);
        list_for_each_entry (iter_bss, &priv->network_list, list) {
@@ -757,15 +757,12 @@ void lbs_debugfs_init(void)
 {
        if (!lbs_dir)
                lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
-
-       return;
 }
 
 void lbs_debugfs_remove(void)
 {
        if (lbs_dir)
                 debugfs_remove(lbs_dir);
-       return;
 }
 
 void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
index 6875e1498bd57e36f54e826c763bb041a9bd3283..a54880e4ad2b99e00eeb0c3114bd796adafbd53b 100644 (file)
@@ -134,6 +134,7 @@ struct lbs_private {
        u8 wpa_ie_len;
        u16 wep_tx_keyidx;
        struct enc_key wep_keys[4];
+       u8 authtype_auto;
 
        /* Wake On LAN */
        uint32_t wol_criteria;
index 7d1a3c6b6ce0cd0f86b05d7a8959bafcf6d97feb..64dd345d30f526f2c10ff0b4c0b03998798e0fc0 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/host.h>
 
 #include "host.h"
 #include "decl.h"
@@ -313,12 +315,30 @@ out:
        return ret;
 }
 
+static int if_sdio_wait_status(struct if_sdio_card *card, const u8 condition)
+{
+       u8 status;
+       unsigned long timeout;
+       int ret = 0;
+
+       timeout = jiffies + HZ;
+       while (1) {
+               status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
+               if (ret)
+                       return ret;
+               if ((status & condition) == condition)
+                       break;
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               mdelay(1);
+       }
+       return ret;
+}
+
 static int if_sdio_card_to_host(struct if_sdio_card *card)
 {
        int ret;
-       u8 status;
        u16 size, type, chunk;
-       unsigned long timeout;
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
@@ -333,19 +353,9 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
                goto out;
        }
 
-       timeout = jiffies + HZ;
-       while (1) {
-               status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
-               if (ret)
-                       goto out;
-               if (status & IF_SDIO_IO_RDY)
-                       break;
-               if (time_after(jiffies, timeout)) {
-                       ret = -ETIMEDOUT;
-                       goto out;
-               }
-               mdelay(1);
-       }
+       ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
+       if (ret)
+               goto out;
 
        /*
         * The transfer must be in one transaction or the firmware
@@ -412,8 +422,6 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
 {
        struct if_sdio_card *card;
        struct if_sdio_packet *packet;
-       unsigned long timeout;
-       u8 status;
        int ret;
        unsigned long flags;
 
@@ -433,25 +441,15 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
 
                sdio_claim_host(card->func);
 
-               timeout = jiffies + HZ;
-               while (1) {
-                       status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
-                       if (ret)
-                               goto release;
-                       if (status & IF_SDIO_IO_RDY)
-                               break;
-                       if (time_after(jiffies, timeout)) {
-                               ret = -ETIMEDOUT;
-                               goto release;
-                       }
-                       mdelay(1);
+               ret = if_sdio_wait_status(card, IF_SDIO_IO_RDY);
+               if (ret == 0) {
+                       ret = sdio_writesb(card->func, card->ioport,
+                                          packet->buffer, packet->nb);
                }
 
-               ret = sdio_writesb(card->func, card->ioport,
-                               packet->buffer, packet->nb);
                if (ret)
-                       goto release;
-release:
+                       lbs_pr_err("error %d sending packet to firmware\n", ret);
+
                sdio_release_host(card->func);
 
                kfree(packet);
@@ -464,10 +462,11 @@ release:
 /* Firmware                                                         */
 /********************************************************************/
 
+#define FW_DL_READY_STATUS (IF_SDIO_IO_RDY | IF_SDIO_DL_RDY)
+
 static int if_sdio_prog_helper(struct if_sdio_card *card)
 {
        int ret;
-       u8 status;
        const struct firmware *fw;
        unsigned long timeout;
        u8 *chunk_buffer;
@@ -499,20 +498,14 @@ static int if_sdio_prog_helper(struct if_sdio_card *card)
        size = fw->size;
 
        while (size) {
-               timeout = jiffies + HZ;
-               while (1) {
-                       status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
-                       if (ret)
-                               goto release;
-                       if ((status & IF_SDIO_IO_RDY) &&
-                                       (status & IF_SDIO_DL_RDY))
-                               break;
-                       if (time_after(jiffies, timeout)) {
-                               ret = -ETIMEDOUT;
-                               goto release;
-                       }
-                       mdelay(1);
-               }
+               ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+               if (ret)
+                       goto release;
+
+               /* On some platforms (like Davinci) the chip needs more time
+                * between helper blocks.
+                */
+               mdelay(2);
 
                chunk_size = min(size, (size_t)60);
 
@@ -582,7 +575,6 @@ out:
 static int if_sdio_prog_real(struct if_sdio_card *card)
 {
        int ret;
-       u8 status;
        const struct firmware *fw;
        unsigned long timeout;
        u8 *chunk_buffer;
@@ -614,20 +606,9 @@ static int if_sdio_prog_real(struct if_sdio_card *card)
        size = fw->size;
 
        while (size) {
-               timeout = jiffies + HZ;
-               while (1) {
-                       status = sdio_readb(card->func, IF_SDIO_STATUS, &ret);
-                       if (ret)
-                               goto release;
-                       if ((status & IF_SDIO_IO_RDY) &&
-                                       (status & IF_SDIO_DL_RDY))
-                               break;
-                       if (time_after(jiffies, timeout)) {
-                               ret = -ETIMEDOUT;
-                               goto release;
-                       }
-                       mdelay(1);
-               }
+               ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+               if (ret)
+                       goto release;
 
                req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
                if (ret)
@@ -943,6 +924,7 @@ static int if_sdio_probe(struct sdio_func *func,
        int ret, i;
        unsigned int model;
        struct if_sdio_packet *packet;
+       struct mmc_host *host = func->card->host;
 
        lbs_deb_enter(LBS_DEB_SDIO);
 
@@ -1023,6 +1005,25 @@ static int if_sdio_probe(struct sdio_func *func,
        if (ret)
                goto disable;
 
+       /* For 1-bit transfers to the 8686 model, we need to enable the
+        * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
+        * bit to allow access to non-vendor registers. */
+       if ((card->model == IF_SDIO_MODEL_8686) &&
+           (host->caps & MMC_CAP_SDIO_IRQ) &&
+           (host->ios.bus_width == MMC_BUS_WIDTH_1)) {
+               u8 reg;
+
+               func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+               reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret);
+               if (ret)
+                       goto release_int;
+
+               reg |= SDIO_BUS_ECSI;
+               sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret);
+               if (ret)
+                       goto release_int;
+       }
+
        card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret);
        if (ret)
                goto release_int;
index fcea5741ba62b9c295cea309de05f21fb9f285e9..f41594c7ac16a09e712cc75a3cf85323870b5c17 100644 (file)
@@ -133,8 +133,6 @@ static void if_usb_write_bulk_callback(struct urb *urb)
                /* print the failure status number for debug */
                lbs_pr_info("URB in failure status: %d\n", urb->status);
        }
-
-       return;
 }
 
 /**
@@ -651,8 +649,6 @@ static void if_usb_receive_fwload(struct urb *urb)
        if_usb_submit_rx_urb_fwload(cardp);
 
        kfree(syncfwheader);
-
-       return;
 }
 
 #define MRVDRV_MIN_PKT_LEN     30
index 598080414b173654f25fb6d4767298b23462b865..d9b8ee130c450eb4006cafa411baa7a5b5038f60 100644 (file)
@@ -229,7 +229,7 @@ static void lbs_tx_timeout(struct net_device *dev)
 
        lbs_pr_err("tx watch dog timeout\n");
 
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 
        if (priv->currenttxskb)
                lbs_send_tx_feedback(priv, 0);
@@ -319,7 +319,7 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
                               struct net_device *dev, int nr_addrs)
 {
        int i = nr_addrs;
-       struct dev_mc_list *mc_list;
+       struct netdev_hw_addr *ha;
        int cnt;
 
        if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST))
@@ -327,19 +327,19 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd,
 
        netif_addr_lock_bh(dev);
        cnt = netdev_mc_count(dev);
-       netdev_for_each_mc_addr(mc_list, dev) {
-               if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) {
+       netdev_for_each_mc_addr(ha, dev) {
+               if (mac_in_list(cmd->maclist, nr_addrs, ha->addr)) {
                        lbs_deb_net("mcast address %s:%pM skipped\n", dev->name,
-                                   mc_list->dmi_addr);
+                                   ha->addr);
                        cnt--;
                        continue;
                }
 
                if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE)
                        break;
-               memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN);
+               memcpy(&cmd->maclist[6*i], ha->addr, ETH_ALEN);
                lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name,
-                           mc_list->dmi_addr);
+                           ha->addr);
                i++;
                cnt--;
        }
@@ -836,6 +836,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
        priv->is_auto_deep_sleep_enabled = 0;
        priv->wakeup_dev_required = 0;
        init_waitqueue_head(&priv->ds_awake_q);
+       priv->authtype_auto = 1;
 
        mutex_init(&priv->lock);
 
index 784dae7147055b64b91821b5366887e4c72c6bb0..a115bfa9513a8776f49139924e475a517884819c 100644 (file)
@@ -39,10 +39,10 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
        struct sk_buff *skb);
 
 /**
- *  @brief This function computes the avgSNR .
+ *  @brief     This function computes the avgSNR .
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @return       avgSNR
+ *  @param     priv    A pointer to struct lbs_private structure
+ *  @return    avgSNR
  */
 static u8 lbs_getavgsnr(struct lbs_private *priv)
 {
@@ -57,10 +57,10 @@ static u8 lbs_getavgsnr(struct lbs_private *priv)
 }
 
 /**
- *  @brief This function computes the AvgNF
+ *  @brief     This function computes the AvgNF
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @return       AvgNF
+ *  @param     priv    A pointer to struct lbs_private structure
+ *  @return    AvgNF
  */
 static u8 lbs_getavgnf(struct lbs_private *priv)
 {
@@ -75,11 +75,11 @@ static u8 lbs_getavgnf(struct lbs_private *priv)
 }
 
 /**
- *  @brief This function save the raw SNR/NF to our internel buffer
+ *  @brief     This function save the raw SNR/NF to our internel buffer
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @param prxpd   A pointer to rxpd structure of received packet
- *  @return       n/a
+ *  @param     priv    A pointer to struct lbs_private structure
+ *  @param     prxpd   A pointer to rxpd structure of received packet
+ *  @return    n/a
  */
 static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
 {
@@ -90,15 +90,14 @@ static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)
        priv->nextSNRNF++;
        if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
                priv->nextSNRNF = 0;
-       return;
 }
 
 /**
- *  @brief This function computes the RSSI in received packet.
+ *  @brief     This function computes the RSSI in received packet.
  *
- *  @param priv    A pointer to struct lbs_private structure
- *  @param prxpd   A pointer to rxpd structure of received packet
- *  @return       n/a
+ *  @param     priv    A pointer to struct lbs_private structure
+ *  @param     prxpd   A pointer to rxpd structure of received packet
+ *  @return    n/a
  */
 static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
 {
@@ -135,9 +134,9 @@ static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)
  *  @brief This function processes received packet and forwards it
  *  to kernel/upper layer
  *
- *  @param priv    A pointer to struct lbs_private
- *  @param skb     A pointer to skb which includes the received packet
- *  @return       0 or -1
+ *  @param     priv    A pointer to struct lbs_private
+ *  @param     skb             A pointer to skb which includes the received packet
+ *  @return    0 or -1
  */
 int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
 {
@@ -197,7 +196,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
                 *    before the snap_type.
                 */
                p_ethhdr = (struct ethhdr *)
-                   ((u8 *) & p_rx_pkt->eth803_hdr
+                   ((u8 *) &p_rx_pkt->eth803_hdr
                     + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
                     - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
                     - sizeof(p_rx_pkt->eth803_hdr.src_addr)
@@ -214,7 +213,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
                hdrchop = (u8 *)p_ethhdr - (u8 *)p_rx_pd;
        } else {
                lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
-                       (u8 *) & p_rx_pkt->rfc1042_hdr,
+                       (u8 *) &p_rx_pkt->rfc1042_hdr,
                        sizeof(p_rx_pkt->rfc1042_hdr));
 
                /* Chop off the rxpd */
@@ -255,8 +254,8 @@ EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
  *  @brief This function converts Tx/Rx rates from the Marvell WLAN format
  *  (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
  *
- *  @param rate    Input rate
- *  @return       Output Rate (0 if invalid)
+ *  @param     rate    Input rate
+ *  @return    Output Rate (0 if invalid)
  */
 static u8 convert_mv_rate_to_radiotap(u8 rate)
 {
@@ -295,9 +294,9 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
  *  @brief This function processes a received 802.11 packet and forwards it
  *  to kernel/upper layer
  *
- *  @param priv    A pointer to struct lbs_private
- *  @param skb     A pointer to skb which includes the received packet
- *  @return       0 or -1
+ *  @param     priv    A pointer to struct lbs_private
+ *  @param     skb             A pointer to skb which includes the received packet
+ *  @return    0 or -1
  */
 static int process_rxed_802_11_packet(struct lbs_private *priv,
        struct sk_buff *skb)
@@ -314,7 +313,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
        p_rx_pkt = (struct rx80211packethdr *) skb->data;
        prxpd = &p_rx_pkt->rx_pd;
 
-       // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+       /* lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); */
 
        if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
                lbs_deb_rx("rx err: frame received with bad length\n");
index 52d244ea3d972809f7a528d8077dea7262879505..a9bf658659ebae51d0fe1575b211cbfbdb0ac054 100644 (file)
@@ -147,8 +147,6 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        dev->stats.tx_packets++;
        dev->stats.tx_bytes += skb->len;
 
-       dev->trans_start = jiffies;
-
        if (priv->monitormode) {
                /* Keep the skb to echo it back once Tx feedback is
                   received from FW */
index 9b555884b08a99dd1c936f49245549a5b87266db..f96a96031a501fbd17a35a0cd63cfdba1fcd6e9d 100644 (file)
@@ -1441,8 +1441,10 @@ static int lbs_set_encode(struct net_device *dev,
                set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
 
        if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+               priv->authtype_auto = 0;
                assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
        } else if (dwrq->flags & IW_ENCODE_OPEN) {
+               priv->authtype_auto = 0;
                assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
        }
 
@@ -1621,8 +1623,10 @@ static int lbs_set_encodeext(struct net_device *dev,
                        goto out;
 
                if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+                       priv->authtype_auto = 0;
                        assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
                } else if (dwrq->flags & IW_ENCODE_OPEN) {
+                       priv->authtype_auto = 0;
                        assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
                }
 
index b620daf59ef7fa3927c3e323779d70d3ec4e49bd..8945afd6ce3ef7e88e182709020660e3183f27d2 100644 (file)
@@ -7,6 +7,8 @@
  *  the Free Software Foundation; either version 2 of the License, or (at
  *  your option) any later version.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 
 #include "libertas_tf.h"
@@ -82,6 +84,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
        int ret = -1;
        u32 i;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        memset(&cmd, 0, sizeof(cmd));
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN);
@@ -104,6 +108,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
                priv->fwrelease >>  8 & 0xff,
                priv->fwrelease       & 0xff,
                priv->fwcapinfo);
+       lbtf_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
+                   cmd.hwifversion, cmd.version);
 
        /* 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
@@ -118,8 +124,10 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
        }
 
        /* if it's unidentified region code, use the default (USA) */
-       if (i >= MRVDRV_MAX_REGION_CODE)
+       if (i >= MRVDRV_MAX_REGION_CODE) {
                priv->regioncode = 0x10;
+               pr_info("unidentified region code; using the default (USA)\n");
+       }
 
        if (priv->current_addr[0] == 0xff)
                memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN);
@@ -128,6 +136,7 @@ int lbtf_update_hw_spec(struct lbtf_private *priv)
 
        lbtf_geo_init(priv);
 out:
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return ret;
 }
 
@@ -141,13 +150,18 @@ out:
  */
 int lbtf_set_channel(struct lbtf_private *priv, u8 channel)
 {
+       int ret = 0;
        struct cmd_ds_802_11_rf_channel cmd;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET);
        cmd.channel = cpu_to_le16(channel);
 
-       return lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+       ret = lbtf_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd);
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
+       return ret;
 }
 
 int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
@@ -155,20 +169,28 @@ int lbtf_beacon_set(struct lbtf_private *priv, struct sk_buff *beacon)
        struct cmd_ds_802_11_beacon_set cmd;
        int size;
 
-       if (beacon->len > MRVL_MAX_BCN_SIZE)
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
+       if (beacon->len > MRVL_MAX_BCN_SIZE) {
+               lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", -1);
                return -1;
+       }
        size =  sizeof(cmd) - sizeof(cmd.beacon) + beacon->len;
        cmd.hdr.size = cpu_to_le16(size);
        cmd.len = cpu_to_le16(beacon->len);
        memcpy(cmd.beacon, (u8 *) beacon->data, beacon->len);
 
        lbtf_cmd_async(priv, CMD_802_11_BEACON_SET, &cmd.hdr, size);
+
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", 0);
        return 0;
 }
 
 int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
-                    int beacon_int) {
+                    int beacon_int)
+{
        struct cmd_ds_802_11_beacon_control cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
@@ -176,6 +198,8 @@ int lbtf_beacon_ctrl(struct lbtf_private *priv, bool beacon_enable,
        cmd.beacon_period = cpu_to_le16(beacon_int);
 
        lbtf_cmd_async(priv, CMD_802_11_BEACON_CTRL, &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return 0;
 }
 
@@ -183,17 +207,28 @@ static void lbtf_queue_cmd(struct lbtf_private *priv,
                          struct cmd_ctrl_node *cmdnode)
 {
        unsigned long flags;
+       lbtf_deb_enter(LBTF_DEB_HOST);
 
-       if (!cmdnode)
-               return;
+       if (!cmdnode) {
+               lbtf_deb_host("QUEUE_CMD: cmdnode is NULL\n");
+               goto qcmd_done;
+       }
 
-       if (!cmdnode->cmdbuf->size)
-               return;
+       if (!cmdnode->cmdbuf->size) {
+               lbtf_deb_host("DNLD_CMD: cmd size is zero\n");
+               goto qcmd_done;
+       }
 
        cmdnode->result = 0;
        spin_lock_irqsave(&priv->driver_lock, flags);
        list_add_tail(&cmdnode->list, &priv->cmdpendingq);
        spin_unlock_irqrestore(&priv->driver_lock, flags);
+
+       lbtf_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
+                    le16_to_cpu(cmdnode->cmdbuf->command));
+
+qcmd_done:
+       lbtf_deb_leave(LBTF_DEB_HOST);
 }
 
 static void lbtf_submit_command(struct lbtf_private *priv,
@@ -206,22 +241,33 @@ static void lbtf_submit_command(struct lbtf_private *priv,
        int timeo = 5 * HZ;
        int ret;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        cmd = cmdnode->cmdbuf;
 
        spin_lock_irqsave(&priv->driver_lock, flags);
        priv->cur_cmd = cmdnode;
        cmdsize = le16_to_cpu(cmd->size);
        command = le16_to_cpu(cmd->command);
+
+       lbtf_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
+                    command, le16_to_cpu(cmd->seqnum), cmdsize);
+       lbtf_deb_hex(LBTF_DEB_CMD, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
+
        ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
-       if (ret)
+       if (ret) {
+               pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
                /* Let the timer kick in and retry, and potentially reset
                   the whole thing if the condition persists */
                timeo = HZ;
+       }
 
        /* Setup the timer after transmit command */
        mod_timer(&priv->command_timer, jiffies + timeo);
+
+       lbtf_deb_leave(LBTF_DEB_HOST);
 }
 
 /**
@@ -231,8 +277,10 @@ static void lbtf_submit_command(struct lbtf_private *priv,
 static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
                                         struct cmd_ctrl_node *cmdnode)
 {
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        if (!cmdnode)
-               return;
+               goto cl_ins_out;
 
        cmdnode->callback = NULL;
        cmdnode->callback_arg = 0;
@@ -240,6 +288,9 @@ static void __lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
        memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE);
 
        list_add_tail(&cmdnode->list, &priv->cmdfreeq);
+
+cl_ins_out:
+       lbtf_deb_leave(LBTF_DEB_HOST);
 }
 
 static void lbtf_cleanup_and_insert_cmd(struct lbtf_private *priv,
@@ -268,29 +319,41 @@ int lbtf_cmd_set_mac_multicast_addr(struct lbtf_private *priv)
 {
        struct cmd_ds_mac_multicast_addr cmd;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
 
        cmd.nr_of_adrs = cpu_to_le16((u16) priv->nr_of_multicastmacaddr);
+
+       lbtf_deb_cmd("MULTICAST_ADR: setting %d addresses\n", cmd.nr_of_adrs);
+
        memcpy(cmd.maclist, priv->multicastlist,
               priv->nr_of_multicastmacaddr * ETH_ALEN);
 
        lbtf_cmd_async(priv, CMD_MAC_MULTICAST_ADR, &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return 0;
 }
 
 void lbtf_set_mode(struct lbtf_private *priv, enum lbtf_mode mode)
 {
        struct cmd_ds_set_mode cmd;
+       lbtf_deb_enter(LBTF_DEB_WEXT);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.mode = cpu_to_le16(mode);
+       lbtf_deb_wext("Switching to mode: 0x%x\n", mode);
        lbtf_cmd_async(priv, CMD_802_11_SET_MODE, &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_WEXT);
 }
 
 void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
 {
        struct cmd_ds_set_bssid cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.activate = activate ? 1 : 0;
@@ -298,11 +361,13 @@ void lbtf_set_bssid(struct lbtf_private *priv, bool activate, const u8 *bssid)
                memcpy(cmd.bssid, bssid, ETH_ALEN);
 
        lbtf_cmd_async(priv, CMD_802_11_SET_BSSID, &cmd.hdr, sizeof(cmd));
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
 {
        struct cmd_ds_802_11_mac_address cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
@@ -310,6 +375,7 @@ int lbtf_set_mac_address(struct lbtf_private *priv, uint8_t *mac_addr)
        memcpy(cmd.macadd, mac_addr, ETH_ALEN);
 
        lbtf_cmd_async(priv, CMD_802_11_MAC_ADDRESS, &cmd.hdr, sizeof(cmd));
+       lbtf_deb_leave(LBTF_DEB_CMD);
        return 0;
 }
 
@@ -318,6 +384,8 @@ int lbtf_set_radio_control(struct lbtf_private *priv)
        int ret = 0;
        struct cmd_ds_802_11_radio_control cmd;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(CMD_ACT_SET);
 
@@ -341,19 +409,28 @@ int lbtf_set_radio_control(struct lbtf_private *priv)
        else
                cmd.control &= cpu_to_le16(~TURN_ON_RF);
 
+       lbtf_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon,
+                   priv->preamble);
+
        ret = lbtf_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd);
+
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
        return ret;
 }
 
 void lbtf_set_mac_control(struct lbtf_private *priv)
 {
        struct cmd_ds_mac_control cmd;
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        cmd.hdr.size = cpu_to_le16(sizeof(cmd));
        cmd.action = cpu_to_le16(priv->mac_control);
        cmd.reserved = 0;
 
        lbtf_cmd_async(priv, CMD_MAC_CONTROL,
                &cmd.hdr, sizeof(cmd));
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 /**
@@ -365,29 +442,43 @@ void lbtf_set_mac_control(struct lbtf_private *priv)
  */
 int lbtf_allocate_cmd_buffer(struct lbtf_private *priv)
 {
+       int ret = 0;
        u32 bufsize;
        u32 i;
        struct cmd_ctrl_node *cmdarray;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        /* Allocate and initialize the command array */
        bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS;
        cmdarray = kzalloc(bufsize, GFP_KERNEL);
-       if (!cmdarray)
-               return -1;
+       if (!cmdarray) {
+               lbtf_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
+               ret = -1;
+               goto done;
+       }
        priv->cmd_array = cmdarray;
 
        /* Allocate and initialize each command buffer in the command array */
        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
                cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL);
-               if (!cmdarray[i].cmdbuf)
-                       return -1;
+               if (!cmdarray[i].cmdbuf) {
+                       lbtf_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
+                       ret = -1;
+                       goto done;
+               }
        }
 
        for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) {
                init_waitqueue_head(&cmdarray[i].cmdwait_q);
                lbtf_cleanup_and_insert_cmd(priv, &cmdarray[i]);
        }
-       return 0;
+
+       ret = 0;
+
+done:
+       lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
+       return ret;
 }
 
 /**
@@ -402,9 +493,13 @@ int lbtf_free_cmd_buffer(struct lbtf_private *priv)
        struct cmd_ctrl_node *cmdarray;
        unsigned int i;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        /* need to check if cmd array is allocated or not */
-       if (priv->cmd_array == NULL)
-               return 0;
+       if (priv->cmd_array == NULL) {
+               lbtf_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
+               goto done;
+       }
 
        cmdarray = priv->cmd_array;
 
@@ -418,6 +513,8 @@ int lbtf_free_cmd_buffer(struct lbtf_private *priv)
        kfree(priv->cmd_array);
        priv->cmd_array = NULL;
 
+done:
+       lbtf_deb_leave(LBTF_DEB_HOST);
        return 0;
 }
 
@@ -433,6 +530,8 @@ static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
        struct cmd_ctrl_node *tempnode;
        unsigned long flags;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        if (!priv)
                return NULL;
 
@@ -442,11 +541,14 @@ static struct cmd_ctrl_node *lbtf_get_cmd_ctrl_node(struct lbtf_private *priv)
                tempnode = list_first_entry(&priv->cmdfreeq,
                                            struct cmd_ctrl_node, list);
                list_del(&tempnode->list);
-       } else
+       } else {
+               lbtf_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
                tempnode = NULL;
+       }
 
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
+       lbtf_deb_leave(LBTF_DEB_HOST);
        return tempnode;
 }
 
@@ -462,16 +564,20 @@ int lbtf_execute_next_command(struct lbtf_private *priv)
        struct cmd_ctrl_node *cmdnode = NULL;
        struct cmd_header *cmd;
        unsigned long flags;
+       int ret = 0;
 
-       /* Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+       /* Debug group is lbtf_deb_THREAD and not lbtf_deb_HOST, because the
         * only caller to us is lbtf_thread() and we get even when a
         * data packet is received */
+       lbtf_deb_enter(LBTF_DEB_THREAD);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
 
        if (priv->cur_cmd) {
+               pr_alert("EXEC_NEXT_CMD: already processing command!\n");
                spin_unlock_irqrestore(&priv->driver_lock, flags);
-               return -1;
+               ret = -1;
+               goto done;
        }
 
        if (!list_empty(&priv->cmdpendingq)) {
@@ -483,11 +589,17 @@ int lbtf_execute_next_command(struct lbtf_private *priv)
                cmd = cmdnode->cmdbuf;
 
                list_del(&cmdnode->list);
+               lbtf_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
+                           le16_to_cpu(cmd->command));
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                lbtf_submit_command(priv, cmdnode);
        } else
                spin_unlock_irqrestore(&priv->driver_lock, flags);
-       return 0;
+
+       ret = 0;
+done:
+       lbtf_deb_leave(LBTF_DEB_THREAD);
+       return ret;
 }
 
 static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
@@ -498,14 +610,22 @@ static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
 {
        struct cmd_ctrl_node *cmdnode;
 
-       if (priv->surpriseremoved)
-               return ERR_PTR(-ENOENT);
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
+       if (priv->surpriseremoved) {
+               lbtf_deb_host("PREP_CMD: card removed\n");
+               cmdnode = ERR_PTR(-ENOENT);
+               goto done;
+       }
 
        cmdnode = lbtf_get_cmd_ctrl_node(priv);
        if (cmdnode == NULL) {
+               lbtf_deb_host("PREP_CMD: cmdnode is NULL\n");
+
                /* Wake up main thread to execute next command */
                queue_work(lbtf_wq, &priv->cmd_work);
-               return ERR_PTR(-ENOBUFS);
+               cmdnode = ERR_PTR(-ENOBUFS);
+               goto done;
        }
 
        cmdnode->callback = callback;
@@ -520,17 +640,24 @@ static struct cmd_ctrl_node *__lbtf_cmd_async(struct lbtf_private *priv,
        cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
        cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
        cmdnode->cmdbuf->result  = 0;
+
+       lbtf_deb_host("PREP_CMD: command 0x%04x\n", command);
+
        cmdnode->cmdwaitqwoken = 0;
        lbtf_queue_cmd(priv, cmdnode);
        queue_work(lbtf_wq, &priv->cmd_work);
 
+ done:
+       lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %p", cmdnode);
        return cmdnode;
 }
 
 void lbtf_cmd_async(struct lbtf_private *priv, uint16_t command,
        struct cmd_header *in_cmd, int in_cmd_size)
 {
+       lbtf_deb_enter(LBTF_DEB_CMD);
        __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size, NULL, 0);
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
@@ -543,30 +670,35 @@ int __lbtf_cmd(struct lbtf_private *priv, uint16_t command,
        unsigned long flags;
        int ret = 0;
 
+       lbtf_deb_enter(LBTF_DEB_HOST);
+
        cmdnode = __lbtf_cmd_async(priv, command, in_cmd, in_cmd_size,
                                  callback, callback_arg);
-       if (IS_ERR(cmdnode))
-               return PTR_ERR(cmdnode);
+       if (IS_ERR(cmdnode)) {
+               ret = PTR_ERR(cmdnode);
+               goto done;
+       }
 
        might_sleep();
        ret = wait_event_interruptible(cmdnode->cmdwait_q,
                                       cmdnode->cmdwaitqwoken);
-       if (ret)        {
-               printk(KERN_DEBUG
-                      "libertastf: command 0x%04x interrupted by signal",
-                      command);
-               return ret;
+       if (ret) {
+               pr_info("PREP_CMD: command 0x%04x interrupted by signal: %d\n",
+                           command, ret);
+               goto done;
        }
 
        spin_lock_irqsave(&priv->driver_lock, flags);
        ret = cmdnode->result;
        if (ret)
-               printk(KERN_DEBUG "libertastf: command 0x%04x failed: %d\n",
+               pr_info("PREP_CMD: command 0x%04x failed: %d\n",
                            command, ret);
 
        __lbtf_cleanup_and_insert_cmd(priv, cmdnode);
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
+done:
+       lbtf_deb_leave_args(LBTF_DEB_HOST, "ret %d", ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(__lbtf_cmd);
@@ -587,6 +719,8 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
        unsigned long flags;
        uint16_t result;
 
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        mutex_lock(&priv->lock);
        spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -602,7 +736,7 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
        result = le16_to_cpu(resp->result);
 
        if (net_ratelimit())
-               printk(KERN_DEBUG "libertastf: cmd response 0x%04x, seq %d, size %d\n",
+               pr_info("libertastf: cmd response 0x%04x, seq %d, size %d\n",
                        respcmd, le16_to_cpu(resp->seqnum),
                        le16_to_cpu(resp->size));
 
@@ -639,7 +773,7 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
                switch (respcmd) {
                case CMD_RET(CMD_GET_HW_SPEC):
                case CMD_RET(CMD_802_11_RESET):
-                       printk(KERN_DEBUG "libertastf: reset failed\n");
+                       pr_info("libertastf: reset failed\n");
                        break;
 
                }
@@ -666,5 +800,6 @@ int lbtf_process_rx_command(struct lbtf_private *priv)
 
 done:
        mutex_unlock(&priv->lock);
+       lbtf_deb_leave_args(LBTF_DEB_CMD, "ret %d", ret);
        return ret;
 }
diff --git a/drivers/net/wireless/libertas_tf/deb_defs.h b/drivers/net/wireless/libertas_tf/deb_defs.h
new file mode 100644 (file)
index 0000000..ae75396
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+  * This header file contains global constant/enum definitions,
+  * global variable declaration.
+  */
+#ifndef _LBS_DEB_DEFS_H_
+#define _LBS_DEB_EFS_H_
+
+#ifndef DRV_NAME
+#define DRV_NAME "libertas_tf"
+#endif
+
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_LIBERTAS_THINFIRM_DEBUG
+#define DEBUG
+#define PROC_DEBUG
+#endif
+
+#define LBTF_DEB_ENTER 0x00000001
+#define LBTF_DEB_LEAVE 0x00000002
+#define LBTF_DEB_MAIN  0x00000004
+#define LBTF_DEB_NET   0x00000008
+#define LBTF_DEB_MESH  0x00000010
+#define LBTF_DEB_WEXT  0x00000020
+#define LBTF_DEB_IOCTL 0x00000040
+#define LBTF_DEB_SCAN  0x00000080
+#define LBTF_DEB_ASSOC 0x00000100
+#define LBTF_DEB_JOIN  0x00000200
+#define LBTF_DEB_11D   0x00000400
+#define LBTF_DEB_DEBUGFS       0x00000800
+#define LBTF_DEB_ETHTOOL       0x00001000
+#define LBTF_DEB_HOST  0x00002000
+#define LBTF_DEB_CMD   0x00004000
+#define LBTF_DEB_RX    0x00008000
+#define LBTF_DEB_TX    0x00010000
+#define LBTF_DEB_USB   0x00020000
+#define LBTF_DEB_CS    0x00040000
+#define LBTF_DEB_FW    0x00080000
+#define LBTF_DEB_THREAD        0x00100000
+#define LBTF_DEB_HEX   0x00200000
+#define LBTF_DEB_SDIO  0x00400000
+#define LBTF_DEB_MACOPS        0x00800000
+
+extern unsigned int lbtf_debug;
+
+
+#ifdef DEBUG
+#define LBTF_DEB_LL(grp, grpnam, fmt, args...) \
+do { if ((lbtf_debug & (grp)) == (grp)) \
+  printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
+         in_interrupt() ? " (INT)" : "", ## args); } while (0)
+#else
+#define LBTF_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
+#endif
+
+#define lbtf_deb_enter(grp) \
+  LBTF_DEB_LL(grp | LBTF_DEB_ENTER, " enter", "%s()\n", __func__);
+#define lbtf_deb_enter_args(grp, fmt, args...) \
+  LBTF_DEB_LL(grp | LBTF_DEB_ENTER, " enter", "%s(" fmt ")\n", __func__, ## args);
+#define lbtf_deb_leave(grp) \
+  LBTF_DEB_LL(grp | LBTF_DEB_LEAVE, " leave", "%s()\n", __func__);
+#define lbtf_deb_leave_args(grp, fmt, args...) \
+  LBTF_DEB_LL(grp | LBTF_DEB_LEAVE, " leave", "%s(), " fmt "\n", \
+  __func__, ##args);
+#define lbtf_deb_main(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_MAIN, " main", fmt, ##args)
+#define lbtf_deb_net(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_NET, " net", fmt, ##args)
+#define lbtf_deb_mesh(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_MESH, " mesh", fmt, ##args)
+#define lbtf_deb_wext(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_WEXT, " wext", fmt, ##args)
+#define lbtf_deb_ioctl(fmt, args...)     LBTF_DEB_LL(LBTF_DEB_IOCTL, " ioctl", fmt, ##args)
+#define lbtf_deb_scan(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_SCAN, " scan", fmt, ##args)
+#define lbtf_deb_assoc(fmt, args...)     LBTF_DEB_LL(LBTF_DEB_ASSOC, " assoc", fmt, ##args)
+#define lbtf_deb_join(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_JOIN, " join", fmt, ##args)
+#define lbtf_deb_11d(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_11D, " 11d", fmt, ##args)
+#define lbtf_deb_debugfs(fmt, args...)   LBTF_DEB_LL(LBTF_DEB_DEBUGFS, " debugfs", fmt, ##args)
+#define lbtf_deb_ethtool(fmt, args...)   LBTF_DEB_LL(LBTF_DEB_ETHTOOL, " ethtool", fmt, ##args)
+#define lbtf_deb_host(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_HOST, " host", fmt, ##args)
+#define lbtf_deb_cmd(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_CMD, " cmd", fmt, ##args)
+#define lbtf_deb_rx(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_RX, " rx", fmt, ##args)
+#define lbtf_deb_tx(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_TX, " tx", fmt, ##args)
+#define lbtf_deb_fw(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_FW, " fw", fmt, ##args)
+#define lbtf_deb_usb(fmt, args...)       LBTF_DEB_LL(LBTF_DEB_USB, " usb", fmt, ##args)
+#define lbtf_deb_usbd(dev, fmt, args...) LBTF_DEB_LL(LBTF_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args)
+#define lbtf_deb_cs(fmt, args...)        LBTF_DEB_LL(LBTF_DEB_CS, " cs", fmt, ##args)
+#define lbtf_deb_thread(fmt, args...)    LBTF_DEB_LL(LBTF_DEB_THREAD, " thread", fmt, ##args)
+#define lbtf_deb_sdio(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_SDIO, " thread", fmt, ##args)
+#define lbtf_deb_macops(fmt, args...)      LBTF_DEB_LL(LBTF_DEB_MACOPS, " thread", fmt, ##args)
+
+#ifdef DEBUG
+static inline void lbtf_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
+{
+       char newprompt[32];
+
+       if (len &&
+           (lbtf_debug & LBTF_DEB_HEX) &&
+           (lbtf_debug & grp)) {
+               snprintf(newprompt, sizeof(newprompt), DRV_NAME " %s: ", prompt);
+               print_hex_dump_bytes(prompt, DUMP_PREFIX_NONE, buf, len);
+       }
+}
+#else
+#define lbtf_deb_hex(grp, prompt, buf, len)    do {} while (0)
+#endif
+
+#endif
index 8cc9db60c14b5c8e52fe8183feac773406cdcbc1..c445500ffc61b95e1e5834aaab6c8a8f2a4e7df6 100644 (file)
@@ -7,6 +7,13 @@
  *  the Free Software Foundation; either version 2 of the License, or (at
  *  your option) any later version.
  */
+#define DRV_NAME "lbtf_usb"
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "libertas_tf.h"
+#include "if_usb.h"
+
 #include <linux/delay.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
 
-#define DRV_NAME "lbtf_usb"
-
-#include "libertas_tf.h"
-#include "if_usb.h"
+#define INSANEDEBUG    0
+#define lbtf_deb_usb2(...) do { if (INSANEDEBUG) lbtf_deb_usbd(__VA_ARGS__); } while (0)
 
 #define MESSAGE_HEADER_LEN     4
 
@@ -53,9 +58,14 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
  */
 static void if_usb_write_bulk_callback(struct urb *urb)
 {
-       if (urb->status != 0)
-               printk(KERN_INFO "libertastf: URB in failure status: %d\n",
-                      urb->status);
+       if (urb->status != 0) {
+               /* print the failure status number for debug */
+               pr_info("URB in failure status: %d\n", urb->status);
+       } else {
+               lbtf_deb_usb2(&urb->dev->dev, "URB status is successful\n");
+               lbtf_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n",
+                            urb->actual_length);
+       }
 }
 
 /**
@@ -65,6 +75,8 @@ static void if_usb_write_bulk_callback(struct urb *urb)
  */
 static void if_usb_free(struct if_usb_card *cardp)
 {
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        /* Unlink tx & rx urb */
        usb_kill_urb(cardp->tx_urb);
        usb_kill_urb(cardp->rx_urb);
@@ -81,6 +93,8 @@ static void if_usb_free(struct if_usb_card *cardp)
 
        kfree(cardp->ep_out_buf);
        cardp->ep_out_buf = NULL;
+
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 static void if_usb_setup_firmware(struct lbtf_private *priv)
@@ -88,23 +102,33 @@ static void if_usb_setup_firmware(struct lbtf_private *priv)
        struct if_usb_card *cardp = priv->card;
        struct cmd_ds_set_boot2_ver b2_cmd;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        if_usb_submit_rx_urb(cardp);
        b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd));
        b2_cmd.action = 0;
        b2_cmd.version = cardp->boot2_version;
 
        if (lbtf_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd))
-               printk(KERN_INFO "libertastf: setting boot2 version failed\n");
+               lbtf_deb_usb("Setting boot2 version failed\n");
+
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 static void if_usb_fw_timeo(unsigned long priv)
 {
        struct if_usb_card *cardp = (void *)priv;
 
-       if (!cardp->fwdnldover)
+       lbtf_deb_enter(LBTF_DEB_USB);
+       if (!cardp->fwdnldover) {
                /* Download timed out */
                cardp->priv->surpriseremoved = 1;
+               pr_err("Download timed out\n");
+       } else {
+               lbtf_deb_usb("Download complete, no event. Assuming success\n");
+       }
        wake_up(&cardp->fw_wq);
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 /**
@@ -125,11 +149,14 @@ static int if_usb_probe(struct usb_interface *intf,
        struct if_usb_card *cardp;
        int i;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
        udev = interface_to_usbdev(intf);
 
        cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
-       if (!cardp)
+       if (!cardp) {
+               pr_err("Out of memory allocating private data.\n");
                goto error;
+       }
 
        setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp);
        init_waitqueue_head(&cardp->fw_wq);
@@ -137,38 +164,62 @@ static int if_usb_probe(struct usb_interface *intf,
        cardp->udev = udev;
        iface_desc = intf->cur_altsetting;
 
+       lbtf_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+                    " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+                    le16_to_cpu(udev->descriptor.bcdUSB),
+                    udev->descriptor.bDeviceClass,
+                    udev->descriptor.bDeviceSubClass,
+                    udev->descriptor.bDeviceProtocol);
+
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
                if (usb_endpoint_is_bulk_in(endpoint)) {
                        cardp->ep_in_size =
                                le16_to_cpu(endpoint->wMaxPacketSize);
                        cardp->ep_in = usb_endpoint_num(endpoint);
+
+                       lbtf_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in);
+                       lbtf_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size);
                } else if (usb_endpoint_is_bulk_out(endpoint)) {
                        cardp->ep_out_size =
                                le16_to_cpu(endpoint->wMaxPacketSize);
                        cardp->ep_out = usb_endpoint_num(endpoint);
+
+                       lbtf_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out);
+                       lbtf_deb_usbd(&udev->dev, "Bulk out size is %d\n",
+                                     cardp->ep_out_size);
                }
        }
-       if (!cardp->ep_out_size || !cardp->ep_in_size)
+       if (!cardp->ep_out_size || !cardp->ep_in_size) {
+               lbtf_deb_usbd(&udev->dev, "Endpoints not found\n");
                /* Endpoints not found */
                goto dealloc;
+       }
 
        cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!cardp->rx_urb)
+       if (!cardp->rx_urb) {
+               lbtf_deb_usbd(&udev->dev, "Rx URB allocation failed\n");
                goto dealloc;
+       }
 
        cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!cardp->tx_urb)
+       if (!cardp->tx_urb) {
+               lbtf_deb_usbd(&udev->dev, "Tx URB allocation failed\n");
                goto dealloc;
+       }
 
        cardp->cmd_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!cardp->cmd_urb)
+       if (!cardp->cmd_urb) {
+               lbtf_deb_usbd(&udev->dev, "Cmd URB allocation failed\n");
                goto dealloc;
+       }
 
        cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
                                    GFP_KERNEL);
-       if (!cardp->ep_out_buf)
+       if (!cardp->ep_out_buf) {
+               lbtf_deb_usbd(&udev->dev, "Could not allocate buffer\n");
                goto dealloc;
+       }
 
        priv = lbtf_add_card(cardp, &udev->dev);
        if (!priv)
@@ -189,6 +240,7 @@ static int if_usb_probe(struct usb_interface *intf,
 dealloc:
        if_usb_free(cardp);
 error:
+lbtf_deb_leave(LBTF_DEB_MAIN);
        return -ENOMEM;
 }
 
@@ -202,6 +254,8 @@ static void if_usb_disconnect(struct usb_interface *intf)
        struct if_usb_card *cardp = usb_get_intfdata(intf);
        struct lbtf_private *priv = (struct lbtf_private *) cardp->priv;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        if_usb_reset_device(cardp);
 
        if (priv)
@@ -212,6 +266,8 @@ static void if_usb_disconnect(struct usb_interface *intf)
 
        usb_set_intfdata(intf, NULL);
        usb_put_dev(interface_to_usbdev(intf));
+
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 /**
@@ -226,6 +282,8 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
        struct fwdata *fwdata = cardp->ep_out_buf;
        u8 *firmware = (u8 *) cardp->fw->data;
 
+       lbtf_deb_enter(LBTF_DEB_FW);
+
        /* If we got a CRC failure on the last block, back
           up and retry it */
        if (!cardp->CRC_OK) {
@@ -233,6 +291,9 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
                cardp->fwseqnum--;
        }
 
+       lbtf_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n",
+                    cardp->totalbytes);
+
        /* struct fwdata (which we sent to the card) has an
           extra __le32 field in between the header and the data,
           which is not in the struct fwheader in the actual
@@ -246,18 +307,33 @@ static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
        memcpy(fwdata->data, &firmware[cardp->totalbytes],
               le32_to_cpu(fwdata->hdr.datalength));
 
+       lbtf_deb_usb2(&cardp->udev->dev, "Data length = %d\n",
+                    le32_to_cpu(fwdata->hdr.datalength));
+
        fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum);
        cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength);
 
        usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) +
                     le32_to_cpu(fwdata->hdr.datalength), 0);
 
-       if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK))
+       if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) {
+               lbtf_deb_usb2(&cardp->udev->dev, "There are data to follow\n");
+               lbtf_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n",
+                            cardp->fwseqnum, cardp->totalbytes);
+       } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
+               lbtf_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n");
+               lbtf_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n");
+
                /* Host has finished FW downloading
                 * Donwloading FW JUMP BLOCK
                 */
                cardp->fwfinalblk = 1;
+       }
 
+       lbtf_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n",
+                    cardp->totalbytes);
+
+       lbtf_deb_leave(LBTF_DEB_FW);
        return 0;
 }
 
@@ -266,6 +342,8 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
        struct cmd_ds_802_11_reset *cmd = cardp->ep_out_buf + 4;
        int ret;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
 
        cmd->hdr.command = cpu_to_le16(CMD_802_11_RESET);
@@ -280,6 +358,8 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
        ret = usb_reset_device(cardp->udev);
        msleep(100);
 
+       lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(if_usb_reset_device);
@@ -297,11 +377,15 @@ EXPORT_SYMBOL_GPL(if_usb_reset_device);
 static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
                        uint16_t nb, u8 data)
 {
+       int ret = -1;
        struct urb *urb;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
        /* check if device is removed */
-       if (cardp->priv->surpriseremoved)
-               return -1;
+       if (cardp->priv->surpriseremoved) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Device removed\n");
+               goto tx_ret;
+       }
 
        if (data)
                urb = cardp->tx_urb;
@@ -315,19 +399,34 @@ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload,
 
        urb->transfer_flags |= URB_ZERO_PACKET;
 
-       if (usb_submit_urb(urb, GFP_ATOMIC))
-               return -1;
-       return 0;
+       if (usb_submit_urb(urb, GFP_ATOMIC)) {
+               lbtf_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret);
+               goto tx_ret;
+       }
+
+       lbtf_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n");
+
+       ret = 0;
+
+tx_ret:
+       lbtf_deb_leave(LBTF_DEB_USB);
+       return ret;
 }
 
 static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
                                  void (*callbackfn)(struct urb *urb))
 {
        struct sk_buff *skb;
+       int ret = -1;
+
+       lbtf_deb_enter(LBTF_DEB_USB);
 
        skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
-       if (!skb)
+       if (!skb) {
+               pr_err("No free skb\n");
+               lbtf_deb_leave(LBTF_DEB_USB);
                return -1;
+       }
 
        cardp->rx_skb = skb;
 
@@ -339,12 +438,19 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
 
        cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
 
-       if (usb_submit_urb(cardp->rx_urb, GFP_ATOMIC)) {
+       lbtf_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+       ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC);
+       if (ret) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret);
                kfree_skb(skb);
                cardp->rx_skb = NULL;
+               lbtf_deb_leave(LBTF_DEB_USB);
                return -1;
-       } else
+       } else {
+               lbtf_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n");
+               lbtf_deb_leave(LBTF_DEB_USB);
                return 0;
+       }
 }
 
 static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp)
@@ -364,8 +470,12 @@ static void if_usb_receive_fwload(struct urb *urb)
        struct fwsyncheader *syncfwheader;
        struct bootcmdresp bcmdresp;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
        if (urb->status) {
+               lbtf_deb_usbd(&cardp->udev->dev,
+                            "URB status is failed during fw load\n");
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
@@ -373,12 +483,17 @@ static void if_usb_receive_fwload(struct urb *urb)
                __le32 *tmp = (__le32 *)(skb->data);
 
                if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
-                   tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY))
+                   tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
                        /* Firmware ready event received */
+                       pr_info("Firmware ready event received\n");
                        wake_up(&cardp->fw_wq);
-               else
+               } else {
+                       lbtf_deb_usb("Waiting for confirmation; got %x %x\n",
+                                   le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1]));
                        if_usb_submit_rx_urb_fwload(cardp);
+               }
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
        if (cardp->bootcmdresp <= 0) {
@@ -389,34 +504,60 @@ static void if_usb_receive_fwload(struct urb *urb)
                        if_usb_submit_rx_urb_fwload(cardp);
                        cardp->bootcmdresp = 1;
                        /* Received valid boot command response */
+                       lbtf_deb_usbd(&cardp->udev->dev,
+                                    "Received valid boot command response\n");
+                       lbtf_deb_leave(LBTF_DEB_USB);
                        return;
                }
                if (bcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) {
                        if (bcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) ||
                            bcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
-                           bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION))
+                           bcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
+                               if (!cardp->bootcmdresp)
+                                       pr_info("Firmware already seems alive; resetting\n");
                                cardp->bootcmdresp = -1;
-               } else if (bcmdresp.cmd == BOOT_CMD_FW_BY_USB &&
-                          bcmdresp.result == BOOT_CMD_RESP_OK)
+                       } else {
+                               pr_info("boot cmd response wrong magic number (0x%x)\n",
+                                           le32_to_cpu(bcmdresp.magic));
+                       }
+               } else if (bcmdresp.cmd != BOOT_CMD_FW_BY_USB) {
+                       pr_info("boot cmd response cmd_tag error (%d)\n",
+                                   bcmdresp.cmd);
+               } else if (bcmdresp.result != BOOT_CMD_RESP_OK) {
+                       pr_info("boot cmd response result error (%d)\n",
+                                   bcmdresp.result);
+               } else {
                        cardp->bootcmdresp = 1;
+                       lbtf_deb_usbd(&cardp->udev->dev,
+                                    "Received valid boot command response\n");
+               }
 
                kfree_skb(skb);
                if_usb_submit_rx_urb_fwload(cardp);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
        syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
        if (!syncfwheader) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
        memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
 
-       if (!syncfwheader->cmd)
+       if (!syncfwheader->cmd) {
+               lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
+               lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
+                            le32_to_cpu(syncfwheader->seqnum));
                cardp->CRC_OK = 1;
-       else
+       } else {
+               lbtf_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n");
                cardp->CRC_OK = 0;
+       }
+
        kfree_skb(skb);
 
        /* reschedule timer for 200ms hence */
@@ -434,7 +575,7 @@ static void if_usb_receive_fwload(struct urb *urb)
 
        kfree(syncfwheader);
 
-       return;
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 #define MRVDRV_MIN_PKT_LEN     30
@@ -445,6 +586,7 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
 {
        if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN
            || recvlength < MRVDRV_MIN_PKT_LEN) {
+               lbtf_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n");
                kfree_skb(skb);
                return;
        }
@@ -460,6 +602,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
                                      struct lbtf_private *priv)
 {
        if (recvlength > LBS_CMD_BUFFER_SIZE) {
+               lbtf_deb_usbd(&cardp->udev->dev,
+                            "The receive buffer is too large\n");
                kfree_skb(skb);
                return;
        }
@@ -489,16 +633,24 @@ static void if_usb_receive(struct urb *urb)
        uint32_t recvtype = 0;
        __le32 *pkt = (__le32 *) skb->data;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        if (recvlength) {
                if (urb->status) {
+                       lbtf_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n",
+                                    urb->status);
                        kfree_skb(skb);
                        goto setup_for_next;
                }
 
                recvbuff = skb->data;
                recvtype = le32_to_cpu(pkt[0]);
+               lbtf_deb_usbd(&cardp->udev->dev,
+                           "Recv length = 0x%x, Recv type = 0x%X\n",
+                           recvlength, recvtype);
        } else if (urb->status) {
                kfree_skb(skb);
+               lbtf_deb_leave(LBTF_DEB_USB);
                return;
        }
 
@@ -515,6 +667,7 @@ static void if_usb_receive(struct urb *urb)
        {
                /* Event cause handling */
                u32 event_cause = le32_to_cpu(pkt[1]);
+               lbtf_deb_usbd(&cardp->udev->dev, "**EVENT** 0x%X\n", event_cause);
 
                /* Icky undocumented magic special case */
                if (event_cause & 0xffff0000) {
@@ -529,21 +682,22 @@ static void if_usb_receive(struct urb *urb)
                } else if (event_cause == LBTF_EVENT_BCN_SENT)
                        lbtf_bcn_sent(priv);
                else
-                       printk(KERN_DEBUG
+                       lbtf_deb_usbd(&cardp->udev->dev,
                               "Unsupported notification %d received\n",
                               event_cause);
                kfree_skb(skb);
                break;
        }
        default:
-               printk(KERN_DEBUG "libertastf: unknown command type 0x%X\n",
-                            recvtype);
+               lbtf_deb_usbd(&cardp->udev->dev,
+                        "libertastf: unknown command type 0x%X\n", recvtype);
                kfree_skb(skb);
                break;
        }
 
 setup_for_next:
        if_usb_submit_rx_urb(cardp);
+       lbtf_deb_leave(LBTF_DEB_USB);
 }
 
 /**
@@ -562,6 +716,9 @@ static int if_usb_host_to_card(struct lbtf_private *priv, uint8_t type,
        struct if_usb_card *cardp = priv->card;
        u8 data = 0;
 
+       lbtf_deb_usbd(&cardp->udev->dev, "*** type = %u\n", type);
+       lbtf_deb_usbd(&cardp->udev->dev, "size after = %d\n", nb);
+
        if (type == MVMS_CMD) {
                *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST);
        } else {
@@ -639,8 +796,10 @@ static int check_fwfile_format(const u8 *data, u32 totlen)
        } while (!exit);
 
        if (ret)
-               printk(KERN_INFO
-                      "libertastf: firmware file format check failed\n");
+               pr_err("firmware file format check FAIL\n");
+       else
+               lbtf_deb_fw("firmware file format check PASS\n");
+
        return ret;
 }
 
@@ -651,10 +810,12 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
        static int reset_count = 10;
        int ret = 0;
 
+       lbtf_deb_enter(LBTF_DEB_USB);
+
        ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
        if (ret < 0) {
-               printk(KERN_INFO "libertastf: firmware %s not found\n",
-                      lbtf_fw_name);
+               pr_err("request_firmware() failed with %#x\n", ret);
+               pr_err("firmware %s not found\n", lbtf_fw_name);
                goto done;
        }
 
@@ -663,6 +824,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
 
 restart:
        if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
+               lbtf_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
                ret = -1;
                goto release_fw;
        }
@@ -709,14 +871,13 @@ restart:
        usb_kill_urb(cardp->rx_urb);
 
        if (!cardp->fwdnldover) {
-               printk(KERN_INFO "libertastf: failed to load fw,"
-                                " resetting device!\n");
+               pr_info("failed to load fw, resetting device!\n");
                if (--reset_count >= 0) {
                        if_usb_reset_device(cardp);
                        goto restart;
                }
 
-               printk(KERN_INFO "libertastf: fw download failure\n");
+               pr_info("FW download failure, time = %d ms\n", i * 100);
                ret = -1;
                goto release_fw;
        }
@@ -730,6 +891,7 @@ restart:
        if_usb_setup_firmware(cardp->priv);
 
  done:
+       lbtf_deb_leave_args(LBTF_DEB_USB, "ret %d", ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(if_usb_prog_firmware);
@@ -751,13 +913,19 @@ static int __init if_usb_init_module(void)
 {
        int ret = 0;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        ret = usb_register(&if_usb_driver);
+
+       lbtf_deb_leave_args(LBTF_DEB_MAIN, "ret %d", ret);
        return ret;
 }
 
 static void __exit if_usb_exit_module(void)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        usb_deregister(&if_usb_driver);
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 module_init(if_usb_init_module);
index 4cc42dd5a005258f10055bcaae3e61617e3bb2e9..fbbaaae7a1aefe4274c5ec0d31d58c2d0acdbe83 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/kthread.h>
 #include <net/mac80211.h>
 
+#include "deb_defs.h"
+
 #ifndef DRV_NAME
 #define DRV_NAME "libertas_tf"
 #endif
index 7945ff5aa3345fc5013ed7942878b598483482b4..6a04c2157f73f3788109afcdfbc50c4ecdf62b9e 100644 (file)
@@ -7,10 +7,12 @@
  *  the Free Software Foundation; either version 2 of the License, or (at
  *  your option) any later version.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 
+#include <linux/etherdevice.h>
 #include "libertas_tf.h"
-#include "linux/etherdevice.h"
 
 #define DRIVER_RELEASE_VERSION "004.p0"
 /* thinfirm version: 5.132.X.pX */
 #define LBTF_FW_VER_MAX                0x0584ffff
 #define QOS_CONTROL_LEN                2
 
-static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION;
+/* Module parameters */
+unsigned int lbtf_debug;
+EXPORT_SYMBOL_GPL(lbtf_debug);
+module_param_named(libertas_tf_debug, lbtf_debug, int, 0644);
+
+static const char lbtf_driver_version[] = "THINFIRM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef DEBUG
+       "-dbg"
+#endif
+       "";
+
 struct workqueue_struct *lbtf_wq;
 
 static const struct ieee80211_channel lbtf_channels[] = {
@@ -81,6 +93,9 @@ static void lbtf_cmd_work(struct work_struct *work)
 {
        struct lbtf_private *priv = container_of(work, struct lbtf_private,
                                         cmd_work);
+
+       lbtf_deb_enter(LBTF_DEB_CMD);
+
        spin_lock_irq(&priv->driver_lock);
        /* command response? */
        if (priv->cmd_response_rxed) {
@@ -108,11 +123,16 @@ static void lbtf_cmd_work(struct work_struct *work)
        priv->cmd_timed_out = 0;
        spin_unlock_irq(&priv->driver_lock);
 
-       if (!priv->fw_ready)
+       if (!priv->fw_ready) {
+               lbtf_deb_leave_args(LBTF_DEB_CMD, "fw not ready");
                return;
+       }
+
        /* Execute the next command */
        if (!priv->cur_cmd)
                lbtf_execute_next_command(priv);
+
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 /**
@@ -126,6 +146,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
 {
        int ret = -1;
 
+       lbtf_deb_enter(LBTF_DEB_FW);
        /*
         * Read priv address from HW
         */
@@ -141,6 +162,7 @@ static int lbtf_setup_firmware(struct lbtf_private *priv)
 
        ret = 0;
 done:
+       lbtf_deb_leave_args(LBTF_DEB_FW, "ret: %d", ret);
        return ret;
 }
 
@@ -152,6 +174,7 @@ static void command_timer_fn(unsigned long data)
 {
        struct lbtf_private *priv = (struct lbtf_private *)data;
        unsigned long flags;
+       lbtf_deb_enter(LBTF_DEB_CMD);
 
        spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -168,10 +191,12 @@ static void command_timer_fn(unsigned long data)
        queue_work(lbtf_wq, &priv->cmd_work);
 out:
        spin_unlock_irqrestore(&priv->driver_lock, flags);
+       lbtf_deb_leave(LBTF_DEB_CMD);
 }
 
 static int lbtf_init_adapter(struct lbtf_private *priv)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        memset(priv->current_addr, 0xff, ETH_ALEN);
        mutex_init(&priv->lock);
 
@@ -188,13 +213,16 @@ static int lbtf_init_adapter(struct lbtf_private *priv)
        if (lbtf_allocate_cmd_buffer(priv))
                return -1;
 
+       lbtf_deb_leave(LBTF_DEB_MAIN);
        return 0;
 }
 
 static void lbtf_free_adapter(struct lbtf_private *priv)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        lbtf_free_cmd_buffer(priv);
        del_timer(&priv->command_timer);
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
@@ -221,14 +249,18 @@ static void lbtf_tx_work(struct work_struct *work)
        struct sk_buff *skb = NULL;
        int err;
 
+       lbtf_deb_enter(LBTF_DEB_MACOPS | LBTF_DEB_TX);
+
        if ((priv->vif->type == NL80211_IFTYPE_AP) &&
            (!skb_queue_empty(&priv->bc_ps_buf)))
                skb = skb_dequeue(&priv->bc_ps_buf);
        else if (priv->skb_to_tx) {
                skb = priv->skb_to_tx;
                priv->skb_to_tx = NULL;
-       } else
+       } else {
+               lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
                return;
+       }
 
        len = skb->len;
        info  = IEEE80211_SKB_CB(skb);
@@ -236,6 +268,7 @@ static void lbtf_tx_work(struct work_struct *work)
 
        if (priv->surpriseremoved) {
                dev_kfree_skb_any(skb);
+               lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
                return;
        }
 
@@ -249,6 +282,7 @@ static void lbtf_tx_work(struct work_struct *work)
                ETH_ALEN);
        txpd->tx_packet_length = cpu_to_le16(len);
        txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
+       lbtf_deb_hex(LBTF_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
        BUG_ON(priv->tx_skb);
        spin_lock_irq(&priv->driver_lock);
        priv->tx_skb = skb;
@@ -257,7 +291,9 @@ static void lbtf_tx_work(struct work_struct *work)
        if (err) {
                dev_kfree_skb_any(skb);
                priv->tx_skb = NULL;
+               pr_err("TX error: %d", err);
        }
+       lbtf_deb_leave(LBTF_DEB_MACOPS | LBTF_DEB_TX);
 }
 
 static int lbtf_op_start(struct ieee80211_hw *hw)
@@ -266,6 +302,8 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
        void *card = priv->card;
        int ret = -1;
 
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
+
        if (!priv->fw_ready)
                /* Upload firmware */
                if (priv->hw_prog_firmware(card))
@@ -286,10 +324,12 @@ static int lbtf_op_start(struct ieee80211_hw *hw)
        }
 
        printk(KERN_INFO "libertastf: Marvell WLAN 802.11 thinfirm adapter\n");
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return 0;
 
 err_prog_firmware:
        priv->hw_reset_device(card);
+       lbtf_deb_leave_args(LBTF_DEB_MACOPS, "error programing fw; ret=%d", ret);
        return ret;
 }
 
@@ -300,6 +340,9 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
        struct sk_buff *skb;
 
        struct cmd_ctrl_node *cmdnode;
+
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
+
        /* Flush pending command nodes */
        spin_lock_irqsave(&priv->driver_lock, flags);
        list_for_each_entry(cmdnode, &priv->cmdpendingq, list) {
@@ -316,13 +359,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw)
        priv->radioon = RADIO_OFF;
        lbtf_set_radio_control(priv);
 
-       return;
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static int lbtf_op_add_interface(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif)
 {
        struct lbtf_private *priv = hw->priv;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
        if (priv->vif != NULL)
                return -EOPNOTSUPP;
 
@@ -340,6 +384,7 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw,
                return -EOPNOTSUPP;
        }
        lbtf_set_mac_address(priv, (u8 *) vif->addr);
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return 0;
 }
 
@@ -347,6 +392,7 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif)
 {
        struct lbtf_private *priv = hw->priv;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
 
        if (priv->vif->type == NL80211_IFTYPE_AP ||
            priv->vif->type == NL80211_IFTYPE_MESH_POINT)
@@ -354,37 +400,38 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw,
        lbtf_set_mode(priv, LBTF_PASSIVE_MODE);
        lbtf_set_bssid(priv, 0, NULL);
        priv->vif = NULL;
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct lbtf_private *priv = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
 
        if (conf->channel->center_freq != priv->cur_freq) {
                priv->cur_freq = conf->channel->center_freq;
                lbtf_set_channel(priv, conf->channel->hw_value);
        }
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
        return 0;
 }
 
 static u64 lbtf_op_prepare_multicast(struct ieee80211_hw *hw,
-                                    int mc_count, struct dev_addr_list *mclist)
+                                    struct netdev_hw_addr_list *mc_list)
 {
        struct lbtf_private *priv = hw->priv;
        int i;
+       struct netdev_hw_addr *ha;
+       int mc_count = netdev_hw_addr_list_count(mc_list);
 
        if (!mc_count || mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE)
                return mc_count;
 
        priv->nr_of_multicastmacaddr = mc_count;
-       for (i = 0; i < mc_count; i++) {
-               if (!mclist)
-                       break;
-               memcpy(&priv->multicastlist[i], mclist->da_addr,
-                               ETH_ALEN);
-               mclist = mclist->next;
-       }
+       i = 0;
+       netdev_hw_addr_list_for_each(ha, mc_list)
+               memcpy(&priv->multicastlist[i++], ha->addr, ETH_ALEN);
 
        return mc_count;
 }
@@ -397,11 +444,16 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
 {
        struct lbtf_private *priv = hw->priv;
        int old_mac_control = priv->mac_control;
+
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
+
        changed_flags &= SUPPORTED_FIF_FLAGS;
        *new_flags &= SUPPORTED_FIF_FLAGS;
 
-       if (!changed_flags)
+       if (!changed_flags) {
+               lbtf_deb_leave(LBTF_DEB_MACOPS);
                return;
+       }
 
        if (*new_flags & (FIF_PROMISC_IN_BSS))
                priv->mac_control |= CMD_ACT_MAC_PROMISCUOUS_ENABLE;
@@ -427,6 +479,8 @@ static void lbtf_op_configure_filter(struct ieee80211_hw *hw,
 
        if (priv->mac_control != old_mac_control)
                lbtf_set_mac_control(priv);
+
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
@@ -436,6 +490,7 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct lbtf_private *priv = hw->priv;
        struct sk_buff *beacon;
+       lbtf_deb_enter(LBTF_DEB_MACOPS);
 
        if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_INT)) {
                switch (priv->vif->type) {
@@ -466,6 +521,8 @@ static void lbtf_op_bss_info_changed(struct ieee80211_hw *hw,
                        priv->preamble = CMD_TYPE_LONG_PREAMBLE;
                lbtf_set_radio_control(priv);
        }
+
+       lbtf_deb_leave(LBTF_DEB_MACOPS);
 }
 
 static const struct ieee80211_ops lbtf_ops = {
@@ -488,6 +545,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
        unsigned int flags;
        struct ieee80211_hdr *hdr;
 
+       lbtf_deb_enter(LBTF_DEB_RX);
+
        prxpd = (struct rxpd *) skb->data;
 
        stats.flag = 0;
@@ -496,7 +555,6 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
        stats.freq = priv->cur_freq;
        stats.band = IEEE80211_BAND_2GHZ;
        stats.signal = prxpd->snr;
-       stats.noise = prxpd->nf;
        /* Marvell rate index has a hole at value 4 */
        if (prxpd->rx_rate > 4)
                --prxpd->rx_rate;
@@ -518,7 +576,15 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
        }
 
        memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+
+       lbtf_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
+              skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+       lbtf_deb_hex(LBTF_DEB_RX, "RX Data", skb->data,
+                    min_t(unsigned int, skb->len, 100));
+
        ieee80211_rx_irqsafe(priv->hw, skb);
+
+       lbtf_deb_leave(LBTF_DEB_RX);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lbtf_rx);
@@ -535,6 +601,8 @@ struct lbtf_private *lbtf_add_card(void *card, struct device *dmdev)
        struct ieee80211_hw *hw;
        struct lbtf_private *priv = NULL;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        hw = ieee80211_alloc_hw(sizeof(struct lbtf_private), &lbtf_ops);
        if (!hw)
                goto done;
@@ -577,6 +645,7 @@ err_init_adapter:
        priv = NULL;
 
 done:
+       lbtf_deb_leave_args(LBTF_DEB_MAIN, "priv %p", priv);
        return priv;
 }
 EXPORT_SYMBOL_GPL(lbtf_add_card);
@@ -586,6 +655,8 @@ int lbtf_remove_card(struct lbtf_private *priv)
 {
        struct ieee80211_hw *hw = priv->hw;
 
+       lbtf_deb_enter(LBTF_DEB_MAIN);
+
        priv->surpriseremoved = 1;
        del_timer(&priv->command_timer);
        lbtf_free_adapter(priv);
@@ -593,6 +664,7 @@ int lbtf_remove_card(struct lbtf_private *priv)
        ieee80211_unregister_hw(hw);
        ieee80211_free_hw(hw);
 
+    lbtf_deb_leave(LBTF_DEB_MAIN);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lbtf_remove_card);
@@ -651,17 +723,21 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent);
 
 static int __init lbtf_init_module(void)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        lbtf_wq = create_workqueue("libertastf");
        if (lbtf_wq == NULL) {
                printk(KERN_ERR "libertastf: couldn't create workqueue\n");
                return -ENOMEM;
        }
+       lbtf_deb_leave(LBTF_DEB_MAIN);
        return 0;
 }
 
 static void __exit lbtf_exit_module(void)
 {
+       lbtf_deb_enter(LBTF_DEB_MAIN);
        destroy_workqueue(lbtf_wq);
+       lbtf_deb_leave(LBTF_DEB_MAIN);
 }
 
 module_init(lbtf_init_module);
index 7cd5f56662fcfe1176deeeffc2a010b7ed843a3e..6f8cb3ee6fed57610ed56756982daf4a4497b493 100644 (file)
@@ -291,7 +291,8 @@ struct mac80211_hwsim_data {
        struct ieee80211_channel *channel;
        unsigned long beacon_int; /* in jiffies unit */
        unsigned int rx_filter;
-       bool started, idle;
+       bool started, idle, scanning;
+       struct mutex mutex;
        struct timer_list beacon_timer;
        enum ps_mode {
                PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL
@@ -651,17 +652,17 @@ static void mac80211_hwsim_beacon(unsigned long arg)
        add_timer(&data->beacon_timer);
 }
 
+static const char *hwsim_chantypes[] = {
+       [NL80211_CHAN_NO_HT] = "noht",
+       [NL80211_CHAN_HT20] = "ht20",
+       [NL80211_CHAN_HT40MINUS] = "ht40-",
+       [NL80211_CHAN_HT40PLUS] = "ht40+",
+};
 
 static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        struct ieee80211_conf *conf = &hw->conf;
-       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",
@@ -672,7 +673,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
        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],
+              hwsim_chantypes[conf->channel_type],
               !!(conf->flags & IEEE80211_CONF_IDLE),
               !!(conf->flags & IEEE80211_CONF_PS),
               smps_modes[conf->smps_mode]);
@@ -760,9 +761,10 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_HT) {
-               printk(KERN_DEBUG "  %s: HT: op_mode=0x%x\n",
+               printk(KERN_DEBUG "  %s: HT: op_mode=0x%x, chantype=%s\n",
                       wiphy_name(hw->wiphy),
-                      info->ht_operation_mode);
+                      info->ht_operation_mode,
+                      hwsim_chantypes[info->channel_type]);
        }
 
        if (changed & BSS_CHANGED_BASIC_RATES) {
@@ -829,6 +831,33 @@ static int mac80211_hwsim_conf_tx(
        return 0;
 }
 
+static int mac80211_hwsim_get_survey(
+       struct ieee80211_hw *hw, int idx,
+       struct survey_info *survey)
+{
+       struct ieee80211_conf *conf = &hw->conf;
+
+       printk(KERN_DEBUG "%s:%s (idx=%d)\n",
+              wiphy_name(hw->wiphy), __func__, idx);
+
+       if (idx != 0)
+               return -ENOENT;
+
+       /* Current channel */
+       survey->channel = conf->channel;
+
+       /*
+        * Magically conjured noise level --- this is only ok for simulated hardware.
+        *
+        * A real driver which cannot determine the real channel noise MUST NOT
+        * report any noise, especially not a magically conjured one :-)
+        */
+       survey->filled = SURVEY_INFO_NOISE_DBM;
+       survey->noise = -92;
+
+       return 0;
+}
+
 #ifdef CONFIG_NL80211_TESTMODE
 /*
  * This section contains example code for using netlink
@@ -946,6 +975,7 @@ static void hw_scan_done(struct work_struct *work)
 }
 
 static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
                                  struct cfg80211_scan_request *req)
 {
        struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL);
@@ -957,9 +987,9 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
        hsd->hw = hw;
        INIT_DELAYED_WORK(&hsd->w, hw_scan_done);
 
-       printk(KERN_DEBUG "hwsim scan request\n");
+       printk(KERN_DEBUG "hwsim hw_scan request\n");
        for (i = 0; i < req->n_channels; i++)
-               printk(KERN_DEBUG "hwsim scan freq %d\n",
+               printk(KERN_DEBUG "hwsim hw_scan freq %d\n",
                        req->channels[i]->center_freq);
 
        ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ);
@@ -967,6 +997,36 @@ static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
        return 0;
 }
 
+static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       mutex_lock(&hwsim->mutex);
+
+       if (hwsim->scanning) {
+               printk(KERN_DEBUG "two hwsim sw_scans detected!\n");
+               goto out;
+       }
+
+       printk(KERN_DEBUG "hwsim sw_scan request, prepping stuff\n");
+       hwsim->scanning = true;
+
+out:
+       mutex_unlock(&hwsim->mutex);
+}
+
+static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       mutex_lock(&hwsim->mutex);
+
+       printk(KERN_DEBUG "hwsim sw_scan_complete\n");
+       hwsim->scanning = false;
+
+       mutex_unlock(&hwsim->mutex);
+}
+
 static struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -982,8 +1042,11 @@ static struct ieee80211_ops mac80211_hwsim_ops =
        .sta_notify = mac80211_hwsim_sta_notify,
        .set_tim = mac80211_hwsim_set_tim,
        .conf_tx = mac80211_hwsim_conf_tx,
+       .get_survey = mac80211_hwsim_get_survey,
        CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
        .ampdu_action = mac80211_hwsim_ampdu_action,
+       .sw_scan_start = mac80211_hwsim_sw_scan,
+       .sw_scan_complete = mac80211_hwsim_sw_scan_complete,
        .flush = mac80211_hwsim_flush,
 };
 
@@ -1179,8 +1242,11 @@ static int __init init_mac80211_hwsim(void)
        if (radios < 1 || radios > 100)
                return -EINVAL;
 
-       if (fake_hw_scan)
+       if (fake_hw_scan) {
                mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
+               mac80211_hwsim_ops.sw_scan_start = NULL;
+               mac80211_hwsim_ops.sw_scan_complete = NULL;
+       }
 
        spin_lock_init(&hwsim_radio_lock);
        INIT_LIST_HEAD(&hwsim_radios);
@@ -1235,7 +1301,8 @@ static int __init init_mac80211_hwsim(void)
                hw->flags = IEEE80211_HW_MFP_CAPABLE |
                            IEEE80211_HW_SIGNAL_DBM |
                            IEEE80211_HW_SUPPORTS_STATIC_SMPS |
-                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
+                           IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                           IEEE80211_HW_AMPDU_AGGREGATION;
 
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
@@ -1285,6 +1352,7 @@ static int __init init_mac80211_hwsim(void)
                }
                /* By default all radios are belonging to the first group */
                data->group = 1;
+               mutex_init(&data->mutex);
 
                /* Work to be done prior to ieee80211_register_hw() */
                switch (regtest) {
index 12fdcb25fd382dfc245aafd85dcb462ebdfa8f77..808adb9090952347feeaafe03b801bb8ae681b62 100644 (file)
@@ -750,7 +750,6 @@ mwl8k_rxd_8366_ap_process(void *_rxd, struct ieee80211_rx_status *status,
        memset(status, 0, sizeof(*status));
 
        status->signal = -rxd->rssi;
-       status->noise = -rxd->noise_floor;
 
        if (rxd->rate & MWL8K_8366_AP_RATE_INFO_MCS_FORMAT) {
                status->flag |= RX_FLAG_HT;
@@ -852,7 +851,6 @@ mwl8k_rxd_sta_process(void *_rxd, struct ieee80211_rx_status *status,
        memset(status, 0, sizeof(*status));
 
        status->signal = -rxd->rssi;
-       status->noise = -rxd->noise_level;
        status->antenna = MWL8K_STA_RATE_INFO_ANTSELECT(rate_info);
        status->rate_idx = MWL8K_STA_RATE_INFO_RATEID(rate_info);
 
@@ -1939,11 +1937,15 @@ struct mwl8k_cmd_mac_multicast_adr {
 
 static struct mwl8k_cmd_pkt *
 __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
-                             int mc_count, struct dev_addr_list *mclist)
+                             struct netdev_hw_addr_list *mc_list)
 {
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_cmd_mac_multicast_adr *cmd;
        int size;
+       int mc_count = 0;
+
+       if (mc_list)
+               mc_count = netdev_hw_addr_list_count(mc_list);
 
        if (allmulti || mc_count > priv->num_mcaddrs) {
                allmulti = 1;
@@ -1964,17 +1966,13 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
        if (allmulti) {
                cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_ALL_MULTICAST);
        } else if (mc_count) {
-               int i;
+               struct netdev_hw_addr *ha;
+               int i = 0;
 
                cmd->action |= cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
                cmd->numaddr = cpu_to_le16(mc_count);
-               for (i = 0; i < mc_count && mclist; i++) {
-                       if (mclist->da_addrlen != ETH_ALEN) {
-                               kfree(cmd);
-                               return NULL;
-                       }
-                       memcpy(cmd->addr[i], mclist->da_addr, ETH_ALEN);
-                       mclist = mclist->next;
+               netdev_hw_addr_list_for_each(ha, mc_list) {
+                       memcpy(cmd->addr[i], ha->addr, ETH_ALEN);
                }
        }
 
@@ -3553,7 +3551,7 @@ mwl8k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 }
 
 static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
-                                  int mc_count, struct dev_addr_list *mclist)
+                                  struct netdev_hw_addr_list *mc_list)
 {
        struct mwl8k_cmd_pkt *cmd;
 
@@ -3564,7 +3562,7 @@ static u64 mwl8k_prepare_multicast(struct ieee80211_hw *hw,
         * we'll end up throwing this packet away and creating a new
         * one in mwl8k_configure_filter().
         */
-       cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_count, mclist);
+       cmd = __mwl8k_cmd_mac_multicast_adr(hw, 0, mc_list);
 
        return (unsigned long)cmd;
 }
@@ -3687,7 +3685,7 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw,
         */
        if (*total_flags & FIF_ALLMULTI) {
                kfree(cmd);
-               cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, 0, NULL);
+               cmd = __mwl8k_cmd_mac_multicast_adr(hw, 1, NULL);
        }
 
        if (cmd != NULL) {
@@ -3984,8 +3982,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 
        hw->queues = MWL8K_TX_QUEUES;
 
-       /* Set rssi and noise values to dBm */
-       hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM;
+       /* Set rssi values to dBm */
+       hw->flags |= IEEE80211_HW_SIGNAL_DBM;
        hw->vif_data_size = sizeof(struct mwl8k_vif);
        hw->sta_data_size = sizeof(struct mwl8k_sta);
 
index e2a2c18920aa016f5d8220f454978931612d2029..60819bcf437735fd43a7f03d14ba988623e8e9e6 100644 (file)
@@ -27,6 +27,17 @@ config HERMES
          configure your card and that /etc/pcmcia/wireless.opts works :
          <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
 
+config HERMES_PRISM
+       bool "Support Prism 2/2.5 chipset"
+       depends on HERMES
+       ---help---
+
+         Say Y to enable support for Prism 2 and 2.5 chipsets.  These
+         chipsets are better handled by the hostap driver.  This driver
+         would not support WPA or firmware download for Prism chipset.
+
+         If you are not sure, say N.
+
 config HERMES_CACHE_FW_ON_INIT
        bool "Cache Hermes firmware on driver initialisation"
        depends on HERMES
@@ -86,7 +97,7 @@ config NORTEL_HERMES
 
 config PCI_HERMES
        tristate "Prism 2.5 PCI 802.11b adaptor support"
-       depends on PCI && HERMES
+       depends on PCI && HERMES && HERMES_PRISM
        help
          Enable support for PCI and mini-PCI 802.11b wireless NICs based on
          the Prism 2.5 chipset.  These are true PCI cards, not the 802.11b
@@ -121,3 +132,10 @@ config PCMCIA_SPECTRUM
          This driver requires firmware download on startup.  Utilities
          for downloading Symbol firmware are available at
          <http://sourceforge.net/projects/orinoco/>
+
+config ORINOCO_USB
+       tristate "Agere Orinoco USB support"
+       depends on USB && HERMES
+       select FW_LOADER
+       ---help---
+         This driver is for USB versions of the Agere Orinoco card.
index 9abd6329bcbd3548640e50c2653b3e79f2568d5b..bfdefb85abcdf1bffebc0e130ef81bd5546241fe 100644 (file)
@@ -11,3 +11,7 @@ obj-$(CONFIG_PCI_HERMES)      += orinoco_pci.o
 obj-$(CONFIG_TMD_HERMES)       += orinoco_tmd.o
 obj-$(CONFIG_NORTEL_HERMES)    += orinoco_nortel.o
 obj-$(CONFIG_PCMCIA_SPECTRUM)  += spectrum_cs.o
+obj-$(CONFIG_ORINOCO_USB)      += orinoco_usb.o
+
+# Orinoco should be endian clean.
+ccflags-y += -D__CHECK_ENDIAN__
index c60df2c1aca305166313aa5f3fc0e60fd201f9ba..9bcee10c9308f861089843ccfe7c9b3009907e6d 100644 (file)
@@ -77,9 +77,9 @@ airport_resume(struct macio_dev *mdev)
 
        enable_irq(card->irq);
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        err = orinoco_up(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        return err;
 }
@@ -195,7 +195,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
        ssleep(1);
 
        /* Reset it before we get the interrupt */
-       hermes_init(hw);
+       hw->ops->init(hw);
 
        if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
                printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
@@ -210,7 +210,7 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
        }
 
        /* Register an interface with the stack */
-       if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+       if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
index 27f2d334264535944d518ce4cac961e987f23e97..8c4169c227ae8786bdf9429012594b6521cbdbb4 100644 (file)
@@ -88,7 +88,9 @@ int orinoco_wiphy_register(struct wiphy *wiphy)
 
        wiphy->rts_threshold = priv->rts_thresh;
        if (!priv->has_mwo)
-               wiphy->frag_threshold = priv->frag_thresh;
+               wiphy->frag_threshold = priv->frag_thresh + 1;
+       wiphy->retry_short = priv->short_retry_limit;
+       wiphy->retry_long = priv->long_retry_limit;
 
        return wiphy_register(wiphy);
 }
@@ -157,6 +159,7 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int orinoco_set_channel(struct wiphy *wiphy,
+                       struct net_device *netdev,
                        struct ieee80211_channel *chan,
                        enum nl80211_channel_type channel_type)
 {
@@ -187,7 +190,7 @@ static int orinoco_set_channel(struct wiphy *wiphy,
        if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Fast channel change - no commit if successful */
                hermes_t *hw = &priv->hw;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_SET_CHANNEL,
                                        channel, NULL);
        }
@@ -196,8 +199,92 @@ static int orinoco_set_channel(struct wiphy *wiphy,
        return err;
 }
 
+static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+       struct orinoco_private *priv = wiphy_priv(wiphy);
+       int frag_value = -1;
+       int rts_value = -1;
+       int err = 0;
+
+       if (changed & WIPHY_PARAM_RETRY_SHORT) {
+               /* Setting short retry not supported */
+               err = -EINVAL;
+       }
+
+       if (changed & WIPHY_PARAM_RETRY_LONG) {
+               /* Setting long retry not supported */
+               err = -EINVAL;
+       }
+
+       if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+               /* Set fragmentation */
+               if (priv->has_mwo) {
+                       if (wiphy->frag_threshold < 0)
+                               frag_value = 0;
+                       else {
+                               printk(KERN_WARNING "%s: Fixed fragmentation "
+                                      "is not supported on this firmware. "
+                                      "Using MWO robust instead.\n",
+                                      priv->ndev->name);
+                               frag_value = 1;
+                       }
+               } else {
+                       if (wiphy->frag_threshold < 0)
+                               frag_value = 2346;
+                       else if ((wiphy->frag_threshold < 257) ||
+                                (wiphy->frag_threshold > 2347))
+                               err = -EINVAL;
+                       else
+                               /* cfg80211 value is 257-2347 (odd only)
+                                * orinoco rid has range 256-2346 (even only) */
+                               frag_value = wiphy->frag_threshold & ~0x1;
+               }
+       }
+
+       if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+               /* Set RTS.
+                *
+                * Prism documentation suggests default of 2432,
+                * and a range of 0-3000.
+                *
+                * Current implementation uses 2347 as the default and
+                * the upper limit.
+                */
+
+               if (wiphy->rts_threshold < 0)
+                       rts_value = 2347;
+               else if (wiphy->rts_threshold > 2347)
+                       err = -EINVAL;
+               else
+                       rts_value = wiphy->rts_threshold;
+       }
+
+       if (!err) {
+               unsigned long flags;
+
+               if (orinoco_lock(priv, &flags) != 0)
+                       return -EBUSY;
+
+               if (frag_value >= 0) {
+                       if (priv->has_mwo)
+                               priv->mwo_robust = frag_value;
+                       else
+                               priv->frag_thresh = frag_value;
+               }
+               if (rts_value >= 0)
+                       priv->rts_thresh = rts_value;
+
+               err = orinoco_commit(priv);
+
+               orinoco_unlock(priv, &flags);
+       }
+
+       return err;
+}
+
 const struct cfg80211_ops orinoco_cfg_ops = {
        .change_virtual_intf = orinoco_change_vif,
        .set_channel = orinoco_set_channel,
        .scan = orinoco_scan,
+       .set_wiphy_params = orinoco_set_wiphy_params,
 };
index 5ea0f7cf85b1d2f8653eb0941f2a50eeaf7861dc..3e1947d097ca83faf849b8de051eb506247f9cb3 100644 (file)
@@ -122,7 +122,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
 
        /* Read current plug data */
-       err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
+       err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
        dev_dbg(dev, "Read PDA returned %d\n", err);
        if (err)
                goto free;
@@ -149,7 +149,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        }
 
        /* Enable aux port to allow programming */
-       err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
+       err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
        dev_dbg(dev, "Program init returned %d\n", err);
        if (err != 0)
                goto abort;
@@ -177,7 +177,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
                goto abort;
 
        /* Tell card we've finished */
-       err = hermesi_program_end(hw);
+       err = hw->ops->program_end(hw);
        dev_dbg(dev, "Program end returned %d\n", err);
        if (err != 0)
                goto abort;
@@ -224,7 +224,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
                if (!pda)
                        return -ENOMEM;
 
-               ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
+               ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
                if (ret)
                        goto free;
        }
@@ -260,7 +260,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
        }
 
        /* Reset hermes chip and make sure it responds */
-       ret = hermes_init(hw);
+       ret = hw->ops->init(hw);
 
        /* hermes_reset() should return 0 with the secondary firmware */
        if (secondary && ret != 0)
index 1a2fca76fd3c87b87aef781dab91f1d9c8bb1ac4..6c6a23e08df652a8db97da4310cb2d4ca6e617f4 100644 (file)
 #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
 #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
 
+/*
+ * AUX port access.  To unlock the AUX port write the access keys to the
+ * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
+ * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
+ */
+#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
+#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
+#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
+#define HERMES_AUX_DISABLED    0x0000  /* Auxiliary port is closed */
+
+#define HERMES_AUX_PW0 0xFE01
+#define HERMES_AUX_PW1 0xDC23
+#define HERMES_AUX_PW2 0xBA45
+
+/* HERMES_CMD_DOWNLD */
+#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
+#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
+
 /*
  * Debugging helpers
  */
@@ -70,6 +90,7 @@
 
 #endif /* ! HERMES_DEBUG */
 
+static const struct hermes_ops hermes_ops_local;
 
 /*
  * Internal functions
@@ -111,9 +132,9 @@ static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0,
  */
 
 /* For doing cmds that wipe the magic constant in SWSUPPORT0 */
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-                      u16 parm0, u16 parm1, u16 parm2,
-                      struct hermes_response *resp)
+static int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
+                             u16 parm0, u16 parm1, u16 parm2,
+                             struct hermes_response *resp)
 {
        int err = 0;
        int k;
@@ -163,17 +184,18 @@ int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
 out:
        return err;
 }
-EXPORT_SYMBOL(hermes_doicmd_wait);
 
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing)
 {
        hw->iobase = address;
        hw->reg_spacing = reg_spacing;
        hw->inten = 0x0;
+       hw->eeprom_pda = false;
+       hw->ops = &hermes_ops_local;
 }
 EXPORT_SYMBOL(hermes_struct_init);
 
-int hermes_init(hermes_t *hw)
+static int hermes_init(hermes_t *hw)
 {
        u16 reg;
        int err = 0;
@@ -217,7 +239,6 @@ int hermes_init(hermes_t *hw)
 
        return err;
 }
-EXPORT_SYMBOL(hermes_init);
 
 /* Issue a command to the chip, and (busy!) wait for it to
  * complete.
@@ -228,8 +249,8 @@ EXPORT_SYMBOL(hermes_init);
  *     > 0 on error returned by the firmware
  *
  * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-                     struct hermes_response *resp)
+static int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+                            struct hermes_response *resp)
 {
        int err;
        int k;
@@ -291,9 +312,8 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
  out:
        return err;
 }
-EXPORT_SYMBOL(hermes_docmd_wait);
 
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
+static int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 {
        int err = 0;
        int k;
@@ -333,7 +353,6 @@ int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
 
        return 0;
 }
-EXPORT_SYMBOL(hermes_allocate);
 
 /* Set up a BAP to read a particular chunk of data from card's internal buffer.
  *
@@ -403,8 +422,8 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
  *       0 on success
  *     > 0 on error from firmware
  */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-                    u16 id, u16 offset)
+static int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
+                           u16 id, u16 offset)
 {
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
        int err = 0;
@@ -422,7 +441,6 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
  out:
        return err;
 }
-EXPORT_SYMBOL(hermes_bap_pread);
 
 /* Write a block of data to the chip's buffer, via the
  * BAP. Synchronization/serialization is the caller's problem.
@@ -432,8 +450,8 @@ EXPORT_SYMBOL(hermes_bap_pread);
  *       0 on success
  *     > 0 on error from firmware
  */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-                     u16 id, u16 offset)
+static int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
+                            u16 id, u16 offset)
 {
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
        int err = 0;
@@ -451,7 +469,6 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
  out:
        return err;
 }
-EXPORT_SYMBOL(hermes_bap_pwrite);
 
 /* Read a Length-Type-Value record from the card.
  *
@@ -461,8 +478,8 @@ EXPORT_SYMBOL(hermes_bap_pwrite);
  * practice.
  *
  * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
-                   u16 *length, void *buf)
+static int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
+                          u16 *length, void *buf)
 {
        int err = 0;
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
@@ -505,10 +522,9 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
 
        return 0;
 }
-EXPORT_SYMBOL(hermes_read_ltv);
 
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-                    u16 length, const void *value)
+static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
+                           u16 length, const void *value)
 {
        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
        int err = 0;
@@ -533,4 +549,228 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
 
        return err;
 }
-EXPORT_SYMBOL(hermes_write_ltv);
+
+/*** Hermes AUX control ***/
+
+static inline void
+hermes_aux_setaddr(hermes_t *hw, u32 addr)
+{
+       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
+       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
+}
+
+static inline int
+hermes_aux_control(hermes_t *hw, int enabled)
+{
+       int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
+       int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
+       int i;
+
+       /* Already open? */
+       if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
+               return 0;
+
+       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
+       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
+       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
+       hermes_write_reg(hw, HERMES_CONTROL, action);
+
+       for (i = 0; i < 20; i++) {
+               udelay(10);
+               if (hermes_read_reg(hw, HERMES_CONTROL) ==
+                   desired_state)
+                       return 0;
+       }
+
+       return -EBUSY;
+}
+
+/*** Hermes programming ***/
+
+/* About to start programming data (Hermes I)
+ * offset is the entry point
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_init(hermes_t *hw, u32 offset)
+{
+       int err;
+
+       /* Disable interrupts?*/
+       /*hw->inten = 0x0;*/
+       /*hermes_write_regn(hw, INTEN, 0);*/
+       /*hermes_set_irqmask(hw, 0);*/
+
+       /* Acknowledge any outstanding command */
+       hermes_write_regn(hw, EVACK, 0xFFFF);
+
+       /* Using init_cmd_wait rather than cmd_wait */
+       err = hw->ops->init_cmd_wait(hw,
+                                    0x0100 | HERMES_CMD_INIT,
+                                    0, 0, 0, NULL);
+       if (err)
+               return err;
+
+       err = hw->ops->init_cmd_wait(hw,
+                                    0x0000 | HERMES_CMD_INIT,
+                                    0, 0, 0, NULL);
+       if (err)
+               return err;
+
+       err = hermes_aux_control(hw, 1);
+       pr_debug("AUX enable returned %d\n", err);
+
+       if (err)
+               return err;
+
+       pr_debug("Enabling volatile, EP 0x%08x\n", offset);
+       err = hw->ops->init_cmd_wait(hw,
+                                    HERMES_PROGRAM_ENABLE_VOLATILE,
+                                    offset & 0xFFFFu,
+                                    offset >> 16,
+                                    0,
+                                    NULL);
+       pr_debug("PROGRAM_ENABLE returned %d\n", err);
+
+       return err;
+}
+
+/* Done programming data (Hermes I)
+ *
+ * Spectrum_cs' Symbol fw does not require this
+ * wl_lkm Agere fw does
+ * Don't know about intersil
+ */
+static int hermesi_program_end(hermes_t *hw)
+{
+       struct hermes_response resp;
+       int rc = 0;
+       int err;
+
+       rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
+
+       pr_debug("PROGRAM_DISABLE returned %d, "
+                "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+                rc, resp.resp0, resp.resp1, resp.resp2);
+
+       if ((rc == 0) &&
+           ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
+               rc = -EIO;
+
+       err = hermes_aux_control(hw, 0);
+       pr_debug("AUX disable returned %d\n", err);
+
+       /* Acknowledge any outstanding command */
+       hermes_write_regn(hw, EVACK, 0xFFFF);
+
+       /* Reinitialise, ignoring return */
+       (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
+                                     0, 0, 0, NULL);
+
+       return rc ? rc : err;
+}
+
+static int hermes_program_bytes(struct hermes *hw, const char *data,
+                               u32 addr, u32 len)
+{
+       /* wl lkm splits the programming into chunks of 2000 bytes.
+        * This restriction appears to come from USB. The PCMCIA
+        * adapters can program the whole lot in one go */
+       hermes_aux_setaddr(hw, addr);
+       hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
+       return 0;
+}
+
+/* Read PDA from the adapter */
+static int hermes_read_pda(hermes_t *hw, __le16 *pda, u32 pda_addr, u16 pda_len)
+{
+       int ret;
+       u16 pda_size;
+       u16 data_len = pda_len;
+       __le16 *data = pda;
+
+       if (hw->eeprom_pda) {
+               /* PDA of spectrum symbol is in eeprom */
+
+               /* Issue command to read EEPROM */
+               ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
+               if (ret)
+                       return ret;
+       } else {
+               /* wl_lkm does not include PDA size in the PDA area.
+                * We will pad the information into pda, so other routines
+                * don't have to be modified */
+               pda[0] = cpu_to_le16(pda_len - 2);
+                       /* Includes CFG_PROD_DATA but not itself */
+               pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+               data_len = pda_len - 4;
+               data = pda + 2;
+       }
+
+       /* Open auxiliary port */
+       ret = hermes_aux_control(hw, 1);
+       pr_debug("AUX enable returned %d\n", ret);
+       if (ret)
+               return ret;
+
+       /* Read PDA */
+       hermes_aux_setaddr(hw, pda_addr);
+       hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
+
+       /* Close aux port */
+       ret = hermes_aux_control(hw, 0);
+       pr_debug("AUX disable returned %d\n", ret);
+
+       /* Check PDA length */
+       pda_size = le16_to_cpu(pda[0]);
+       pr_debug("Actual PDA length %d, Max allowed %d\n",
+                pda_size, pda_len);
+       if (pda_size > pda_len)
+               return -EINVAL;
+
+       return 0;
+}
+
+static void hermes_lock_irqsave(spinlock_t *lock,
+                               unsigned long *flags) __acquires(lock)
+{
+       spin_lock_irqsave(lock, *flags);
+}
+
+static void hermes_unlock_irqrestore(spinlock_t *lock,
+                                    unsigned long *flags) __releases(lock)
+{
+       spin_unlock_irqrestore(lock, *flags);
+}
+
+static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
+{
+       spin_lock_irq(lock);
+}
+
+static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
+{
+       spin_unlock_irq(lock);
+}
+
+/* Hermes operations for local buses */
+static const struct hermes_ops hermes_ops_local = {
+       .init = hermes_init,
+       .cmd_wait = hermes_docmd_wait,
+       .init_cmd_wait = hermes_doicmd_wait,
+       .allocate = hermes_allocate,
+       .read_ltv = hermes_read_ltv,
+       .write_ltv = hermes_write_ltv,
+       .bap_pread = hermes_bap_pread,
+       .bap_pwrite = hermes_bap_pwrite,
+       .read_pda = hermes_read_pda,
+       .program_init = hermesi_program_init,
+       .program_end = hermesi_program_end,
+       .program = hermes_program_bytes,
+       .lock_irqsave = hermes_lock_irqsave,
+       .unlock_irqrestore = hermes_unlock_irqrestore,
+       .lock_irq = hermes_lock_irq,
+       .unlock_irq = hermes_unlock_irq,
+};
index 2dddbb597c4d26715dba1303b407038505182501..9ca34e722b45fc0d335b42ad339f40d25305c65e 100644 (file)
@@ -374,6 +374,37 @@ struct hermes_multicast {
 /* Timeouts */
 #define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
 
+struct hermes;
+
+/* Functions to access hardware */
+struct hermes_ops {
+       int (*init)(struct hermes *hw);
+       int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
+                       struct hermes_response *resp);
+       int (*init_cmd_wait)(struct hermes *hw, u16 cmd,
+                            u16 parm0, u16 parm1, u16 parm2,
+                            struct hermes_response *resp);
+       int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
+       int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
+                       u16 *length, void *buf);
+       int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
+                        u16 length, const void *value);
+       int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
+                        u16 id, u16 offset);
+       int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
+                         int len, u16 id, u16 offset);
+       int (*read_pda)(struct hermes *hw, __le16 *pda,
+                       u32 pda_addr, u16 pda_len);
+       int (*program_init)(struct hermes *hw, u32 entry_point);
+       int (*program_end)(struct hermes *hw);
+       int (*program)(struct hermes *hw, const char *buf,
+                      u32 addr, u32 len);
+       void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
+       void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
+       void (*lock_irq)(spinlock_t *lock);
+       void (*unlock_irq)(spinlock_t *lock);
+};
+
 /* Basic control structure */
 typedef struct hermes {
        void __iomem *iobase;
@@ -381,6 +412,9 @@ typedef struct hermes {
 #define HERMES_16BIT_REGSPACING        0
 #define HERMES_32BIT_REGSPACING        1
        u16 inten; /* Which interrupts should be enabled? */
+       bool eeprom_pda;
+       const struct hermes_ops *ops;
+       void *priv;
 } hermes_t;
 
 /* Register access convenience macros */
@@ -394,22 +428,6 @@ typedef struct hermes {
 
 /* Function prototypes */
 void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing);
-int hermes_init(hermes_t *hw);
-int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
-                     struct hermes_response *resp);
-int hermes_doicmd_wait(hermes_t *hw, u16 cmd,
-                      u16 parm0, u16 parm1, u16 parm2,
-                      struct hermes_response *resp);
-int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
-                      u16 id, u16 offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
-                       u16 id, u16 offset);
-int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
-                   u16 *length, void *buf);
-int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
-                     u16 length, const void *value);
 
 /* Inline functions */
 
@@ -426,13 +444,13 @@ static inline void hermes_set_irqmask(hermes_t *hw, u16 events)
 
 static inline int hermes_enable_port(hermes_t *hw, int port)
 {
-       return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
+       return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
                                 0, NULL);
 }
 
 static inline int hermes_disable_port(hermes_t *hw, int port)
 {
-       return hermes_docmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
+       return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
                                 0, NULL);
 }
 
@@ -440,7 +458,7 @@ static inline int hermes_disable_port(hermes_t *hw, int port)
  * information frame in __orinoco_ev_info() */
 static inline int hermes_inquire(hermes_t *hw, u16 rid)
 {
-       return hermes_docmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
+       return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
 }
 
 #define HERMES_BYTES_TO_RECLEN(n) ((((n)+1)/2) + 1)
@@ -475,10 +493,10 @@ static inline void hermes_clear_words(struct hermes *hw, int off,
 }
 
 #define HERMES_READ_RECORD(hw, bap, rid, buf) \
-       (hermes_read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
+       (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
 #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
-       (hermes_write_ltv((hw), (bap), (rid), \
-                         HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
+       (hw->ops->write_ltv((hw), (bap), (rid), \
+                           HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
 
 static inline int hermes_read_wordrec(hermes_t *hw, int bap, u16 rid, u16 *word)
 {
index fb157eb889ca19f20d507e7933b471ba8c564385..6da85e75fce071e2205a1a95767e8ee891af3dbc 100644 (file)
 
 #define PFX "hermes_dld: "
 
-/*
- * AUX port access.  To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
-#define HERMES_AUX_DISABLED    0x0000  /* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE             (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE     (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE        (0x0300 | HERMES_CMD_DOWNLD)
-
 /* End markers used in dblocks */
 #define PDI_END                0x00000000      /* End of PDA */
 #define BLOCK_END      0xFFFFFFFF      /* Last image block */
 #define TEXT_END       0x1A            /* End of text header */
 
-/* Limit the amout we try to download in a single shot.
- * Size is in bytes.
- */
-#define MAX_DL_SIZE 1024
-#define LIMIT_PROGRAM_SIZE 0
-
 /*
  * The following structures have little-endian fields denoted by
  * the leading underscore.  Don't access them directly - use inline
@@ -165,41 +139,6 @@ pdi_len(const struct pdi *pdi)
        return 2 * (le16_to_cpu(pdi->len) - 1);
 }
 
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(hermes_t *hw, u32 addr)
-{
-       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
-       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(hermes_t *hw, int enabled)
-{
-       int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
-       int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
-       int i;
-
-       /* Already open? */
-       if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
-               return 0;
-
-       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
-       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
-       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
-       hermes_write_reg(hw, HERMES_CONTROL, action);
-
-       for (i = 0; i < 20; i++) {
-               udelay(10);
-               if (hermes_read_reg(hw, HERMES_CONTROL) ==
-                   desired_state)
-                       return 0;
-       }
-
-       return -EBUSY;
-}
-
 /*** Plug Data Functions ***/
 
 /*
@@ -271,62 +210,7 @@ hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
                return -EINVAL;
 
        /* do the actual plugging */
-       hermes_aux_setaddr(hw, pdr_addr(pdr));
-       hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
-       return 0;
-}
-
-/* Read PDA from the adapter */
-int hermes_read_pda(hermes_t *hw,
-                   __le16 *pda,
-                   u32 pda_addr,
-                   u16 pda_len,
-                   int use_eeprom) /* can we get this into hw? */
-{
-       int ret;
-       u16 pda_size;
-       u16 data_len = pda_len;
-       __le16 *data = pda;
-
-       if (use_eeprom) {
-               /* PDA of spectrum symbol is in eeprom */
-
-               /* Issue command to read EEPROM */
-               ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
-               if (ret)
-                       return ret;
-       } else {
-               /* wl_lkm does not include PDA size in the PDA area.
-                * We will pad the information into pda, so other routines
-                * don't have to be modified */
-               pda[0] = cpu_to_le16(pda_len - 2);
-                       /* Includes CFG_PROD_DATA but not itself */
-               pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
-               data_len = pda_len - 4;
-               data = pda + 2;
-       }
-
-       /* Open auxiliary port */
-       ret = hermes_aux_control(hw, 1);
-       pr_debug(PFX "AUX enable returned %d\n", ret);
-       if (ret)
-               return ret;
-
-       /* read PDA from EEPROM */
-       hermes_aux_setaddr(hw, pda_addr);
-       hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
-       /* Close aux port */
-       ret = hermes_aux_control(hw, 0);
-       pr_debug(PFX "AUX disable returned %d\n", ret);
-
-       /* Check PDA length */
-       pda_size = le16_to_cpu(pda[0]);
-       pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
-                pda_size, pda_len);
-       if (pda_size > pda_len)
-               return -EINVAL;
+       hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
 
        return 0;
 }
@@ -389,101 +273,13 @@ hermes_blocks_length(const char *first_block, const void *end)
 
 /*** Hermes programming ***/
 
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_init(hermes_t *hw, u32 offset)
-{
-       int err;
-
-       /* Disable interrupts?*/
-       /*hw->inten = 0x0;*/
-       /*hermes_write_regn(hw, INTEN, 0);*/
-       /*hermes_set_irqmask(hw, 0);*/
-
-       /* Acknowledge any outstanding command */
-       hermes_write_regn(hw, EVACK, 0xFFFF);
-
-       /* Using doicmd_wait rather than docmd_wait */
-       err = hermes_doicmd_wait(hw,
-                                0x0100 | HERMES_CMD_INIT,
-                                0, 0, 0, NULL);
-       if (err)
-               return err;
-
-       err = hermes_doicmd_wait(hw,
-                                0x0000 | HERMES_CMD_INIT,
-                                0, 0, 0, NULL);
-       if (err)
-               return err;
-
-       err = hermes_aux_control(hw, 1);
-       pr_debug(PFX "AUX enable returned %d\n", err);
-
-       if (err)
-               return err;
-
-       pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
-       err = hermes_doicmd_wait(hw,
-                                HERMES_PROGRAM_ENABLE_VOLATILE,
-                                offset & 0xFFFFu,
-                                offset >> 16,
-                                0,
-                                NULL);
-       pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
-
-       return err;
-}
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-int hermesi_program_end(hermes_t *hw)
-{
-       struct hermes_response resp;
-       int rc = 0;
-       int err;
-
-       rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
-       pr_debug(PFX "PROGRAM_DISABLE returned %d, "
-                "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
-                rc, resp.resp0, resp.resp1, resp.resp2);
-
-       if ((rc == 0) &&
-           ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
-               rc = -EIO;
-
-       err = hermes_aux_control(hw, 0);
-       pr_debug(PFX "AUX disable returned %d\n", err);
-
-       /* Acknowledge any outstanding command */
-       hermes_write_regn(hw, EVACK, 0xFFFF);
-
-       /* Reinitialise, ignoring return */
-       (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
-                                 0, 0, 0, NULL);
-
-       return rc ? rc : err;
-}
-
 /* Program the data blocks */
 int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 {
        const struct dblock *blk;
        u32 blkaddr;
        u32 blklen;
-#if LIMIT_PROGRAM_SIZE
-       u32 addr;
-       u32 len;
-#endif
+       int err = 0;
 
        blk = (const struct dblock *) first_block;
 
@@ -498,30 +294,10 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
                pr_debug(PFX "Programming block of length %d "
                         "to address 0x%08x\n", blklen, blkaddr);
 
-#if !LIMIT_PROGRAM_SIZE
-               /* wl_lkm driver splits this into writes of 2000 bytes */
-               hermes_aux_setaddr(hw, blkaddr);
-               hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-                                  blklen);
-#else
-               len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
-               addr = blkaddr;
-
-               while (addr < (blkaddr + blklen)) {
-                       pr_debug(PFX "Programming subblock of length %d "
-                                "to address 0x%08x. Data @ %p\n",
-                                len, addr, &blk->data[addr - blkaddr]);
-
-                       hermes_aux_setaddr(hw, addr);
-                       hermes_write_bytes(hw, HERMES_AUXDATA,
-                                          &blk->data[addr - blkaddr],
-                                          len);
-
-                       addr += len;
-                       len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
-                               (blkaddr + blklen - addr) : MAX_DL_SIZE;
-               }
-#endif
+               err = hw->ops->program(hw, blk->data, blkaddr, blklen);
+               if (err)
+                       break;
+
                blk = (const struct dblock *) &blk->data[blklen];
 
                if ((void *) blk > (end - sizeof(*blk)))
@@ -530,7 +306,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
                blkaddr = dblock_addr(blk);
                blklen = dblock_len(blk);
        }
-       return 0;
+       return err;
 }
 
 /*** Default plugging data for Hermes I ***/
@@ -690,9 +466,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
                        if ((pdi_len(pdi) == pdr_len(pdr)) &&
                            ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
                                /* do the actual plugging */
-                               hermes_aux_setaddr(hw, pdr_addr(pdr));
-                               hermes_write_bytes(hw, HERMES_AUXDATA,
-                                                  pdi->data, pdi_len(pdi));
+                               hw->ops->program(hw, pdi->data, pdr_addr(pdr),
+                                                pdi_len(pdi));
                        }
                }
 
index e6369242e49c85479f222c51a7ba5afc81706301..6fbd78850123fe100737f5bfec9d69005857d254 100644 (file)
@@ -177,9 +177,9 @@ int determine_fw_capabilities(struct orinoco_private *priv,
                /* 3Com MAC : 00:50:DA:* */
                memset(tmp, 0, sizeof(tmp));
                /* Get the Symbol firmware version */
-               err = hermes_read_ltv(hw, USER_BAP,
-                                     HERMES_RID_SECONDARYVERSION_SYMBOL,
-                                     SYMBOL_MAX_VER_LEN, NULL, &tmp);
+               err = hw->ops->read_ltv(hw, USER_BAP,
+                                       HERMES_RID_SECONDARYVERSION_SYMBOL,
+                                       SYMBOL_MAX_VER_LEN, NULL, &tmp);
                if (err) {
                        dev_warn(dev, "Error %d reading Symbol firmware info. "
                                 "Wildly guessing capabilities...\n", err);
@@ -262,6 +262,13 @@ int determine_fw_capabilities(struct orinoco_private *priv,
        if (fw_name)
                dev_info(dev, "Firmware determined as %s\n", fw_name);
 
+#ifndef CONFIG_HERMES_PRISM
+       if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+               dev_err(dev, "Support for Prism chipset is not enabled\n");
+               return -ENODEV;
+       }
+#endif
+
        return 0;
 }
 
@@ -279,8 +286,8 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        u16 reclen;
 
        /* Get the MAC address */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                             ETH_ALEN, NULL, dev_addr);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                               ETH_ALEN, NULL, dev_addr);
        if (err) {
                dev_warn(dev, "Failed to read MAC address!\n");
                goto out;
@@ -289,8 +296,8 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
        dev_dbg(dev, "MAC address %pM\n", dev_addr);
 
        /* Get the station name */
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                             sizeof(nickbuf), &reclen, &nickbuf);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                               sizeof(nickbuf), &reclen, &nickbuf);
        if (err) {
                dev_err(dev, "failed to read station name\n");
                goto out;
@@ -367,6 +374,32 @@ int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
                err = hermes_read_wordrec(hw, USER_BAP,
                                          HERMES_RID_CNFPREAMBLE_SYMBOL,
                                          &priv->preamble);
+               if (err) {
+                       dev_err(dev, "Failed to read preamble setup\n");
+                       goto out;
+               }
+       }
+
+       /* Retry settings */
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
+                                 &priv->short_retry_limit);
+       if (err) {
+               dev_err(dev, "Failed to read short retry limit\n");
+               goto out;
+       }
+
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
+                                 &priv->long_retry_limit);
+       if (err) {
+               dev_err(dev, "Failed to read long retry limit\n");
+               goto out;
+       }
+
+       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
+                                 &priv->retry_lifetime);
+       if (err) {
+               dev_err(dev, "Failed to read max retry lifetime\n");
+               goto out;
        }
 
 out:
@@ -380,11 +413,11 @@ int orinoco_hw_allocate_fid(struct orinoco_private *priv)
        struct hermes *hw = &priv->hw;
        int err;
 
-       err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+       err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
        if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
                /* Try workaround for old Symbol firmware bug */
                priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
-               err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+               err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
 
                dev_warn(dev, "Firmware ALLOC bug detected "
                         "(old Symbol firmware?). Work around %s\n",
@@ -430,8 +463,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        struct hermes_idstring idbuf;
 
        /* Set the MAC address */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
-                              HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+                                HERMES_BYTES_TO_RECLEN(ETH_ALEN),
+                                dev->dev_addr);
        if (err) {
                printk(KERN_ERR "%s: Error %d setting MAC address\n",
                       dev->name, err);
@@ -494,7 +528,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
        memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
        /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
                        HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
                        &idbuf);
        if (err) {
@@ -502,7 +536,7 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
                       dev->name, err);
                return err;
        }
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
                        HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
                        &idbuf);
        if (err) {
@@ -514,9 +548,9 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        /* Set the station name */
        idbuf.len = cpu_to_le16(strlen(priv->nick));
        memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-       err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
-                              HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-                              &idbuf);
+       err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+                                HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+                                &idbuf);
        if (err) {
                printk(KERN_ERR "%s: Error %d setting nickname\n",
                       dev->name, err);
@@ -631,12 +665,12 @@ int orinoco_hw_program_rids(struct orinoco_private *priv)
        if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Enable monitor mode */
                dev->type = ARPHRD_IEEE80211;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_MONITOR, 0, NULL);
        } else {
                /* Disable monitor mode */
                dev->type = ARPHRD_ETHER;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_STOP, 0, NULL);
        }
        if (err)
@@ -662,8 +696,8 @@ int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
        if ((key < 0) || (key >= 4))
                return -EINVAL;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
-                             sizeof(tsc_arr), NULL, &tsc_arr);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
+                               sizeof(tsc_arr), NULL, &tsc_arr);
        if (!err)
                memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
 
@@ -842,7 +876,7 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
                                memcpy(key, priv->keys[i].key,
                                       priv->keys[i].key_len);
 
-                               err = hermes_write_ltv(hw, USER_BAP,
+                               err = hw->ops->write_ltv(hw, USER_BAP,
                                                HERMES_RID_CNFDEFAULTKEY0 + i,
                                                HERMES_BYTES_TO_RECLEN(keylen),
                                                key);
@@ -1049,17 +1083,17 @@ int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
         * group address if either we want to multicast, or if we were
         * multicasting and want to stop */
        if (!promisc && (mc_count || priv->mc_count)) {
-               struct dev_mc_list *p;
+               struct netdev_hw_addr *ha;
                struct hermes_multicast mclist;
                int i = 0;
 
-               netdev_for_each_mc_addr(p, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        if (i == mc_count)
                                break;
-                       memcpy(mclist.addr[i++], p->dmi_addr, ETH_ALEN);
+                       memcpy(mclist.addr[i++], ha->addr, ETH_ALEN);
                }
 
-               err = hermes_write_ltv(hw, USER_BAP,
+               err = hw->ops->write_ltv(hw, USER_BAP,
                                   HERMES_RID_CNFGROUPADDRESSES,
                                   HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
                                   &mclist);
@@ -1101,15 +1135,15 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
                rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
                        HERMES_RID_CNFDESIREDSSID;
 
-               err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
-                                     NULL, &essidbuf);
+               err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+                                       NULL, &essidbuf);
                if (err)
                        goto fail_unlock;
        } else {
                *active = 0;
 
-               err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
-                                     sizeof(essidbuf), NULL, &essidbuf);
+               err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
+                                       sizeof(essidbuf), NULL, &essidbuf);
                if (err)
                        goto fail_unlock;
        }
@@ -1180,8 +1214,8 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
-                             sizeof(list), NULL, &list);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
+                               sizeof(list), NULL, &list);
        orinoco_unlock(priv, &flags);
 
        if (err)
@@ -1248,7 +1282,7 @@ int orinoco_hw_trigger_scan(struct orinoco_private *priv,
                                idbuf.len = cpu_to_le16(len);
                                memcpy(idbuf.val, ssid->ssid, len);
 
-                               err = hermes_write_ltv(hw, USER_BAP,
+                               err = hw->ops->write_ltv(hw, USER_BAP,
                                               HERMES_RID_CNFSCANSSID_AGERE,
                                               HERMES_BYTES_TO_RECLEN(len + 2),
                                               &idbuf);
@@ -1312,8 +1346,8 @@ int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
        hermes_t *hw = &priv->hw;
        int err;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, addr);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                               ETH_ALEN, NULL, addr);
 
        return err;
 }
index 9799a1d14a638e37ebb12d698c9a16408cbe4049..97af71e7995075b18b7badb6fd7f3f92d9bf1d98 100644 (file)
@@ -22,7 +22,6 @@
 
 /* Forward declarations */
 struct orinoco_private;
-struct dev_addr_list;
 
 int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
                              size_t fw_name_len, u32 *hw_ver);
index 413e9ab6cab3bb1fb70782f85c07066ec55eac31..ca71f08709bcd0616b8f9d19d2a3332e6f74122a 100644 (file)
@@ -254,7 +254,7 @@ void set_port_type(struct orinoco_private *priv)
 /* Device methods                                                   */
 /********************************************************************/
 
-static int orinoco_open(struct net_device *dev)
+int orinoco_open(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
@@ -272,8 +272,9 @@ static int orinoco_open(struct net_device *dev)
 
        return err;
 }
+EXPORT_SYMBOL(orinoco_open);
 
-static int orinoco_stop(struct net_device *dev)
+int orinoco_stop(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        int err = 0;
@@ -281,25 +282,27 @@ static int orinoco_stop(struct net_device *dev)
        /* We mustn't use orinoco_lock() here, because we need to be
           able to close the interface even if hw_unavailable is set
           (e.g. as we're released after a PC Card removal) */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
 
        priv->open = 0;
 
        err = __orinoco_down(priv);
 
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        return err;
 }
+EXPORT_SYMBOL(orinoco_stop);
 
-static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
+struct net_device_stats *orinoco_get_stats(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
 
        return &priv->stats;
 }
+EXPORT_SYMBOL(orinoco_get_stats);
 
-static void orinoco_set_multicast_list(struct net_device *dev)
+void orinoco_set_multicast_list(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        unsigned long flags;
@@ -313,8 +316,9 @@ static void orinoco_set_multicast_list(struct net_device *dev)
        __orinoco_set_multicast_list(dev);
        orinoco_unlock(priv, &flags);
 }
+EXPORT_SYMBOL(orinoco_set_multicast_list);
 
-static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
+int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct orinoco_private *priv = ndev_priv(dev);
 
@@ -330,23 +334,115 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
 
        return 0;
 }
+EXPORT_SYMBOL(orinoco_change_mtu);
 
 /********************************************************************/
 /* Tx path                                                          */
 /********************************************************************/
 
+/* Add encapsulation and MIC to the existing SKB.
+ * The main xmit routine will then send the whole lot to the card.
+ * Need 8 bytes headroom
+ * Need 8 bytes tailroom
+ *
+ *                          With encapsulated ethernet II frame
+ *                          --------
+ *                          803.3 header (14 bytes)
+ *                           dst[6]
+ * --------                  src[6]
+ * 803.3 header (14 bytes)   len[2]
+ *  dst[6]                  803.2 header (8 bytes)
+ *  src[6]                   encaps[6]
+ *  len[2] <- leave alone -> len[2]
+ * --------                 -------- <-- 0
+ * Payload                  Payload
+ * ...                      ...
+ *
+ * --------                 --------
+ *                          MIC (8 bytes)
+ *                          --------
+ *
+ * returns 0 on success, -ENOMEM on error.
+ */
+int orinoco_process_xmit_skb(struct sk_buff *skb,
+                            struct net_device *dev,
+                            struct orinoco_private *priv,
+                            int *tx_control,
+                            u8 *mic_buf)
+{
+       struct orinoco_tkip_key *key;
+       struct ethhdr *eh;
+       int do_mic;
+
+       key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
+
+       do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
+                 (key != NULL));
+
+       if (do_mic)
+               *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
+                       HERMES_TXCTRL_MIC;
+
+       eh = (struct ethhdr *)skb->data;
+
+       /* Encapsulate Ethernet-II frames */
+       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
+               struct header_struct {
+                       struct ethhdr eth;      /* 802.3 header */
+                       u8 encap[6];            /* 802.2 header */
+               } __attribute__ ((packed)) hdr;
+               int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
+
+               if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
+                       if (net_ratelimit())
+                               printk(KERN_ERR
+                                      "%s: Not enough headroom for 802.2 headers %d\n",
+                                      dev->name, skb_headroom(skb));
+                       return -ENOMEM;
+               }
+
+               /* Fill in new header */
+               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
+               hdr.eth.h_proto = htons(len);
+               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
+
+               /* Make room for the new header, and copy it in */
+               eh = (struct ethhdr *) skb_push(skb, ENCAPS_OVERHEAD);
+               memcpy(eh, &hdr, sizeof(hdr));
+       }
+
+       /* Calculate Michael MIC */
+       if (do_mic) {
+               size_t len = skb->len - ETH_HLEN;
+               u8 *mic = &mic_buf[0];
+
+               /* Have to write to an even address, so copy the spare
+                * byte across */
+               if (skb->len % 2) {
+                       *mic = skb->data[skb->len - 1];
+                       mic++;
+               }
+
+               orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
+                           eh->h_dest, eh->h_source, 0 /* priority */,
+                           skb->data + ETH_HLEN,
+                           len, mic);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(orinoco_process_xmit_skb);
+
 static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
-       struct orinoco_tkip_key *key;
        hermes_t *hw = &priv->hw;
        int err = 0;
        u16 txfid = priv->txfid;
-       struct ethhdr *eh;
        int tx_control;
        unsigned long flags;
-       int do_mic;
+       u8 mic_buf[MICHAEL_MIC_LEN+1];
 
        if (!netif_running(dev)) {
                printk(KERN_ERR "%s: Tx on stopped device!\n",
@@ -378,16 +474,12 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        if (skb->len < ETH_HLEN)
                goto drop;
 
-       key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
-
-       do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
-                 (key != NULL));
-
        tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
 
-       if (do_mic)
-               tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
-                       HERMES_TXCTRL_MIC;
+       err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
+                                      &mic_buf[0]);
+       if (err)
+               goto drop;
 
        if (priv->has_alt_txcntl) {
                /* WPA enabled firmwares have tx_cntl at the end of
@@ -400,8 +492,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(&desc, 0, sizeof(desc));
 
                *txcntl = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                         txfid, 0);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing Tx "
@@ -414,8 +506,8 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(&desc, 0, sizeof(desc));
 
                desc.tx_control = cpu_to_le16(tx_control);
-               err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
-                                       txfid, 0);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
+                                         txfid, 0);
                if (err) {
                        if (net_ratelimit())
                                printk(KERN_ERR "%s: Error %d writing Tx "
@@ -430,68 +522,24 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                                   HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
        }
 
-       eh = (struct ethhdr *)skb->data;
-
-       /* Encapsulate Ethernet-II frames */
-       if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
-               struct header_struct {
-                       struct ethhdr eth;      /* 802.3 header */
-                       u8 encap[6];            /* 802.2 header */
-               } __attribute__ ((packed)) hdr;
-
-               /* Strip destination and source from the data */
-               skb_pull(skb, 2 * ETH_ALEN);
-
-               /* And move them to a separate header */
-               memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
-               hdr.eth.h_proto = htons(sizeof(encaps_hdr) + skb->len);
-               memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
-               /* Insert the SNAP header */
-               if (skb_headroom(skb) < sizeof(hdr)) {
-                       printk(KERN_ERR
-                              "%s: Not enough headroom for 802.2 headers %d\n",
-                              dev->name, skb_headroom(skb));
-                       goto drop;
-               }
-               eh = (struct ethhdr *) skb_push(skb, sizeof(hdr));
-               memcpy(eh, &hdr, sizeof(hdr));
-       }
-
-       err = hermes_bap_pwrite(hw, USER_BAP, skb->data, skb->len,
-                               txfid, HERMES_802_3_OFFSET);
+       err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
+                                 txfid, HERMES_802_3_OFFSET);
        if (err) {
                printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
                       dev->name, err);
                goto busy;
        }
 
-       /* Calculate Michael MIC */
-       if (do_mic) {
-               u8 mic_buf[MICHAEL_MIC_LEN + 1];
-               u8 *mic;
-               size_t offset;
-               size_t len;
+       if (tx_control & HERMES_TXCTRL_MIC) {
+               size_t offset = HERMES_802_3_OFFSET + skb->len;
+               size_t len = MICHAEL_MIC_LEN;
 
-               if (skb->len % 2) {
-                       /* MIC start is on an odd boundary */
-                       mic_buf[0] = skb->data[skb->len - 1];
-                       mic = &mic_buf[1];
-                       offset = skb->len - 1;
-                       len = MICHAEL_MIC_LEN + 1;
-               } else {
-                       mic = &mic_buf[0];
-                       offset = skb->len;
-                       len = MICHAEL_MIC_LEN;
+               if (offset % 2) {
+                       offset--;
+                       len++;
                }
-
-               orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
-                           eh->h_dest, eh->h_source, 0 /* priority */,
-                           skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
-
-               /* Write the MIC */
-               err = hermes_bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
-                                       txfid, HERMES_802_3_OFFSET + offset);
+               err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
+                                         txfid, offset);
                if (err) {
                        printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
                               dev->name, err);
@@ -502,7 +550,7 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
        /* Finally, we actually initiate the send */
        netif_stop_queue(dev);
 
-       err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
+       err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
                                txfid, NULL);
        if (err) {
                netif_start_queue(dev);
@@ -512,7 +560,6 @@ static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                goto busy;
        }
 
-       dev->trans_start = jiffies;
        stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
        goto ok;
 
@@ -572,9 +619,9 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
                return; /* Nothing's really happened */
 
        /* Read part of the frame header - we need status and addr1 */
-       err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-                              sizeof(struct hermes_txexc_data),
-                              fid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
+                                sizeof(struct hermes_txexc_data),
+                                fid, 0);
 
        hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
        stats->tx_errors++;
@@ -615,7 +662,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        netif_wake_queue(dev);
 }
 
-static void orinoco_tx_timeout(struct net_device *dev)
+void orinoco_tx_timeout(struct net_device *dev)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
@@ -630,6 +677,7 @@ static void orinoco_tx_timeout(struct net_device *dev)
 
        schedule_work(&priv->reset_work);
 }
+EXPORT_SYMBOL(orinoco_tx_timeout);
 
 /********************************************************************/
 /* Rx path (data frames)                                            */
@@ -764,9 +812,9 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
 
        /* If any, copy the data from the card to the skb */
        if (datalen > 0) {
-               err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
-                                      ALIGN(datalen, 2), rxfid,
-                                      HERMES_802_2_OFFSET);
+               err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+                                        ALIGN(datalen, 2), rxfid,
+                                        HERMES_802_2_OFFSET);
                if (err) {
                        printk(KERN_ERR "%s: error %d reading monitor frame\n",
                               dev->name, err);
@@ -792,7 +840,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
        stats->rx_dropped++;
 }
 
-static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        struct net_device_stats *stats = &priv->stats;
@@ -814,8 +862,8 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
 
        rxfid = hermes_read_regn(hw, RXFID);
 
-       err = hermes_bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
-                              rxfid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
+                                rxfid, 0);
        if (err) {
                printk(KERN_ERR "%s: error %d reading Rx descriptor. "
                       "Frame dropped.\n", dev->name, err);
@@ -882,9 +930,9 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
           nothing is removed.  2 is for aligning the IP header.  */
        skb_reserve(skb, ETH_HLEN + 2);
 
-       err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
-                              ALIGN(length, 2), rxfid,
-                              HERMES_802_2_OFFSET);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+                                ALIGN(length, 2), rxfid,
+                                HERMES_802_2_OFFSET);
        if (err) {
                printk(KERN_ERR "%s: error %d reading frame. "
                       "Frame dropped.\n", dev->name, err);
@@ -913,6 +961,7 @@ update_stats:
 out:
        kfree(desc);
 }
+EXPORT_SYMBOL(__orinoco_ev_rx);
 
 static void orinoco_rx(struct net_device *dev,
                       struct hermes_rx_descriptor *desc,
@@ -1145,9 +1194,9 @@ static void orinoco_join_ap(struct work_struct *work)
                goto out;
 
        /* Read scan results from the firmware */
-       err = hermes_read_ltv(hw, USER_BAP,
-                             HERMES_RID_SCANRESULTSTABLE,
-                             MAX_SCAN_LEN, &len, buf);
+       err = hw->ops->read_ltv(hw, USER_BAP,
+                               HERMES_RID_SCANRESULTSTABLE,
+                               MAX_SCAN_LEN, &len, buf);
        if (err) {
                printk(KERN_ERR "%s: Cannot read scan results\n",
                       dev->name);
@@ -1194,8 +1243,8 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
        union iwreq_data wrqu;
        int err;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
-                             ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+                               ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
        if (err != 0)
                return;
 
@@ -1217,8 +1266,8 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
        if (!priv->has_wpa)
                return;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
-                             sizeof(buf), NULL, &buf);
+       err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
+                               sizeof(buf), NULL, &buf);
        if (err != 0)
                return;
 
@@ -1247,8 +1296,9 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
        if (!priv->has_wpa)
                return;
 
-       err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO,
-                             sizeof(buf), NULL, &buf);
+       err = hw->ops->read_ltv(hw, USER_BAP,
+                               HERMES_RID_CURRENT_ASSOC_RESP_INFO,
+                               sizeof(buf), NULL, &buf);
        if (err != 0)
                return;
 
@@ -1353,7 +1403,7 @@ static void orinoco_process_scan_results(struct work_struct *work)
        spin_unlock_irqrestore(&priv->scan_lock, flags);
 }
 
-static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
+void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
 {
        struct orinoco_private *priv = ndev_priv(dev);
        u16 infofid;
@@ -1371,8 +1421,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
        infofid = hermes_read_regn(hw, INFOFID);
 
        /* Read the info frame header - don't try too hard */
-       err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),
-                              infofid, 0);
+       err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
+                                infofid, 0);
        if (err) {
                printk(KERN_ERR "%s: error %d reading info frame. "
                       "Frame dropped.\n", dev->name, err);
@@ -1393,8 +1443,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        len = sizeof(tallies);
                }
 
-               err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
+                                        infofid, sizeof(info));
                if (err)
                        break;
 
@@ -1429,8 +1479,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
                }
 
-               err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
+                                        infofid, sizeof(info));
                if (err)
                        break;
                newstatus = le16_to_cpu(linkstatus.linkstatus);
@@ -1494,8 +1544,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                }
 
                /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
+                                        infofid, sizeof(info));
                if (err) {
                        kfree(buf);
                        qabort_scan(priv);
@@ -1547,8 +1597,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                        break;
 
                /* Read scan data */
-               err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
-                                      infofid, sizeof(info));
+               err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
+                                        infofid, sizeof(info));
                if (err)
                        kfree(bss);
                else
@@ -1568,9 +1618,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
                /* We don't actually do anything about it */
                break;
        }
-
-       return;
 }
+EXPORT_SYMBOL(__orinoco_ev_info);
 
 static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
 {
@@ -1647,7 +1696,7 @@ static int orinoco_reinit_firmware(struct orinoco_private *priv)
        struct hermes *hw = &priv->hw;
        int err;
 
-       err = hermes_init(hw);
+       err = hw->ops->init(hw);
        if (priv->do_fw_download && !err) {
                err = orinoco_download(priv);
                if (err)
@@ -1735,7 +1784,7 @@ void orinoco_reset(struct work_struct *work)
        }
 
        /* This has to be called from user context */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
 
        priv->hw_unavailable--;
 
@@ -1750,7 +1799,7 @@ void orinoco_reset(struct work_struct *work)
                        dev->trans_start = jiffies;
        }
 
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        return;
  disable:
@@ -1984,7 +2033,7 @@ int orinoco_init(struct orinoco_private *priv)
        priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
 
        /* Initialize the firmware */
-       err = hermes_init(hw);
+       err = hw->ops->init(hw);
        if (err != 0) {
                dev_err(dev, "Failed to initialize firmware (err = %d)\n",
                        err);
@@ -2067,9 +2116,9 @@ int orinoco_init(struct orinoco_private *priv)
 
        /* Make the hardware available, as long as it hasn't been
         * removed elsewhere (e.g. by PCMCIA hot unplug) */
-       spin_lock_irq(&priv->lock);
+       orinoco_lock_irq(priv);
        priv->hw_unavailable--;
-       spin_unlock_irq(&priv->lock);
+       orinoco_unlock_irq(priv);
 
        dev_dbg(dev, "Ready\n");
 
@@ -2192,7 +2241,8 @@ EXPORT_SYMBOL(alloc_orinocodev);
  */
 int orinoco_if_add(struct orinoco_private *priv,
                   unsigned long base_addr,
-                  unsigned int irq)
+                  unsigned int irq,
+                  const struct net_device_ops *ops)
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct wireless_dev *wdev;
@@ -2211,16 +2261,21 @@ int orinoco_if_add(struct orinoco_private *priv,
 
        /* Setup / override net_device fields */
        dev->ieee80211_ptr = wdev;
-       dev->netdev_ops = &orinoco_netdev_ops;
        dev->watchdog_timeo = HZ; /* 1 second timeout */
        dev->wireless_handlers = &orinoco_handler_def;
 #ifdef WIRELESS_SPY
        dev->wireless_data = &priv->wireless_data;
 #endif
+       /* Default to standard ops if not set */
+       if (ops)
+               dev->netdev_ops = ops;
+       else
+               dev->netdev_ops = &orinoco_netdev_ops;
+
        /* we use the default eth_mac_addr for setting the MAC addr */
 
        /* Reserve space in skb for the SNAP header */
-       dev->hard_header_len += ENCAPS_OVERHEAD;
+       dev->needed_headroom = ENCAPS_OVERHEAD;
 
        netif_carrier_off(dev);
 
@@ -2305,7 +2360,7 @@ int orinoco_up(struct orinoco_private *priv)
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
 
        err = orinoco_reinit_firmware(priv);
        if (err) {
@@ -2325,7 +2380,7 @@ int orinoco_up(struct orinoco_private *priv)
        }
 
 exit:
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        return 0;
 }
@@ -2337,7 +2392,7 @@ void orinoco_down(struct orinoco_private *priv)
        unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        err = __orinoco_down(priv);
        if (err)
                printk(KERN_WARNING "%s: Error %d downing interface\n",
@@ -2345,7 +2400,7 @@ void orinoco_down(struct orinoco_private *priv)
 
        netif_device_detach(dev);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 }
 EXPORT_SYMBOL(orinoco_down);
 
index 21ab36cd76c795b74604df687a15e5a1f8658a86..4dadf9880a974c5820ab915700385b1e9b6d46ab 100644 (file)
@@ -33,18 +33,6 @@ int orinoco_commit(struct orinoco_private *priv);
 void orinoco_reset(struct work_struct *work);
 
 /* Information element helpers - find a home for these... */
-static inline u8 *orinoco_get_ie(u8 *data, size_t len,
-                                enum ieee80211_eid eid)
-{
-       u8 *p = data;
-       while ((p + 2) < (data + len)) {
-               if (p[0] == eid)
-                       return p;
-               p += p[1] + 2;
-       }
-       return NULL;
-}
-
 #define WPA_OUI_TYPE   "\x00\x50\xF2\x01"
 #define WPA_SELECTOR_LEN 4
 static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
index 665ef56f8382cba58ed3bbfcc2d20d230bce57db..a6da86e0a70faaf7d88bd76b95af9a4fd9846448 100644 (file)
@@ -131,6 +131,8 @@ struct orinoco_private {
        u16 ap_density, rts_thresh;
        u16 pm_on, pm_mcast, pm_period, pm_timeout;
        u16 preamble;
+       u16 short_retry_limit, long_retry_limit;
+       u16 retry_lifetime;
 #ifdef WIRELESS_SPY
        struct iw_spy_data spy_data; /* iwspy support */
        struct iw_public_data   wireless_data;
@@ -188,12 +190,30 @@ extern void free_orinocodev(struct orinoco_private *priv);
 extern int orinoco_init(struct orinoco_private *priv);
 extern int orinoco_if_add(struct orinoco_private *priv,
                          unsigned long base_addr,
-                         unsigned int irq);
+                         unsigned int irq,
+                         const struct net_device_ops *ops);
 extern void orinoco_if_del(struct orinoco_private *priv);
 extern int orinoco_up(struct orinoco_private *priv);
 extern void orinoco_down(struct orinoco_private *priv);
 extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 
+extern void __orinoco_ev_info(struct net_device *dev, hermes_t *hw);
+extern void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw);
+
+int orinoco_process_xmit_skb(struct sk_buff *skb,
+                            struct net_device *dev,
+                            struct orinoco_private *priv,
+                            int *tx_control,
+                            u8 *mic);
+
+/* Common ndo functions exported for reuse by orinoco_usb */
+int orinoco_open(struct net_device *dev);
+int orinoco_stop(struct net_device *dev);
+struct net_device_stats *orinoco_get_stats(struct net_device *dev);
+void orinoco_set_multicast_list(struct net_device *dev);
+int orinoco_change_mtu(struct net_device *dev, int new_mtu);
+void orinoco_tx_timeout(struct net_device *dev);
+
 /********************************************************************/
 /* Locking and synchronization functions                            */
 /********************************************************************/
@@ -201,11 +221,11 @@ extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
 static inline int orinoco_lock(struct orinoco_private *priv,
                               unsigned long *flags)
 {
-       spin_lock_irqsave(&priv->lock, *flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, flags);
        if (priv->hw_unavailable) {
                DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
                       priv->ndev);
-               spin_unlock_irqrestore(&priv->lock, *flags);
+               priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
                return -EBUSY;
        }
        return 0;
@@ -214,7 +234,17 @@ static inline int orinoco_lock(struct orinoco_private *priv,
 static inline void orinoco_unlock(struct orinoco_private *priv,
                                  unsigned long *flags)
 {
-       spin_unlock_irqrestore(&priv->lock, *flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
+}
+
+static inline void orinoco_lock_irq(struct orinoco_private *priv)
+{
+       priv->hw.ops->lock_irq(&priv->lock);
+}
+
+static inline void orinoco_unlock_irq(struct orinoco_private *priv)
+{
+       priv->hw.ops->unlock_irq(&priv->lock);
 }
 
 /*** Navigate from net_device to orinoco_private ***/
index 03056ab73032b2067b5239d983b1ffa5de74aaad..b16d5db52a4d96f858db37a79d066c873ac6014a 100644 (file)
@@ -281,7 +281,7 @@ orinoco_cs_config(struct pcmcia_device *link)
 
        /* Register an interface with the stack */
        if (orinoco_if_add(priv, link->io.BasePort1,
-                          link->irq) != 0) {
+                          link->irq, NULL) != 0) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
@@ -306,9 +306,9 @@ orinoco_cs_release(struct pcmcia_device *link)
 
        /* We're committed to taking the device away now, so mark the
         * hardware as unavailable */
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        pcmcia_disable_device(link);
        if (priv->hw.iobase)
@@ -353,87 +353,90 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
        "Pavel Roskin <proski@gnu.org>, et al)";
 
 static struct pcmcia_device_id orinoco_cs_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
-       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
-       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
-       PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
-       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
        PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
        PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
-       PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
        PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
        PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
        PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */
        PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
-       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
-       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
-       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
-       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
        PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
        PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
        PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
        PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
+       PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
+       PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
+       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
+       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
+       PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
+       PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
+       PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+       PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
+       PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
+       PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
+       PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
+       PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
+       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
+       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
+       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
+       PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
+       PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
+       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
+       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
+       PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
+#ifdef CONFIG_HERMES_PRISM
+       /* Only entries that certainly identify Prism chipset */
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
+       PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
+       PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
+       PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
+       PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
+       PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
+       PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
+       PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
        PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
        PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
        PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
        PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
        PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
        PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
-       PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
-       PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
+       PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
        PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
        PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
-       PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
-       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
-       PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
-       PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
-       PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
-       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
        PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
-       PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+       PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
        PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
        PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
        PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
+       PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
        PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
        PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
-       PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
-       PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
-       PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
-       PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
-       PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
-       PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
+       PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
        PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
        PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
        PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
-       PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
        PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
-       PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
-       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
-       PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
        PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
-       PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
-       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
        PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
-       PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
+       PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
        PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
-       PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
        PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
        PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
-       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
-       PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
-       PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
        PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
        PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
-       PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
        PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
        PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
        PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
        PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
        PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
+#endif
        PCMCIA_DEVICE_NULL,
 };
 MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
index 075f446b3139269cd0e492dd17fcba6c65fe19c8..bc3ea0b67a4f8ec83eb62f283455bdf4b05034af 100644 (file)
@@ -220,7 +220,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
index bda5317cc596038c91f2e966c94c69185c9a1ac6..468197f86673e3b0569e993218d96ac257f44c04 100644 (file)
@@ -170,7 +170,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
index e0d5874ab42fb9090ccaad1fa3e39e882ce4acef..9358f4d2307bb19265f462227bc3c8dd81ace14e 100644 (file)
@@ -259,7 +259,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
index 88cbc7902aa0a1e5c31de5a6b66534babbed8561..784605f0af157e193c6f99e5eab5d0ce2afa3d29 100644 (file)
@@ -156,7 +156,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
                goto fail;
        }
 
-       err = orinoco_if_add(priv, 0, 0);
+       err = orinoco_if_add(priv, 0, 0, NULL);
        if (err) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto fail;
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
new file mode 100644 (file)
index 0000000..78f089b
--- /dev/null
@@ -0,0 +1,1795 @@
+/*
+ * USB Orinoco driver
+ *
+ * Copyright (c) 2003 Manuel Estrada Sainz
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use your
+ * version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ *
+ * Queueing code based on linux-wlan-ng 0.2.1-pre5
+ *
+ * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
+ *
+ *     The license is the same as above.
+ *
+ * Initialy based on USB Skeleton driver - 0.7
+ *
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ * NOTE: The original USB Skeleton driver is GPL, but all that code is
+ * gone so MPL/GPL applies.
+ */
+
+#define DRIVER_NAME "orinoco_usb"
+#define PFX DRIVER_NAME ": "
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/timer.h>
+
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+
+#include "mic.h"
+#include "orinoco.h"
+
+#ifndef URB_ASYNC_UNLINK
+#define URB_ASYNC_UNLINK 0
+#endif
+
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD                (sizeof(encaps_hdr) + 2)
+
+struct header_struct {
+       /* 802.3 */
+       u8 dest[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       __be16 len;
+       /* 802.2 */
+       u8 dsap;
+       u8 ssap;
+       u8 ctrl;
+       /* SNAP */
+       u8 oui[3];
+       __be16 ethertype;
+} __attribute__ ((packed));
+
+struct ez_usb_fw {
+       u16 size;
+       const u8 *code;
+};
+
+static struct ez_usb_fw firmware = {
+       .size = 0,
+       .code = NULL,
+};
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* Debugging macros */
+#undef dbg
+#define dbg(format, arg...) \
+       do { if (debug) printk(KERN_DEBUG PFX "%s: " format "\n", \
+                              __func__ , ## arg); } while (0)
+#undef err
+#define err(format, arg...) \
+       do { printk(KERN_ERR PFX format "\n", ## arg); } while (0)
+
+/* Module paramaters */
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+MODULE_FIRMWARE("orinoco_ezusb_fw");
+
+/*
+ * Under some conditions, the card gets stuck and stops paying attention
+ * to the world (i.e. data communication stalls) until we do something to
+ * it.  Sending an INQ_TALLIES command seems to be enough and should be
+ * harmless otherwise.  This behaviour has been observed when using the
+ * driver on a systemimager client during installation.  In the past a
+ * timer was used to send INQ_TALLIES commands when there was no other
+ * activity, but it was troublesome and was removed.
+ */
+
+#define USB_COMPAQ_VENDOR_ID     0x049f /* Compaq Computer Corp. */
+#define USB_COMPAQ_WL215_ID      0x001f /* Compaq WL215 USB Adapter */
+#define USB_COMPAQ_W200_ID       0x0076 /* Compaq W200 USB Adapter */
+#define USB_HP_WL215_ID          0x0082 /* Compaq WL215 USB Adapter */
+
+#define USB_MELCO_VENDOR_ID      0x0411
+#define USB_BUFFALO_L11_ID       0x0006 /* BUFFALO WLI-USB-L11 */
+#define USB_BUFFALO_L11G_WR_ID   0x000B /* BUFFALO WLI-USB-L11G-WR */
+#define USB_BUFFALO_L11G_ID      0x000D /* BUFFALO WLI-USB-L11G */
+
+#define USB_LUCENT_VENDOR_ID     0x047E /* Lucent Technologies */
+#define USB_LUCENT_ORINOCO_ID    0x0300 /* Lucent/Agere Orinoco USB Client */
+
+#define USB_AVAYA8_VENDOR_ID     0x0D98
+#define USB_AVAYAE_VENDOR_ID     0x0D9E
+#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya Wireless USB Card */
+
+#define USB_AGERE_VENDOR_ID      0x0D4E /* Agere Systems */
+#define USB_AGERE_MODEL0801_ID   0x1000 /* Wireless USB Card Model 0801 */
+#define USB_AGERE_MODEL0802_ID   0x1001 /* Wireless USB Card Model 0802 */
+#define USB_AGERE_REBRANDED_ID   0x047A /* WLAN USB Card */
+
+#define USB_ELSA_VENDOR_ID       0x05CC
+#define USB_ELSA_AIRLANCER_ID    0x3100 /* ELSA AirLancer USB-11 */
+
+#define USB_LEGEND_VENDOR_ID     0x0E7C
+#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet WLAN USB Card */
+
+#define USB_SAMSUNG_VENDOR_ID    0x04E8
+#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
+#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */
+#define USB_SAMSUNG_SEW2003U_ID  0x7011 /* Samsung SEW-2003U Card */
+
+#define USB_IGATE_VENDOR_ID      0x0681
+#define USB_IGATE_IGATE_11M_ID   0x0012 /* I-GATE 11M USB Card */
+
+#define USB_FUJITSU_VENDOR_ID    0x0BF8
+#define USB_FUJITSU_E1100_ID     0x1002 /* connect2AIR WLAN E-1100 USB */
+
+#define USB_2WIRE_VENDOR_ID      0x1630
+#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire Wireless USB adapter */
+
+
+#define EZUSB_REQUEST_FW_TRANS         0xA0
+#define EZUSB_REQUEST_TRIGER           0xAA
+#define EZUSB_REQUEST_TRIG_AC          0xAC
+#define EZUSB_CPUCS_REG                        0x7F92
+
+#define EZUSB_RID_TX                   0x0700
+#define EZUSB_RID_RX                   0x0701
+#define EZUSB_RID_INIT1                        0x0702
+#define EZUSB_RID_ACK                  0x0710
+#define EZUSB_RID_READ_PDA             0x0800
+#define EZUSB_RID_PROG_INIT            0x0852
+#define EZUSB_RID_PROG_SET_ADDR                0x0853
+#define EZUSB_RID_PROG_BYTES           0x0854
+#define EZUSB_RID_PROG_END             0x0855
+#define EZUSB_RID_DOCMD                        0x0860
+
+/* Recognize info frames */
+#define EZUSB_IS_INFO(id)              ((id >= 0xF000) && (id <= 0xF2FF))
+
+#define EZUSB_MAGIC                    0x0210
+
+#define EZUSB_FRAME_DATA               1
+#define EZUSB_FRAME_CONTROL            2
+
+#define DEF_TIMEOUT                    (3*HZ)
+
+#define BULK_BUF_SIZE                  2048
+
+#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
+
+#define FW_BUF_SIZE                    64
+#define FW_VAR_OFFSET_PTR              0x359
+#define FW_VAR_VALUE                   0
+#define FW_HOLE_START                  0x100
+#define FW_HOLE_END                    0x300
+
+struct ezusb_packet {
+       __le16 magic;           /* 0x0210 */
+       u8 req_reply_count;
+       u8 ans_reply_count;
+       __le16 frame_type;      /* 0x01 for data frames, 0x02 otherwise */
+       __le16 size;            /* transport size */
+       __le16 crc;             /* CRC up to here */
+       __le16 hermes_len;
+       __le16 hermes_rid;
+       u8 data[0];
+} __attribute__ ((packed));
+
+/* Table of devices that work or may work with this driver */
+static struct usb_device_id ezusb_table[] = {
+       {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)},
+       {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)},
+       {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)},
+       {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)},
+       {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)},
+       {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)},
+       {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)},
+       {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
+       {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
+       {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)},
+       {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)},
+       {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)},
+       {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)},
+       {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID,
+                       0, 0)},
+       {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)},
+       {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)},
+       {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)},
+       {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)},
+       {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)},
+       {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)},
+       {}                      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, ezusb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct ezusb_priv {
+       struct usb_device *udev;
+       struct net_device *dev;
+       struct mutex mtx;
+       spinlock_t req_lock;
+       struct list_head req_pending;
+       struct list_head req_active;
+       spinlock_t reply_count_lock;
+       u16 hermes_reg_fake[0x40];
+       u8 *bap_buf;
+       struct urb *read_urb;
+       int read_pipe;
+       int write_pipe;
+       u8 reply_count;
+};
+
+enum ezusb_state {
+       EZUSB_CTX_START,
+       EZUSB_CTX_QUEUED,
+       EZUSB_CTX_REQ_SUBMITTED,
+       EZUSB_CTX_REQ_COMPLETE,
+       EZUSB_CTX_RESP_RECEIVED,
+       EZUSB_CTX_REQ_TIMEOUT,
+       EZUSB_CTX_REQ_FAILED,
+       EZUSB_CTX_RESP_TIMEOUT,
+       EZUSB_CTX_REQSUBMIT_FAIL,
+       EZUSB_CTX_COMPLETE,
+};
+
+struct request_context {
+       struct list_head list;
+       atomic_t refcount;
+       struct completion done; /* Signals that CTX is dead */
+       int killed;
+       struct urb *outurb;     /* OUT for req pkt */
+       struct ezusb_priv *upriv;
+       struct ezusb_packet *buf;
+       int buf_length;
+       struct timer_list timer;        /* Timeout handling */
+       enum ezusb_state state; /* Current state */
+       /* the RID that we will wait for */
+       u16 out_rid;
+       u16 in_rid;
+};
+
+
+/* Forward declarations */
+static void ezusb_ctx_complete(struct request_context *ctx);
+static void ezusb_req_queue_run(struct ezusb_priv *upriv);
+static void ezusb_bulk_in_callback(struct urb *urb);
+
+static inline u8 ezusb_reply_inc(u8 count)
+{
+       if (count < 0x7F)
+               return count + 1;
+       else
+               return 1;
+}
+
+static void ezusb_request_context_put(struct request_context *ctx)
+{
+       if (!atomic_dec_and_test(&ctx->refcount))
+               return;
+
+       WARN_ON(!ctx->done.done);
+       BUG_ON(ctx->outurb->status == -EINPROGRESS);
+       BUG_ON(timer_pending(&ctx->timer));
+       usb_free_urb(ctx->outurb);
+       kfree(ctx->buf);
+       kfree(ctx);
+}
+
+static inline void ezusb_mod_timer(struct ezusb_priv *upriv,
+                                  struct timer_list *timer,
+                                  unsigned long expire)
+{
+       if (!upriv->udev)
+               return;
+       mod_timer(timer, expire);
+}
+
+static void ezusb_request_timerfn(u_long _ctx)
+{
+       struct request_context *ctx = (void *) _ctx;
+
+       ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+       if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) {
+               ctx->state = EZUSB_CTX_REQ_TIMEOUT;
+       } else {
+               ctx->state = EZUSB_CTX_RESP_TIMEOUT;
+               dbg("couldn't unlink");
+               atomic_inc(&ctx->refcount);
+               ctx->killed = 1;
+               ezusb_ctx_complete(ctx);
+               ezusb_request_context_put(ctx);
+       }
+};
+
+static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
+                                              u16 out_rid, u16 in_rid)
+{
+       struct request_context *ctx;
+
+       ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx)
+               return NULL;
+
+       memset(ctx, 0, sizeof(*ctx));
+
+       ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
+       if (!ctx->buf) {
+               kfree(ctx);
+               return NULL;
+       }
+       ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!ctx->outurb) {
+               kfree(ctx->buf);
+               kfree(ctx);
+               return NULL;
+       }
+
+       ctx->upriv = upriv;
+       ctx->state = EZUSB_CTX_START;
+       ctx->out_rid = out_rid;
+       ctx->in_rid = in_rid;
+
+       atomic_set(&ctx->refcount, 1);
+       init_completion(&ctx->done);
+
+       init_timer(&ctx->timer);
+       ctx->timer.function = ezusb_request_timerfn;
+       ctx->timer.data = (u_long) ctx;
+       return ctx;
+}
+
+
+/* Hopefully the real complete_all will soon be exported, in the mean
+ * while this should work. */
+static inline void ezusb_complete_all(struct completion *comp)
+{
+       complete(comp);
+       complete(comp);
+       complete(comp);
+       complete(comp);
+}
+
+static void ezusb_ctx_complete(struct request_context *ctx)
+{
+       struct ezusb_priv *upriv = ctx->upriv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       list_del_init(&ctx->list);
+       if (upriv->udev) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               ezusb_req_queue_run(upriv);
+               spin_lock_irqsave(&upriv->req_lock, flags);
+       }
+
+       switch (ctx->state) {
+       case EZUSB_CTX_COMPLETE:
+       case EZUSB_CTX_REQSUBMIT_FAIL:
+       case EZUSB_CTX_REQ_FAILED:
+       case EZUSB_CTX_REQ_TIMEOUT:
+       case EZUSB_CTX_RESP_TIMEOUT:
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) {
+                       struct net_device *dev = upriv->dev;
+                       struct orinoco_private *priv = ndev_priv(dev);
+                       struct net_device_stats *stats = &priv->stats;
+
+                       if (ctx->state != EZUSB_CTX_COMPLETE)
+                               stats->tx_errors++;
+                       else
+                               stats->tx_packets++;
+
+                       netif_wake_queue(dev);
+               }
+               ezusb_complete_all(&ctx->done);
+               ezusb_request_context_put(ctx);
+               break;
+
+       default:
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               if (!upriv->udev) {
+                       /* This is normal, as all request contexts get flushed
+                        * when the device is disconnected */
+                       err("Called, CTX not terminating, but device gone");
+                       ezusb_complete_all(&ctx->done);
+                       ezusb_request_context_put(ctx);
+                       break;
+               }
+
+               err("Called, CTX not in terminating state.");
+               /* Things are really bad if this happens. Just leak
+                * the CTX because it may still be linked to the
+                * queue or the OUT urb may still be active.
+                * Just leaking at least prevents an Oops or Panic.
+                */
+               break;
+       }
+}
+
+/**
+ * ezusb_req_queue_run:
+ * Description:
+ *     Note: Only one active CTX at any one time, because there's no
+ *     other (reliable) way to match the response URB to the correct
+ *     CTX.
+ **/
+static void ezusb_req_queue_run(struct ezusb_priv *upriv)
+{
+       unsigned long flags;
+       struct request_context *ctx;
+       int result;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       if (!list_empty(&upriv->req_active))
+               goto unlock;
+
+       if (list_empty(&upriv->req_pending))
+               goto unlock;
+
+       ctx =
+           list_entry(upriv->req_pending.next, struct request_context,
+                      list);
+
+       if (!ctx->upriv->udev)
+               goto unlock;
+
+       /* We need to split this off to avoid a race condition */
+       list_move_tail(&ctx->list, &upriv->req_active);
+
+       if (ctx->state == EZUSB_CTX_QUEUED) {
+               atomic_inc(&ctx->refcount);
+               result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
+               if (result) {
+                       ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
+
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+                       err("Fatal, failed to submit command urb."
+                           " error=%d\n", result);
+
+                       ezusb_ctx_complete(ctx);
+                       ezusb_request_context_put(ctx);
+                       goto done;
+               }
+
+               ctx->state = EZUSB_CTX_REQ_SUBMITTED;
+               ezusb_mod_timer(ctx->upriv, &ctx->timer,
+                               jiffies + DEF_TIMEOUT);
+       }
+
+ unlock:
+       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+ done:
+       return;
+}
+
+static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
+                                 struct request_context *ctx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       if (!ctx->upriv->udev) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               goto done;
+       }
+       atomic_inc(&ctx->refcount);
+       list_add_tail(&ctx->list, &upriv->req_pending);
+       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+       ctx->state = EZUSB_CTX_QUEUED;
+       ezusb_req_queue_run(upriv);
+
+ done:
+       return;
+}
+
+static void ezusb_request_out_callback(struct urb *urb)
+{
+       unsigned long flags;
+       enum ezusb_state state;
+       struct request_context *ctx = urb->context;
+       struct ezusb_priv *upriv = ctx->upriv;
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+
+       del_timer(&ctx->timer);
+
+       if (ctx->killed) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               pr_warning("interrupt called with dead ctx");
+               goto out;
+       }
+
+       state = ctx->state;
+
+       if (urb->status == 0) {
+               switch (state) {
+               case EZUSB_CTX_REQ_SUBMITTED:
+                       if (ctx->in_rid) {
+                               ctx->state = EZUSB_CTX_REQ_COMPLETE;
+                               /* reply URB still pending */
+                               ezusb_mod_timer(upriv, &ctx->timer,
+                                               jiffies + DEF_TIMEOUT);
+                               spin_unlock_irqrestore(&upriv->req_lock,
+                                                      flags);
+                               break;
+                       }
+                       /* fall through */
+               case EZUSB_CTX_RESP_RECEIVED:
+                       /* IN already received before this OUT-ACK */
+                       ctx->state = EZUSB_CTX_COMPLETE;
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+                       ezusb_ctx_complete(ctx);
+                       break;
+
+               default:
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+                       err("Unexpected state(0x%x, %d) in OUT URB",
+                           state, urb->status);
+                       break;
+               }
+       } else {
+               /* If someone cancels the OUT URB then its status
+                * should be either -ECONNRESET or -ENOENT.
+                */
+               switch (state) {
+               case EZUSB_CTX_REQ_SUBMITTED:
+               case EZUSB_CTX_RESP_RECEIVED:
+                       ctx->state = EZUSB_CTX_REQ_FAILED;
+                       /* fall through */
+
+               case EZUSB_CTX_REQ_FAILED:
+               case EZUSB_CTX_REQ_TIMEOUT:
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+                       ezusb_ctx_complete(ctx);
+                       break;
+
+               default:
+                       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+                       err("Unexpected state(0x%x, %d) in OUT URB",
+                           state, urb->status);
+                       break;
+               }
+       }
+ out:
+       ezusb_request_context_put(ctx);
+}
+
+static void ezusb_request_in_callback(struct ezusb_priv *upriv,
+                                     struct urb *urb)
+{
+       struct ezusb_packet *ans = urb->transfer_buffer;
+       struct request_context *ctx = NULL;
+       enum ezusb_state state;
+       unsigned long flags;
+
+       /* Find the CTX on the active queue that requested this URB */
+       spin_lock_irqsave(&upriv->req_lock, flags);
+       if (upriv->udev) {
+               struct list_head *item;
+
+               list_for_each(item, &upriv->req_active) {
+                       struct request_context *c;
+                       int reply_count;
+
+                       c = list_entry(item, struct request_context, list);
+                       reply_count =
+                           ezusb_reply_inc(c->buf->req_reply_count);
+                       if ((ans->ans_reply_count == reply_count)
+                           && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) {
+                               ctx = c;
+                               break;
+                       }
+                       dbg("Skipped (0x%x/0x%x) (%d/%d)",
+                           le16_to_cpu(ans->hermes_rid),
+                           c->in_rid, ans->ans_reply_count, reply_count);
+               }
+       }
+
+       if (ctx == NULL) {
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               err("%s: got unexpected RID: 0x%04X", __func__,
+                   le16_to_cpu(ans->hermes_rid));
+               ezusb_req_queue_run(upriv);
+               return;
+       }
+
+       /* The data we want is in the in buffer, exchange */
+       urb->transfer_buffer = ctx->buf;
+       ctx->buf = (void *) ans;
+       ctx->buf_length = urb->actual_length;
+
+       state = ctx->state;
+       switch (state) {
+       case EZUSB_CTX_REQ_SUBMITTED:
+               /* We have received our response URB before
+                * our request has been acknowledged. Do NOT
+                * destroy our CTX yet, because our OUT URB
+                * is still alive ...
+                */
+               ctx->state = EZUSB_CTX_RESP_RECEIVED;
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               /* Let the machine continue running. */
+               break;
+
+       case EZUSB_CTX_REQ_COMPLETE:
+               /* This is the usual path: our request
+                * has already been acknowledged, and
+                * we have now received the reply.
+                */
+               ctx->state = EZUSB_CTX_COMPLETE;
+
+               /* Stop the intimer */
+               del_timer(&ctx->timer);
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               /* Call the completion handler */
+               ezusb_ctx_complete(ctx);
+               break;
+
+       default:
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+               pr_warning("Matched IN URB, unexpected context state(0x%x)",
+                    state);
+               /* Throw this CTX away and try submitting another */
+               del_timer(&ctx->timer);
+               ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+               usb_unlink_urb(ctx->outurb);
+               ezusb_req_queue_run(upriv);
+               break;
+       }                       /* switch */
+}
+
+
+static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
+                              struct request_context *ctx)
+{
+       switch (ctx->state) {
+       case EZUSB_CTX_QUEUED:
+       case EZUSB_CTX_REQ_SUBMITTED:
+       case EZUSB_CTX_REQ_COMPLETE:
+       case EZUSB_CTX_RESP_RECEIVED:
+               if (in_softirq()) {
+                       /* If we get called from a timer, timeout timers don't
+                        * get the chance to run themselves. So we make sure
+                        * that we don't sleep for ever */
+                       int msecs = DEF_TIMEOUT * (1000 / HZ);
+                       while (!ctx->done.done && msecs--)
+                               udelay(1000);
+               } else {
+                       wait_event_interruptible(ctx->done.wait,
+                                                ctx->done.done);
+               }
+               break;
+       default:
+               /* Done or failed - nothing to wait for */
+               break;
+       }
+}
+
+static inline u16 build_crc(struct ezusb_packet *data)
+{
+       u16 crc = 0;
+       u8 *bytes = (u8 *)data;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               crc = (crc << 1) + bytes[i];
+
+       return crc;
+}
+
+/**
+ * ezusb_fill_req:
+ *
+ * if data == NULL and length > 0 the data is assumed to be already in
+ * the target buffer and only the header is filled.
+ *
+ */
+static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid,
+                         const void *data, u16 frame_type, u8 reply_count)
+{
+       int total_size = sizeof(*req) + length;
+
+       BUG_ON(total_size > BULK_BUF_SIZE);
+
+       req->magic = cpu_to_le16(EZUSB_MAGIC);
+       req->req_reply_count = reply_count;
+       req->ans_reply_count = 0;
+       req->frame_type = cpu_to_le16(frame_type);
+       req->size = cpu_to_le16(length + 4);
+       req->crc = cpu_to_le16(build_crc(req));
+       req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length));
+       req->hermes_rid = cpu_to_le16(rid);
+       if (data)
+               memcpy(req->data, data, length);
+       return total_size;
+}
+
+static int ezusb_submit_in_urb(struct ezusb_priv *upriv)
+{
+       int retval = 0;
+       void *cur_buf = upriv->read_urb->transfer_buffer;
+
+       if (upriv->read_urb->status == -EINPROGRESS) {
+               dbg("urb busy, not resubmiting");
+               retval = -EBUSY;
+               goto exit;
+       }
+       usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe,
+                         cur_buf, BULK_BUF_SIZE,
+                         ezusb_bulk_in_callback, upriv);
+       upriv->read_urb->transfer_flags = 0;
+       retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC);
+       if (retval)
+               err("%s submit failed %d", __func__, retval);
+
+ exit:
+       return retval;
+}
+
+static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
+{
+       u8 res_val = reset;     /* avoid argument promotion */
+
+       if (!upriv->udev) {
+               err("%s: !upriv->udev", __func__);
+               return -EFAULT;
+       }
+       return usb_control_msg(upriv->udev,
+                              usb_sndctrlpipe(upriv->udev, 0),
+                              EZUSB_REQUEST_FW_TRANS,
+                              USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                              USB_DIR_OUT, EZUSB_CPUCS_REG, 0, &res_val,
+                              sizeof(res_val), DEF_TIMEOUT);
+}
+
+static int ezusb_firmware_download(struct ezusb_priv *upriv,
+                                  struct ez_usb_fw *fw)
+{
+       u8 fw_buffer[FW_BUF_SIZE];
+       int retval, addr;
+       int variant_offset;
+
+       /*
+        * This byte is 1 and should be replaced with 0.  The offset is
+        * 0x10AD in version 0.0.6.  The byte in question should follow
+        * the end of the code pointed to by the jump in the beginning
+        * of the firmware.  Also, it is read by code located at 0x358.
+        */
+       variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]);
+       if (variant_offset >= fw->size) {
+               printk(KERN_ERR PFX "Invalid firmware variant offset: "
+                      "0x%04x\n", variant_offset);
+               retval = -EINVAL;
+               goto fail;
+       }
+
+       retval = ezusb_8051_cpucs(upriv, 1);
+       if (retval < 0)
+               goto fail;
+       for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) {
+               /* 0x100-0x300 should be left alone, it contains card
+                * specific data, like USB enumeration information */
+               if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END))
+                       continue;
+
+               memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE);
+               if (variant_offset >= addr &&
+                   variant_offset < addr + FW_BUF_SIZE) {
+                       dbg("Patching card_variant byte at 0x%04X",
+                           variant_offset);
+                       fw_buffer[variant_offset - addr] = FW_VAR_VALUE;
+               }
+               retval = usb_control_msg(upriv->udev,
+                                        usb_sndctrlpipe(upriv->udev, 0),
+                                        EZUSB_REQUEST_FW_TRANS,
+                                        USB_TYPE_VENDOR | USB_RECIP_DEVICE
+                                        | USB_DIR_OUT,
+                                        addr, 0x0,
+                                        fw_buffer, FW_BUF_SIZE,
+                                        DEF_TIMEOUT);
+
+               if (retval < 0)
+                       goto fail;
+       }
+       retval = ezusb_8051_cpucs(upriv, 0);
+       if (retval < 0)
+               goto fail;
+
+       goto exit;
+ fail:
+       printk(KERN_ERR PFX "Firmware download failed, error %d\n",
+              retval);
+ exit:
+       return retval;
+}
+
+static int ezusb_access_ltv(struct ezusb_priv *upriv,
+                           struct request_context *ctx,
+                           u16 length, const void *data, u16 frame_type,
+                           void *ans_buff, int ans_size, u16 *ans_length)
+{
+       int req_size;
+       int retval = 0;
+       enum ezusb_state state;
+
+       BUG_ON(in_irq());
+
+       if (!upriv->udev) {
+               dbg("Device disconnected");
+               return -ENODEV;
+       }
+
+       if (upriv->read_urb->status != -EINPROGRESS)
+               err("%s: in urb not pending", __func__);
+
+       /* protect upriv->reply_count, guarantee sequential numbers */
+       spin_lock_bh(&upriv->reply_count_lock);
+       req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data,
+                                 frame_type, upriv->reply_count);
+       usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe,
+                         ctx->buf, req_size,
+                         ezusb_request_out_callback, ctx);
+
+       if (ctx->in_rid)
+               upriv->reply_count = ezusb_reply_inc(upriv->reply_count);
+
+       ezusb_req_enqueue_run(upriv, ctx);
+
+       spin_unlock_bh(&upriv->reply_count_lock);
+
+       if (ctx->in_rid)
+               ezusb_req_ctx_wait(upriv, ctx);
+
+       state = ctx->state;
+       switch (state) {
+       case EZUSB_CTX_COMPLETE:
+               retval = ctx->outurb->status;
+               break;
+
+       case EZUSB_CTX_QUEUED:
+       case EZUSB_CTX_REQ_SUBMITTED:
+               if (!ctx->in_rid)
+                       break;
+       default:
+               err("%s: Unexpected context state %d", __func__,
+                   state);
+               /* fall though */
+       case EZUSB_CTX_REQ_TIMEOUT:
+       case EZUSB_CTX_REQ_FAILED:
+       case EZUSB_CTX_RESP_TIMEOUT:
+       case EZUSB_CTX_REQSUBMIT_FAIL:
+               printk(KERN_ERR PFX "Access failed, resetting (state %d,"
+                      " reply_count %d)\n", state, upriv->reply_count);
+               upriv->reply_count = 0;
+               if (state == EZUSB_CTX_REQ_TIMEOUT
+                   || state == EZUSB_CTX_RESP_TIMEOUT) {
+                       printk(KERN_ERR PFX "ctx timed out\n");
+                       retval = -ETIMEDOUT;
+               } else {
+                       printk(KERN_ERR PFX "ctx failed\n");
+                       retval = -EFAULT;
+               }
+               goto exit;
+               break;
+       }
+       if (ctx->in_rid) {
+               struct ezusb_packet *ans = ctx->buf;
+               int exp_len;
+
+               if (ans->hermes_len != 0)
+                       exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
+               else
+                       exp_len = 14;
+
+               if (exp_len != ctx->buf_length) {
+                       err("%s: length mismatch for RID 0x%04x: "
+                           "expected %d, got %d", __func__,
+                           ctx->in_rid, exp_len, ctx->buf_length);
+                       retval = -EIO;
+                       goto exit;
+               }
+
+               if (ans_buff)
+                       memcpy(ans_buff, ans->data,
+                              min_t(int, exp_len, ans_size));
+               if (ans_length)
+                       *ans_length = le16_to_cpu(ans->hermes_len);
+       }
+ exit:
+       ezusb_request_context_put(ctx);
+       return retval;
+}
+
+static int ezusb_write_ltv(hermes_t *hw, int bap, u16 rid,
+                          u16 length, const void *data)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       u16 frame_type;
+       struct request_context *ctx;
+
+       if (length == 0)
+               return -EINVAL;
+
+       length = HERMES_RECLEN_TO_BYTES(length);
+
+       /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be
+        * set to be empty, but the USB bridge doesn't like it */
+       if (length == 0)
+               return 0;
+
+       ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       if (rid == EZUSB_RID_TX)
+               frame_type = EZUSB_FRAME_DATA;
+       else
+               frame_type = EZUSB_FRAME_CONTROL;
+
+       return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
+                               NULL, 0, NULL);
+}
+
+static int ezusb_read_ltv(hermes_t *hw, int bap, u16 rid,
+                         unsigned bufsize, u16 *length, void *buf)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       if ((bufsize < 0) || (bufsize % 2))
+               return -EINVAL;
+
+       ctx = ezusb_alloc_ctx(upriv, rid, rid);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
+                               buf, bufsize, length);
+}
+
+static int ezusb_doicmd_wait(hermes_t *hw, u16 cmd, u16 parm0, u16 parm1,
+                            u16 parm2, struct hermes_response *resp)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       __le16 data[4] = {
+               cpu_to_le16(cmd),
+               cpu_to_le16(parm0),
+               cpu_to_le16(parm1),
+               cpu_to_le16(parm2),
+       };
+       dbg("0x%04X, parm0 0x%04X, parm1 0x%04X, parm2 0x%04X",
+           cmd, parm0, parm1, parm2);
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
+                           struct hermes_response *resp)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       __le16 data[4] = {
+               cpu_to_le16(cmd),
+               cpu_to_le16(parm0),
+               0,
+               0,
+       };
+       dbg("0x%04X, parm0 0x%04X", cmd, parm0);
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_bap_pread(struct hermes *hw, int bap,
+                          void *buf, int len, u16 id, u16 offset)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer;
+       int actual_length = upriv->read_urb->actual_length;
+
+       if (id == EZUSB_RID_RX) {
+               if ((sizeof(*ans) + offset + len) > actual_length) {
+                       printk(KERN_ERR PFX "BAP read beyond buffer end "
+                              "in rx frame\n");
+                       return -EINVAL;
+               }
+               memcpy(buf, ans->data + offset, len);
+               return 0;
+       }
+
+       if (EZUSB_IS_INFO(id)) {
+               /* Include 4 bytes for length/type */
+               if ((sizeof(*ans) + offset + len - 4) > actual_length) {
+                       printk(KERN_ERR PFX "BAP read beyond buffer end "
+                              "in info frame\n");
+                       return -EFAULT;
+               }
+               memcpy(buf, ans->data + offset - 4, len);
+       } else {
+               printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
+                         u32 pda_addr, u16 pda_len)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+       __le16 data[] = {
+               cpu_to_le16(pda_addr & 0xffff),
+               cpu_to_le16(pda_len - 4)
+       };
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
+       if (!ctx)
+               return -ENOMEM;
+
+       /* wl_lkm does not include PDA size in the PDA area.
+        * We will pad the information into pda, so other routines
+        * don't have to be modified */
+       pda[0] = cpu_to_le16(pda_len - 2);
+       /* Includes CFG_PROD_DATA but not itself */
+       pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
+                               NULL);
+}
+
+static int ezusb_program_init(struct hermes *hw, u32 entry_point)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+       __le32 data = cpu_to_le32(entry_point);
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_end(struct hermes *hw)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, 0, NULL,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program_bytes(struct hermes *hw, const char *buf,
+                              u32 addr, u32 len)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       struct request_context *ctx;
+       __le32 data = cpu_to_le32(addr);
+       int err;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
+                              EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+       if (err)
+               return err;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
+       if (!ctx)
+               return -ENOMEM;
+
+       return ezusb_access_ltv(upriv, ctx, len, buf,
+                               EZUSB_FRAME_CONTROL, NULL, 0, NULL);
+}
+
+static int ezusb_program(struct hermes *hw, const char *buf,
+                        u32 addr, u32 len)
+{
+       u32 ch_addr;
+       u32 ch_len;
+       int err = 0;
+
+       /* We can only send 2048 bytes out of the bulk xmit at a time,
+        * so we have to split any programming into chunks of <2048
+        * bytes. */
+
+       ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
+       ch_addr = addr;
+
+       while (ch_addr < (addr + len)) {
+               pr_debug("Programming subblock of length %d "
+                        "to address 0x%08x. Data @ %p\n",
+                        ch_len, ch_addr, &buf[ch_addr - addr]);
+
+               err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
+                                         ch_addr, ch_len);
+               if (err)
+                       break;
+
+               ch_addr += ch_len;
+               ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
+                       (addr + len - ch_addr) : MAX_DL_SIZE;
+       }
+
+       return err;
+}
+
+static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct orinoco_private *priv = ndev_priv(dev);
+       struct net_device_stats *stats = &priv->stats;
+       struct ezusb_priv *upriv = priv->card;
+       u8 mic[MICHAEL_MIC_LEN+1];
+       int err = 0;
+       int tx_control;
+       unsigned long flags;
+       struct request_context *ctx;
+       u8 *buf;
+       int tx_size;
+
+       if (!netif_running(dev)) {
+               printk(KERN_ERR "%s: Tx on stopped device!\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (netif_queue_stopped(dev)) {
+               printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (orinoco_lock(priv, &flags) != 0) {
+               printk(KERN_ERR
+                      "%s: ezusb_xmit() called while hw_unavailable\n",
+                      dev->name);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (!netif_carrier_ok(dev) ||
+           (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
+               /* Oops, the firmware hasn't established a connection,
+                  silently drop the packet (this seems to be the
+                  safest approach). */
+               goto drop;
+       }
+
+       /* Check packet length */
+       if (skb->len < ETH_HLEN)
+               goto drop;
+
+       ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
+       if (!ctx)
+               goto busy;
+
+       memset(ctx->buf, 0, BULK_BUF_SIZE);
+       buf = ctx->buf->data;
+
+       tx_control = 0;
+
+       err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
+                                      &mic[0]);
+       if (err)
+               goto drop;
+
+       {
+               __le16 *tx_cntl = (__le16 *)buf;
+               *tx_cntl = cpu_to_le16(tx_control);
+               buf += sizeof(*tx_cntl);
+       }
+
+       memcpy(buf, skb->data, skb->len);
+       buf += skb->len;
+
+       if (tx_control & HERMES_TXCTRL_MIC) {
+               u8 *m = mic;
+               /* Mic has been offset so it can be copied to an even
+                * address. We're copying eveything anyway, so we
+                * don't need to copy that first byte. */
+               if (skb->len % 2)
+                       m++;
+               memcpy(buf, m, MICHAEL_MIC_LEN);
+               buf += MICHAEL_MIC_LEN;
+       }
+
+       /* Finally, we actually initiate the send */
+       netif_stop_queue(dev);
+
+       /* The card may behave better if we send evenly sized usb transfers */
+       tx_size = ALIGN(buf - ctx->buf->data, 2);
+
+       err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
+                              EZUSB_FRAME_DATA, NULL, 0, NULL);
+
+       if (err) {
+               netif_start_queue(dev);
+               if (net_ratelimit())
+                       printk(KERN_ERR "%s: Error %d transmitting packet\n",
+                               dev->name, err);
+               goto busy;
+       }
+
+       dev->trans_start = jiffies;
+       stats->tx_bytes += skb->len;
+       goto ok;
+
+ drop:
+       stats->tx_errors++;
+       stats->tx_dropped++;
+
+ ok:
+       orinoco_unlock(priv, &flags);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+
+ busy:
+       orinoco_unlock(priv, &flags);
+       return NETDEV_TX_BUSY;
+}
+
+static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid)
+{
+       *fid = EZUSB_RID_TX;
+       return 0;
+}
+
+
+static int ezusb_hard_reset(struct orinoco_private *priv)
+{
+       struct ezusb_priv *upriv = priv->card;
+       int retval = ezusb_8051_cpucs(upriv, 1);
+
+       if (retval < 0) {
+               err("Failed to reset");
+               return retval;
+       }
+
+       retval = ezusb_8051_cpucs(upriv, 0);
+       if (retval < 0) {
+               err("Failed to unreset");
+               return retval;
+       }
+
+       dbg("sending control message");
+       retval = usb_control_msg(upriv->udev,
+                                usb_sndctrlpipe(upriv->udev, 0),
+                                EZUSB_REQUEST_TRIGER,
+                                USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                USB_DIR_OUT, 0x0, 0x0, NULL, 0,
+                                DEF_TIMEOUT);
+       if (retval < 0) {
+               err("EZUSB_REQUEST_TRIGER failed retval %d", retval);
+               return retval;
+       }
+#if 0
+       dbg("Sending EZUSB_REQUEST_TRIG_AC");
+       retval = usb_control_msg(upriv->udev,
+                                usb_sndctrlpipe(upriv->udev, 0),
+                                EZUSB_REQUEST_TRIG_AC,
+                                USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                USB_DIR_OUT, 0x00FA, 0x0, NULL, 0,
+                                DEF_TIMEOUT);
+       if (retval < 0) {
+               err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval);
+               return retval;
+       }
+#endif
+
+       return 0;
+}
+
+
+static int ezusb_init(hermes_t *hw)
+{
+       struct ezusb_priv *upriv = hw->priv;
+       int retval;
+
+       BUG_ON(in_interrupt());
+       BUG_ON(!upriv);
+
+       upriv->reply_count = 0;
+       /* Write the MAGIC number on the simulated registers to keep
+        * orinoco.c happy */
+       hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+       hermes_write_regn(hw, RXFID, EZUSB_RID_RX);
+
+       usb_kill_urb(upriv->read_urb);
+       ezusb_submit_in_urb(upriv);
+
+       retval = ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
+                                HERMES_BYTES_TO_RECLEN(2), "\x10\x00");
+       if (retval < 0) {
+               printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
+               return retval;
+       }
+
+       retval = ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL);
+       if (retval < 0) {
+               printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
+               return retval;
+       }
+
+       return 0;
+}
+
+static void ezusb_bulk_in_callback(struct urb *urb)
+{
+       struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context;
+       struct ezusb_packet *ans = urb->transfer_buffer;
+       u16 crc;
+       u16 hermes_rid;
+
+       if (upriv->udev == NULL) {
+               dbg("disconnected");
+               return;
+       }
+
+       if (urb->status == -ETIMEDOUT) {
+               /* When a device gets unplugged we get this every time
+                * we resubmit, flooding the logs.  Since we don't use
+                * USB timeouts, it shouldn't happen any other time*/
+               pr_warning("%s: urb timed out, not resubmiting", __func__);
+               return;
+       }
+       if (urb->status == -ECONNABORTED) {
+               pr_warning("%s: connection abort, resubmiting urb",
+                    __func__);
+               goto resubmit;
+       }
+       if ((urb->status == -EILSEQ)
+           || (urb->status == -ENOENT)
+           || (urb->status == -ECONNRESET)) {
+               dbg("status %d, not resubmiting", urb->status);
+               return;
+       }
+       if (urb->status)
+               dbg("status: %d length: %d",
+                   urb->status, urb->actual_length);
+       if (urb->actual_length < sizeof(*ans)) {
+               err("%s: short read, ignoring", __func__);
+               goto resubmit;
+       }
+       crc = build_crc(ans);
+       if (le16_to_cpu(ans->crc) != crc) {
+               err("CRC error, ignoring packet");
+               goto resubmit;
+       }
+
+       hermes_rid = le16_to_cpu(ans->hermes_rid);
+       if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) {
+               ezusb_request_in_callback(upriv, urb);
+       } else if (upriv->dev) {
+               struct net_device *dev = upriv->dev;
+               struct orinoco_private *priv = ndev_priv(dev);
+               hermes_t *hw = &priv->hw;
+
+               if (hermes_rid == EZUSB_RID_RX) {
+                       __orinoco_ev_rx(dev, hw);
+               } else {
+                       hermes_write_regn(hw, INFOFID,
+                                         le16_to_cpu(ans->hermes_rid));
+                       __orinoco_ev_info(dev, hw);
+               }
+       }
+
+ resubmit:
+       if (upriv->udev)
+               ezusb_submit_in_urb(upriv);
+}
+
+static inline void ezusb_delete(struct ezusb_priv *upriv)
+{
+       struct net_device *dev;
+       struct list_head *item;
+       struct list_head *tmp_item;
+       unsigned long flags;
+
+       BUG_ON(in_interrupt());
+       BUG_ON(!upriv);
+
+       dev = upriv->dev;
+       mutex_lock(&upriv->mtx);
+
+       upriv->udev = NULL;     /* No timer will be rearmed from here */
+
+       usb_kill_urb(upriv->read_urb);
+
+       spin_lock_irqsave(&upriv->req_lock, flags);
+       list_for_each_safe(item, tmp_item, &upriv->req_active) {
+               struct request_context *ctx;
+               int err;
+
+               ctx = list_entry(item, struct request_context, list);
+               atomic_inc(&ctx->refcount);
+
+               ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
+               err = usb_unlink_urb(ctx->outurb);
+
+               spin_unlock_irqrestore(&upriv->req_lock, flags);
+               if (err == -EINPROGRESS)
+                       wait_for_completion(&ctx->done);
+
+               del_timer_sync(&ctx->timer);
+               /* FIXME: there is an slight chance for the irq handler to
+                * be running */
+               if (!list_empty(&ctx->list))
+                       ezusb_ctx_complete(ctx);
+
+               ezusb_request_context_put(ctx);
+               spin_lock_irqsave(&upriv->req_lock, flags);
+       }
+       spin_unlock_irqrestore(&upriv->req_lock, flags);
+
+       list_for_each_safe(item, tmp_item, &upriv->req_pending)
+           ezusb_ctx_complete(list_entry(item,
+                                         struct request_context, list));
+
+       if (upriv->read_urb->status == -EINPROGRESS)
+               printk(KERN_ERR PFX "Some URB in progress\n");
+
+       mutex_unlock(&upriv->mtx);
+
+       kfree(upriv->read_urb->transfer_buffer);
+       if (upriv->bap_buf != NULL)
+               kfree(upriv->bap_buf);
+       if (upriv->read_urb != NULL)
+               usb_free_urb(upriv->read_urb);
+       if (upriv->dev) {
+               struct orinoco_private *priv = ndev_priv(upriv->dev);
+               orinoco_if_del(priv);
+               free_orinocodev(priv);
+       }
+}
+
+static void ezusb_lock_irqsave(spinlock_t *lock,
+                              unsigned long *flags) __acquires(lock)
+{
+       spin_lock_bh(lock);
+}
+
+static void ezusb_unlock_irqrestore(spinlock_t *lock,
+                                   unsigned long *flags) __releases(lock)
+{
+       spin_unlock_bh(lock);
+}
+
+static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock)
+{
+       spin_lock_bh(lock);
+}
+
+static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock)
+{
+       spin_unlock_bh(lock);
+}
+
+static const struct hermes_ops ezusb_ops = {
+       .init = ezusb_init,
+       .cmd_wait = ezusb_docmd_wait,
+       .init_cmd_wait = ezusb_doicmd_wait,
+       .allocate = ezusb_allocate,
+       .read_ltv = ezusb_read_ltv,
+       .write_ltv = ezusb_write_ltv,
+       .bap_pread = ezusb_bap_pread,
+       .read_pda = ezusb_read_pda,
+       .program_init = ezusb_program_init,
+       .program_end = ezusb_program_end,
+       .program = ezusb_program,
+       .lock_irqsave = ezusb_lock_irqsave,
+       .unlock_irqrestore = ezusb_unlock_irqrestore,
+       .lock_irq = ezusb_lock_irq,
+       .unlock_irq = ezusb_unlock_irq,
+};
+
+static const struct net_device_ops ezusb_netdev_ops = {
+       .ndo_open               = orinoco_open,
+       .ndo_stop               = orinoco_stop,
+       .ndo_start_xmit         = ezusb_xmit,
+       .ndo_set_multicast_list = orinoco_set_multicast_list,
+       .ndo_change_mtu         = orinoco_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_tx_timeout         = orinoco_tx_timeout,
+       .ndo_get_stats          = orinoco_get_stats,
+};
+
+static int ezusb_probe(struct usb_interface *interface,
+                      const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(interface);
+       struct orinoco_private *priv;
+       hermes_t *hw;
+       struct ezusb_priv *upriv = NULL;
+       struct usb_interface_descriptor *iface_desc;
+       struct usb_endpoint_descriptor *ep;
+       const struct firmware *fw_entry;
+       int retval = 0;
+       int i;
+
+       priv = alloc_orinocodev(sizeof(*upriv), &udev->dev,
+                               ezusb_hard_reset, NULL);
+       if (!priv) {
+               err("Couldn't allocate orinocodev");
+               goto exit;
+       }
+
+       hw = &priv->hw;
+
+       upriv = priv->card;
+
+       mutex_init(&upriv->mtx);
+       spin_lock_init(&upriv->reply_count_lock);
+
+       spin_lock_init(&upriv->req_lock);
+       INIT_LIST_HEAD(&upriv->req_pending);
+       INIT_LIST_HEAD(&upriv->req_active);
+
+       upriv->udev = udev;
+
+       hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake;
+       hw->reg_spacing = HERMES_16BIT_REGSPACING;
+       hw->priv = upriv;
+       hw->ops = &ezusb_ops;
+
+       /* set up the endpoint information */
+       /* check out the endpoints */
+
+       iface_desc = &interface->altsetting[0].desc;
+       for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
+               ep = &interface->altsetting[0].endpoint[i].desc;
+
+               if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                    == USB_DIR_IN) &&
+                   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                    == USB_ENDPOINT_XFER_BULK)) {
+                       /* we found a bulk in endpoint */
+                       if (upriv->read_urb != NULL) {
+                               pr_warning("Found a second bulk in ep, ignored");
+                               continue;
+                       }
+
+                       upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+                       if (!upriv->read_urb) {
+                               err("No free urbs available");
+                               goto error;
+                       }
+                       if (le16_to_cpu(ep->wMaxPacketSize) != 64)
+                               pr_warning("bulk in: wMaxPacketSize!= 64");
+                       if (ep->bEndpointAddress != (2 | USB_DIR_IN))
+                               pr_warning("bulk in: bEndpointAddress: %d",
+                                    ep->bEndpointAddress);
+                       upriv->read_pipe = usb_rcvbulkpipe(udev,
+                                                        ep->
+                                                        bEndpointAddress);
+                       upriv->read_urb->transfer_buffer =
+                           kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
+                       if (!upriv->read_urb->transfer_buffer) {
+                               err("Couldn't allocate IN buffer");
+                               goto error;
+                       }
+               }
+
+               if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                    == USB_DIR_OUT) &&
+                   ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                    == USB_ENDPOINT_XFER_BULK)) {
+                       /* we found a bulk out endpoint */
+                       if (upriv->bap_buf != NULL) {
+                               pr_warning("Found a second bulk out ep, ignored");
+                               continue;
+                       }
+
+                       if (le16_to_cpu(ep->wMaxPacketSize) != 64)
+                               pr_warning("bulk out: wMaxPacketSize != 64");
+                       if (ep->bEndpointAddress != 2)
+                               pr_warning("bulk out: bEndpointAddress: %d",
+                                    ep->bEndpointAddress);
+                       upriv->write_pipe = usb_sndbulkpipe(udev,
+                                                         ep->
+                                                         bEndpointAddress);
+                       upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
+                       if (!upriv->bap_buf) {
+                               err("Couldn't allocate bulk_out_buffer");
+                               goto error;
+                       }
+               }
+       }
+       if (!upriv->bap_buf || !upriv->read_urb) {
+               err("Didn't find the required bulk endpoints");
+               goto error;
+       }
+
+       if (request_firmware(&fw_entry, "orinoco_ezusb_fw",
+                            &interface->dev) == 0) {
+               firmware.size = fw_entry->size;
+               firmware.code = fw_entry->data;
+       }
+       if (firmware.size && firmware.code) {
+               ezusb_firmware_download(upriv, &firmware);
+       } else {
+               err("No firmware to download");
+               goto error;
+       }
+
+       if (ezusb_hard_reset(priv) < 0) {
+               err("Cannot reset the device");
+               goto error;
+       }
+
+       /* If the firmware is already downloaded orinoco.c will call
+        * ezusb_init but if the firmware is not already there, that will make
+        * the kernel very unstable, so we try initializing here and quit in
+        * case of error */
+       if (ezusb_init(hw) < 0) {
+               err("Couldn't initialize the device");
+               err("Firmware may not be downloaded or may be wrong.");
+               goto error;
+       }
+
+       /* Initialise the main driver */
+       if (orinoco_init(priv) != 0) {
+               err("orinoco_init() failed\n");
+               goto error;
+       }
+
+       if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {
+               upriv->dev = NULL;
+               err("%s: orinoco_if_add() failed", __func__);
+               goto error;
+       }
+       upriv->dev = priv->ndev;
+
+       goto exit;
+
+ error:
+       ezusb_delete(upriv);
+       if (upriv->dev) {
+               /* upriv->dev was 0, so ezusb_delete() didn't free it */
+               free_orinocodev(priv);
+       }
+       upriv = NULL;
+       retval = -EFAULT;
+ exit:
+       if (fw_entry) {
+               firmware.code = NULL;
+               firmware.size = 0;
+               release_firmware(fw_entry);
+       }
+       usb_set_intfdata(interface, upriv);
+       return retval;
+}
+
+
+static void ezusb_disconnect(struct usb_interface *intf)
+{
+       struct ezusb_priv *upriv = usb_get_intfdata(intf);
+       usb_set_intfdata(intf, NULL);
+       ezusb_delete(upriv);
+       printk(KERN_INFO PFX "Disconnected\n");
+}
+
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver orinoco_driver = {
+       .name = DRIVER_NAME,
+       .probe = ezusb_probe,
+       .disconnect = ezusb_disconnect,
+       .id_table = ezusb_table,
+};
+
+/* Can't be declared "const" or the whole __initdata section will
+ * become const */
+static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
+    " (Manuel Estrada Sainz)";
+
+static int __init ezusb_module_init(void)
+{
+       int err;
+
+       printk(KERN_DEBUG "%s\n", version);
+
+       /* register this driver with the USB subsystem */
+       err = usb_register(&orinoco_driver);
+       if (err < 0) {
+               printk(KERN_ERR PFX "usb_register failed, error %d\n",
+                      err);
+               return err;
+       }
+
+       return 0;
+}
+
+static void __exit ezusb_module_exit(void)
+{
+       /* deregister this driver with the USB subsystem */
+       usb_deregister(&orinoco_driver);
+}
+
+
+module_init(ezusb_module_init);
+module_exit(ezusb_module_exit);
+
+MODULE_AUTHOR("Manuel Estrada Sainz");
+MODULE_DESCRIPTION
+    ("Driver for Orinoco wireless LAN cards using EZUSB bridge");
+MODULE_LICENSE("Dual MPL/GPL");
index 330d42d453330ddbe7209fe81cff1de7b1f2b608..4300d9db7d8caab2d70442b7cbd37a9da69adef9 100644 (file)
@@ -127,7 +127,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
-       u8 *ie;
+       const u8 *ie;
        u64 timestamp;
        s32 signal;
        u16 capability;
@@ -136,7 +136,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
        int chan, freq;
 
        ie_len = len - sizeof(*bss);
-       ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+       ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
        chan = ie ? ie[2] : 0;
        freq = ieee80211_dsss_chan_to_freq(chan);
        channel = ieee80211_get_channel(wiphy, freq);
index 41b9ce425855eee5c2f7812316106aefa08361c2..b51a9adc80f6274648af92d4338cc37b5719b500 100644 (file)
@@ -337,6 +337,7 @@ spectrum_cs_config(struct pcmcia_device *link)
                goto failed;
 
        hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
+       hw->eeprom_pda = true;
 
        /*
         * This actually configures the PCMCIA socket -- setting up
@@ -359,7 +360,7 @@ spectrum_cs_config(struct pcmcia_device *link)
 
        /* Register an interface with the stack */
        if (orinoco_if_add(priv, link->io.BasePort1,
-                          link->irq) != 0) {
+                          link->irq, NULL) != 0) {
                printk(KERN_ERR PFX "orinoco_if_add() failed\n");
                goto failed;
        }
@@ -384,9 +385,9 @@ spectrum_cs_release(struct pcmcia_device *link)
 
        /* We're committed to taking the device away now, so mark the
         * hardware as unavailable */
-       spin_lock_irqsave(&priv->lock, flags);
+       priv->hw.ops->lock_irqsave(&priv->lock, &flags);
        priv->hw_unavailable++;
-       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
 
        pcmcia_disable_device(link);
        if (priv->hw.iobase)
index fbcc6e1a2e1d55f9631304e1f4562db55118bb01..5775124e2aeefd57215324cb1c778ad983f8b024 100644 (file)
@@ -458,7 +458,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
        if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
                /* Fast channel change - no commit if successful */
                hermes_t *hw = &priv->hw;
-               err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+               err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
                                            HERMES_TEST_SET_CHANNEL,
                                        chan, NULL);
        }
@@ -538,125 +538,6 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
        return -EINPROGRESS;            /* Call commit handler */
 }
 
-static int orinoco_ioctl_setrts(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct iw_param *rrq,
-                               char *extra)
-{
-       struct orinoco_private *priv = ndev_priv(dev);
-       int val = rrq->value;
-       unsigned long flags;
-
-       if (rrq->disabled)
-               val = 2347;
-
-       if ((val < 0) || (val > 2347))
-               return -EINVAL;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       priv->rts_thresh = val;
-       orinoco_unlock(priv, &flags);
-
-       return -EINPROGRESS;            /* Call commit handler */
-}
-
-static int orinoco_ioctl_getrts(struct net_device *dev,
-                               struct iw_request_info *info,
-                               struct iw_param *rrq,
-                               char *extra)
-{
-       struct orinoco_private *priv = ndev_priv(dev);
-
-       rrq->value = priv->rts_thresh;
-       rrq->disabled = (rrq->value == 2347);
-       rrq->fixed = 1;
-
-       return 0;
-}
-
-static int orinoco_ioctl_setfrag(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *frq,
-                                char *extra)
-{
-       struct orinoco_private *priv = ndev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (priv->has_mwo) {
-               if (frq->disabled)
-                       priv->mwo_robust = 0;
-               else {
-                       if (frq->fixed)
-                               printk(KERN_WARNING "%s: Fixed fragmentation "
-                                      "is not supported on this firmware. "
-                                      "Using MWO robust instead.\n",
-                                      dev->name);
-                       priv->mwo_robust = 1;
-               }
-       } else {
-               if (frq->disabled)
-                       priv->frag_thresh = 2346;
-               else {
-                       if ((frq->value < 256) || (frq->value > 2346))
-                               err = -EINVAL;
-                       else
-                               /* must be even */
-                               priv->frag_thresh = frq->value & ~0x1;
-               }
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
-static int orinoco_ioctl_getfrag(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_param *frq,
-                                char *extra)
-{
-       struct orinoco_private *priv = ndev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err;
-       u16 val;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       if (priv->has_mwo) {
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFMWOROBUST_AGERE,
-                                         &val);
-               if (err)
-                       val = 0;
-
-               frq->value = val ? 2347 : 0;
-               frq->disabled = !val;
-               frq->fixed = 0;
-       } else {
-               err = hermes_read_wordrec(hw, USER_BAP,
-                                         HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
-                                         &val);
-               if (err)
-                       val = 0;
-
-               frq->value = val;
-               frq->disabled = (val >= 2346);
-               frq->fixed = 1;
-       }
-
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
 static int orinoco_ioctl_setrate(struct net_device *dev,
                                 struct iw_request_info *info,
                                 struct iw_param *rrq,
@@ -1201,60 +1082,6 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
        return ret;
 }
 
-static int orinoco_ioctl_getretry(struct net_device *dev,
-                                 struct iw_request_info *info,
-                                 struct iw_param *rrq,
-                                 char *extra)
-{
-       struct orinoco_private *priv = ndev_priv(dev);
-       hermes_t *hw = &priv->hw;
-       int err = 0;
-       u16 short_limit, long_limit, lifetime;
-       unsigned long flags;
-
-       if (orinoco_lock(priv, &flags) != 0)
-               return -EBUSY;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
-                                 &short_limit);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
-                                 &long_limit);
-       if (err)
-               goto out;
-
-       err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
-                                 &lifetime);
-       if (err)
-               goto out;
-
-       rrq->disabled = 0;              /* Can't be disabled */
-
-       /* Note : by default, display the retry number */
-       if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-               rrq->flags = IW_RETRY_LIFETIME;
-               rrq->value = lifetime * 1000;   /* ??? */
-       } else {
-               /* By default, display the min number */
-               if ((rrq->flags & IW_RETRY_LONG)) {
-                       rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
-                       rrq->value = long_limit;
-               } else {
-                       rrq->flags = IW_RETRY_LIMIT;
-                       rrq->value = short_limit;
-                       if (short_limit != long_limit)
-                               rrq->flags |= IW_RETRY_SHORT;
-               }
-       }
-
- out:
-       orinoco_unlock(priv, &flags);
-
-       return err;
-}
-
 static int orinoco_ioctl_reset(struct net_device *dev,
                               struct iw_request_info *info,
                               void *wrqu,
@@ -1446,8 +1273,8 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
        if (orinoco_lock(priv, &flags) != 0)
                return -EBUSY;
 
-       err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
-                             extra);
+       err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+                               extra);
        if (err)
                goto out;
 
@@ -1506,46 +1333,44 @@ static const struct iw_priv_args orinoco_privtab[] = {
  * Structures to export the Wireless Handlers
  */
 
-#define STD_IW_HANDLER(id, func) \
-       [IW_IOCTL_IDX(id)] = (iw_handler) func
 static const iw_handler        orinoco_handler[] = {
-       STD_IW_HANDLER(SIOCSIWCOMMIT,   orinoco_ioctl_commit),
-       STD_IW_HANDLER(SIOCGIWNAME,     cfg80211_wext_giwname),
-       STD_IW_HANDLER(SIOCSIWFREQ,     orinoco_ioctl_setfreq),
-       STD_IW_HANDLER(SIOCGIWFREQ,     orinoco_ioctl_getfreq),
-       STD_IW_HANDLER(SIOCSIWMODE,     cfg80211_wext_siwmode),
-       STD_IW_HANDLER(SIOCGIWMODE,     cfg80211_wext_giwmode),
-       STD_IW_HANDLER(SIOCSIWSENS,     orinoco_ioctl_setsens),
-       STD_IW_HANDLER(SIOCGIWSENS,     orinoco_ioctl_getsens),
-       STD_IW_HANDLER(SIOCGIWRANGE,    cfg80211_wext_giwrange),
-       STD_IW_HANDLER(SIOCSIWSPY,      iw_handler_set_spy),
-       STD_IW_HANDLER(SIOCGIWSPY,      iw_handler_get_spy),
-       STD_IW_HANDLER(SIOCSIWTHRSPY,   iw_handler_set_thrspy),
-       STD_IW_HANDLER(SIOCGIWTHRSPY,   iw_handler_get_thrspy),
-       STD_IW_HANDLER(SIOCSIWAP,       orinoco_ioctl_setwap),
-       STD_IW_HANDLER(SIOCGIWAP,       orinoco_ioctl_getwap),
-       STD_IW_HANDLER(SIOCSIWSCAN,     cfg80211_wext_siwscan),
-       STD_IW_HANDLER(SIOCGIWSCAN,     cfg80211_wext_giwscan),
-       STD_IW_HANDLER(SIOCSIWESSID,    orinoco_ioctl_setessid),
-       STD_IW_HANDLER(SIOCGIWESSID,    orinoco_ioctl_getessid),
-       STD_IW_HANDLER(SIOCSIWRATE,     orinoco_ioctl_setrate),
-       STD_IW_HANDLER(SIOCGIWRATE,     orinoco_ioctl_getrate),
-       STD_IW_HANDLER(SIOCSIWRTS,      orinoco_ioctl_setrts),
-       STD_IW_HANDLER(SIOCGIWRTS,      orinoco_ioctl_getrts),
-       STD_IW_HANDLER(SIOCSIWFRAG,     orinoco_ioctl_setfrag),
-       STD_IW_HANDLER(SIOCGIWFRAG,     orinoco_ioctl_getfrag),
-       STD_IW_HANDLER(SIOCGIWRETRY,    orinoco_ioctl_getretry),
-       STD_IW_HANDLER(SIOCSIWENCODE,   orinoco_ioctl_setiwencode),
-       STD_IW_HANDLER(SIOCGIWENCODE,   orinoco_ioctl_getiwencode),
-       STD_IW_HANDLER(SIOCSIWPOWER,    orinoco_ioctl_setpower),
-       STD_IW_HANDLER(SIOCGIWPOWER,    orinoco_ioctl_getpower),
-       STD_IW_HANDLER(SIOCSIWGENIE,    orinoco_ioctl_set_genie),
-       STD_IW_HANDLER(SIOCGIWGENIE,    orinoco_ioctl_get_genie),
-       STD_IW_HANDLER(SIOCSIWMLME,     orinoco_ioctl_set_mlme),
-       STD_IW_HANDLER(SIOCSIWAUTH,     orinoco_ioctl_set_auth),
-       STD_IW_HANDLER(SIOCGIWAUTH,     orinoco_ioctl_get_auth),
-       STD_IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
-       STD_IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
+       IW_HANDLER(SIOCSIWCOMMIT,       (iw_handler)orinoco_ioctl_commit),
+       IW_HANDLER(SIOCGIWNAME,         (iw_handler)cfg80211_wext_giwname),
+       IW_HANDLER(SIOCSIWFREQ,         (iw_handler)orinoco_ioctl_setfreq),
+       IW_HANDLER(SIOCGIWFREQ,         (iw_handler)orinoco_ioctl_getfreq),
+       IW_HANDLER(SIOCSIWMODE,         (iw_handler)cfg80211_wext_siwmode),
+       IW_HANDLER(SIOCGIWMODE,         (iw_handler)cfg80211_wext_giwmode),
+       IW_HANDLER(SIOCSIWSENS,         (iw_handler)orinoco_ioctl_setsens),
+       IW_HANDLER(SIOCGIWSENS,         (iw_handler)orinoco_ioctl_getsens),
+       IW_HANDLER(SIOCGIWRANGE,        (iw_handler)cfg80211_wext_giwrange),
+       IW_HANDLER(SIOCSIWSPY,          iw_handler_set_spy),
+       IW_HANDLER(SIOCGIWSPY,          iw_handler_get_spy),
+       IW_HANDLER(SIOCSIWTHRSPY,       iw_handler_set_thrspy),
+       IW_HANDLER(SIOCGIWTHRSPY,       iw_handler_get_thrspy),
+       IW_HANDLER(SIOCSIWAP,           (iw_handler)orinoco_ioctl_setwap),
+       IW_HANDLER(SIOCGIWAP,           (iw_handler)orinoco_ioctl_getwap),
+       IW_HANDLER(SIOCSIWSCAN,         (iw_handler)cfg80211_wext_siwscan),
+       IW_HANDLER(SIOCGIWSCAN,         (iw_handler)cfg80211_wext_giwscan),
+       IW_HANDLER(SIOCSIWESSID,        (iw_handler)orinoco_ioctl_setessid),
+       IW_HANDLER(SIOCGIWESSID,        (iw_handler)orinoco_ioctl_getessid),
+       IW_HANDLER(SIOCSIWRATE,         (iw_handler)orinoco_ioctl_setrate),
+       IW_HANDLER(SIOCGIWRATE,         (iw_handler)orinoco_ioctl_getrate),
+       IW_HANDLER(SIOCSIWRTS,          (iw_handler)cfg80211_wext_siwrts),
+       IW_HANDLER(SIOCGIWRTS,          (iw_handler)cfg80211_wext_giwrts),
+       IW_HANDLER(SIOCSIWFRAG,         (iw_handler)cfg80211_wext_siwfrag),
+       IW_HANDLER(SIOCGIWFRAG,         (iw_handler)cfg80211_wext_giwfrag),
+       IW_HANDLER(SIOCGIWRETRY,        (iw_handler)cfg80211_wext_giwretry),
+       IW_HANDLER(SIOCSIWENCODE,       (iw_handler)orinoco_ioctl_setiwencode),
+       IW_HANDLER(SIOCGIWENCODE,       (iw_handler)orinoco_ioctl_getiwencode),
+       IW_HANDLER(SIOCSIWPOWER,        (iw_handler)orinoco_ioctl_setpower),
+       IW_HANDLER(SIOCGIWPOWER,        (iw_handler)orinoco_ioctl_getpower),
+       IW_HANDLER(SIOCSIWGENIE,        orinoco_ioctl_set_genie),
+       IW_HANDLER(SIOCGIWGENIE,        orinoco_ioctl_get_genie),
+       IW_HANDLER(SIOCSIWMLME,         orinoco_ioctl_set_mlme),
+       IW_HANDLER(SIOCSIWAUTH,         orinoco_ioctl_set_auth),
+       IW_HANDLER(SIOCGIWAUTH,         orinoco_ioctl_get_auth),
+       IW_HANDLER(SIOCSIWENCODEEXT,    orinoco_ioctl_set_encodeext),
+       IW_HANDLER(SIOCGIWENCODEEXT,    orinoco_ioctl_get_encodeext),
 };
 
 
@@ -1553,15 +1378,15 @@ static const iw_handler orinoco_handler[] = {
   Added typecasting since we no longer use iwreq_data -- Moustafa
  */
 static const iw_handler        orinoco_private_handler[] = {
-       [0] = (iw_handler) orinoco_ioctl_reset,
-       [1] = (iw_handler) orinoco_ioctl_reset,
-       [2] = (iw_handler) orinoco_ioctl_setport3,
-       [3] = (iw_handler) orinoco_ioctl_getport3,
-       [4] = (iw_handler) orinoco_ioctl_setpreamble,
-       [5] = (iw_handler) orinoco_ioctl_getpreamble,
-       [6] = (iw_handler) orinoco_ioctl_setibssport,
-       [7] = (iw_handler) orinoco_ioctl_getibssport,
-       [9] = (iw_handler) orinoco_ioctl_getrid,
+       [0] = (iw_handler)orinoco_ioctl_reset,
+       [1] = (iw_handler)orinoco_ioctl_reset,
+       [2] = (iw_handler)orinoco_ioctl_setport3,
+       [3] = (iw_handler)orinoco_ioctl_getport3,
+       [4] = (iw_handler)orinoco_ioctl_setpreamble,
+       [5] = (iw_handler)orinoco_ioctl_getpreamble,
+       [6] = (iw_handler)orinoco_ioctl_setibssport,
+       [7] = (iw_handler)orinoco_ioctl_getibssport,
+       [9] = (iw_handler)orinoco_ioctl_getrid,
 };
 
 const struct iw_handler_def orinoco_handler_def = {
index a7cb9eb759a154023acbaa72e87a1d42788727c2..c072f41747cac9cf1e0c6c9c37c4c01e53c41a7c 100644 (file)
@@ -546,7 +546,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
                     IEEE80211_HW_SUPPORTS_PS |
                     IEEE80211_HW_PS_NULLFUNC_STACK |
                     IEEE80211_HW_BEACON_FILTER |
-                    IEEE80211_HW_NOISE_DBM;
+                    IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 
        dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                      BIT(NL80211_IFTYPE_ADHOC) |
index c24067f1a0cb526560f40247aa647c1c57e2f734..07c4528f6e6b895d59e2cddc3fd30edcf80cb000 100644 (file)
@@ -132,7 +132,7 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
 
 static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
        int ring_index, struct p54p_desc *ring, u32 ring_limit,
-       struct sk_buff **rx_buf)
+       struct sk_buff **rx_buf, u32 index)
 {
        struct p54p_priv *priv = dev->priv;
        struct p54p_ring_control *ring_control = priv->ring_control;
@@ -140,7 +140,7 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
 
        idx = le32_to_cpu(ring_control->host_idx[ring_index]);
        limit = idx;
-       limit -= le32_to_cpu(ring_control->device_idx[ring_index]);
+       limit -= index;
        limit = ring_limit - limit;
 
        i = idx % ring_limit;
@@ -232,7 +232,7 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
                i %= ring_limit;
        }
 
-       p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf);
+       p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf, *index);
 }
 
 static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
@@ -445,10 +445,10 @@ static int p54p_open(struct ieee80211_hw *dev)
        priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
 
        p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
-               ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data);
+               ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data, 0);
 
        p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
-               ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt);
+               ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt, 0);
 
        P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
        P54P_READ(ring_control_base);
index 743a6c68b29d023cf9e5be018a46390d32b50a55..d5b197b4d5bb492ac70c8e2a98297a2e82e5e356 100644 (file)
@@ -875,7 +875,6 @@ static void p54u_stop(struct ieee80211_hw *dev)
           the hardware is still usable next time we want to start it.
           until then, we just stop listening to the hardware.. */
        p54u_free_urbs(dev);
-       return;
 }
 
 static int __devinit p54u_probe(struct usb_interface *intf,
index 66057999a93ce03f8a917280eb0857c49d00ae0b..4e6891099d43d98d960619004e41d953cba3c1b1 100644 (file)
@@ -38,7 +38,7 @@ static void p54_dump_tx_queue(struct p54_common *priv)
        u32 largest_hole = 0, free;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n",
+       printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) ---\n",
               wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
 
        prev_addr = priv->rx_start;
@@ -350,7 +350,6 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
                rx_status->flag |= RX_FLAG_MMIC_ERROR;
 
        rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
-       rx_status->noise = priv->noise;
        if (hdr->rate & 0x10)
                rx_status->flag |= RX_FLAG_SHORTPRE;
        if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
index a45818ebfdfb250b991d14983de249b3c2ee82bb..8d1190c0f06241c1af9f7755c5500a6f1c48b94a 100644 (file)
@@ -210,8 +210,6 @@ prism54_update_stats(struct work_struct *work)
        priv->local_iwstatistics.discard.retries = r.u;
 
        mutex_unlock(&priv->stats_lock);
-
-       return;
 }
 
 struct iw_statistics *
index 689d59a13d5b295b0db107807ee9ef22a2131af0..2c8cc954d1b6d85092f4d4f999ab1a8151e79ddb 100644 (file)
@@ -228,14 +228,14 @@ islpci_interrupt(int irq, void *config)
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
                DEBUG(SHOW_FUNCTION_CALLS,
-                     "IRQ: Identification register 0x%p 0x%x \n", device, reg);
+                     "IRQ: Identification register 0x%p 0x%x\n", device, reg);
 #endif
 
                /* check for each bit in the register separately */
                if (reg & ISL38XX_INT_IDENT_UPDATE) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
                        /* Queue has been updated */
-                       DEBUG(SHOW_TRACING, "IRQ: Update flag \n");
+                       DEBUG(SHOW_TRACING, "IRQ: Update flag\n");
 
                        DEBUG(SHOW_QUEUE_INDEXES,
                              "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",
@@ -301,7 +301,7 @@ islpci_interrupt(int irq, void *config)
                                                ISL38XX_CB_RX_DATA_LQ) != 0) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
                                DEBUG(SHOW_TRACING,
-                                     "Received frame in Data Low Queue \n");
+                                     "Received frame in Data Low Queue\n");
 #endif
                                islpci_eth_receive(priv);
                        }
@@ -326,7 +326,7 @@ islpci_interrupt(int irq, void *config)
                        /* Device has been initialized */
 #if VERBOSE > SHOW_ERROR_MESSAGES
                        DEBUG(SHOW_TRACING,
-                             "IRQ: Init flag, device initialized \n");
+                             "IRQ: Init flag, device initialized\n");
 #endif
                        wake_up(&priv->reset_done);
                }
@@ -334,7 +334,7 @@ islpci_interrupt(int irq, void *config)
                if (reg & ISL38XX_INT_IDENT_SLEEP) {
                        /* Device intends to move to powersave state */
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");
+                       DEBUG(SHOW_TRACING, "IRQ: Sleep flag\n");
 #endif
                        isl38xx_handle_sleep_request(priv->control_block,
                                                     &powerstate,
@@ -344,7 +344,7 @@ islpci_interrupt(int irq, void *config)
                if (reg & ISL38XX_INT_IDENT_WAKEUP) {
                        /* Device has been woken up to active state */
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");
+                       DEBUG(SHOW_TRACING, "IRQ: Wakeup flag\n");
 #endif
 
                        isl38xx_handle_wakeup(priv->control_block,
@@ -635,7 +635,7 @@ islpci_alloc_memory(islpci_private *priv)
              ioremap(pci_resource_start(priv->pdev, 0),
                      ISL38XX_PCI_MEM_SIZE))) {
                /* error in remapping the PCI device memory address range */
-               printk(KERN_ERR "PCI memory remapping failed \n");
+               printk(KERN_ERR "PCI memory remapping failed\n");
                return -1;
        }
 
@@ -902,7 +902,7 @@ islpci_setup(struct pci_dev *pdev)
 
        if (register_netdev(ndev)) {
                DEBUG(SHOW_ERROR_MESSAGES,
-                     "ERROR: register_netdev() failed \n");
+                     "ERROR: register_netdev() failed\n");
                goto do_islpci_free_memory;
        }
 
@@ -946,7 +946,7 @@ islpci_set_state(islpci_private *priv, islpci_state_t new_state)
                if (!priv->state_off)
                        priv->state = new_state;
                break;
-       };
+       }
 #if 0
        printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n",
               priv->ndev->name, old_state, new_state, priv->state_off);
index ac99eaaeabcee9831afdf5928271b6cc431e7d28..2fc52bc2d7dde40e4d242f9502ddd7d499356277 100644 (file)
@@ -90,7 +90,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
        u32 curr_frag;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit\n");
 #endif
 
        /* lock the driver code */
@@ -141,7 +141,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
                        }
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data,
+                       DEBUG(SHOW_TRACING, "memmove %p %p %i\n", skb->data,
                              src, skb->len);
 #endif
                } else {
@@ -224,8 +224,6 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
                priv->data_low_tx_full = 1;
        }
 
-       /* set the transmission time */
-       ndev->trans_start = jiffies;
        ndev->stats.tx_packets++;
        ndev->stats.tx_bytes += skb->len;
 
@@ -320,7 +318,7 @@ islpci_eth_receive(islpci_private *priv)
        int discard = 0;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive\n");
 #endif
 
        /* the device has written an Ethernet frame in the data area
@@ -432,7 +430,7 @@ islpci_eth_receive(islpci_private *priv)
                skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2);
                if (unlikely(skb == NULL)) {
                        /* error allocating an sk_buff structure elements */
-                       DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n");
+                       DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb\n");
                        break;
                }
                skb_reserve(skb, (4 - (long) skb->data) & 0x03);
index adb289723a967e5fe474332e1c256b7aa94649ad..a5224f6160e4b8f913ba3150a1891c1beb0e7d15 100644 (file)
@@ -114,7 +114,7 @@ islpci_mgmt_rx_fill(struct net_device *ndev)
        u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill\n");
 #endif
 
        while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) {
@@ -212,7 +212,7 @@ islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
        {
                pimfor_header_t *h = buf.mem;
                DEBUG(SHOW_PIMFOR_FRAMES,
-                     "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n",
+                     "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x\n",
                      h->operation, oid, h->device_id, h->flags, length);
 
                /* display the buffer contents for debugging */
@@ -280,7 +280,7 @@ islpci_mgt_receive(struct net_device *ndev)
        u32 curr_frag;
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n");
+       DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive\n");
 #endif
 
        /* Only once per interrupt, determine fragment range to
@@ -339,7 +339,7 @@ islpci_mgt_receive(struct net_device *ndev)
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
                DEBUG(SHOW_PIMFOR_FRAMES,
-                     "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n",
+                     "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x\n",
                      header->operation, header->oid, header->device_id,
                      header->flags, header->length);
 
index d66933d70fb9cac31c0ce007e05de592dcabca99..9b796cae4afe8436ee04556d0227d8b57d021ff7 100644 (file)
@@ -820,7 +820,7 @@ mgt_response_to_str(enum oid_num_t n, union oid_res_t *r, char *str)
                        k = snprintf(str, PRIV_STR_SIZE, "nr=%u\n", list->nr);
                        for (i = 0; i < list->nr; i++)
                                k += snprintf(str + k, PRIV_STR_SIZE - k,
-                                             "bss[%u] : \nage=%u\nchannel=%u\n"
+                                             "bss[%u] :\nage=%u\nchannel=%u\n"
                                              "capinfo=0x%X\nrates=0x%X\n"
                                              "basic_rates=0x%X\n",
                                              i, list->bsslist[i].age,
index f7d2a34ca53162d5f7dad5f10454c7cb40cae1a8..abff8934db13a1e02f62e56b7ff0561c42891be5 100644 (file)
@@ -546,7 +546,7 @@ static int ray_init(struct net_device *dev)
        local->fw_ver = local->startup_res.firmware_version[0];
        local->fw_bld = local->startup_res.firmware_version[1];
        local->fw_var = local->startup_res.firmware_version[2];
-       dev_dbg(&link->dev, "ray_init firmware version %d.%d \n", local->fw_ver,
+       dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver,
              local->fw_bld);
 
        local->tib_length = 0x20;
@@ -726,8 +726,6 @@ static void verify_dl_startup(u_long data)
                start_net((u_long) local);
        else
                join_net((u_long) local);
-
-       return;
 } /* end verify_dl_startup */
 
 /*===========================================================================*/
@@ -755,7 +753,6 @@ static void start_net(u_long data)
                return;
        }
        local->card_status = CARD_DOING_ACQ;
-       return;
 } /* end start_net */
 
 /*===========================================================================*/
@@ -786,7 +783,6 @@ static void join_net(u_long data)
                return;
        }
        local->card_status = CARD_DOING_ACQ;
-       return;
 }
 
 /*============================================================================
@@ -932,7 +928,6 @@ static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
        case XMIT_MSG_BAD:
        case XMIT_OK:
        default:
-               dev->trans_start = jiffies;
                dev_kfree_skb(skb);
        }
 
@@ -1103,10 +1098,10 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 /*
  * Wireless Handler : get protocol name
  */
-static int ray_get_name(struct net_device *dev,
-                       struct iw_request_info *info, char *cwrq, char *extra)
+static int ray_get_name(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
-       strcpy(cwrq, "IEEE 802.11-FH");
+       strcpy(wrqu->name, "IEEE 802.11-FH");
        return 0;
 }
 
@@ -1114,9 +1109,8 @@ static int ray_get_name(struct net_device *dev,
 /*
  * Wireless Handler : set frequency
  */
-static int ray_set_freq(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct iw_freq *fwrq, char *extra)
+static int ray_set_freq(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
        int err = -EINPROGRESS; /* Call commit handler */
@@ -1126,10 +1120,10 @@ static int ray_set_freq(struct net_device *dev,
                return -EBUSY;
 
        /* Setting by channel number */
-       if ((fwrq->m > USA_HOP_MOD) || (fwrq->e > 0))
+       if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0))
                err = -EOPNOTSUPP;
        else
-               local->sparm.b5.a_hop_pattern = fwrq->m;
+               local->sparm.b5.a_hop_pattern = wrqu->freq.m;
 
        return err;
 }
@@ -1138,14 +1132,13 @@ static int ray_set_freq(struct net_device *dev,
 /*
  * Wireless Handler : get frequency
  */
-static int ray_get_freq(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct iw_freq *fwrq, char *extra)
+static int ray_get_freq(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
-       fwrq->m = local->sparm.b5.a_hop_pattern;
-       fwrq->e = 0;
+       wrqu->freq.m = local->sparm.b5.a_hop_pattern;
+       wrqu->freq.e = 0;
        return 0;
 }
 
@@ -1153,9 +1146,8 @@ static int ray_get_freq(struct net_device *dev,
 /*
  * Wireless Handler : set ESSID
  */
-static int ray_set_essid(struct net_device *dev,
-                        struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra)
+static int ray_set_essid(struct net_device *dev, struct iw_request_info *info,
+                        union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
@@ -1164,19 +1156,17 @@ static int ray_set_essid(struct net_device *dev,
                return -EBUSY;
 
        /* Check if we asked for `any' */
-       if (dwrq->flags == 0) {
+       if (wrqu->essid.flags == 0)
                /* Corey : can you do that ? */
                return -EOPNOTSUPP;
-       } else {
-               /* Check the size of the string */
-               if (dwrq->length > IW_ESSID_MAX_SIZE) {
-                       return -E2BIG;
-               }
 
-               /* Set the ESSID in the card */
-               memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
-               memcpy(local->sparm.b5.a_current_ess_id, extra, dwrq->length);
-       }
+       /* Check the size of the string */
+       if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
+               return -E2BIG;
+
+       /* Set the ESSID in the card */
+       memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
+       memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length);
 
        return -EINPROGRESS;    /* Call commit handler */
 }
@@ -1185,9 +1175,8 @@ static int ray_set_essid(struct net_device *dev,
 /*
  * Wireless Handler : get ESSID
  */
-static int ray_get_essid(struct net_device *dev,
-                        struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra)
+static int ray_get_essid(struct net_device *dev, struct iw_request_info *info,
+                        union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
@@ -1195,8 +1184,8 @@ static int ray_get_essid(struct net_device *dev,
        memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
 
        /* Push it out ! */
-       dwrq->length = strlen(extra);
-       dwrq->flags = 1;        /* active */
+       wrqu->essid.length = strlen(extra);
+       wrqu->essid.flags = 1;  /* active */
 
        return 0;
 }
@@ -1205,14 +1194,13 @@ static int ray_get_essid(struct net_device *dev,
 /*
  * Wireless Handler : get AP address
  */
-static int ray_get_wap(struct net_device *dev,
-                      struct iw_request_info *info,
-                      struct sockaddr *awrq, char *extra)
+static int ray_get_wap(struct net_device *dev, struct iw_request_info *info,
+                      union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
-       memcpy(awrq->sa_data, local->bss_id, ETH_ALEN);
-       awrq->sa_family = ARPHRD_ETHER;
+       memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN);
+       wrqu->ap_addr.sa_family = ARPHRD_ETHER;
 
        return 0;
 }
@@ -1221,9 +1209,8 @@ static int ray_get_wap(struct net_device *dev,
 /*
  * Wireless Handler : set Bit-Rate
  */
-static int ray_set_rate(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct iw_param *vwrq, char *extra)
+static int ray_set_rate(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
@@ -1232,15 +1219,15 @@ static int ray_set_rate(struct net_device *dev,
                return -EBUSY;
 
        /* Check if rate is in range */
-       if ((vwrq->value != 1000000) && (vwrq->value != 2000000))
+       if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000))
                return -EINVAL;
 
        /* Hack for 1.5 Mb/s instead of 2 Mb/s */
        if ((local->fw_ver == 0x55) &&  /* Please check */
-           (vwrq->value == 2000000))
+           (wrqu->bitrate.value == 2000000))
                local->net_default_tx_rate = 3;
        else
-               local->net_default_tx_rate = vwrq->value / 500000;
+               local->net_default_tx_rate = wrqu->bitrate.value / 500000;
 
        return 0;
 }
@@ -1249,17 +1236,16 @@ static int ray_set_rate(struct net_device *dev,
 /*
  * Wireless Handler : get Bit-Rate
  */
-static int ray_get_rate(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct iw_param *vwrq, char *extra)
+static int ray_get_rate(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
        if (local->net_default_tx_rate == 3)
-               vwrq->value = 2000000;  /* Hum... */
+               wrqu->bitrate.value = 2000000;  /* Hum... */
        else
-               vwrq->value = local->net_default_tx_rate * 500000;
-       vwrq->fixed = 0;        /* We are in auto mode */
+               wrqu->bitrate.value = local->net_default_tx_rate * 500000;
+       wrqu->bitrate.fixed = 0;        /* We are in auto mode */
 
        return 0;
 }
@@ -1268,19 +1254,18 @@ static int ray_get_rate(struct net_device *dev,
 /*
  * Wireless Handler : set RTS threshold
  */
-static int ray_set_rts(struct net_device *dev,
-                      struct iw_request_info *info,
-                      struct iw_param *vwrq, char *extra)
+static int ray_set_rts(struct net_device *dev, struct iw_request_info *info,
+                      union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
-       int rthr = vwrq->value;
+       int rthr = wrqu->rts.value;
 
        /* Reject if card is already initialised */
        if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* if(wrq->u.rts.fixed == 0) we should complain */
-       if (vwrq->disabled)
+       if (wrqu->rts.disabled)
                rthr = 32767;
        else {
                if ((rthr < 0) || (rthr > 2347))   /* What's the max packet size ??? */
@@ -1296,16 +1281,15 @@ static int ray_set_rts(struct net_device *dev,
 /*
  * Wireless Handler : get RTS threshold
  */
-static int ray_get_rts(struct net_device *dev,
-                      struct iw_request_info *info,
-                      struct iw_param *vwrq, char *extra)
+static int ray_get_rts(struct net_device *dev, struct iw_request_info *info,
+                      union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
-       vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
+       wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
            + local->sparm.b5.a_rts_threshold[1];
-       vwrq->disabled = (vwrq->value == 32767);
-       vwrq->fixed = 1;
+       wrqu->rts.disabled = (wrqu->rts.value == 32767);
+       wrqu->rts.fixed = 1;
 
        return 0;
 }
@@ -1314,19 +1298,18 @@ static int ray_get_rts(struct net_device *dev,
 /*
  * Wireless Handler : set Fragmentation threshold
  */
-static int ray_set_frag(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct iw_param *vwrq, char *extra)
+static int ray_set_frag(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
-       int fthr = vwrq->value;
+       int fthr = wrqu->frag.value;
 
        /* Reject if card is already initialised */
        if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* if(wrq->u.frag.fixed == 0) should complain */
-       if (vwrq->disabled)
+       if (wrqu->frag.disabled)
                fthr = 32767;
        else {
                if ((fthr < 256) || (fthr > 2347))      /* To check out ! */
@@ -1342,16 +1325,15 @@ static int ray_set_frag(struct net_device *dev,
 /*
  * Wireless Handler : get Fragmentation threshold
  */
-static int ray_get_frag(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct iw_param *vwrq, char *extra)
+static int ray_get_frag(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
-       vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
+       wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
            + local->sparm.b5.a_frag_threshold[1];
-       vwrq->disabled = (vwrq->value == 32767);
-       vwrq->fixed = 1;
+       wrqu->frag.disabled = (wrqu->frag.value == 32767);
+       wrqu->frag.fixed = 1;
 
        return 0;
 }
@@ -1360,8 +1342,8 @@ static int ray_get_frag(struct net_device *dev,
 /*
  * Wireless Handler : set Mode of Operation
  */
-static int ray_set_mode(struct net_device *dev,
-                       struct iw_request_info *info, __u32 *uwrq, char *extra)
+static int ray_set_mode(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
        int err = -EINPROGRESS; /* Call commit handler */
@@ -1371,7 +1353,7 @@ static int ray_set_mode(struct net_device *dev,
        if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
-       switch (*uwrq) {
+       switch (wrqu->mode) {
        case IW_MODE_ADHOC:
                card_mode = 0;
                /* Fall through */
@@ -1389,15 +1371,15 @@ static int ray_set_mode(struct net_device *dev,
 /*
  * Wireless Handler : get Mode of Operation
  */
-static int ray_get_mode(struct net_device *dev,
-                       struct iw_request_info *info, __u32 *uwrq, char *extra)
+static int ray_get_mode(struct net_device *dev, struct iw_request_info *info,
+                       union iwreq_data *wrqu, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
        if (local->sparm.b5.a_network_type)
-               *uwrq = IW_MODE_INFRA;
+               wrqu->mode = IW_MODE_INFRA;
        else
-               *uwrq = IW_MODE_ADHOC;
+               wrqu->mode = IW_MODE_ADHOC;
 
        return 0;
 }
@@ -1406,16 +1388,15 @@ static int ray_get_mode(struct net_device *dev,
 /*
  * Wireless Handler : get range info
  */
-static int ray_get_range(struct net_device *dev,
-                        struct iw_request_info *info,
-                        struct iw_point *dwrq, char *extra)
+static int ray_get_range(struct net_device *dev, struct iw_request_info *info,
+                        union iwreq_data *wrqu, char *extra)
 {
        struct iw_range *range = (struct iw_range *)extra;
 
-       memset((char *)range, 0, sizeof(struct iw_range));
+       memset(range, 0, sizeof(struct iw_range));
 
        /* Set the length (very important for backward compatibility) */
-       dwrq->length = sizeof(struct iw_range);
+       wrqu->data.length = sizeof(struct iw_range);
 
        /* Set the Wireless Extension versions */
        range->we_version_compiled = WIRELESS_EXT;
@@ -1438,8 +1419,7 @@ static int ray_get_range(struct net_device *dev,
 /*
  * Wireless Private Handler : set framing mode
  */
-static int ray_set_framing(struct net_device *dev,
-                          struct iw_request_info *info,
+static int ray_set_framing(struct net_device *dev, struct iw_request_info *info,
                           union iwreq_data *wrqu, char *extra)
 {
        translate = *(extra);   /* Set framing mode */
@@ -1451,8 +1431,7 @@ static int ray_set_framing(struct net_device *dev,
 /*
  * Wireless Private Handler : get framing mode
  */
-static int ray_get_framing(struct net_device *dev,
-                          struct iw_request_info *info,
+static int ray_get_framing(struct net_device *dev, struct iw_request_info *info,
                           union iwreq_data *wrqu, char *extra)
 {
        *(extra) = translate;
@@ -1464,8 +1443,7 @@ static int ray_get_framing(struct net_device *dev,
 /*
  * Wireless Private Handler : get country
  */
-static int ray_get_country(struct net_device *dev,
-                          struct iw_request_info *info,
+static int ray_get_country(struct net_device *dev, struct iw_request_info *info,
                           union iwreq_data *wrqu, char *extra)
 {
        *(extra) = country;
@@ -1477,10 +1455,9 @@ static int ray_get_country(struct net_device *dev,
 /*
  * Commit handler : called after a bunch of SET operations
  */
-static int ray_commit(struct net_device *dev, struct iw_request_info *info,    /* NULL */
-                     void *zwrq,       /* NULL */
-                     char *extra)
-{ /* NULL */
+static int ray_commit(struct net_device *dev, struct iw_request_info *info,
+                     union iwreq_data *wrqu, char *extra)
+{
        return 0;
 }
 
@@ -1521,28 +1498,28 @@ static iw_stats *ray_get_wireless_stats(struct net_device *dev)
  */
 
 static const iw_handler ray_handler[] = {
-       [SIOCSIWCOMMIT - SIOCIWFIRST] = (iw_handler) ray_commit,
-       [SIOCGIWNAME - SIOCIWFIRST] = (iw_handler) ray_get_name,
-       [SIOCSIWFREQ - SIOCIWFIRST] = (iw_handler) ray_set_freq,
-       [SIOCGIWFREQ - SIOCIWFIRST] = (iw_handler) ray_get_freq,
-       [SIOCSIWMODE - SIOCIWFIRST] = (iw_handler) ray_set_mode,
-       [SIOCGIWMODE - SIOCIWFIRST] = (iw_handler) ray_get_mode,
-       [SIOCGIWRANGE - SIOCIWFIRST] = (iw_handler) ray_get_range,
+       IW_HANDLER(SIOCSIWCOMMIT, ray_commit),
+       IW_HANDLER(SIOCGIWNAME, ray_get_name),
+       IW_HANDLER(SIOCSIWFREQ, ray_set_freq),
+       IW_HANDLER(SIOCGIWFREQ, ray_get_freq),
+       IW_HANDLER(SIOCSIWMODE, ray_set_mode),
+       IW_HANDLER(SIOCGIWMODE, ray_get_mode),
+       IW_HANDLER(SIOCGIWRANGE, ray_get_range),
 #ifdef WIRELESS_SPY
-       [SIOCSIWSPY - SIOCIWFIRST] = (iw_handler) iw_handler_set_spy,
-       [SIOCGIWSPY - SIOCIWFIRST] = (iw_handler) iw_handler_get_spy,
-       [SIOCSIWTHRSPY - SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy,
-       [SIOCGIWTHRSPY - SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy,
+       IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
+       IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
+       IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
+       IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
 #endif /* WIRELESS_SPY */
-       [SIOCGIWAP - SIOCIWFIRST] = (iw_handler) ray_get_wap,
-       [SIOCSIWESSID - SIOCIWFIRST] = (iw_handler) ray_set_essid,
-       [SIOCGIWESSID - SIOCIWFIRST] = (iw_handler) ray_get_essid,
-       [SIOCSIWRATE - SIOCIWFIRST] = (iw_handler) ray_set_rate,
-       [SIOCGIWRATE - SIOCIWFIRST] = (iw_handler) ray_get_rate,
-       [SIOCSIWRTS - SIOCIWFIRST] = (iw_handler) ray_set_rts,
-       [SIOCGIWRTS - SIOCIWFIRST] = (iw_handler) ray_get_rts,
-       [SIOCSIWFRAG - SIOCIWFIRST] = (iw_handler) ray_set_frag,
-       [SIOCGIWFRAG - SIOCIWFIRST] = (iw_handler) ray_get_frag,
+       IW_HANDLER(SIOCGIWAP, ray_get_wap),
+       IW_HANDLER(SIOCSIWESSID, ray_set_essid),
+       IW_HANDLER(SIOCGIWESSID, ray_get_essid),
+       IW_HANDLER(SIOCSIWRATE, ray_set_rate),
+       IW_HANDLER(SIOCGIWRATE, ray_get_rate),
+       IW_HANDLER(SIOCSIWRTS, ray_set_rts),
+       IW_HANDLER(SIOCGIWRTS, ray_get_rts),
+       IW_HANDLER(SIOCSIWFRAG, ray_set_frag),
+       IW_HANDLER(SIOCGIWFRAG, ray_get_frag),
 };
 
 #define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
@@ -1550,9 +1527,9 @@ static const iw_handler ray_handler[] = {
 #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3     /* Get country code */
 
 static const iw_handler ray_private_handler[] = {
-       [0] = (iw_handler) ray_set_framing,
-       [1] = (iw_handler) ray_get_framing,
-       [3] = (iw_handler) ray_get_country,
+       [0] = ray_set_framing,
+       [1] = ray_get_framing,
+       [3] = ray_get_country,
 };
 
 static const struct iw_priv_args ray_private_args[] = {
@@ -1636,7 +1613,6 @@ static int ray_dev_close(struct net_device *dev)
 static void ray_reset(struct net_device *dev)
 {
        pr_debug("ray_reset entered\n");
-       return;
 }
 
 /*===========================================================================*/
@@ -1883,17 +1859,17 @@ static void ray_update_multi_list(struct net_device *dev, int all)
                writeb(0xff, &pccs->var);
                local->num_multi = 0xff;
        } else {
-               struct dev_mc_list *dmi;
+               struct netdev_hw_addr *ha;
                int i = 0;
 
                /* Copy the kernel's list of MC addresses to card */
-               netdev_for_each_mc_addr(dmi, dev) {
-                       memcpy_toio(p, dmi->dmi_addr, ETH_ALEN);
+               netdev_for_each_mc_addr(ha, dev) {
+                       memcpy_toio(p, ha->addr, ETH_ALEN);
                        dev_dbg(&link->dev,
                              "ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",
-                             dmi->dmi_addr[0], dmi->dmi_addr[1],
-                             dmi->dmi_addr[2], dmi->dmi_addr[3],
-                             dmi->dmi_addr[4], dmi->dmi_addr[5]);
+                             ha->addr[0], ha->addr[1],
+                             ha->addr[2], ha->addr[3],
+                             ha->addr[4], ha->addr[5]);
                        p += ETH_ALEN;
                        i++;
                }
@@ -2242,7 +2218,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
                            (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
                             FCS_LEN)) {
                                pr_debug(
-                                     "ray_cs invalid packet length %d received \n",
+                                     "ray_cs invalid packet length %d received\n",
                                      rx_len);
                                return;
                        }
@@ -2253,7 +2229,7 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
                            (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
                             FCS_LEN)) {
                                pr_debug(
-                                     "ray_cs invalid packet length %d received \n",
+                                     "ray_cs invalid packet length %d received\n",
                                      rx_len);
                                return;
                        }
@@ -2761,11 +2737,11 @@ static int ray_cs_proc_show(struct seq_file *m, void *v)
                        seq_printf(m, "Hop dwell            = %d Kus\n",
                                   pfh->dwell_time[0] +
                                   256 * pfh->dwell_time[1]);
-                       seq_printf(m, "Hop set              = %d \n",
+                       seq_printf(m, "Hop set              = %d\n",
                                   pfh->hop_set);
-                       seq_printf(m, "Hop pattern          = %d \n",
+                       seq_printf(m, "Hop pattern          = %d\n",
                                   pfh->hop_pattern);
-                       seq_printf(m, "Hop index            = %d \n",
+                       seq_printf(m, "Hop index            = %d\n",
                                   pfh->hop_index);
                        p += p[1] + 2;
                } else {
index 1de5b22d3efe8402a514d769ebd893c1a5d3549a..2d2890878deae2162abf5dea253821f09f55e461 100644 (file)
@@ -118,6 +118,7 @@ MODULE_PARM_DESC(workaround_interval,
 #define OID_802_11_ADD_KEY                     cpu_to_le32(0x0d01011d)
 #define OID_802_11_REMOVE_KEY                  cpu_to_le32(0x0d01011e)
 #define OID_802_11_ASSOCIATION_INFORMATION     cpu_to_le32(0x0d01011f)
+#define OID_802_11_CAPABILITY                  cpu_to_le32(0x0d010122)
 #define OID_802_11_PMKID                       cpu_to_le32(0x0d010123)
 #define OID_802_11_NETWORK_TYPES_SUPPORTED     cpu_to_le32(0x0d010203)
 #define OID_802_11_NETWORK_TYPE_IN_USE         cpu_to_le32(0x0d010204)
@@ -359,6 +360,30 @@ struct ndis_80211_assoc_info {
        __le32 offset_resp_ies;
 } __attribute__((packed));
 
+struct ndis_80211_auth_encr_pair {
+       __le32 auth_mode;
+       __le32 encr_mode;
+} __attribute__((packed));
+
+struct ndis_80211_capability {
+       __le32 length;
+       __le32 version;
+       __le32 num_pmkids;
+       __le32 num_auth_encr_pair;
+       struct ndis_80211_auth_encr_pair auth_encr_pair[0];
+} __attribute__((packed));
+
+struct ndis_80211_bssid_info {
+       u8 bssid[6];
+       u8 pmkid[16];
+};
+
+struct ndis_80211_pmkid {
+       __le32 length;
+       __le32 bssid_info_count;
+       struct ndis_80211_bssid_info bssid_info[0];
+};
+
 /*
  *  private data
  */
@@ -477,13 +502,7 @@ struct rndis_wlan_private {
        /* encryption stuff */
        int  encr_tx_key_index;
        struct rndis_wlan_encr_key encr_keys[4];
-       enum nl80211_auth_type wpa_auth_type;
        int  wpa_version;
-       int  wpa_keymgmt;
-       int  wpa_ie_len;
-       u8  *wpa_ie;
-       int  wpa_cipher_pair;
-       int  wpa_cipher_group;
 
        u8 command_buffer[COMMAND_BUFFER_SIZE];
 };
@@ -516,7 +535,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 
 static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
 
-static int rndis_set_channel(struct wiphy *wiphy,
+static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
 
 static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
@@ -535,6 +554,14 @@ static int rndis_get_station(struct wiphy *wiphy, struct net_device *dev,
 static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
                               int idx, u8 *mac, struct station_info *sinfo);
 
+static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+                               struct cfg80211_pmksa *pmksa);
+
+static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+                               struct cfg80211_pmksa *pmksa);
+
+static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev);
+
 static struct cfg80211_ops rndis_config_ops = {
        .change_virtual_intf = rndis_change_virtual_intf,
        .scan = rndis_scan,
@@ -551,6 +578,9 @@ static struct cfg80211_ops rndis_config_ops = {
        .set_default_key = rndis_set_default_key,
        .get_station = rndis_get_station,
        .dump_station = rndis_dump_station,
+       .set_pmksa = rndis_set_pmksa,
+       .del_pmksa = rndis_del_pmksa,
+       .flush_pmksa = rndis_flush_pmksa,
 };
 
 static void *rndis_wiphy_privid = &rndis_wiphy_privid;
@@ -705,6 +735,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
                struct rndis_query_c    *get_c;
        } u;
        int ret, buflen;
+       int resplen, respoffs, copylen;
 
        buflen = *len + sizeof(*u.get);
        if (buflen < CONTROL_BUFFER_SIZE)
@@ -734,11 +765,34 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
                           le32_to_cpu(u.get_c->status));
 
        if (ret == 0) {
-               memcpy(data, u.buf + le32_to_cpu(u.get_c->offset) + 8, *len);
+               resplen = le32_to_cpu(u.get_c->len);
+               respoffs = le32_to_cpu(u.get_c->offset) + 8;
 
-               ret = le32_to_cpu(u.get_c->len);
-               if (ret > *len)
-                       *len = ret;
+               if (respoffs > buflen) {
+                       /* Device returned data offset outside buffer, error. */
+                       netdev_dbg(dev->net, "%s(%s): received invalid "
+                               "data offset: %d > %d\n", __func__,
+                               oid_to_string(oid), respoffs, buflen);
+
+                       ret = -EINVAL;
+                       goto exit_unlock;
+               }
+
+               if ((resplen + respoffs) > buflen) {
+                       /* Device would have returned more data if buffer would
+                        * have been big enough. Copy just the bits that we got.
+                        */
+                       copylen = buflen - respoffs;
+               } else {
+                       copylen = resplen;
+               }
+
+               if (copylen > *len)
+                       copylen = *len;
+
+               memcpy(data, u.buf + respoffs, copylen);
+
+               *len = resplen;
 
                ret = rndis_error_status(u.get_c->status);
                if (ret < 0)
@@ -747,6 +801,7 @@ static int rndis_query_oid(struct usbnet *dev, __le32 oid, void *data, int *len)
                                   le32_to_cpu(u.get_c->status), ret);
        }
 
+exit_unlock:
        mutex_unlock(&priv->command_lock);
 
        if (u.buf != priv->command_buffer)
@@ -1092,8 +1147,6 @@ static int set_auth_mode(struct usbnet *usbdev, u32 wpa_version,
        }
 
        priv->wpa_version = wpa_version;
-       priv->wpa_auth_type = auth_type;
-       priv->wpa_keymgmt = keymgmt;
 
        return 0;
 }
@@ -1118,7 +1171,6 @@ static int set_priv_filter(struct usbnet *usbdev)
 
 static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
 {
-       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        __le32 tmp;
        int encr_mode, ret;
 
@@ -1147,8 +1199,6 @@ static int set_encr_mode(struct usbnet *usbdev, int pairwise, int groupwise)
                return ret;
        }
 
-       priv->wpa_cipher_pair = pairwise;
-       priv->wpa_cipher_group = groupwise;
        return 0;
 }
 
@@ -1496,7 +1546,7 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
 static void set_multicast_list(struct usbnet *usbdev)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        __le32 filter, basefilter;
        int ret;
        char *mc_addrs = NULL;
@@ -1535,9 +1585,9 @@ static void set_multicast_list(struct usbnet *usbdev)
                        return;
                }
 
-               netdev_for_each_mc_addr(mclist, usbdev->net)
+               netdev_for_each_mc_addr(ha, usbdev->net)
                        memcpy(mc_addrs + i++ * ETH_ALEN,
-                              mclist->dmi_addr, ETH_ALEN);
+                              ha->addr, ETH_ALEN);
        }
        netif_addr_unlock_bh(usbdev->net);
 
@@ -1569,6 +1619,194 @@ set_filter:
                   le32_to_cpu(filter), ret);
 }
 
+#ifdef DEBUG
+static void debug_print_pmkids(struct usbnet *usbdev,
+                               struct ndis_80211_pmkid *pmkids,
+                               const char *func_str)
+{
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+       int i, len, count, max_pmkids, entry_len;
+
+       max_pmkids = priv->wdev.wiphy->max_num_pmkids;
+       len = le32_to_cpu(pmkids->length);
+       count = le32_to_cpu(pmkids->bssid_info_count);
+
+       entry_len = (count > 0) ? (len - sizeof(*pmkids)) / count : -1;
+
+       netdev_dbg(usbdev->net, "%s(): %d PMKIDs (data len: %d, entry len: "
+                               "%d)\n", func_str, count, len, entry_len);
+
+       if (count > max_pmkids)
+               count = max_pmkids;
+
+       for (i = 0; i < count; i++) {
+               u32 *tmp = (u32 *)pmkids->bssid_info[i].pmkid;
+
+               netdev_dbg(usbdev->net, "%s():  bssid: %pM, "
+                               "pmkid: %08X:%08X:%08X:%08X\n",
+                               func_str, pmkids->bssid_info[i].bssid,
+                               cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
+                               cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
+       }
+}
+#else
+static void debug_print_pmkids(struct usbnet *usbdev,
+                               struct ndis_80211_pmkid *pmkids,
+                               const char *func_str)
+{
+       return;
+}
+#endif
+
+static struct ndis_80211_pmkid *get_device_pmkids(struct usbnet *usbdev)
+{
+       struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
+       struct ndis_80211_pmkid *pmkids;
+       int len, ret, max_pmkids;
+
+       max_pmkids = priv->wdev.wiphy->max_num_pmkids;
+       len = sizeof(*pmkids) + max_pmkids * sizeof(pmkids->bssid_info[0]);
+
+       pmkids = kzalloc(len, GFP_KERNEL);
+       if (!pmkids)
+               return ERR_PTR(-ENOMEM);
+
+       pmkids->length = cpu_to_le32(len);
+       pmkids->bssid_info_count = cpu_to_le32(max_pmkids);
+
+       ret = rndis_query_oid(usbdev, OID_802_11_PMKID, pmkids, &len);
+       if (ret < 0) {
+               netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d)"
+                               " -> %d\n", __func__, len, max_pmkids, ret);
+
+               kfree(pmkids);
+               return ERR_PTR(ret);
+       }
+
+       if (le32_to_cpu(pmkids->bssid_info_count) > max_pmkids)
+               pmkids->bssid_info_count = cpu_to_le32(max_pmkids);
+
+       debug_print_pmkids(usbdev, pmkids, __func__);
+
+       return pmkids;
+}
+
+static int set_device_pmkids(struct usbnet *usbdev,
+                               struct ndis_80211_pmkid *pmkids)
+{
+       int ret, len, num_pmkids;
+
+       num_pmkids = le32_to_cpu(pmkids->bssid_info_count);
+       len = sizeof(*pmkids) + num_pmkids * sizeof(pmkids->bssid_info[0]);
+       pmkids->length = cpu_to_le32(len);
+
+       debug_print_pmkids(usbdev, pmkids, __func__);
+
+       ret = rndis_set_oid(usbdev, OID_802_11_PMKID, pmkids,
+                                               le32_to_cpu(pmkids->length));
+       if (ret < 0) {
+               netdev_dbg(usbdev->net, "%s(): OID_802_11_PMKID(%d, %d) -> %d"
+                               "\n", __func__, len, num_pmkids, ret);
+       }
+
+       kfree(pmkids);
+       return ret;
+}
+
+static struct ndis_80211_pmkid *remove_pmkid(struct usbnet *usbdev,
+                                               struct ndis_80211_pmkid *pmkids,
+                                               struct cfg80211_pmksa *pmksa,
+                                               int max_pmkids)
+{
+       int i, len, count, newlen, err;
+
+       len = le32_to_cpu(pmkids->length);
+       count = le32_to_cpu(pmkids->bssid_info_count);
+
+       if (count > max_pmkids)
+               count = max_pmkids;
+
+       for (i = 0; i < count; i++)
+               if (!compare_ether_addr(pmkids->bssid_info[i].bssid,
+                                                       pmksa->bssid))
+                       break;
+
+       /* pmkid not found */
+       if (i == count) {
+               netdev_dbg(usbdev->net, "%s(): bssid not found (%pM)\n",
+                                       __func__, pmksa->bssid);
+               err = -ENOENT;
+               goto error;
+       }
+
+       for (; i + 1 < count; i++)
+               pmkids->bssid_info[i] = pmkids->bssid_info[i + 1];
+
+       count--;
+       newlen = sizeof(*pmkids) + count * sizeof(pmkids->bssid_info[0]);
+
+       pmkids->length = cpu_to_le32(newlen);
+       pmkids->bssid_info_count = cpu_to_le32(count);
+
+       return pmkids;
+error:
+       kfree(pmkids);
+       return ERR_PTR(err);
+}
+
+static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
+                                               struct ndis_80211_pmkid *pmkids,
+                                               struct cfg80211_pmksa *pmksa,
+                                               int max_pmkids)
+{
+       int i, err, len, count, newlen;
+
+       len = le32_to_cpu(pmkids->length);
+       count = le32_to_cpu(pmkids->bssid_info_count);
+
+       if (count > max_pmkids)
+               count = max_pmkids;
+
+       /* update with new pmkid */
+       for (i = 0; i < count; i++) {
+               if (compare_ether_addr(pmkids->bssid_info[i].bssid,
+                                                       pmksa->bssid))
+                       continue;
+
+               memcpy(pmkids->bssid_info[i].pmkid, pmksa->pmkid,
+                                                               WLAN_PMKID_LEN);
+
+               return pmkids;
+       }
+
+       /* out of space, return error */
+       if (i == max_pmkids) {
+               netdev_dbg(usbdev->net, "%s(): out of space\n", __func__);
+               err = -ENOSPC;
+               goto error;
+       }
+
+       /* add new pmkid */
+       newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]);
+
+       pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
+       if (!pmkids) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       pmkids->length = cpu_to_le32(newlen);
+       pmkids->bssid_info_count = cpu_to_le32(count + 1);
+
+       memcpy(pmkids->bssid_info[count].bssid, pmksa->bssid, ETH_ALEN);
+       memcpy(pmkids->bssid_info[count].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
+
+       return pmkids;
+error:
+       kfree(pmkids);
+       return ERR_PTR(err);
+}
+
 /*
  * cfg80211 ops
  */
@@ -2053,7 +2291,7 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return deauthenticate(usbdev);
 }
 
-static int rndis_set_channel(struct wiphy *wiphy,
+static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
        struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
 {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
@@ -2179,6 +2417,78 @@ static int rndis_dump_station(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static int rndis_set_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+                               struct cfg80211_pmksa *pmksa)
+{
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
+       struct ndis_80211_pmkid *pmkids;
+       u32 *tmp = (u32 *)pmksa->pmkid;
+
+       netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__,
+                       pmksa->bssid,
+                       cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
+                       cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
+
+       pmkids = get_device_pmkids(usbdev);
+       if (IS_ERR(pmkids)) {
+               /* couldn't read PMKID cache from device */
+               return PTR_ERR(pmkids);
+       }
+
+       pmkids = update_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids);
+       if (IS_ERR(pmkids)) {
+               /* not found, list full, etc */
+               return PTR_ERR(pmkids);
+       }
+
+       return set_device_pmkids(usbdev, pmkids);
+}
+
+static int rndis_del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
+                               struct cfg80211_pmksa *pmksa)
+{
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
+       struct ndis_80211_pmkid *pmkids;
+       u32 *tmp = (u32 *)pmksa->pmkid;
+
+       netdev_dbg(usbdev->net, "%s(%pM, %08X:%08X:%08X:%08X)\n", __func__,
+                       pmksa->bssid,
+                       cpu_to_be32(tmp[0]), cpu_to_be32(tmp[1]),
+                       cpu_to_be32(tmp[2]), cpu_to_be32(tmp[3]));
+
+       pmkids = get_device_pmkids(usbdev);
+       if (IS_ERR(pmkids)) {
+               /* Couldn't read PMKID cache from device */
+               return PTR_ERR(pmkids);
+       }
+
+       pmkids = remove_pmkid(usbdev, pmkids, pmksa, wiphy->max_num_pmkids);
+       if (IS_ERR(pmkids)) {
+               /* not found, etc */
+               return PTR_ERR(pmkids);
+       }
+
+       return set_device_pmkids(usbdev, pmkids);
+}
+
+static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
+{
+       struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+       struct usbnet *usbdev = priv->usbdev;
+       struct ndis_80211_pmkid pmkid;
+
+       netdev_dbg(usbdev->net, "%s()\n", __func__);
+
+       memset(&pmkid, 0, sizeof(pmkid));
+
+       pmkid.length = cpu_to_le32(sizeof(pmkid));
+       pmkid.bssid_info_count = cpu_to_le32(0);
+
+       return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid));
+}
+
 /*
  * workers, indication handlers, device poller
  */
@@ -2523,12 +2833,14 @@ static void rndis_wlan_indication(struct usbnet *usbdev, void *ind, int buflen)
        }
 }
 
-static int rndis_wlan_get_caps(struct usbnet *usbdev)
+static int rndis_wlan_get_caps(struct usbnet *usbdev, struct wiphy *wiphy)
 {
        struct {
                __le32  num_items;
                __le32  items[8];
        } networks_supported;
+       struct ndis_80211_capability *caps;
+       u8 caps_buf[sizeof(*caps) + sizeof(caps->auth_encr_pair) * 16];
        int len, retval, i, n;
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
 
@@ -2556,6 +2868,21 @@ static int rndis_wlan_get_caps(struct usbnet *usbdev)
                }
        }
 
+       /* get device 802.11 capabilities, number of PMKIDs */
+       caps = (struct ndis_80211_capability *)caps_buf;
+       len = sizeof(caps_buf);
+       retval = rndis_query_oid(usbdev, OID_802_11_CAPABILITY, caps, &len);
+       if (retval >= 0) {
+               netdev_dbg(usbdev->net, "OID_802_11_CAPABILITY -> len %d, "
+                               "ver %d, pmkids %d, auth-encr-pairs %d\n",
+                               le32_to_cpu(caps->length),
+                               le32_to_cpu(caps->version),
+                               le32_to_cpu(caps->num_pmkids),
+                               le32_to_cpu(caps->num_auth_encr_pair));
+               wiphy->max_num_pmkids = le32_to_cpu(caps->num_pmkids);
+       } else
+               wiphy->max_num_pmkids = 0;
+
        return retval;
 }
 
@@ -2803,7 +3130,7 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
        wiphy->max_scan_ssids = 1;
 
        /* TODO: fill-out band/encr information based on priv->caps */
-       rndis_wlan_get_caps(usbdev);
+       rndis_wlan_get_caps(usbdev, wiphy);
 
        memcpy(priv->channels, rndis_channels, sizeof(rndis_channels));
        memcpy(priv->rates, rndis_rates, sizeof(rndis_rates));
@@ -2863,9 +3190,6 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
        flush_workqueue(priv->workqueue);
        destroy_workqueue(priv->workqueue);
 
-       if (priv && priv->wpa_ie_len)
-               kfree(priv->wpa_ie);
-
        rndis_unbind(usbdev, intf);
 
        wiphy_unregister(priv->wdev.wiphy);
index 5239e082cd0f51b75c6978167a3b6782510c864a..eea1ef2f502bd3c926599b2308901277e35250ef 100644 (file)
@@ -87,7 +87,7 @@ if RT2800PCI
 
 config RT2800PCI_RT30XX
        bool "rt2800pci - Include support for rt30xx (PCI/PCIe/PCMCIA) devices"
-       default n
+       default y
        ---help---
          This adds support for rt30xx wireless chipset family to the
          rt2800pci driver.
@@ -156,7 +156,7 @@ if RT2800USB
 
 config RT2800USB_RT30XX
        bool "rt2800usb - Include support for rt30xx (USB) devices"
-       default n
+       default y
        ---help---
          This adds support for rt30xx wireless chipset family to the
          rt2800usb driver.
index 5f5204b8289178941f579ea81319230ced397e77..4ba7b038928fa1a0108c84319f2aa85b2a6054c6 100644 (file)
@@ -526,6 +526,10 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 1);
                rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+       } else {
+               rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+               rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
+               rt2x00pci_register_write(rt2x00dev, CSR20, reg);
        }
 
        rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
@@ -1003,19 +1007,19 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
-       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-       rt2x00_desc_write(entry_priv->desc, 1, word);
+       rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
-       rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, skb->len);
-       rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, txdesc->length);
+       rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, txdesc->length);
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 3, &word);
@@ -1036,6 +1040,11 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1);
        rt2x00_desc_write(txd, 4, word);
 
+       /*
+        * Writing TXD word 0 must the last to prevent a race condition with
+        * the device, whereby the device may take hold of the TXD before we
+        * finished updating it.
+        */
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
@@ -1051,12 +1060,19 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
                           test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
        rt2x00_desc_write(txd, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
  * TX data initialization
  */
-static void rt2400pci_write_beacon(struct queue_entry *entry)
+static void rt2400pci_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@@ -1072,20 +1088,19 @@ static void rt2400pci_write_beacon(struct queue_entry *entry)
        rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-       /*
-        * Replace rt2x00lib allocated descriptor with the
-        * pointer to the _real_ hardware descriptor.
-        * After that, map the beacon to DMA and update the
-        * descriptor.
-        */
-       memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry_priv->desc;
-
        rt2x00queue_map_txskb(rt2x00dev, entry->skb);
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
+
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
 static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
@@ -1093,17 +1108,6 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (queue == QID_BEACON) {
-               rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-               if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-                       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-                       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
-                       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-               }
-               return;
-       }
-
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
        rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
        rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
index 2a73f593aab0cb82ef4bdaa1e949b82cd7e7d4a2..89d132d4af1276e11ccf451004c00a3aa6e71fb2 100644 (file)
@@ -574,6 +574,10 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 1);
                rt2x00pci_register_write(rt2x00dev, CSR20, reg);
+       } else {
+               rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
+               rt2x00_set_field32(&reg, CSR20_AUTOWAKE, 0);
+               rt2x00pci_register_write(rt2x00dev, CSR20, reg);
        }
 
        rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
@@ -1161,15 +1165,15 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
-       rt2x00_desc_read(entry_priv->desc, 1, &word);
+       rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
-       rt2x00_desc_write(entry_priv->desc, 1, word);
+       rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
        rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
@@ -1190,6 +1194,11 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags));
        rt2x00_desc_write(txd, 10, word);
 
+       /*
+        * Writing TXD word 0 must the last to prevent a race condition with
+        * the device, whereby the device may take hold of the TXD before we
+        * finished updating it.
+        */
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
@@ -1205,15 +1214,22 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
        rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
                           test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
        rt2x00_desc_write(txd, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
  * TX data initialization
  */
-static void rt2500pci_write_beacon(struct queue_entry *entry)
+static void rt2500pci_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@@ -1229,20 +1245,19 @@ static void rt2500pci_write_beacon(struct queue_entry *entry)
        rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
        rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 
-       /*
-        * Replace rt2x00lib allocated descriptor with the
-        * pointer to the _real_ hardware descriptor.
-        * After that, map the beacon to DMA and update the
-        * descriptor.
-        */
-       memcpy(entry_priv->desc, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry_priv->desc;
-
        rt2x00queue_map_txskb(rt2x00dev, entry->skb);
 
        rt2x00_desc_read(entry_priv->desc, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
        rt2x00_desc_write(entry_priv->desc, 1, word);
+
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
 }
 
 static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
@@ -1250,17 +1265,6 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (queue == QID_BEACON) {
-               rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
-               if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
-                       rt2x00_set_field32(&reg, CSR14_TBCN, 1);
-                       rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
-                       rt2x00pci_register_write(rt2x00dev, CSR14, reg);
-               }
-               return;
-       }
-
        rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
        rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, (queue == QID_AC_BE));
        rt2x00_set_field32(&reg, TXCSR0_KICK_TX, (queue == QID_AC_BK));
index 8ebb705fe106f6c6403bcc953c6e04d18a9403dd..9ae96a626e6d0fafc6b8a633af03c75a135c5b3d 100644 (file)
@@ -649,6 +649,10 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00_set_field16(&reg, MAC_CSR18_AUTO_WAKE, 1);
                rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
+       } else {
+               rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
+               rt2x00_set_field16(&reg, MAC_CSR18_AUTO_WAKE, 0);
+               rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
        }
 
        rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
@@ -1030,12 +1034,30 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
+       rt2x00_desc_read(txd, 0, &word);
+       rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
+       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_ACK,
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_OFDM,
+                          (txdesc->rate_mode == RATE_MODE_OFDM));
+       rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
+                          test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
+       rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
+       rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
+       rt2x00_desc_write(txd, 0, word);
+
        rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset);
        rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs);
@@ -1055,23 +1077,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                _rt2x00_desc_write(txd, 4, skbdesc->iv[1]);
        }
 
-       rt2x00_desc_read(txd, 0, &word);
-       rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit);
-       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_OFDM,
-                          (txdesc->rate_mode == RATE_MODE_OFDM));
-       rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
-                          test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
-       rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
-       rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
-       rt2x00_desc_write(txd, 0, word);
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
@@ -1079,22 +1089,15 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
  */
 static void rt2500usb_beacondone(struct urb *urb);
 
-static void rt2500usb_write_beacon(struct queue_entry *entry)
+static void rt2500usb_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint);
        int length;
-       u16 reg;
-
-       /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry->skb->data;
+       u16 reg, reg0;
 
        /*
         * Disable beaconing while we are reloading the beacon data,
@@ -1104,6 +1107,11 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
        rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
        rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 
+       /*
+        * Take the descriptor in front of the skb into account.
+        */
+       skb_push(entry->skb, TXD_DESC_SIZE);
+
        /*
         * USB devices cannot blindly pass the skb->len as the
         * length of the data to usb_fill_bulk_urb. Pass the skb
@@ -1129,6 +1137,26 @@ static void rt2500usb_write_beacon(struct queue_entry *entry)
         * Send out the guardian byte.
         */
        usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC);
+
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+       rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+       reg0 = reg;
+       rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+       /*
+        * Beacon generation will fail initially.
+        * To prevent this we need to change the TXRX_CSR19
+        * register several times (reg0 is the same as reg
+        * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
+        * and 1 in reg).
+        */
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
+       rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
 }
 
 static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
@@ -1145,37 +1173,6 @@ static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
-static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
-{
-       u16 reg, reg0;
-
-       if (queue != QID_BEACON) {
-               rt2x00usb_kick_tx_queue(rt2x00dev, queue);
-               return;
-       }
-
-       rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
-       if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
-               rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
-               rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
-               reg0 = reg;
-               rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
-               /*
-                * Beacon generation will fail initially.
-                * To prevent this we need to change the TXRX_CSR19
-                * register several times (reg0 is the same as reg
-                * except for TXRX_CSR19_BEACON_GEN, which is 0 in reg0
-                * and 1 in reg).
-                */
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
-               rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
-       }
-}
-
 /*
  * RX control handlers
  */
@@ -1210,11 +1207,9 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
        if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC;
 
-       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
-               rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
-               if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
-                       rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
-       }
+       rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER);
+       if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR))
+               rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY;
 
        if (rxdesc->cipher != CIPHER_NONE) {
                _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
@@ -1643,11 +1638,6 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        char *tx_power;
        unsigned int i;
 
-       /*
-        * Disable powersaving as default.
-        */
-       rt2x00dev->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
        /*
         * Initialize all hw fields.
         */
@@ -1781,7 +1771,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
        .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt2500usb_write_beacon,
        .get_tx_data_len        = rt2500usb_get_tx_data_len,
-       .kick_tx_queue          = rt2500usb_kick_tx_queue,
+       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
        .kill_tx_queue          = rt2x00usb_kill_tx_queue,
        .fill_rxdone            = rt2500usb_fill_rxdone,
        .config_shared_key      = rt2500usb_config_key,
index 74c0433dba3788659ff9ccfc1c5060cb7387282c..2aa03751c341d18848f668beb26868bdc252abb5 100644 (file)
 #define RF3021                         0x0007
 #define RF3022                         0x0008
 #define RF3052                         0x0009
+#define RF3320                         0x000b
 
 /*
- * Chipset version.
+ * Chipset revisions.
  */
-#define RT2860C_VERSION                        0x0100
-#define RT2860D_VERSION                        0x0101
-#define RT2880E_VERSION                        0x0200
-#define RT2883_VERSION                 0x0300
-#define RT3070_VERSION                 0x0200
+#define REV_RT2860C                    0x0100
+#define REV_RT2860D                    0x0101
+#define REV_RT2870D                    0x0101
+#define REV_RT2872E                    0x0200
+#define REV_RT3070E                    0x0200
+#define REV_RT3070F                    0x0201
+#define REV_RT3071E                    0x0211
+#define REV_RT3090E                    0x0211
+#define REV_RT3390E                    0x0211
 
 /*
  * Signal information.
 #define NUM_TX_QUEUES                  4
 
 /*
- * USB registers.
+ * Registers.
  */
 
+/*
+ * OPT_14: Unknown register used by rt3xxx devices.
+ */
+#define OPT_14_CSR                     0x0114
+#define OPT_14_CSR_BIT0                        FIELD32(0x00000001)
+
 /*
  * INT_SOURCE_CSR: Interrupt source register.
  * Write one to clear corresponding bit.
- * TX_FIFO_STATUS: FIFO Statistics is full, sw should read 0x171c
+ * TX_FIFO_STATUS: FIFO Statistics is full, sw should read TX_STA_FIFO
  */
 #define INT_SOURCE_CSR                 0x0200
 #define INT_SOURCE_CSR_RXDELAYINT      FIELD32(0x00000001)
  */
 #define EFUSE_DATA3                    0x059c
 
+/*
+ * LDO_CFG0
+ */
+#define LDO_CFG0                       0x05d4
+#define LDO_CFG0_DELAY3                        FIELD32(0x000000ff)
+#define LDO_CFG0_DELAY2                        FIELD32(0x0000ff00)
+#define LDO_CFG0_DELAY1                        FIELD32(0x00ff0000)
+#define LDO_CFG0_BGSEL                 FIELD32(0x03000000)
+#define LDO_CFG0_LDO_CORE_VLEVEL       FIELD32(0x1c000000)
+#define LD0_CFG0_LDO25_LEVEL           FIELD32(0x60000000)
+#define LDO_CFG0_LDO25_LARGEA          FIELD32(0x80000000)
+
+/*
+ * GPIO_SWITCH
+ */
+#define GPIO_SWITCH                    0x05dc
+#define GPIO_SWITCH_0                  FIELD32(0x00000001)
+#define GPIO_SWITCH_1                  FIELD32(0x00000002)
+#define GPIO_SWITCH_2                  FIELD32(0x00000004)
+#define GPIO_SWITCH_3                  FIELD32(0x00000008)
+#define GPIO_SWITCH_4                  FIELD32(0x00000010)
+#define GPIO_SWITCH_5                  FIELD32(0x00000020)
+#define GPIO_SWITCH_6                  FIELD32(0x00000040)
+#define GPIO_SWITCH_7                  FIELD32(0x00000080)
+
 /*
  * MAC Control/Status Registers(CSR).
  * Some values are set in TU, whereas 1 TU == 1024 us.
  * TX_BAND_CFG: 0x1 use upper 20MHz, 0x0 use lower 20MHz
  */
 #define TX_BAND_CFG                    0x132c
-#define TX_BAND_CFG_HT40_PLUS          FIELD32(0x00000001)
+#define TX_BAND_CFG_HT40_MINUS         FIELD32(0x00000001)
 #define TX_BAND_CFG_A                  FIELD32(0x00000002)
 #define TX_BAND_CFG_BG                 FIELD32(0x00000004)
 
@@ -1483,7 +1519,7 @@ struct mac_iveiv_entry {
  * BBP 3: RX Antenna
  */
 #define BBP3_RX_ANTENNA                        FIELD8(0x18)
-#define BBP3_HT40_PLUS                 FIELD8(0x20)
+#define BBP3_HT40_MINUS                        FIELD8(0x20)
 
 /*
  * BBP 4: Bandwidth
@@ -1491,15 +1527,33 @@ struct mac_iveiv_entry {
 #define BBP4_TX_BF                     FIELD8(0x01)
 #define BBP4_BANDWIDTH                 FIELD8(0x18)
 
+/*
+ * BBP 138: Unknown
+ */
+#define BBP138_RX_ADC1                 FIELD8(0x02)
+#define BBP138_RX_ADC2                 FIELD8(0x04)
+#define BBP138_TX_DAC1                 FIELD8(0x20)
+#define BBP138_TX_DAC2                 FIELD8(0x40)
+
 /*
  * RFCSR registers
  * The wordsize of the RFCSR is 8 bits.
  */
 
+/*
+ * RFCSR 1:
+ */
+#define RFCSR1_RF_BLOCK_EN             FIELD8(0x01)
+#define RFCSR1_RX0_PD                  FIELD8(0x04)
+#define RFCSR1_TX0_PD                  FIELD8(0x08)
+#define RFCSR1_RX1_PD                  FIELD8(0x10)
+#define RFCSR1_TX1_PD                  FIELD8(0x20)
+
 /*
  * RFCSR 6:
  */
-#define RFCSR6_R                       FIELD8(0x03)
+#define RFCSR6_R1                      FIELD8(0x03)
+#define RFCSR6_R2                      FIELD8(0x40)
 
 /*
  * RFCSR 7:
@@ -1511,6 +1565,33 @@ struct mac_iveiv_entry {
  */
 #define RFCSR12_TX_POWER               FIELD8(0x1f)
 
+/*
+ * RFCSR 13:
+ */
+#define RFCSR13_TX_POWER               FIELD8(0x1f)
+
+/*
+ * RFCSR 15:
+ */
+#define RFCSR15_TX_LO2_EN              FIELD8(0x08)
+
+/*
+ * RFCSR 17:
+ */
+#define RFCSR17_TXMIXER_GAIN           FIELD8(0x07)
+#define RFCSR17_TX_LO1_EN              FIELD8(0x08)
+#define RFCSR17_R                      FIELD8(0x20)
+
+/*
+ * RFCSR 20:
+ */
+#define RFCSR20_RX_LO1_EN              FIELD8(0x08)
+
+/*
+ * RFCSR 21:
+ */
+#define RFCSR21_RX_LO2_EN              FIELD8(0x08)
+
 /*
  * RFCSR 22:
  */
@@ -1521,6 +1602,14 @@ struct mac_iveiv_entry {
  */
 #define RFCSR23_FREQ_OFFSET            FIELD8(0x7f)
 
+/*
+ * RFCSR 27:
+ */
+#define RFCSR27_R1                     FIELD8(0x03)
+#define RFCSR27_R2                     FIELD8(0x04)
+#define RFCSR27_R3                     FIELD8(0x30)
+#define RFCSR27_R4                     FIELD8(0x40)
+
 /*
  * RFCSR 30:
  */
@@ -1603,6 +1692,8 @@ struct mac_iveiv_entry {
 #define EEPROM_NIC_WPS_PBC             FIELD16(0x0080)
 #define EEPROM_NIC_BW40M_BG            FIELD16(0x0100)
 #define EEPROM_NIC_BW40M_A             FIELD16(0x0200)
+#define EEPROM_NIC_ANT_DIVERSITY       FIELD16(0x0800)
+#define EEPROM_NIC_DAC_TEST            FIELD16(0x8000)
 
 /*
  * EEPROM frequency
@@ -1658,6 +1749,12 @@ struct mac_iveiv_entry {
 #define EEPROM_RSSI_BG2_OFFSET2                FIELD16(0x00ff)
 #define EEPROM_RSSI_BG2_LNA_A1         FIELD16(0xff00)
 
+/*
+ * EEPROM TXMIXER GAIN BG offset (note overlaps with EEPROM RSSI BG2).
+ */
+#define EEPROM_TXMIXER_GAIN_BG         0x0024
+#define EEPROM_TXMIXER_GAIN_BG_VAL     FIELD16(0x0007)
+
 /*
  * EEPROM RSSI A offset
  */
index c015ce9fdd09925da8e46dff2495c9d69e24d7a8..db4250d1c8b35cc68abfe078a10753d5ad97e198 100644 (file)
@@ -41,9 +41,6 @@
 #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
 #include "rt2x00usb.h"
 #endif
-#if defined(CONFIG_RT2X00_LIB_PCI) || defined(CONFIG_RT2X00_LIB_PCI_MODULE)
-#include "rt2x00pci.h"
-#endif
 #include "rt2800lib.h"
 #include "rt2800.h"
 #include "rt2800usb.h"
@@ -76,6 +73,23 @@ MODULE_LICENSE("GPL");
        rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \
                            H2M_MAILBOX_CSR_OWNER, (__reg))
 
+static inline bool rt2800_is_305x_soc(struct rt2x00_dev *rt2x00dev)
+{
+       /* check for rt2872 on SoC */
+       if (!rt2x00_is_soc(rt2x00dev) ||
+           !rt2x00_rt(rt2x00dev, RT2872))
+               return false;
+
+       /* we know for sure that these rf chipsets are used on rt305x boards */
+       if (rt2x00_rf(rt2x00dev, RF3020) ||
+           rt2x00_rf(rt2x00dev, RF3021) ||
+           rt2x00_rf(rt2x00dev, RF3022))
+               return true;
+
+       NOTICE(rt2x00dev, "Unknown RF chipset on rt305x\n");
+       return false;
+}
+
 static void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev,
                             const unsigned int word, const u8 value)
 {
@@ -268,6 +282,104 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
 }
 EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
 
+void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+{
+       __le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
+       u32 word;
+
+       /*
+        * Initialize TX Info descriptor
+        */
+       rt2x00_desc_read(txwi, 0, &word);
+       rt2x00_set_field32(&word, TXWI_W0_FRAG,
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
+       rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
+       rt2x00_set_field32(&word, TXWI_W0_TS,
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_AMPDU,
+                          test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
+       rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->txop);
+       rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
+       rt2x00_set_field32(&word, TXWI_W0_BW,
+                          test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
+                          test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
+       rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
+       rt2x00_desc_write(txwi, 0, word);
+
+       rt2x00_desc_read(txwi, 1, &word);
+       rt2x00_set_field32(&word, TXWI_W1_ACK,
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W1_NSEQ,
+                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
+       rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
+       rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
+                          test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
+                          txdesc->key_idx : 0xff);
+       rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
+                          txdesc->length);
+       rt2x00_set_field32(&word, TXWI_W1_PACKETID, txdesc->queue + 1);
+       rt2x00_desc_write(txwi, 1, word);
+
+       /*
+        * Always write 0 to IV/EIV fields, hardware will insert the IV
+        * from the IVEIV register when TXD_W3_WIV is set to 0.
+        * When TXD_W3_WIV is set to 1 it will use the IV data
+        * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
+        * crypto entry in the registers should be used to encrypt the frame.
+        */
+       _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
+       _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
+}
+EXPORT_SYMBOL_GPL(rt2800_write_txwi);
+
+void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
+{
+       __le32 *rxwi = (__le32 *) skb->data;
+       u32 word;
+
+       rt2x00_desc_read(rxwi, 0, &word);
+
+       rxdesc->cipher = rt2x00_get_field32(word, RXWI_W0_UDF);
+       rxdesc->size = rt2x00_get_field32(word, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
+
+       rt2x00_desc_read(rxwi, 1, &word);
+
+       if (rt2x00_get_field32(word, RXWI_W1_SHORT_GI))
+               rxdesc->flags |= RX_FLAG_SHORT_GI;
+
+       if (rt2x00_get_field32(word, RXWI_W1_BW))
+               rxdesc->flags |= RX_FLAG_40MHZ;
+
+       /*
+        * Detect RX rate, always use MCS as signal type.
+        */
+       rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
+       rxdesc->signal = rt2x00_get_field32(word, RXWI_W1_MCS);
+       rxdesc->rate_mode = rt2x00_get_field32(word, RXWI_W1_PHYMODE);
+
+       /*
+        * Mask of 0x8 bit to remove the short preamble flag.
+        */
+       if (rxdesc->rate_mode == RATE_MODE_CCK)
+               rxdesc->signal &= ~0x8;
+
+       rt2x00_desc_read(rxwi, 2, &word);
+
+       rxdesc->rssi =
+           (rt2x00_get_field32(word, RXWI_W2_RSSI0) +
+            rt2x00_get_field32(word, RXWI_W2_RSSI1)) / 2;
+
+       /*
+        * Remove RXWI descriptor from start of buffer.
+        */
+       skb_pull(skb, RXWI_DESC_SIZE);
+}
+EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
+
 #ifdef CONFIG_RT2X00_LIB_DEBUGFS
 const struct rt2x00debug rt2800_rt2x00debug = {
        .owner  = THIS_MODULE,
@@ -360,11 +472,6 @@ static int rt2800_blink_set(struct led_classdev *led_cdev,
        rt2800_register_read(led->rt2x00dev, LED_CFG, &reg);
        rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, *delay_on);
        rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, *delay_off);
-       rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
-       rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
-       rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 3);
-       rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
-       rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
        rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
 
        return 0;
@@ -610,10 +717,6 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp)
 {
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
-       rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 0x20);
-       rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
-
        rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY,
                           !!erp->short_preamble);
@@ -632,15 +735,10 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp)
 
        rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
        rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, erp->slot_time);
-       rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
        rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, erp->sifs);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, erp->sifs);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
        rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, erp->eifs);
-       rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
        rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
 
        rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
@@ -718,10 +816,10 @@ static void rt2800_config_lna_gain(struct rt2x00_dev *rt2x00dev,
        rt2x00dev->lna_gain = lna_gain;
 }
 
-static void rt2800_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
-                                      struct ieee80211_conf *conf,
-                                      struct rf_channel *rf,
-                                      struct channel_info *info)
+static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
 {
        rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
 
@@ -787,10 +885,10 @@ static void rt2800_config_channel_rt2x(struct rt2x00_dev *rt2x00dev,
        rt2800_rf_write(rt2x00dev, 4, rf->rf4);
 }
 
-static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
-                                      struct ieee80211_conf *conf,
-                                      struct rf_channel *rf,
-                                      struct channel_info *info)
+static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
 {
        u8 rfcsr;
 
@@ -798,7 +896,7 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3);
 
        rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR6_R, rf->rf2);
+       rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2);
        rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
 
        rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
@@ -806,6 +904,11 @@ static void rt2800_config_channel_rt3x(struct rt2x00_dev *rt2x00dev,
                          TXPOWER_G_TO_DEV(info->tx_power1));
        rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
 
+       rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
+                         TXPOWER_G_TO_DEV(info->tx_power2));
+       rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
+
        rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
        rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
        rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
@@ -827,15 +930,13 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        unsigned int tx_pin;
        u8 bbp;
 
-       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);
+       if (rt2x00_rf(rt2x00dev, RF2020) ||
+           rt2x00_rf(rt2x00dev, RF3020) ||
+           rt2x00_rf(rt2x00dev, RF3021) ||
+           rt2x00_rf(rt2x00dev, RF3022))
+               rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
        else
-               rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info);
+               rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
 
        /*
         * Change BBP settings
@@ -863,7 +964,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        }
 
        rt2800_register_read(rt2x00dev, TX_BAND_CFG, &reg);
-       rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_PLUS, conf_is_ht40_plus(conf));
+       rt2x00_set_field32(&reg, TX_BAND_CFG_HT40_MINUS, conf_is_ht40_minus(conf));
        rt2x00_set_field32(&reg, TX_BAND_CFG_A, rf->channel > 14);
        rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
        rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg);
@@ -896,11 +997,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2800_bbp_write(rt2x00dev, 4, bbp);
 
        rt2800_bbp_read(rt2x00dev, 3, &bbp);
-       rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf));
+       rt2x00_set_field8(&bbp, BBP3_HT40_MINUS, conf_is_ht40_minus(conf));
        rt2800_bbp_write(rt2x00dev, 3, bbp);
 
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
                if (conf_is_ht40(conf)) {
                        rt2800_bbp_write(rt2x00dev, 69, 0x1a);
                        rt2800_bbp_write(rt2x00dev, 70, 0x0a);
@@ -988,10 +1088,6 @@ static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
                           libconf->conf->short_frame_max_tx_count);
        rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT,
                           libconf->conf->long_frame_max_tx_count);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
-       rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
        rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg);
 }
 
@@ -1015,13 +1111,13 @@ static void rt2800_config_ps(struct rt2x00_dev *rt2x00dev,
 
                rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
        } else {
-               rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
-
                rt2800_register_read(rt2x00dev, AUTOWAKEUP_CFG, &reg);
                rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTO_LEAD_TIME, 0);
                rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_TBCN_BEFORE_WAKE, 0);
                rt2x00_set_field32(&reg, AUTOWAKEUP_CFG_AUTOWAKE, 0);
                rt2800_register_write(rt2x00dev, AUTOWAKEUP_CFG, reg);
+
+               rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
        }
 }
 
@@ -1062,9 +1158,10 @@ EXPORT_SYMBOL_GPL(rt2800_link_stats);
 static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
 {
        if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
-               if (rt2x00_is_usb(rt2x00dev) &&
-                   rt2x00_rt(rt2x00dev, RT3070) &&
-                   (rt2x00_rev(rt2x00dev) == RT3070_VERSION))
+               if (rt2x00_rt(rt2x00dev, RT3070) ||
+                   rt2x00_rt(rt2x00dev, RT3071) ||
+                   rt2x00_rt(rt2x00dev, RT3090) ||
+                   rt2x00_rt(rt2x00dev, RT3390))
                        return 0x1c + (2 * rt2x00dev->lna_gain);
                else
                        return 0x2e + rt2x00dev->lna_gain;
@@ -1095,8 +1192,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner);
 void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
                       const u32 count)
 {
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) == RT2860C_VERSION))
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C))
                return;
 
        /*
@@ -1114,8 +1210,17 @@ EXPORT_SYMBOL_GPL(rt2800_link_tuner);
 int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 {
        u32 reg;
+       u16 eeprom;
        unsigned int i;
 
+       rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_RX_DMA, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_RX_DMA_BUSY, 0);
+       rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
+       rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+
        if (rt2x00_is_usb(rt2x00dev)) {
                /*
                 * Wait until BBP and RF are ready.
@@ -1135,8 +1240,25 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
                rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
                rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
                                      reg & ~0x00002000);
-       } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))
+       } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
+               /*
+                * Reset DMA indexes
+                */
+               rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+               rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+               rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+               rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+               rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
                rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+       }
 
        rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
        rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
@@ -1181,12 +1303,42 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, BCN_TIME_CFG_TX_TIME_COMPENSATE, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
-       if (rt2x00_is_usb(rt2x00dev) &&
-           rt2x00_rt(rt2x00dev, RT3070) &&
-           (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
+       rt2800_config_filter(rt2x00dev, FIF_ALLMULTI);
+
+       rt2800_register_read(rt2x00dev, BKOFF_SLOT_CFG, &reg);
+       rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_SLOT_TIME, 9);
+       rt2x00_set_field32(&reg, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2);
+       rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg);
+
+       if (rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
-               rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
+                       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+                       if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+                               rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                                     0x0000002c);
+                       else
+                               rt2800_register_write(rt2x00dev, TX_SW_CFG2,
+                                                     0x0000000f);
+               } else {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+               }
+               rt2800_register_write(rt2x00dev, TX_SW_CFG2, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3070)) {
+               rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000002c);
+               } else {
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
+                       rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+               }
        } else {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -1205,19 +1357,15 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
 
        rt2800_register_read(rt2x00dev, TX_TIMEOUT_CFG, &reg);
        rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_MPDU_LIFETIME, 9);
+       rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_RX_ACK_TIMEOUT, 32);
        rt2x00_set_field32(&reg, TX_TIMEOUT_CFG_TX_OP_TIMEOUT, 10);
        rt2800_register_write(rt2x00dev, TX_TIMEOUT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, MAX_LEN_CFG, &reg);
        rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE);
-       if ((rt2x00_rt(rt2x00dev, RT2872) &&
-            (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION)) ||
-           rt2x00_rt(rt2x00dev, RT2880) ||
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT2872, REV_RT2872E) ||
            rt2x00_rt(rt2x00dev, RT2883) ||
-           rt2x00_rt(rt2x00dev, RT2890) ||
-           rt2x00_rt(rt2x00dev, RT3052) ||
-           (rt2x00_rt(rt2x00dev, RT3070) &&
-            (rt2x00_rev(rt2x00dev) < RT3070_VERSION)))
+           rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070E))
                rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 2);
        else
                rt2x00_set_field32(&reg, MAX_LEN_CFG_MAX_PSDU, 1);
@@ -1225,38 +1373,61 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, MAX_LEN_CFG_MIN_MPDU, 0);
        rt2800_register_write(rt2x00dev, MAX_LEN_CFG, reg);
 
+       rt2800_register_read(rt2x00dev, LED_CFG, &reg);
+       rt2x00_set_field32(&reg, LED_CFG_ON_PERIOD, 70);
+       rt2x00_set_field32(&reg, LED_CFG_OFF_PERIOD, 30);
+       rt2x00_set_field32(&reg, LED_CFG_SLOW_BLINK_PERIOD, 3);
+       rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, 3);
+       rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, 3);
+       rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE, 3);
+       rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, 1);
+       rt2800_register_write(rt2x00dev, LED_CFG, reg);
+
        rt2800_register_write(rt2x00dev, PBF_MAX_PCNT, 0x1f3fbf9f);
 
+       rt2800_register_read(rt2x00dev, TX_RTY_CFG, &reg);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_SHORT_RTY_LIMIT, 15);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_LIMIT, 31);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_LONG_RTY_THRE, 2000);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_NON_AGG_RTY_MODE, 0);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_AGG_RTY_MODE, 0);
+       rt2x00_set_field32(&reg, TX_RTY_CFG_TX_AUTO_FB_ENABLE, 1);
+       rt2800_register_write(rt2x00dev, TX_RTY_CFG, reg);
+
        rt2800_register_read(rt2x00dev, AUTO_RSP_CFG, &reg);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_AUTORESPONDER, 1);
+       rt2x00_set_field32(&reg, AUTO_RSP_CFG_BAC_ACK_POLICY, 1);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MMODE, 0);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_CTS_40_MREF, 0);
+       rt2x00_set_field32(&reg, AUTO_RSP_CFG_AR_PREAMBLE, 1);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_DUAL_CTS_EN, 0);
        rt2x00_set_field32(&reg, AUTO_RSP_CFG_ACK_CTS_PSM_BIT, 0);
        rt2800_register_write(rt2x00dev, AUTO_RSP_CFG, reg);
 
        rt2800_register_read(rt2x00dev, CCK_PROT_CFG, &reg);
-       rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 8);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_RATE, 3);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_CTRL, 0);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, CCK_PROT_CFG_RTS_TH_EN, 1);
        rt2800_register_write(rt2x00dev, CCK_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, OFDM_PROT_CFG, &reg);
-       rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 8);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_RATE, 3);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_CTRL, 0);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM20, 1);
-       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 1);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF20, 1);
-       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, OFDM_PROT_CFG_RTS_TH_EN, 1);
        rt2800_register_write(rt2x00dev, OFDM_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, MM20_PROT_CFG, &reg);
@@ -1269,11 +1440,13 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, MM20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, MM20_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, MM20_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, MM40_PROT_CFG, &reg);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_RATE, 0x4084);
-       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL, 0);
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_CTRL,
+                          !rt2x00_is_usb(rt2x00dev));
        rt2x00_set_field32(&reg, MM40_PROT_CFG_PROTECT_NAV, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_CCK, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_OFDM, 1);
@@ -1281,6 +1454,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, MM40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, MM40_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, MM40_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, GF20_PROT_CFG, &reg);
@@ -1293,6 +1467,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_MM40, 0);
        rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, GF20_PROT_CFG_TX_OP_ALLOW_GF40, 0);
+       rt2x00_set_field32(&reg, GF20_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, GF20_PROT_CFG, reg);
 
        rt2800_register_read(rt2x00dev, GF40_PROT_CFG, &reg);
@@ -1305,6 +1480,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_MM40, 1);
        rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF20, 1);
        rt2x00_set_field32(&reg, GF40_PROT_CFG_TX_OP_ALLOW_GF40, 1);
+       rt2x00_set_field32(&reg, GF40_PROT_CFG_RTS_TH_EN, 0);
        rt2800_register_write(rt2x00dev, GF40_PROT_CFG, reg);
 
        if (rt2x00_is_usb(rt2x00dev)) {
@@ -1334,6 +1510,22 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2800_register_write(rt2x00dev, TX_RTS_CFG, reg);
 
        rt2800_register_write(rt2x00dev, EXP_ACK_TIME, 0x002400ca);
+
+       /*
+        * Usually the CCK SIFS time should be set to 10 and the OFDM SIFS
+        * time should be set to 16. However, the original Ralink driver uses
+        * 16 for both and indeed using a value of 10 for CCK SIFS results in
+        * connection problems with 11g + CTS protection. Hence, use the same
+        * defaults as the Ralink driver: 16 for both, CCK and OFDM SIFS.
+        */
+       rt2800_register_read(rt2x00dev, XIFS_TIME_CFG, &reg);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_CCKM_SIFS_TIME, 16);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_SIFS_TIME, 16);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_OFDM_XIFS_TIME, 4);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_EIFS, 314);
+       rt2x00_set_field32(&reg, XIFS_TIME_CFG_BB_RXEND_ENABLE, 1);
+       rt2800_register_write(rt2x00dev, XIFS_TIME_CFG, reg);
+
        rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
 
        /*
@@ -1481,45 +1673,79 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
                     rt2800_wait_bbp_ready(rt2x00dev)))
                return -EACCES;
 
+       if (rt2800_is_305x_soc(rt2x00dev))
+               rt2800_bbp_write(rt2x00dev, 31, 0x08);
+
        rt2800_bbp_write(rt2x00dev, 65, 0x2c);
        rt2800_bbp_write(rt2x00dev, 66, 0x38);
-       rt2800_bbp_write(rt2x00dev, 69, 0x12);
+
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) {
+               rt2800_bbp_write(rt2x00dev, 69, 0x16);
+               rt2800_bbp_write(rt2x00dev, 73, 0x12);
+       } else {
+               rt2800_bbp_write(rt2x00dev, 69, 0x12);
+               rt2800_bbp_write(rt2x00dev, 73, 0x10);
+       }
+
        rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-       rt2800_bbp_write(rt2x00dev, 73, 0x10);
-       rt2800_bbp_write(rt2x00dev, 81, 0x37);
+
+       if (rt2x00_rt(rt2x00dev, RT3070) ||
+           rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_bbp_write(rt2x00dev, 79, 0x13);
+               rt2800_bbp_write(rt2x00dev, 80, 0x05);
+               rt2800_bbp_write(rt2x00dev, 81, 0x33);
+       } else if (rt2800_is_305x_soc(rt2x00dev)) {
+               rt2800_bbp_write(rt2x00dev, 78, 0x0e);
+               rt2800_bbp_write(rt2x00dev, 80, 0x08);
+       } else {
+               rt2800_bbp_write(rt2x00dev, 81, 0x37);
+       }
+
        rt2800_bbp_write(rt2x00dev, 82, 0x62);
        rt2800_bbp_write(rt2x00dev, 83, 0x6a);
-       rt2800_bbp_write(rt2x00dev, 84, 0x99);
+
+       if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D) ||
+           rt2x00_rt_rev(rt2x00dev, RT2870, REV_RT2870D))
+               rt2800_bbp_write(rt2x00dev, 84, 0x19);
+       else
+               rt2800_bbp_write(rt2x00dev, 84, 0x99);
+
        rt2800_bbp_write(rt2x00dev, 86, 0x00);
        rt2800_bbp_write(rt2x00dev, 91, 0x04);
        rt2800_bbp_write(rt2x00dev, 92, 0x00);
-       rt2800_bbp_write(rt2x00dev, 103, 0x00);
-       rt2800_bbp_write(rt2x00dev, 105, 0x05);
 
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) == RT2860C_VERSION)) {
-               rt2800_bbp_write(rt2x00dev, 69, 0x16);
-               rt2800_bbp_write(rt2x00dev, 73, 0x12);
-       }
-
-       if (rt2x00_rt(rt2x00dev, RT2860) &&
-           (rt2x00_rev(rt2x00dev) > RT2860D_VERSION))
-               rt2800_bbp_write(rt2x00dev, 84, 0x19);
+       if (rt2x00_rt_rev_gte(rt2x00dev, RT3070, REV_RT3070F) ||
+           rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
+           rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
+           rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
+           rt2800_is_305x_soc(rt2x00dev))
+               rt2800_bbp_write(rt2x00dev, 103, 0xc0);
+       else
+               rt2800_bbp_write(rt2x00dev, 103, 0x00);
 
-       if (rt2x00_is_usb(rt2x00dev) &&
-           rt2x00_rt(rt2x00dev, RT3070) &&
-           (rt2x00_rev(rt2x00dev) == RT3070_VERSION)) {
-               rt2800_bbp_write(rt2x00dev, 70, 0x0a);
-               rt2800_bbp_write(rt2x00dev, 84, 0x99);
+       if (rt2800_is_305x_soc(rt2x00dev))
+               rt2800_bbp_write(rt2x00dev, 105, 0x01);
+       else
                rt2800_bbp_write(rt2x00dev, 105, 0x05);
-       }
+       rt2800_bbp_write(rt2x00dev, 106, 0x35);
 
-       if (rt2x00_rt(rt2x00dev, RT3052)) {
-               rt2800_bbp_write(rt2x00dev, 31, 0x08);
-               rt2800_bbp_write(rt2x00dev, 78, 0x0e);
-               rt2800_bbp_write(rt2x00dev, 80, 0x08);
+       if (rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_bbp_read(rt2x00dev, 138, &value);
+
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+                       value |= 0x20;
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+                       value &= ~0x02;
+
+               rt2800_bbp_write(rt2x00dev, 138, value);
        }
 
+
        for (i = 0; i < EEPROM_BBP_SIZE; i++) {
                rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
 
@@ -1598,19 +1824,16 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
 {
        u8 rfcsr;
        u8 bbp;
+       u32 reg;
+       u16 eeprom;
 
-       if (rt2x00_is_usb(rt2x00dev) &&
-           rt2x00_rt(rt2x00dev, RT3070) &&
-           (rt2x00_rev(rt2x00dev) != RT3070_VERSION))
+       if (!rt2x00_rt(rt2x00dev, RT3070) &&
+           !rt2x00_rt(rt2x00dev, RT3071) &&
+           !rt2x00_rt(rt2x00dev, RT3090) &&
+           !rt2x00_rt(rt2x00dev, RT3390) &&
+           !rt2800_is_305x_soc(rt2x00dev))
                return 0;
 
-       if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
-               if (!rt2x00_rf(rt2x00dev, RF3020) &&
-                   !rt2x00_rf(rt2x00dev, RF3021) &&
-                   !rt2x00_rf(rt2x00dev, RF3022))
-                       return 0;
-       }
-
        /*
         * Init RF calibration.
         */
@@ -1621,13 +1844,15 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
        rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
 
-       if (rt2x00_is_usb(rt2x00dev)) {
+       if (rt2x00_rt(rt2x00dev, RT3070) ||
+           rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090)) {
                rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
                rt2800_rfcsr_write(rt2x00dev, 5, 0x03);
                rt2800_rfcsr_write(rt2x00dev, 6, 0x02);
                rt2800_rfcsr_write(rt2x00dev, 7, 0x70);
                rt2800_rfcsr_write(rt2x00dev, 9, 0x0f);
-               rt2800_rfcsr_write(rt2x00dev, 10, 0x71);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0x41);
                rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
                rt2800_rfcsr_write(rt2x00dev, 12, 0x7b);
                rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
@@ -1640,9 +1865,41 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
                rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
                rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
-               rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
                rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
-       } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
+       } else if (rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_rfcsr_write(rt2x00dev, 0, 0xa0);
+               rt2800_rfcsr_write(rt2x00dev, 1, 0xe1);
+               rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+               rt2800_rfcsr_write(rt2x00dev, 3, 0x62);
+               rt2800_rfcsr_write(rt2x00dev, 4, 0x40);
+               rt2800_rfcsr_write(rt2x00dev, 5, 0x8b);
+               rt2800_rfcsr_write(rt2x00dev, 6, 0x42);
+               rt2800_rfcsr_write(rt2x00dev, 7, 0x34);
+               rt2800_rfcsr_write(rt2x00dev, 8, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0x61);
+               rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+               rt2800_rfcsr_write(rt2x00dev, 12, 0x3b);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0xe0);
+               rt2800_rfcsr_write(rt2x00dev, 14, 0x90);
+               rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+               rt2800_rfcsr_write(rt2x00dev, 16, 0xe0);
+               rt2800_rfcsr_write(rt2x00dev, 17, 0x94);
+               rt2800_rfcsr_write(rt2x00dev, 18, 0x5c);
+               rt2800_rfcsr_write(rt2x00dev, 19, 0x4a);
+               rt2800_rfcsr_write(rt2x00dev, 20, 0xb2);
+               rt2800_rfcsr_write(rt2x00dev, 21, 0xf6);
+               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 23, 0x14);
+               rt2800_rfcsr_write(rt2x00dev, 24, 0x08);
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 28, 0x41);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
+               rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+       } else if (rt2800_is_305x_soc(rt2x00dev)) {
                rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
                rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
                rt2800_rfcsr_write(rt2x00dev, 2, 0xf7);
@@ -1673,15 +1930,57 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 27, 0x23);
                rt2800_rfcsr_write(rt2x00dev, 28, 0x13);
                rt2800_rfcsr_write(rt2x00dev, 29, 0x83);
+               rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x00);
+               return 0;
+       }
+
+       if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
+               rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+               rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+               rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+                  rt2x00_rt(rt2x00dev, RT3090)) {
+               rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
+               rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x14);
+
+               rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+               rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E)) {
+                       rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+                       if (rt2x00_get_field16(eeprom, EEPROM_NIC_DAC_TEST))
+                               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+                       else
+                               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 0);
+               }
+               rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
+               rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
+               rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
        }
 
        /*
         * Set RX Filter calibration for 20MHz and 40MHz
         */
-       rt2x00dev->calibration[0] =
-           rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
-       rt2x00dev->calibration[1] =
-           rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+       if (rt2x00_rt(rt2x00dev, RT3070)) {
+               rt2x00dev->calibration[0] =
+                       rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x16);
+               rt2x00dev->calibration[1] =
+                       rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
+       } else if (rt2x00_rt(rt2x00dev, RT3071) ||
+                  rt2x00_rt(rt2x00dev, RT3090) ||
+                  rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2x00dev->calibration[0] =
+                       rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x13);
+               rt2x00dev->calibration[1] =
+                       rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x15);
+       }
 
        /*
         * Set back to initial state
@@ -1699,6 +1998,81 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
        rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 0);
        rt2800_bbp_write(rt2x00dev, 4, bbp);
 
+       if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E))
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x03);
+
+       rt2800_register_read(rt2x00dev, OPT_14_CSR, &reg);
+       rt2x00_set_field32(&reg, OPT_14_CSR_BIT0, 1);
+       rt2800_register_write(rt2x00dev, OPT_14_CSR, reg);
+
+       rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR17_TX_LO1_EN, 0);
+       if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
+           rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+               if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+                       rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
+       }
+       rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
+       if (rt2x00_get_field16(eeprom, EEPROM_TXMIXER_GAIN_BG_VAL) >= 1)
+               rt2x00_set_field8(&rfcsr, RFCSR17_TXMIXER_GAIN,
+                                 rt2x00_get_field16(eeprom,
+                                                  EEPROM_TXMIXER_GAIN_BG_VAL));
+       rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
+
+       if (rt2x00_rt(rt2x00dev, RT3090)) {
+               rt2800_bbp_read(rt2x00dev, 138, &bbp);
+
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) == 1)
+                       rt2x00_set_field8(&bbp, BBP138_RX_ADC1, 0);
+               if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) == 1)
+                       rt2x00_set_field8(&bbp, BBP138_TX_DAC1, 1);
+
+               rt2800_bbp_write(rt2x00dev, 138, bbp);
+       }
+
+       if (rt2x00_rt(rt2x00dev, RT3071) ||
+           rt2x00_rt(rt2x00dev, RT3090) ||
+           rt2x00_rt(rt2x00dev, RT3390)) {
+               rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+               rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 15, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR15_TX_LO2_EN, 0);
+               rt2800_rfcsr_write(rt2x00dev, 15, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 20, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR20_RX_LO1_EN, 0);
+               rt2800_rfcsr_write(rt2x00dev, 20, rfcsr);
+
+               rt2800_rfcsr_read(rt2x00dev, 21, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR21_RX_LO2_EN, 0);
+               rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
+       }
+
+       if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3071)) {
+               rt2800_rfcsr_read(rt2x00dev, 27, &rfcsr);
+               if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F) ||
+                   rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E))
+                       rt2x00_set_field8(&rfcsr, RFCSR27_R1, 3);
+               else
+                       rt2x00_set_field8(&rfcsr, RFCSR27_R1, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR27_R2, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR27_R3, 0);
+               rt2x00_set_field8(&rfcsr, RFCSR27_R4, 0);
+               rt2800_rfcsr_write(rt2x00dev, 27, rfcsr);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2800_init_rfcsr);
@@ -1774,10 +2148,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
                EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
        } else if (rt2x00_rt(rt2x00dev, RT2860) ||
                   rt2x00_rt(rt2x00dev, RT2870) ||
-                  rt2x00_rt(rt2x00dev, RT2872) ||
-                  rt2x00_rt(rt2x00dev, RT2880) ||
-                  (rt2x00_rt(rt2x00dev, RT2883) &&
-                   (rt2x00_rev(rt2x00dev) < RT2883_VERSION))) {
+                  rt2x00_rt(rt2x00dev, RT2872)) {
                /*
                 * There is a max of 2 RX streams for RT28x0 series
                 */
@@ -1882,10 +2253,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        if (!rt2x00_rt(rt2x00dev, RT2860) &&
            !rt2x00_rt(rt2x00dev, RT2870) &&
            !rt2x00_rt(rt2x00dev, RT2872) &&
-           !rt2x00_rt(rt2x00dev, RT2880) &&
            !rt2x00_rt(rt2x00dev, RT2883) &&
-           !rt2x00_rt(rt2x00dev, RT2890) &&
-           !rt2x00_rt(rt2x00dev, RT3052) &&
            !rt2x00_rt(rt2x00dev, RT3070) &&
            !rt2x00_rt(rt2x00dev, RT3071) &&
            !rt2x00_rt(rt2x00dev, RT3090) &&
@@ -1954,7 +2322,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
 EXPORT_SYMBOL_GPL(rt2800_init_eeprom);
 
 /*
- * RF value list for rt28x0
+ * RF value list for rt28xx
  * Supports: 2.4 GHz (all) & 5.2 GHz (RF2850 & RF2750)
  */
 static const struct rf_channel rf_vals[] = {
@@ -2029,10 +2397,10 @@ static const struct rf_channel rf_vals[] = {
 };
 
 /*
- * RF value list for rt3070
- * Supports: 2.4 GHz
+ * RF value list for rt3xxx
+ * Supports: 2.4 GHz (all) & 5.2 GHz (RF3052)
  */
-static const struct rf_channel rf_vals_302x[] = {
+static const struct rf_channel rf_vals_3x[] = {
        {1,  241, 2, 2 },
        {2,  241, 2, 7 },
        {3,  242, 2, 2 },
@@ -2047,6 +2415,51 @@ static const struct rf_channel rf_vals_302x[] = {
        {12, 246, 2, 7 },
        {13, 247, 2, 2 },
        {14, 248, 2, 4 },
+
+       /* 802.11 UNI / HyperLan 2 */
+       {36, 0x56, 0, 4},
+       {38, 0x56, 0, 6},
+       {40, 0x56, 0, 8},
+       {44, 0x57, 0, 0},
+       {46, 0x57, 0, 2},
+       {48, 0x57, 0, 4},
+       {52, 0x57, 0, 8},
+       {54, 0x57, 0, 10},
+       {56, 0x58, 0, 0},
+       {60, 0x58, 0, 4},
+       {62, 0x58, 0, 6},
+       {64, 0x58, 0, 8},
+
+       /* 802.11 HyperLan 2 */
+       {100, 0x5b, 0, 8},
+       {102, 0x5b, 0, 10},
+       {104, 0x5c, 0, 0},
+       {108, 0x5c, 0, 4},
+       {110, 0x5c, 0, 6},
+       {112, 0x5c, 0, 8},
+       {116, 0x5d, 0, 0},
+       {118, 0x5d, 0, 2},
+       {120, 0x5d, 0, 4},
+       {124, 0x5d, 0, 8},
+       {126, 0x5d, 0, 10},
+       {128, 0x5e, 0, 0},
+       {132, 0x5e, 0, 4},
+       {134, 0x5e, 0, 6},
+       {136, 0x5e, 0, 8},
+       {140, 0x5f, 0, 0},
+
+       /* 802.11 UNII */
+       {149, 0x5f, 0, 9},
+       {151, 0x5f, 0, 11},
+       {153, 0x60, 0, 1},
+       {157, 0x60, 0, 5},
+       {159, 0x60, 0, 7},
+       {161, 0x60, 0, 9},
+       {165, 0x61, 0, 1},
+       {167, 0x61, 0, 3},
+       {169, 0x61, 0, 5},
+       {171, 0x61, 0, 7},
+       {173, 0x61, 0, 9},
 };
 
 int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
@@ -2087,11 +2500,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
        if (rt2x00_rf(rt2x00dev, RF2820) ||
-           rt2x00_rf(rt2x00dev, RF2720) ||
-           rt2x00_rf(rt2x00dev, RF3052)) {
+           rt2x00_rf(rt2x00dev, RF2720)) {
                spec->num_channels = 14;
                spec->channels = rf_vals;
-       } else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, 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;
@@ -2099,8 +2512,12 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                   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;
+               spec->num_channels = 14;
+               spec->channels = rf_vals_3x;
+       } else if (rt2x00_rf(rt2x00dev, RF3052)) {
+               spec->supported_bands |= SUPPORT_BAND_5GHZ;
+               spec->num_channels = ARRAY_SIZE(rf_vals_3x);
+               spec->channels = rf_vals_3x;
        }
 
        /*
@@ -2111,8 +2528,11 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        else
                spec->ht.ht_supported = false;
 
+       /*
+        * Don't set IEEE80211_HT_CAP_SUP_WIDTH_20_40 for now as it causes
+        * reception problems with HT40 capable 11n APs
+        */
        spec->ht.cap =
-           IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
            IEEE80211_HT_CAP_GRN_FLD |
            IEEE80211_HT_CAP_SGI_20 |
            IEEE80211_HT_CAP_SGI_40 |
index ebabeae62d1b9cabe6eae884cc1286e8697ed261..94de999e229032841ea9793b89e4ffd7f4810354 100644 (file)
@@ -111,6 +111,9 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 command, const u8 token,
                        const u8 arg0, const u8 arg1);
 
+void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
+void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
+
 extern const struct rt2x00debug rt2800_rt2x00debug;
 
 int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);
index 91cce2d0f6dbca20a6dc63fa96c9bf3015e1d771..b2f23272c3aae3efa74524f10b894bc88d521637 100644 (file)
@@ -60,6 +60,12 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
        unsigned int i;
        u32 reg;
 
+       /*
+        * SOC devices don't support MCU requests.
+        */
+       if (rt2x00_is_soc(rt2x00dev))
+               return;
+
        for (i = 0; i < 200; i++) {
                rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
 
@@ -341,19 +347,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
        struct queue_entry_priv_pci *entry_priv;
        u32 reg;
 
-       rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
-       rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
-       rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-
-       rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
-       rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
        /*
         * Initialize registers.
         */
@@ -620,63 +613,30 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
 /*
  * TX descriptor initialization
  */
+static int rt2800pci_write_tx_data(struct queue_entry* entry,
+                                  struct txentry_desc *txdesc)
+{
+       int ret;
+
+       ret = rt2x00pci_write_tx_data(entry, txdesc);
+       if (ret)
+               return ret;
+
+       rt2800_write_txwi(entry->skb, txdesc);
+
+       return 0;
+}
+
+
 static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct sk_buff *skb,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
-       __le32 *txwi = (__le32 *)(skb->data - rt2x00dev->ops->extra_tx_headroom);
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
-       /*
-        * Initialize TX Info descriptor
-        */
-       rt2x00_desc_read(txwi, 0, &word);
-       rt2x00_set_field32(&word, TXWI_W0_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
-       rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
-       rt2x00_set_field32(&word, TXWI_W0_TS,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_AMPDU,
-                          test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
-       rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
-       rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
-       rt2x00_set_field32(&word, TXWI_W0_BW,
-                          test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
-                          test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
-       rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
-       rt2x00_desc_write(txwi, 0, word);
-
-       rt2x00_desc_read(txwi, 1, &word);
-       rt2x00_set_field32(&word, TXWI_W1_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W1_NSEQ,
-                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
-       rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
-                          test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
-                          txdesc->key_idx : 0xff);
-       rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
-                          skb->len - txdesc->l2pad);
-       rt2x00_set_field32(&word, TXWI_W1_PACKETID,
-                          skbdesc->entry->queue->qid + 1);
-       rt2x00_desc_write(txwi, 1, word);
-
-       /*
-        * Always write 0 to IV/EIV fields, hardware will insert the IV
-        * from the IVEIV register when TXD_W3_WIV is set to 0.
-        * When TXD_W3_WIV is set to 1 it will use the IV data
-        * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
-        * crypto entry in the registers should be used to encrypt the frame.
-        */
-       _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
-       _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
-
        /*
         * The buffers pointed by SD_PTR0/SD_LEN0 and SD_PTR1/SD_LEN1
         * must contains a TXWI structure + 802.11 header + padding + 802.11
@@ -698,15 +658,14 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W1_BURST,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W1_SD_LEN0,
-                          rt2x00dev->ops->extra_tx_headroom);
+       rt2x00_set_field32(&word, TXD_W1_SD_LEN0, TXWI_DESC_SIZE);
        rt2x00_set_field32(&word, TXD_W1_LAST_SEC0, 0);
        rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0);
        rt2x00_desc_write(txd, 1, word);
 
        rt2x00_desc_read(txd, 2, &word);
        rt2x00_set_field32(&word, TXD_W2_SD_PTR1,
-                          skbdesc->skb_dma + rt2x00dev->ops->extra_tx_headroom);
+                          skbdesc->skb_dma + TXWI_DESC_SIZE);
        rt2x00_desc_write(txd, 2, word);
 
        rt2x00_desc_read(txd, 3, &word);
@@ -714,15 +673,21 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                           !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W3_QSEL, 2);
        rt2x00_desc_write(txd, 3, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
  * TX data initialization
  */
-static void rt2800pci_write_beacon(struct queue_entry *entry)
+static void rt2800pci_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        unsigned int beacon_base;
        u32 reg;
 
@@ -735,15 +700,25 @@ static void rt2800pci_write_beacon(struct queue_entry *entry)
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
        /*
-        * Write entire beacon with descriptor to register.
+        * Add the TXWI for the beacon to the skb.
+        */
+       rt2800_write_txwi(entry->skb, txdesc);
+       skb_push(entry->skb, TXWI_DESC_SIZE);
+
+       /*
+        * Write entire beacon with TXWI to register.
         */
        beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-       rt2800_register_multiwrite(rt2x00dev,
-                                     beacon_base,
-                                     skbdesc->desc, skbdesc->desc_len);
-       rt2800_register_multiwrite(rt2x00dev,
-                                     beacon_base + skbdesc->desc_len,
-                                     entry->skb->data, entry->skb->len);
+       rt2800_register_multiwrite(rt2x00dev, beacon_base,
+                                  entry->skb->data, entry->skb->len);
+
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
        /*
         * Clean up beacon skb.
@@ -757,18 +732,6 @@ static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 {
        struct data_queue *queue;
        unsigned int idx, qidx = 0;
-       u32 reg;
-
-       if (queue_idx == QID_BEACON) {
-               rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-               if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
-                       rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
-                       rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-                       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-               }
-               return;
-       }
 
        if (queue_idx > QID_HCCA && queue_idx != QID_MGMT)
                return;
@@ -811,34 +774,21 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct queue_entry_priv_pci *entry_priv = entry->priv_data;
        __le32 *rxd = entry_priv->desc;
-       __le32 *rxwi = (__le32 *)entry->skb->data;
-       u32 rxd3;
-       u32 rxwi0;
-       u32 rxwi1;
-       u32 rxwi2;
-       u32 rxwi3;
-
-       rt2x00_desc_read(rxd, 3, &rxd3);
-       rt2x00_desc_read(rxwi, 0, &rxwi0);
-       rt2x00_desc_read(rxwi, 1, &rxwi1);
-       rt2x00_desc_read(rxwi, 2, &rxwi2);
-       rt2x00_desc_read(rxwi, 3, &rxwi3);
-
-       if (rt2x00_get_field32(rxd3, RXD_W3_CRC_ERROR))
+       u32 word;
+
+       rt2x00_desc_read(rxd, 3, &word);
+
+       if (rt2x00_get_field32(word, RXD_W3_CRC_ERROR))
                rxdesc->flags |= RX_FLAG_FAILED_FCS_CRC;
 
-       if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
-               /*
-                * Unfortunately we don't know the cipher type used during
-                * decryption. This prevents us from correct providing
-                * correct statistics through debugfs.
-                */
-               rxdesc->cipher = rt2x00_get_field32(rxwi0, RXWI_W0_UDF);
-               rxdesc->cipher_status =
-                   rt2x00_get_field32(rxd3, RXD_W3_CIPHER_ERROR);
-       }
+       /*
+        * Unfortunately we don't know the cipher type used during
+        * decryption. This prevents us from correct providing
+        * correct statistics through debugfs.
+        */
+       rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W3_CIPHER_ERROR);
 
-       if (rt2x00_get_field32(rxd3, RXD_W3_DECRYPTED)) {
+       if (rt2x00_get_field32(word, RXD_W3_DECRYPTED)) {
                /*
                 * Hardware has stripped IV/EIV data from 802.11 frame during
                 * decryption. Unfortunately the descriptor doesn't contain
@@ -853,51 +803,22 @@ static void rt2800pci_fill_rxdone(struct queue_entry *entry,
                        rxdesc->flags |= RX_FLAG_MMIC_ERROR;
        }
 
-       if (rt2x00_get_field32(rxd3, RXD_W3_MY_BSS))
+       if (rt2x00_get_field32(word, RXD_W3_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-       if (rt2x00_get_field32(rxd3, RXD_W3_L2PAD))
+       if (rt2x00_get_field32(word, RXD_W3_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
 
-       if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
-               rxdesc->flags |= RX_FLAG_SHORT_GI;
-
-       if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
-               rxdesc->flags |= RX_FLAG_40MHZ;
-
        /*
-        * Detect RX rate, always use MCS as signal type.
+        * Process the RXWI structure that is at the start of the buffer.
         */
-       rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
-       rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
-       rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
-
-       /*
-        * Mask of 0x8 bit to remove the short preamble flag.
-        */
-       if (rxdesc->rate_mode == RATE_MODE_CCK)
-               rxdesc->signal &= ~0x8;
-
-       rxdesc->rssi =
-           (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
-            rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
-
-       rxdesc->noise =
-           (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
-            rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2;
-
-       rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
+       rt2800_process_rxwi(entry->skb, rxdesc);
 
        /*
         * Set RX IDX in register to inform hardware that we have handled
         * this entry and it is available for reuse again.
         */
        rt2800_register_write(rt2x00dev, RX_CRX_IDX, entry->entry_idx);
-
-       /*
-        * Remove TXWI descriptor from start of buffer.
-        */
-       skb_pull(entry->skb, RXWI_DESC_SIZE);
 }
 
 /*
@@ -907,14 +828,12 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
 {
        struct data_queue *queue;
        struct queue_entry *entry;
-       struct queue_entry *entry_done;
-       struct queue_entry_priv_pci *entry_priv;
+       __le32 *txwi;
        struct txdone_entry_desc txdesc;
        u32 word;
        u32 reg;
        u32 old_reg;
-       unsigned int type;
-       unsigned int index;
+       int wcid, ack, pid, tx_wcid, tx_ack, tx_pid;
        u16 mcs, real_mcs;
 
        /*
@@ -936,76 +855,89 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
                        break;
                old_reg = reg;
 
+               wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+               ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+               pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+
                /*
                 * Skip this entry when it contains an invalid
                 * queue identication number.
                 */
-               type = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE) - 1;
-               if (type >= QID_RX)
+               if (pid <= 0 || pid > QID_RX)
                        continue;
 
-               queue = rt2x00queue_get_queue(rt2x00dev, type);
+               queue = rt2x00queue_get_queue(rt2x00dev, pid - 1);
                if (unlikely(!queue))
                        continue;
 
                /*
-                * Skip this entry when it contains an invalid
-                * index number.
+                * Inside each queue, we process each entry in a chronological
+                * order. We first check that the queue is not empty.
                 */
-               index = rt2x00_get_field32(reg, TX_STA_FIFO_WCID) - 1;
-               if (unlikely(index >= queue->limit))
+               if (rt2x00queue_empty(queue))
                        continue;
+               entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
 
-               entry = &queue->entries[index];
-               entry_priv = entry->priv_data;
-               rt2x00_desc_read((__le32 *)entry->skb->data, 0, &word);
+               /* Check if we got a match by looking at WCID/ACK/PID
+                * fields */
+               txwi = (__le32 *)(entry->skb->data -
+                                 rt2x00dev->ops->extra_tx_headroom);
 
-               entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-               while (entry != entry_done) {
-                       /*
-                        * Catch up.
-                        * Just report any entries we missed as failed.
-                        */
-                       WARNING(rt2x00dev,
-                               "TX status report missed for entry %d\n",
-                               entry_done->entry_idx);
+               rt2x00_desc_read(txwi, 1, &word);
+               tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+               tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
+               tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
 
-                       txdesc.flags = 0;
-                       __set_bit(TXDONE_UNKNOWN, &txdesc.flags);
-                       txdesc.retry = 0;
-
-                       rt2x00lib_txdone(entry_done, &txdesc);
-                       entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-               }
+               if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid))
+                       WARNING(rt2x00dev, "invalid TX_STA_FIFO content\n");
 
                /*
                 * Obtain the status about this packet.
                 */
                txdesc.flags = 0;
-               if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS))
-                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
-               else
-                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
+               rt2x00_desc_read(txwi, 0, &word);
+               mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
+               real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
 
                /*
                 * Ralink has a retry mechanism using a global fallback
-                * table. We setup this fallback table to try immediate
-                * lower rate for all rates. In the TX_STA_FIFO,
-                * the MCS field contains the MCS used for the successfull
-                * transmission. If the first transmission succeed,
-                * we have mcs == tx_mcs. On the second transmission,
-                * we have mcs = tx_mcs - 1. So the number of
-                * retry is (tx_mcs - mcs).
+                * table. We setup this fallback table to try the immediate
+                * lower rate for all rates. In the TX_STA_FIFO, the MCS field
+                * always contains the MCS used for the last transmission, be
+                * it successful or not.
                 */
-               mcs = rt2x00_get_field32(word, TXWI_W0_MCS);
-               real_mcs = rt2x00_get_field32(reg, TX_STA_FIFO_MCS);
+               if (rt2x00_get_field32(reg, TX_STA_FIFO_TX_SUCCESS)) {
+                       /*
+                        * Transmission succeeded. The number of retries is
+                        * mcs - real_mcs
+                        */
+                       __set_bit(TXDONE_SUCCESS, &txdesc.flags);
+                       txdesc.retry = ((mcs > real_mcs) ? mcs - real_mcs : 0);
+               } else {
+                       /*
+                        * Transmission failed. The number of retries is
+                        * always 7 in this case (for a total number of 8
+                        * frames sent).
+                        */
+                       __set_bit(TXDONE_FAILURE, &txdesc.flags);
+                       txdesc.retry = 7;
+               }
+
                __set_bit(TXDONE_FALLBACK, &txdesc.flags);
-               txdesc.retry = mcs - min(mcs, real_mcs);
+
 
                rt2x00lib_txdone(entry, &txdesc);
        }
 }
 
+static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
+{
+       struct ieee80211_conf conf = { .flags = 0 };
+       struct rt2x00lib_conf libconf = { .conf = &conf };
+
+       rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
+}
+
 static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
 {
        struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -1030,6 +962,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
        if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TX_FIFO_STATUS))
                rt2800pci_txdone(rt2x00dev);
 
+       if (rt2x00_get_field32(reg, INT_SOURCE_CSR_AUTO_WAKEUP))
+               rt2800pci_wakeup(rt2x00dev);
+
        return IRQ_HANDLED;
 }
 
@@ -1128,7 +1063,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
        .reset_tuner            = rt2800_reset_tuner,
        .link_tuner             = rt2800_link_tuner,
        .write_tx_desc          = rt2800pci_write_tx_desc,
-       .write_tx_data          = rt2x00pci_write_tx_data,
+       .write_tx_data          = rt2800pci_write_tx_data,
        .write_beacon           = rt2800pci_write_beacon,
        .kick_tx_queue          = rt2800pci_kick_tx_queue,
        .kill_tx_queue          = rt2800pci_kill_tx_queue,
@@ -1184,6 +1119,7 @@ static const struct rt2x00_ops rt2800pci_ops = {
 /*
  * RT2800pci module information.
  */
+#ifdef CONFIG_RT2800PCI_PCI
 static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
@@ -1208,9 +1144,11 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
        { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
        { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
+       { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) },
 #endif
        { 0, }
 };
+#endif /* CONFIG_RT2800PCI_PCI */
 
 MODULE_AUTHOR(DRV_PROJECT);
 MODULE_VERSION(DRV_VERSION);
index d27d7d5d850cc6ea7c63b85f29da3c010c9d6c37..0f8b84b7224cace0167ebe5b0065da28af08986c 100644 (file)
@@ -400,60 +400,16 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                    struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txi = skbdesc->desc;
-       __le32 *txwi = &txi[TXINFO_DESC_SIZE / sizeof(__le32)];
+       __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
        u32 word;
 
        /*
-        * Initialize TX Info descriptor
+        * Initialize TXWI descriptor
         */
-       rt2x00_desc_read(txwi, 0, &word);
-       rt2x00_set_field32(&word, TXWI_W0_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MIMO_PS, 0);
-       rt2x00_set_field32(&word, TXWI_W0_CF_ACK, 0);
-       rt2x00_set_field32(&word, TXWI_W0_TS,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_AMPDU,
-                          test_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_MPDU_DENSITY, txdesc->mpdu_density);
-       rt2x00_set_field32(&word, TXWI_W0_TX_OP, txdesc->ifs);
-       rt2x00_set_field32(&word, TXWI_W0_MCS, txdesc->mcs);
-       rt2x00_set_field32(&word, TXWI_W0_BW,
-                          test_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_SHORT_GI,
-                          test_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W0_STBC, txdesc->stbc);
-       rt2x00_set_field32(&word, TXWI_W0_PHYMODE, txdesc->rate_mode);
-       rt2x00_desc_write(txwi, 0, word);
-
-       rt2x00_desc_read(txwi, 1, &word);
-       rt2x00_set_field32(&word, TXWI_W1_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W1_NSEQ,
-                          test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags));
-       rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->ba_size);
-       rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID,
-                          test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ?
-                          txdesc->key_idx : 0xff);
-       rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT,
-                          skb->len - txdesc->l2pad);
-       rt2x00_set_field32(&word, TXWI_W1_PACKETID,
-                          skbdesc->entry->queue->qid + 1);
-       rt2x00_desc_write(txwi, 1, word);
+       rt2800_write_txwi(skb, txdesc);
 
        /*
-        * Always write 0 to IV/EIV fields, hardware will insert the IV
-        * from the IVEIV register when TXINFO_W0_WIV is set to 0.
-        * When TXINFO_W0_WIV is set to 1 it will use the IV data
-        * from the descriptor. The TXWI_W1_WIRELESS_CLI_ID indicates which
-        * crypto entry in the registers should be used to encrypt the frame.
-        */
-       _rt2x00_desc_write(txwi, 2, 0 /* skbdesc->iv[0] */);
-       _rt2x00_desc_write(txwi, 3, 0 /* skbdesc->iv[1] */);
-
-       /*
-        * Initialize TX descriptor
+        * Initialize TXINFO descriptor
         */
        rt2x00_desc_read(txi, 0, &word);
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_PKT_LEN,
@@ -466,25 +422,24 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXINFO_W0_USB_DMA_TX_BURST,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_desc_write(txi, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txi;
+       skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
 }
 
 /*
  * TX data initialization
  */
-static void rt2800usb_write_beacon(struct queue_entry *entry)
+static void rt2800usb_write_beacon(struct queue_entry *entry,
+                                  struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        unsigned int beacon_base;
        u32 reg;
 
-       /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry->skb->data;
-
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
@@ -493,6 +448,12 @@ static void rt2800usb_write_beacon(struct queue_entry *entry)
        rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
        rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
 
+       /*
+        * Add the TXWI for the beacon to the skb.
+        */
+       rt2800_write_txwi(entry->skb, txdesc);
+       skb_push(entry->skb, TXWI_DESC_SIZE);
+
        /*
         * Write entire beacon with descriptor to register.
         */
@@ -502,6 +463,14 @@ static void rt2800usb_write_beacon(struct queue_entry *entry)
                                            entry->skb->data, entry->skb->len,
                                            REGISTER_TIMEOUT32(entry->skb->len));
 
+       /*
+        * Enable beaconing again.
+        */
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+       rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
        /*
         * Clean up the beacon skb.
         */
@@ -524,84 +493,53 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
-static void rt2800usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                   const enum data_queue_qid queue)
-{
-       u32 reg;
-
-       if (queue != QID_BEACON) {
-               rt2x00usb_kick_tx_queue(rt2x00dev, queue);
-               return;
-       }
-
-       rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
-       if (!rt2x00_get_field32(reg, BCN_TIME_CFG_BEACON_GEN)) {
-               rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
-               rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
-               rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
-               rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-       }
-}
-
 /*
  * RX control handlers
  */
 static void rt2800usb_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);
        __le32 *rxi = (__le32 *)entry->skb->data;
-       __le32 *rxwi;
        __le32 *rxd;
-       u32 rxi0;
-       u32 rxwi0;
-       u32 rxwi1;
-       u32 rxwi2;
-       u32 rxwi3;
-       u32 rxd0;
+       u32 word;
        int rx_pkt_len;
 
+       /*
+        * Copy descriptor to the skbdesc->desc buffer, making it safe from
+        * moving of frame data in rt2x00usb.
+        */
+       memcpy(skbdesc->desc, rxi, skbdesc->desc_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);
+       rt2x00_desc_read(rxi, 0, &word);
+       rx_pkt_len = rt2x00_get_field32(word, RXINFO_W0_USB_DMA_RX_PKT_LEN);
 
        /*
-        * FIXME : we need to check for rx_pkt_len validity
+        * Remove the RXINFO structure from the sbk.
         */
-       rxd = (__le32 *)(entry->skb->data + RXINFO_DESC_SIZE + rx_pkt_len);
+       skb_pull(entry->skb, RXINFO_DESC_SIZE);
 
        /*
-        * Copy descriptor to the skbdesc->desc buffer, making it safe from
-        * moving of frame data in rt2x00usb.
+        * FIXME: we need to check for rx_pkt_len validity
         */
-       memcpy(skbdesc->desc, rxi, skbdesc->desc_len);
+       rxd = (__le32 *)(entry->skb->data + rx_pkt_len);
 
        /*
         * It is now safe to read the descriptor on all architectures.
         */
-       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);
+       rt2x00_desc_read(rxd, 0, &word);
 
-       if (rt2x00_get_field32(rxd0, RXD_W0_CRC_ERROR))
+       if (rt2x00_get_field32(word, 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, RXD_W0_CIPHER_ERROR);
-       }
+       rxdesc->cipher_status = rt2x00_get_field32(word, RXD_W0_CIPHER_ERROR);
 
-       if (rt2x00_get_field32(rxd0, RXD_W0_DECRYPTED)) {
+       if (rt2x00_get_field32(word, RXD_W0_DECRYPTED)) {
                /*
                 * Hardware has stripped IV/EIV data from 802.11 frame during
                 * decryption. Unfortunately the descriptor doesn't contain
@@ -616,45 +554,21 @@ static void rt2800usb_fill_rxdone(struct queue_entry *entry,
                        rxdesc->flags |= RX_FLAG_MMIC_ERROR;
        }
 
-       if (rt2x00_get_field32(rxd0, RXD_W0_MY_BSS))
+       if (rt2x00_get_field32(word, RXD_W0_MY_BSS))
                rxdesc->dev_flags |= RXDONE_MY_BSS;
 
-       if (rt2x00_get_field32(rxd0, RXD_W0_L2PAD))
+       if (rt2x00_get_field32(word, RXD_W0_L2PAD))
                rxdesc->dev_flags |= RXDONE_L2PAD;
 
-       if (rt2x00_get_field32(rxwi1, RXWI_W1_SHORT_GI))
-               rxdesc->flags |= RX_FLAG_SHORT_GI;
-
-       if (rt2x00_get_field32(rxwi1, RXWI_W1_BW))
-               rxdesc->flags |= RX_FLAG_40MHZ;
-
        /*
-        * Detect RX rate, always use MCS as signal type.
+        * Remove RXD descriptor from end of buffer.
         */
-       rxdesc->dev_flags |= RXDONE_SIGNAL_MCS;
-       rxdesc->rate_mode = rt2x00_get_field32(rxwi1, RXWI_W1_PHYMODE);
-       rxdesc->signal = rt2x00_get_field32(rxwi1, RXWI_W1_MCS);
+       skb_trim(entry->skb, rx_pkt_len);
 
        /*
-        * Mask of 0x8 bit to remove the short preamble flag.
+        * Process the RXWI structure.
         */
-       if (rxdesc->rate_mode == RATE_MODE_CCK)
-               rxdesc->signal &= ~0x8;
-
-       rxdesc->rssi =
-           (rt2x00_get_field32(rxwi2, RXWI_W2_RSSI0) +
-            rt2x00_get_field32(rxwi2, RXWI_W2_RSSI1)) / 2;
-
-       rxdesc->noise =
-           (rt2x00_get_field32(rxwi3, RXWI_W3_SNR0) +
-            rt2x00_get_field32(rxwi3, RXWI_W3_SNR1)) / 2;
-
-       rxdesc->size = rt2x00_get_field32(rxwi0, RXWI_W0_MPDU_TOTAL_BYTE_COUNT);
-
-       /*
-        * Remove RXWI descriptor from start of buffer.
-        */
-       skb_pull(entry->skb, skbdesc->desc_len);
+       rt2800_process_rxwi(entry->skb, rxdesc);
 }
 
 /*
@@ -747,7 +661,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
        .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt2800usb_write_beacon,
        .get_tx_data_len        = rt2800usb_get_tx_data_len,
-       .kick_tx_queue          = rt2800usb_kick_tx_queue,
+       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
        .kill_tx_queue          = rt2x00usb_kill_tx_queue,
        .fill_rxdone            = rt2800usb_fill_rxdone,
        .config_shared_key      = rt2800_config_shared_key,
@@ -806,6 +720,10 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Allwin */
+       { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Amit */
        { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Askey */
@@ -841,13 +759,18 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* EnGenius */
-       { USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gigabyte */
        { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Hawking */
        { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Linksys */
        { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -876,6 +799,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -905,8 +830,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AirTies */
        { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Allwin */
+       { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* ASUS */
+       { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AzureWave */
        { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Conceptronic */
        { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Corega */
@@ -916,20 +850,46 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Draytek */
+       { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* EnGenius */
        { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gigabyte */
        { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* I-O DATA */
        { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Logitec */
+       { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* MSI */
        { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
+       /* Para */
+       { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Pegatron */
        { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -944,14 +904,22 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sitecom */
        { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
 #endif
 #ifdef CONFIG_RT2800USB_RT35XX
+       /* Allwin */
+       { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Askey */
        { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Cisco */
@@ -966,37 +934,27 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sitecom */
        { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
        /*
         * Unclear what kind of devices these are (they aren't supported by the
-        * vendor driver).
+        * vendor linux driver).
         */
-       /* Allwin */
-       { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Amigo */
        { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Askey */
-       { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* ASUS */
        { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* AzureWave */
        { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Belkin */
        { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Buffalo */
@@ -1015,24 +973,13 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* EnGenius */
-       { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gemtek */
        { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Gigabyte */
        { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Hawking */
-       { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* I-O DATA */
-       { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* LevelOne */
        { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
@@ -1042,43 +989,23 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Motorola */
        { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* MSI */
-       { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Ovislink */
+       { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Para */
-       { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Pegatron */
        { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Planex */
        { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Qcom */
        { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
-       /* Sitecom */
-       { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x004a), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x0df6, 0x004d), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* SMC */
        { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
-       { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
+       { USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) },
        /* Sweex */
        { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
        { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
index d1d8ae94b4d4757026f90867ca46cf1e3dbb37c8..2bca6a71a7f5e67911a37b9ac95fc37be8b45e18 100644 (file)
@@ -79,8 +79,6 @@
  */
 #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 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.
  */
index d9daa9c406fadf2d914dab71f89313ba5636e51a..6c1ff4c15c8430d4288b4bb0e687d812e912d1e5 100644 (file)
@@ -177,16 +177,15 @@ struct rt2x00_chip {
 #define RT2573         0x2573
 #define RT2860         0x2860  /* 2.4GHz PCI/CB */
 #define RT2870         0x2870
-#define RT2872         0x2872
-#define RT2880         0x2880  /* WSOC */
+#define RT2872         0x2872  /* WSOC */
 #define RT2883         0x2883  /* WSOC */
-#define RT2890         0x2890  /* 2.4GHz PCIe */
-#define RT3052         0x3052  /* WSOC */
 #define RT3070         0x3070
 #define RT3071         0x3071
 #define RT3090         0x3090  /* 2.4GHz PCIe */
 #define RT3390         0x3390
 #define RT3572         0x3572
+#define RT3593         0x3593  /* PCIe */
+#define RT3883         0x3883  /* WSOC */
 
        u16 rf;
        u16 rev;
@@ -550,8 +549,10 @@ struct rt2x00lib_ops {
        void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
                               struct sk_buff *skb,
                               struct txentry_desc *txdesc);
-       int (*write_tx_data) (struct queue_entry *entry);
-       void (*write_beacon) (struct queue_entry *entry);
+       int (*write_tx_data) (struct queue_entry *entry,
+                             struct txentry_desc *txdesc);
+       void (*write_beacon) (struct queue_entry *entry,
+                             struct txentry_desc *txdesc);
        int (*get_tx_data_len) (struct queue_entry *entry);
        void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
                               const enum data_queue_qid queue);
@@ -930,12 +931,12 @@ static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
             rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev);
 }
 
-static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
+static inline bool rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt)
 {
        return (rt2x00dev->chip.rt == rt);
 }
 
-static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
+static inline bool rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf)
 {
        return (rt2x00dev->chip.rf == rf);
 }
@@ -945,6 +946,24 @@ static inline u16 rt2x00_rev(struct rt2x00_dev *rt2x00dev)
        return rt2x00dev->chip.rev;
 }
 
+static inline bool rt2x00_rt_rev(struct rt2x00_dev *rt2x00dev,
+                                const u16 rt, const u16 rev)
+{
+       return (rt2x00_rt(rt2x00dev, rt) && rt2x00_rev(rt2x00dev) == rev);
+}
+
+static inline bool rt2x00_rt_rev_lt(struct rt2x00_dev *rt2x00dev,
+                                   const u16 rt, const u16 rev)
+{
+       return (rt2x00_rt(rt2x00dev, rt) && rt2x00_rev(rt2x00dev) < rev);
+}
+
+static inline bool rt2x00_rt_rev_gte(struct rt2x00_dev *rt2x00dev,
+                                    const u16 rt, const u16 rev)
+{
+       return (rt2x00_rt(rt2x00dev, rt) && rt2x00_rev(rt2x00dev) >= rev);
+}
+
 static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev,
                                        enum rt2x00_chip_intf intf)
 {
index d291c7862e10641d04d92fdadbca6e44cb133e76..583dacd8d2419dadc08af51dbaa8d7f9e30b7760 100644 (file)
@@ -128,6 +128,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
 
        /* Pull buffer to correct size */
        skb_pull(skb, txdesc->iv_len);
+       txdesc->length -= txdesc->iv_len;
 
        /* IV/EIV data has officially been stripped */
        skbdesc->flags |= SKBDESC_IV_STRIPPED;
index 9569fb4e5bc5625b5586b13294b6435fbb83e398..e9fe93fd804268a943368d65237c2657896bd25f 100644 (file)
@@ -156,10 +156,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
                            enum rt2x00_dump_type type, struct sk_buff *skb)
 {
        struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
-       struct skb_frame_desc *desc = get_skb_frame_desc(skb);
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
        struct sk_buff *skbcopy;
        struct rt2x00dump_hdr *dump_hdr;
        struct timeval timestamp;
+       u32 data_len;
 
        do_gettimeofday(&timestamp);
 
@@ -171,7 +172,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
                return;
        }
 
-       skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + skb->len,
+       data_len = skb->len;
+       if (skbdesc->flags & SKBDESC_DESC_IN_SKB)
+               data_len -= skbdesc->desc_len;
+
+       skbcopy = alloc_skb(sizeof(*dump_hdr) + skbdesc->desc_len + data_len,
                            GFP_ATOMIC);
        if (!skbcopy) {
                DEBUG(rt2x00dev, "Failed to copy skb for dump.\n");
@@ -181,18 +186,20 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
        dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr));
        dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION);
        dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr));
-       dump_hdr->desc_length = cpu_to_le32(desc->desc_len);
-       dump_hdr->data_length = cpu_to_le32(skb->len);
+       dump_hdr->desc_length = cpu_to_le32(skbdesc->desc_len);
+       dump_hdr->data_length = cpu_to_le32(data_len);
        dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt);
        dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf);
        dump_hdr->chip_rev = cpu_to_le16(rt2x00dev->chip.rev);
        dump_hdr->type = cpu_to_le16(type);
-       dump_hdr->queue_index = desc->entry->queue->qid;
-       dump_hdr->entry_index = desc->entry->entry_idx;
+       dump_hdr->queue_index = skbdesc->entry->queue->qid;
+       dump_hdr->entry_index = skbdesc->entry->entry_idx;
        dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec);
        dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec);
 
-       memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len);
+       if (!(skbdesc->flags & SKBDESC_DESC_IN_SKB))
+               memcpy(skb_put(skbcopy, skbdesc->desc_len), skbdesc->desc,
+                      skbdesc->desc_len);
        memcpy(skb_put(skbcopy, skb->len), skb->data, skb->len);
 
        skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy);
@@ -700,8 +707,6 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 exit:
        rt2x00debug_deregister(rt2x00dev);
        ERROR(rt2x00dev, "Failed to register debug handler.\n");
-
-       return;
 }
 
 void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
index eda73ba735a6e388ed8d9f68d22668af84ead912..3ae468c4d7604b3b8e82eac570445bdbf098ab7a 100644 (file)
@@ -435,7 +435,6 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
        rx_status->mactime = rxdesc.timestamp;
        rx_status->rate_idx = rate_idx;
        rx_status->signal = rxdesc.rssi;
-       rx_status->noise = rxdesc.noise;
        rx_status->flag = rxdesc.flags;
        rx_status->antenna = rt2x00dev->link.ant.active.rx;
 
index 727019a748e7507148b264b9495618070df41262..ed303b423e4180e095b68f0ab11459e675679098 100644 (file)
  *     the tx event which has either succeeded or failed. A frame
  *     with this type should also have been reported with as a
  *     %DUMP_FRAME_TX frame.
+ * @DUMP_FRAME_BEACON: This beacon frame is queued for transmission to the
+ *     hardware.
  */
 enum rt2x00_dump_type {
        DUMP_FRAME_RXDONE = 1,
        DUMP_FRAME_TX = 2,
        DUMP_FRAME_TXDONE = 3,
+       DUMP_FRAME_BEACON = 4,
 };
 
 /**
index 34beb00c4347a8d8f032ad6191762945331eefca..b818a43c4672733792295f2dec5163137e860ce4 100644 (file)
@@ -79,7 +79,7 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
                ERROR(rt2x00dev,
                      "Current firmware does not support detected chipset.\n");
                goto exit;
-       };
+       }
 
        rt2x00dev->fw = fw;
 
index 1056c92143a80dcc5a3e175efab36564d28517fa..5a407602ce3e2da54bae581765e89a7842fe8935 100644 (file)
@@ -35,6 +35,7 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
 {
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
        struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
 
        if (tx_info->control.sta)
                txdesc->mpdu_density =
@@ -66,4 +67,20 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
                __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
        if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
                __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
+
+       /*
+        * Determine IFS values
+        * - Use TXOP_BACKOFF for management frames
+        * - Use TXOP_SIFS for fragment bursts
+        * - Use TXOP_HTTXOP for everything else
+        *
+        * Note: rt2800 devices won't use CTS protection (if used)
+        * for frames not transmitted with TXOP_HTTXOP
+        */
+       if (ieee80211_is_mgmt(hdr->frame_control))
+               txdesc->txop = TXOP_BACKOFF;
+       else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
+               txdesc->txop = TXOP_SIFS;
+       else
+               txdesc->txop = TXOP_HTTXOP;
 }
index cf3f1c0c43822fe70d0390bfd4ff060c306c07c3..a016f7ccde29a1c347e72a3c82750fff0c700390 100644 (file)
@@ -63,11 +63,10 @@ EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
 /*
  * TX data handlers.
  */
-int rt2x00pci_write_tx_data(struct queue_entry *entry)
+int rt2x00pci_write_tx_data(struct queue_entry *entry,
+                           struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct queue_entry_priv_pci *entry_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc;
 
        /*
         * This should not happen, we already checked the entry
@@ -82,13 +81,6 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry)
                return -EINVAL;
        }
 
-       /*
-        * Fill in skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       skbdesc->desc = entry_priv->desc;
-       skbdesc->desc_len = entry->queue->desc_size;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
index 8149ff68410a5f3a7bed11c6bf72e7b201bfed48..51bcef3839ce3ae52fe00974de87d0978f43ef4f 100644 (file)
@@ -92,7 +92,8 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
  * This function will initialize the DMA and skb descriptor
  * to prepare the entry for the actual TX operation.
  */
-int rt2x00pci_write_tx_data(struct queue_entry *entry);
+int rt2x00pci_write_tx_data(struct queue_entry *entry,
+                           struct txentry_desc *txdesc);
 
 /**
  * struct queue_entry_priv_pci: Per entry PCI specific information
index a0bd36fc4d2e928227478f7b7f266978ccb4813b..20dbdd6fb9047e63ed98a64d084072f1642084e8 100644 (file)
@@ -334,12 +334,10 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
        txdesc->aifs = entry->queue->aifs;
 
        /*
-        * Header and alignment information.
+        * Header and frame information.
         */
+       txdesc->length = entry->skb->len;
        txdesc->header_length = ieee80211_get_hdrlen_from_skb(entry->skb);
-       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.
@@ -423,6 +421,7 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
 {
        struct data_queue *queue = entry->queue;
        struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
+       enum rt2x00_dump_type dump_type;
 
        rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
 
@@ -430,21 +429,26 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
         * All processing on the frame has been completed, this means
         * it is now ready to be dumped to userspace through debugfs.
         */
-       rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
+       dump_type = (txdesc->queue == QID_BEACON) ?
+                                       DUMP_FRAME_BEACON : DUMP_FRAME_TX;
+       rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
+}
+
+static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
+                                     struct txentry_desc *txdesc)
+{
+       struct data_queue *queue = entry->queue;
+       struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
 
        /*
         * Check if we need to kick the queue, there are however a few rules
-        *      1) Don't kick beacon queue
-        *      2) Don't kick unless this is the last in frame in a burst.
+        *      1) Don't kick unless this is the last in frame in a burst.
         *         When the burst flag is set, this frame is always followed
         *         by another frame which in some way are related to eachother.
         *         This is true for fragments, RTS or CTS-to-self frames.
-        *      3) Rule 2 can be broken when the available entries
+        *      2) Rule 1 can be broken when the available entries
         *         in the queue are less then a certain threshold.
         */
-       if (entry->queue->qid == QID_BEACON)
-               return;
-
        if (rt2x00queue_threshold(queue) ||
            !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
                rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, queue->qid);
@@ -526,7 +530,8 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
         * call failed. Since we always return NETDEV_TX_OK to mac80211,
         * this frame will simply be dropped.
         */
-       if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) {
+       if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry,
+                                                              &txdesc))) {
                clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
                entry->skb = NULL;
                return -EIO;
@@ -539,6 +544,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
 
        rt2x00queue_index_inc(queue, Q_INDEX);
        rt2x00queue_write_tx_descriptor(entry, &txdesc);
+       rt2x00queue_kick_tx_queue(entry, &txdesc);
 
        return 0;
 }
@@ -550,7 +556,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        struct rt2x00_intf *intf = vif_to_intf(vif);
        struct skb_frame_desc *skbdesc;
        struct txentry_desc txdesc;
-       __le32 desc[16];
 
        if (unlikely(!intf->beacon))
                return -ENOBUFS;
@@ -582,20 +587,11 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
         */
        rt2x00queue_create_tx_descriptor(intf->beacon, &txdesc);
 
-       /*
-        * For the descriptor we use a local array from where the
-        * driver can move it to the correct location required for
-        * the hardware.
-        */
-       memset(desc, 0, sizeof(desc));
-
        /*
         * Fill in skb descriptor
         */
        skbdesc = get_skb_frame_desc(intf->beacon->skb);
        memset(skbdesc, 0, sizeof(*skbdesc));
-       skbdesc->desc = desc;
-       skbdesc->desc_len = intf->beacon->queue->desc_size;
        skbdesc->entry = intf->beacon;
 
        /*
@@ -604,12 +600,9 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
        rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
 
        /*
-        * Send beacon to hardware.
-        * Also enable beacon generation, which might have been disabled
-        * by the driver during the config_beacon() callback function.
+        * Send beacon to hardware and enable beacon genaration..
         */
-       rt2x00dev->ops->lib->write_beacon(intf->beacon);
-       rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, QID_BEACON);
+       rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
 
        mutex_unlock(&intf->beacon_skb_mutex);
 
index c1e482bb37b36f18544d27eeaef8e41b6e1852be..f79170849addf1737318da037e7c84d9a5a557cd 100644 (file)
@@ -94,12 +94,15 @@ enum data_queue_qid {
  *     mac80211 but was stripped for processing by the driver.
  * @SKBDESC_NOT_MAC80211: Frame didn't originate from mac80211,
  *     don't try to pass it back.
+ * @SKBDESC_DESC_IN_SKB: The descriptor is at the start of the
+ *     skb, instead of in the desc field.
  */
 enum skb_frame_desc_flags {
        SKBDESC_DMA_MAPPED_RX = 1 << 0,
        SKBDESC_DMA_MAPPED_TX = 1 << 1,
        SKBDESC_IV_STRIPPED = 1 << 2,
        SKBDESC_NOT_MAC80211 = 1 << 3,
+       SKBDESC_DESC_IN_SKB = 1 << 4,
 };
 
 /**
@@ -183,7 +186,6 @@ enum rxdone_entry_desc_flags {
  * @timestamp: RX Timestamp
  * @signal: Signal of the received frame.
  * @rssi: RSSI of the received frame.
- * @noise: Measured noise during frame reception.
  * @size: Data size of the received frame.
  * @flags: MAC80211 receive flags (See &enum mac80211_rx_flags).
  * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags).
@@ -197,7 +199,6 @@ struct rxdone_entry_desc {
        u64 timestamp;
        int signal;
        int rssi;
-       int noise;
        int size;
        int flags;
        int dev_flags;
@@ -287,8 +288,8 @@ enum txentry_desc_flags {
  *
  * @flags: Descriptor flags (See &enum queue_entry_flags).
  * @queue: Queue identification (See &enum data_queue_qid).
+ * @length: Length of the entire frame.
  * @header_length: Length of 802.11 header.
- * @l2pad: Amount of padding to align 802.11 payload to 4-byte boundrary.
  * @length_high: PLCP length high word.
  * @length_low: PLCP length low word.
  * @signal: PLCP signal.
@@ -301,6 +302,7 @@ enum txentry_desc_flags {
  * @retry_limit: Max number of retries.
  * @aifs: AIFS value.
  * @ifs: IFS value.
+ * @txop: IFS value for 11n capable chips.
  * @cw_min: cwmin value.
  * @cw_max: cwmax value.
  * @cipher: Cipher type used for encryption.
@@ -313,8 +315,8 @@ struct txentry_desc {
 
        enum data_queue_qid queue;
 
+       u16 length;
        u16 header_length;
-       u16 l2pad;
 
        u16 length_high;
        u16 length_low;
@@ -330,6 +332,7 @@ struct txentry_desc {
        short retry_limit;
        short aifs;
        short ifs;
+       short txop;
        short cw_min;
        short cw_max;
 
index 603bfc0adaa3484012e8b0c1b63ad1840ee8d1b6..b9fe94873ee00ddee8389b9bbdb041104e43686b 100644 (file)
@@ -100,6 +100,16 @@ enum ifs {
        IFS_NONE = 3,
 };
 
+/*
+ * IFS backoff values for HT devices
+ */
+enum txop {
+       TXOP_HTTXOP = 0,
+       TXOP_PIFS = 1,
+       TXOP_SIFS = 2,
+       TXOP_BACKOFF = 3,
+};
+
 /*
  * Cipher types for hardware encryption
  */
index f9a7f8b1741134e57e840ea01baa0bb4ace149b8..bd1546ba7ad27206c1d17f00e012c2ca942c17cf 100644 (file)
@@ -216,12 +216,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
        rt2x00lib_txdone(entry, &txdesc);
 }
 
-int rt2x00usb_write_tx_data(struct queue_entry *entry)
+int rt2x00usb_write_tx_data(struct queue_entry *entry,
+                           struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
        struct queue_entry_priv_usb *entry_priv = entry->priv_data;
-       struct skb_frame_desc *skbdesc;
        u32 length;
 
        /*
@@ -230,13 +230,6 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry)
        skb_push(entry->skb, entry->queue->desc_size);
        memset(entry->skb->data, 0, entry->queue->desc_size);
 
-       /*
-        * Fill in skb descriptor
-        */
-       skbdesc = get_skb_frame_desc(entry->skb);
-       skbdesc->desc = entry->skb->data;
-       skbdesc->desc_len = entry->queue->desc_size;
-
        /*
         * USB devices cannot blindly pass the skb->len as the
         * length of the data to usb_fill_bulk_urb. Pass the skb
index 3da6841b5d4251be61d30bf058c625fc2ede0715..621d0f8292514cf93079dbb6a553d9524bbc8d76 100644 (file)
@@ -376,7 +376,8 @@ void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
  * This function will initialize the URB and skb descriptor
  * to prepare the entry for the actual TX operation.
  */
-int rt2x00usb_write_tx_data(struct queue_entry *entry);
+int rt2x00usb_write_tx_data(struct queue_entry *entry,
+                           struct txentry_desc *txdesc);
 
 /**
  * struct queue_entry_priv_usb: Per entry USB specific information
index 432e75f960b72d409cb3f925fb3249312eff6071..2e3076f67535502b93bfbf7cde4b4cc2267521c0 100644 (file)
@@ -1764,7 +1764,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       struct queue_entry_priv_pci *entry_priv = skbdesc->entry->priv_data;
+       __le32 *txd = entry_priv->desc;
        u32 word;
 
        /*
@@ -1802,17 +1803,23 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       rt2x00_desc_read(txd, 6, &word);
-       rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
-                          skbdesc->skb_dma);
-       rt2x00_desc_write(txd, 6, word);
+       if (txdesc->queue != QID_BEACON) {
+               rt2x00_desc_read(txd, 6, &word);
+               rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+                                  skbdesc->skb_dma);
+               rt2x00_desc_write(txd, 6, word);
 
-       if (skbdesc->desc_len > TXINFO_SIZE) {
                rt2x00_desc_read(txd, 11, &word);
-               rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skb->len);
+               rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0,
+                                  txdesc->length);
                rt2x00_desc_write(txd, 11, word);
        }
 
+       /*
+        * Writing TXD word 0 must the last to prevent a race condition with
+        * the device, whereby the device may take hold of the TXD before we
+        * finished updating it.
+        */
        rt2x00_desc_read(txd, 0, &word);
        rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
        rt2x00_set_field32(&word, TXD_W0_VALID, 1);
@@ -1832,20 +1839,28 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
                           test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
        rt2x00_set_field32(&word, TXD_W0_BURST,
                           test_bit(ENTRY_TXD_BURST, &txdesc->flags));
        rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
        rt2x00_desc_write(txd, 0, word);
+
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len =
+               (txdesc->queue == QID_BEACON) ?  TXINFO_SIZE : TXD_DESC_SIZE;
 }
 
 /*
  * TX data initialization
  */
-static void rt61pci_write_beacon(struct queue_entry *entry)
+static void rt61pci_write_beacon(struct queue_entry *entry,
+                                struct txentry_desc *txdesc)
 {
        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;
        unsigned int beacon_base;
        u32 reg;
 
@@ -1861,13 +1876,24 @@ static void rt61pci_write_beacon(struct queue_entry *entry)
         * Write entire beacon with descriptor to register.
         */
        beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
-       rt2x00pci_register_multiwrite(rt2x00dev,
-                                     beacon_base,
-                                     skbdesc->desc, skbdesc->desc_len);
-       rt2x00pci_register_multiwrite(rt2x00dev,
-                                     beacon_base + skbdesc->desc_len,
+       rt2x00pci_register_multiwrite(rt2x00dev, beacon_base,
+                                     entry_priv->desc, TXINFO_SIZE);
+       rt2x00pci_register_multiwrite(rt2x00dev, beacon_base + TXINFO_SIZE,
                                      entry->skb->data, entry->skb->len);
 
+       /*
+        * Enable beaconing again.
+        *
+        * For Wi-Fi faily generated beacons between participating
+        * stations. Set TBTT phase adaptive adjustment step to 8us.
+        */
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+       rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+       rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+
        /*
         * Clean up beacon skb.
         */
@@ -1880,23 +1906,6 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (queue == QID_BEACON) {
-               /*
-                * For Wi-Fi faily generated beacons between participating
-                * stations. Set TBTT phase adaptive adjustment step to 8us.
-                */
-               rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
-
-               rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
-               if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
-                       rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-                       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-                       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-                       rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
-               }
-               return;
-       }
-
        rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
        rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, (queue == QID_AC_BE));
        rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, (queue == QID_AC_BK));
@@ -1968,12 +1977,8 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry,
        if (rt2x00_get_field32(word0, 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(word0, RXD_W0_CIPHER_ALG);
-               rxdesc->cipher_status =
-                   rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
-       }
+       rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+       rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
 
        if (rxdesc->cipher != CIPHER_NONE) {
                _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]);
@@ -2118,6 +2123,14 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
        }
 }
 
+static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
+{
+       struct ieee80211_conf conf = { .flags = 0 };
+       struct rt2x00lib_conf libconf = { .conf = &conf };
+
+       rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
+}
+
 static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
 {
        struct rt2x00_dev *rt2x00dev = dev_instance;
@@ -2165,6 +2178,12 @@ static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
                rt2x00pci_register_write(rt2x00dev,
                                         M2H_CMD_DONE_CSR, 0xffffffff);
 
+       /*
+        * 4 - MCU Autowakeup interrupt.
+        */
+       if (rt2x00_get_field32(reg_mcu, MCU_INT_SOURCE_CSR_TWAKEUP))
+               rt61pci_wakeup(rt2x00dev);
+
        return IRQ_HANDLED;
 }
 
index bb58d797fb72910afdd0598450d3323732bcd8ce..e35bd19c3c5aeb09ffec25549bf4ef0d07064385 100644 (file)
@@ -861,15 +861,15 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
                rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
                                            USB_MODE_SLEEP, REGISTER_TIMEOUT);
        } else {
-               rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
-                                           USB_MODE_WAKEUP, REGISTER_TIMEOUT);
-
                rt2x00usb_register_read(rt2x00dev, MAC_CSR11, &reg);
                rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN, 0);
                rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP, 0);
                rt2x00_set_field32(&reg, MAC_CSR11_AUTOWAKE, 0);
                rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 0);
                rt2x00usb_register_write(rt2x00dev, MAC_CSR11, reg);
+
+               rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
+                                           USB_MODE_WAKEUP, REGISTER_TIMEOUT);
        }
 }
 
@@ -1441,12 +1441,38 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
                                  struct txentry_desc *txdesc)
 {
        struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
-       __le32 *txd = skbdesc->desc;
+       __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
        u32 word;
 
        /*
         * Start writing the descriptor words.
         */
+       rt2x00_desc_read(txd, 0, &word);
+       rt2x00_set_field32(&word, TXD_W0_BURST,
+                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_ACK,
+                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_OFDM,
+                          (txdesc->rate_mode == RATE_MODE_OFDM));
+       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
+       rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
+                          test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
+                          test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
+       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, txdesc->length);
+       rt2x00_set_field32(&word, TXD_W0_BURST2,
+                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
+       rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
+       rt2x00_desc_write(txd, 0, word);
+
        rt2x00_desc_read(txd, 1, &word);
        rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->queue);
        rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs);
@@ -1475,50 +1501,23 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
        rt2x00_desc_write(txd, 5, word);
 
-       rt2x00_desc_read(txd, 0, &word);
-       rt2x00_set_field32(&word, TXD_W0_BURST,
-                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_VALID, 1);
-       rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
-                          test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_ACK,
-                          test_bit(ENTRY_TXD_ACK, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
-                          test_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_OFDM,
-                          (txdesc->rate_mode == RATE_MODE_OFDM));
-       rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
-       rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
-                          test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_TKIP_MIC,
-                          test_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_KEY_TABLE,
-                          test_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_KEY_INDEX, txdesc->key_idx);
-       rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
-       rt2x00_set_field32(&word, TXD_W0_BURST2,
-                          test_bit(ENTRY_TXD_BURST, &txdesc->flags));
-       rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, txdesc->cipher);
-       rt2x00_desc_write(txd, 0, word);
+       /*
+        * Register descriptor details in skb frame descriptor.
+        */
+       skbdesc->desc = txd;
+       skbdesc->desc_len = TXD_DESC_SIZE;
 }
 
 /*
  * TX data initialization
  */
-static void rt73usb_write_beacon(struct queue_entry *entry)
+static void rt73usb_write_beacon(struct queue_entry *entry,
+                                struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
-       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        unsigned int beacon_base;
        u32 reg;
 
-       /*
-        * Add the descriptor in front of the skb.
-        */
-       skb_push(entry->skb, entry->queue->desc_size);
-       memcpy(entry->skb->data, skbdesc->desc, skbdesc->desc_len);
-       skbdesc->desc = entry->skb->data;
-
        /*
         * Disable beaconing while we are reloading the beacon data,
         * otherwise we might be sending out invalid data.
@@ -1527,6 +1526,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
        rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
        rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
 
+       /*
+        * Take the descriptor in front of the skb into account.
+        */
+       skb_push(entry->skb, TXD_DESC_SIZE);
+
        /*
         * Write entire beacon with descriptor to register.
         */
@@ -1536,6 +1540,19 @@ static void rt73usb_write_beacon(struct queue_entry *entry)
                                            entry->skb->data, entry->skb->len,
                                            REGISTER_TIMEOUT32(entry->skb->len));
 
+       /*
+        * Enable beaconing again.
+        *
+        * For Wi-Fi faily generated beacons between participating stations.
+        * Set TBTT phase adaptive adjustment step to 8us (default 16us)
+        */
+       rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+       rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+       rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+       rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+
        /*
         * Clean up the beacon skb.
         */
@@ -1557,31 +1574,6 @@ static int rt73usb_get_tx_data_len(struct queue_entry *entry)
        return length;
 }
 
-static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-                                 const enum data_queue_qid queue)
-{
-       u32 reg;
-
-       if (queue != QID_BEACON) {
-               rt2x00usb_kick_tx_queue(rt2x00dev, queue);
-               return;
-       }
-
-       /*
-        * For Wi-Fi faily generated beacons between participating stations.
-        * Set TBTT phase adaptive adjustment step to 8us (default 16us)
-        */
-       rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
-
-       rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
-       if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
-               rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
-               rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
-               rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
-               rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
-       }
-}
-
 /*
  * RX control handlers
  */
@@ -1645,12 +1637,8 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry,
        if (rt2x00_get_field32(word0, 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(word0, RXD_W0_CIPHER_ALG);
-               rxdesc->cipher_status =
-                   rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
-       }
+       rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER_ALG);
+       rxdesc->cipher_status = rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR);
 
        if (rxdesc->cipher != CIPHER_NONE) {
                _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]);
@@ -2266,7 +2254,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
        .write_tx_data          = rt2x00usb_write_tx_data,
        .write_beacon           = rt73usb_write_beacon,
        .get_tx_data_len        = rt73usb_get_tx_data_len,
-       .kick_tx_queue          = rt73usb_kick_tx_queue,
+       .kick_tx_queue          = rt2x00usb_kick_tx_queue,
        .kill_tx_queue          = rt2x00usb_kill_tx_queue,
        .fill_rxdone            = rt73usb_fill_rxdone,
        .config_shared_key      = rt73usb_config_shared_key,
diff --git a/drivers/net/wireless/rtl818x/Kconfig b/drivers/net/wireless/rtl818x/Kconfig
new file mode 100644 (file)
index 0000000..17d80fe
--- /dev/null
@@ -0,0 +1,88 @@
+#
+# RTL818X Wireless LAN device configuration
+#
+config RTL8180
+       tristate "Realtek 8180/8185 PCI support"
+       depends on MAC80211 && PCI && EXPERIMENTAL
+       select EEPROM_93CX6
+       ---help---
+         This is a driver for RTL8180 and RTL8185 based cards.
+         These are PCI based chips found in cards such as:
+
+         (RTL8185 802.11g)
+         A-Link WL54PC
+
+         (RTL8180 802.11b)
+         Belkin F5D6020 v3
+         Belkin F5D6020 v3
+         Dlink DWL-610
+         Dlink DWL-510
+         Netgear MA521
+         Level-One WPC-0101
+         Acer Aspire 1357 LMi
+         VCTnet PC-11B1
+         Ovislink AirLive WL-1120PCM
+         Mentor WL-PCI
+         Linksys WPC11 v4
+         TrendNET TEW-288PI
+         D-Link DWL-520 Rev D
+         Repotec RP-WP7126
+         TP-Link TL-WN250/251
+         Zonet ZEW1000
+         Longshine LCS-8031-R
+         HomeLine HLW-PCC200
+         GigaFast WF721-AEX
+         Planet WL-3553
+         Encore ENLWI-PCI1-NT
+         TrendNET TEW-266PC
+         Gigabyte GN-WLMR101
+         Siemens-fujitsu Amilo D1840W
+         Edimax EW-7126
+         PheeNet WL-11PCIR
+         Tonze PC-2100T
+         Planet WL-8303
+         Dlink DWL-650 v M1
+         Edimax EW-7106
+         Q-Tec 770WC
+         Topcom Skyr@cer 4011b
+         Roper FreeLan 802.11b (edition 2004)
+         Wistron Neweb Corp CB-200B
+         Pentagram HorNET
+         QTec 775WC
+         TwinMOS Booming B Series
+         Micronet SP906BB
+         Sweex LC700010
+         Surecom EP-9428
+         Safecom SWLCR-1100
+
+         Thanks to Realtek for their support!
+
+config RTL8187
+       tristate "Realtek 8187 and 8187B USB support"
+       depends on MAC80211 && USB
+       select EEPROM_93CX6
+       ---help---
+         This is a driver for RTL8187 and RTL8187B based cards.
+         These are USB based chips found in devices such as:
+
+         Netgear WG111v2
+         Level 1 WNC-0301USB
+         Micronet SP907GK V5
+         Encore ENUWI-G2
+         Trendnet TEW-424UB
+         ASUS P5B Deluxe/P5K Premium motherboards
+         Toshiba Satellite Pro series of laptops
+         Asus Wireless Link
+         Linksys WUSB54GC-EU v2
+           (v1 = rt73usb; v3 is rt2070-based,
+            use staging/rt3070 or try rt2800usb)
+
+         Thanks to Realtek for their support!
+
+# If possible, automatically enable LEDs for RTL8187.
+
+config RTL8187_LEDS
+       bool
+       depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187)
+       default y
+
index de3844fe06d84bfecde1cbb2d4db3e8c7b5dca94..4baf0cf0826fef967a131807eacbd83446b57689 100644 (file)
@@ -55,6 +55,14 @@ struct rtl8180_tx_ring {
        struct sk_buff_head queue;
 };
 
+struct rtl8180_vif {
+       struct ieee80211_hw *dev;
+
+       /* beaconing */
+       struct delayed_work beacon_work;
+       bool enable_beacon;
+};
+
 struct rtl8180_priv {
        /* common between rtl818x drivers */
        struct rtl818x_csr __iomem *map;
@@ -78,6 +86,9 @@ struct rtl8180_priv {
        u32 anaparam;
        u16 rfparam;
        u8 csthreshold;
+
+       /* sequence # */
+       u16 seqno;
 };
 
 void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
index 2131a442831aa678746bf359d03e46a1745c9f06..515817de29058483c25d00d7537de67fd9b8776a 100644 (file)
@@ -188,6 +188,7 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio)
                        info->flags |= IEEE80211_TX_STAT_ACK;
 
                info->status.rates[0].count = (flags & 0xFF) + 1;
+               info->status.rates[1].idx = -1;
 
                ieee80211_tx_status_irqsafe(dev, skb);
                if (ring->entries - skb_queue_len(&ring->queue) == 2)
@@ -233,6 +234,7 @@ static irqreturn_t rtl8180_interrupt(int irq, void *dev_id)
 static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct rtl8180_priv *priv = dev->priv;
        struct rtl8180_tx_ring *ring;
        struct rtl8180_tx_desc *entry;
@@ -284,6 +286,14 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        }
 
        spin_lock_irqsave(&priv->lock, flags);
+
+       if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+                       priv->seqno += 0x10;
+               hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(priv->seqno);
+       }
+
        idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
        entry = &ring->desc[idx];
 
@@ -297,7 +307,8 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
        entry->flags = cpu_to_le32(tx_flags);
        __skb_queue_tail(&ring->queue, skb);
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
-               ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
+               ieee80211_stop_queue(dev, prio);
+
        spin_unlock_irqrestore(&priv->lock, flags);
 
        rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4)));
@@ -652,10 +663,59 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
                rtl8180_free_tx_ring(dev, i);
 }
 
+static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+{
+       struct rtl8180_priv *priv = dev->priv;
+
+       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
+              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
+}
+
+void rtl8180_beacon_work(struct work_struct *work)
+{
+       struct rtl8180_vif *vif_priv =
+               container_of(work, struct rtl8180_vif, beacon_work.work);
+       struct ieee80211_vif *vif =
+               container_of((void *)vif_priv, struct ieee80211_vif, drv_priv);
+       struct ieee80211_hw *dev = vif_priv->dev;
+       struct ieee80211_mgmt *mgmt;
+       struct sk_buff *skb;
+       int err = 0;
+
+       /* don't overflow the tx ring */
+       if (ieee80211_queue_stopped(dev, 0))
+               goto resched;
+
+       /* grab a fresh beacon */
+       skb = ieee80211_beacon_get(dev, vif);
+
+       /*
+        * update beacon timestamp w/ TSF value
+        * TODO: make hardware update beacon timestamp
+        */
+       mgmt = (struct ieee80211_mgmt *)skb->data;
+       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));
+
+       /* TODO: use actual beacon queue */
+       skb_set_queue_mapping(skb, 0);
+
+       err = rtl8180_tx(dev, skb);
+       WARN_ON(err);
+
+resched:
+       /*
+        * schedule next beacon
+        * TODO: use hardware support for beacon timing
+        */
+       schedule_delayed_work(&vif_priv->beacon_work,
+                       usecs_to_jiffies(1024 * vif->bss_conf.beacon_int));
+}
+
 static int rtl8180_add_interface(struct ieee80211_hw *dev,
                                 struct ieee80211_vif *vif)
 {
        struct rtl8180_priv *priv = dev->priv;
+       struct rtl8180_vif *vif_priv;
 
        /*
         * We only support one active interface at a time.
@@ -665,6 +725,7 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,
 
        switch (vif->type) {
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
                break;
        default:
                return -EOPNOTSUPP;
@@ -672,6 +733,12 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,
 
        priv->vif = vif;
 
+       /* Initialize driver private area */
+       vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
+       vif_priv->dev = dev;
+       INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8180_beacon_work);
+       vif_priv->enable_beacon = false;
+
        rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
        rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
                          le32_to_cpu(*(__le32 *)vif->addr));
@@ -705,8 +772,11 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
                                     u32 changed)
 {
        struct rtl8180_priv *priv = dev->priv;
+       struct rtl8180_vif *vif_priv;
        int i;
 
+       vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
+
        if (changed & BSS_CHANGED_BSSID) {
                for (i = 0; i < ETH_ALEN; i++)
                        rtl818x_iowrite8(priv, &priv->map->BSSID[i],
@@ -721,13 +791,22 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
        }
 
        if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
-               priv->rf->conf_erp(dev, info);
+               priv->rf->conf_erp(dev, info);
+
+       if (changed & BSS_CHANGED_BEACON_ENABLED)
+               vif_priv->enable_beacon = info->enable_beacon;
+
+       if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) {
+               cancel_delayed_work_sync(&vif_priv->beacon_work);
+               if (vif_priv->enable_beacon)
+                       schedule_work(&vif_priv->beacon_work.work);
+       }
 }
 
-static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
-                                    struct dev_addr_list *mc_list)
+static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev,
+                                    struct netdev_hw_addr_list *mc_list)
 {
-       return mc_count;
+       return netdev_hw_addr_list_count(mc_list);
 }
 
 static void rtl8180_configure_filter(struct ieee80211_hw *dev,
@@ -762,14 +841,6 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
        rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
 }
 
-static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
-{
-       struct rtl8180_priv *priv = dev->priv;
-
-       return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
-              (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
-}
-
 static const struct ieee80211_ops rtl8180_ops = {
        .tx                     = rtl8180_tx,
        .start                  = rtl8180_start,
@@ -827,6 +898,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        const char *chip_name, *rf_name = NULL;
        u32 reg;
        u16 eeprom_val;
+       u8 mac_addr[ETH_ALEN];
 
        err = pci_enable_device(pdev);
        if (err) {
@@ -855,8 +927,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
                goto err_free_reg;
        }
 
-       if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) ||
-           (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) {
+       if ((err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) ||
+           (err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))) {
                printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n",
                       pci_name(pdev));
                goto err_free_reg;
@@ -905,7 +977,9 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                     IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_SIGNAL_UNSPEC;
-       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       dev->vif_data_size = sizeof(struct rtl8180_vif);
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                       BIT(NL80211_IFTYPE_ADHOC);
        dev->queues = 1;
        dev->max_signal = 65;
 
@@ -987,12 +1061,13 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
                eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam);
        }
 
-       eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3);
-       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+       eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)mac_addr, 3);
+       if (!is_valid_ether_addr(mac_addr)) {
                printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using"
                       " randomly generated MAC addr\n", pci_name(pdev));
-               random_ether_addr(dev->wiphy->perm_addr);
+               random_ether_addr(mac_addr);
        }
+       SET_IEEE80211_PERM_ADDR(dev, mac_addr);
 
        /* CCK TX power */
        for (i = 0; i < 14; i += 2) {
@@ -1024,7 +1099,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
        }
 
        printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n",
-              wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
+              wiphy_name(dev->wiphy), mac_addr,
               chip_name, priv->rf->name);
 
        return 0;
index 1d30792973f5ef78dfaad45ea439f23c159618c2..891b8490e34978b0d0bbb71b777a9da617f35cb4 100644 (file)
@@ -1194,9 +1194,9 @@ static void rtl8187_bss_info_changed(struct ieee80211_hw *dev,
 }
 
 static u64 rtl8187_prepare_multicast(struct ieee80211_hw *dev,
-                                    int mc_count, struct dev_addr_list *mc_list)
+                                    struct netdev_hw_addr_list *mc_list)
 {
-       return mc_count;
+       return netdev_hw_addr_list_count(mc_list);
 }
 
 static void rtl8187_configure_filter(struct ieee80211_hw *dev,
@@ -1333,6 +1333,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        u16 txpwr, reg;
        u16 product_id = le16_to_cpu(udev->descriptor.idProduct);
        int err, i;
+       u8 mac_addr[ETH_ALEN];
 
        dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
        if (!dev) {
@@ -1390,12 +1391,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        udelay(10);
 
        eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR,
-                              (__le16 __force *)dev->wiphy->perm_addr, 3);
-       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+                              (__le16 __force *)mac_addr, 3);
+       if (!is_valid_ether_addr(mac_addr)) {
                printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly "
                       "generated MAC address\n");
-               random_ether_addr(dev->wiphy->perm_addr);
+               random_ether_addr(mac_addr);
        }
+       SET_IEEE80211_PERM_ADDR(dev, mac_addr);
 
        channel = priv->channels;
        for (i = 0; i < 3; i++) {
@@ -1526,7 +1528,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
        skb_queue_head_init(&priv->b_tx_status.queue);
 
        printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
-              wiphy_name(dev->wiphy), dev->wiphy->perm_addr,
+              wiphy_name(dev->wiphy), mac_addr,
               chip_name, priv->asic_rev, priv->rf->name, priv->rfkill_mask);
 
 #ifdef CONFIG_RTL8187_LEDS
index 785e0244e3057fdcc85097d4e52553155a8e59c1..337fc7bec5a5056ee9bbb73ba6ff16417d704b75 100644 (file)
@@ -51,3 +51,27 @@ config WL1271
 
          If you choose to build a module, it'll be called wl1271. Say N if
          unsure.
+
+config WL1271_SPI
+       tristate "TI wl1271 SPI support"
+       depends on WL1271 && SPI_MASTER
+       ---help---
+         This module adds support for the SPI interface of adapters using
+         TI wl1271 chipset.  Select this if your platform is using
+         the SPI bus.
+
+         If you choose to build a module, it'll be called wl1251_spi.
+         Say N if unsure.
+
+config WL1271_SDIO
+       tristate "TI wl1271 SDIO support"
+       depends on WL1271 && MMC && ARM
+       ---help---
+         This module adds support for the SDIO interface of adapters using
+         TI wl1271 chipset.  Select this if your platform is using
+         the SDIO bus.
+
+         If you choose to build a module, it'll be called
+         wl1271_sdio. Say N if unsure.
+
+
index f47ec94c16dcba89c86e54cfcda56d6710b75d65..27ddd2be0a9168da0bf63f3787e4ac30432fe8cb 100644 (file)
@@ -7,10 +7,12 @@ obj-$(CONFIG_WL1251)  += wl1251.o
 obj-$(CONFIG_WL1251_SPI)       += wl1251_spi.o
 obj-$(CONFIG_WL1251_SDIO)      += wl1251_sdio.o
 
-wl1271-objs            = wl1271_main.o  wl1271_spi.o wl1271_cmd.o  \
+wl1271-objs            = wl1271_main.o  wl1271_cmd.o wl1271_io.o \
                          wl1271_event.o wl1271_tx.o  wl1271_rx.o   \
                          wl1271_ps.o    wl1271_acx.o wl1271_boot.o \
-                         wl1271_init.o  wl1271_debugfs.o wl1271_io.o
+                         wl1271_init.o  wl1271_debugfs.o
 
 wl1271-$(CONFIG_NL80211_TESTMODE)      += wl1271_testmode.o
 obj-$(CONFIG_WL1271)   += wl1271.o
+obj-$(CONFIG_WL1271_SPI)       += wl1271_spi.o
+obj-$(CONFIG_WL1271_SDIO)      += wl1271_sdio.o
index 37c61c19cae5da8f99b95bc674abcd57c560ffb3..4f5f02a26e6272887fabf4f896915f8b916c782f 100644 (file)
@@ -256,6 +256,8 @@ struct wl1251_debugfs {
 struct wl1251_if_operations {
        void (*read)(struct wl1251 *wl, int addr, void *buf, size_t len);
        void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len);
+       void (*read_elp)(struct wl1251 *wl, int addr, u32 *val);
+       void (*write_elp)(struct wl1251 *wl, int addr, u32 val);
        void (*reset)(struct wl1251 *wl);
        void (*enable_irq)(struct wl1251 *wl);
        void (*disable_irq)(struct wl1251 *wl);
index d5ac79aeaa735cecdca705f6e556b774807c69c6..2545123931e85357e152f9ffc6dfc35a8834e873 100644 (file)
@@ -497,7 +497,8 @@ int wl1251_boot(struct wl1251 *wl)
        /* 2. start processing NVS file */
        if (wl->use_eeprom) {
                wl1251_reg_write32(wl, ACX_REG_EE_START, START_EEPROM_MGR);
-               msleep(4000);
+               /* Wait for EEPROM NVS burst read to complete */
+               msleep(40);
                wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, USE_EEPROM);
        } else {
                ret = wl1251_boot_upload_nvs(wl);
index b89d2ac62efb04275e0e5f49073a31e3082d16c6..c545e9d5f512a34f2cc8a61e847f829dc74d73bc 100644 (file)
@@ -48,6 +48,26 @@ static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
        wl->if_ops->write(wl, addr, &val, sizeof(u32));
 }
 
+static inline u32 wl1251_read_elp(struct wl1251 *wl, int addr)
+{
+       u32 response;
+
+       if (wl->if_ops->read_elp)
+               wl->if_ops->read_elp(wl, addr, &response);
+       else
+               wl->if_ops->read(wl, addr, &response, sizeof(u32));
+
+       return response;
+}
+
+static inline void wl1251_write_elp(struct wl1251 *wl, int addr, u32 val)
+{
+       if (wl->if_ops->write_elp)
+               wl->if_ops->write_elp(wl, addr, val);
+       else
+               wl->if_ops->write(wl, addr, &val, sizeof(u32));
+}
+
 /* Memory target IO, address is translated to partition 0 */
 void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
 void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
index 1c8226eee40938aafc13cbb89e1797305c8e5df9..00b24282fc738cad290466902ec12735e131cb50 100644 (file)
@@ -147,8 +147,8 @@ static void wl1251_fw_wakeup(struct wl1251 *wl)
        u32 elp_reg;
 
        elp_reg = ELPCTRL_WAKE_UP;
-       wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
-       elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+       wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+       elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
 
        if (!(elp_reg & ELPCTRL_WLAN_READY))
                wl1251_warning("WLAN not ready");
@@ -202,8 +202,8 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
                        goto out;
        }
 
-       /* No NVS from netlink, try to get it from the filesystem */
-       if (wl->nvs == NULL) {
+       if (wl->nvs == NULL && !wl->use_eeprom) {
+               /* No NVS from netlink, try to get it from the filesystem */
                ret = wl1251_fetch_nvs(wl);
                if (ret < 0)
                        goto out;
@@ -857,6 +857,7 @@ out:
 }
 
 static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
                             struct cfg80211_scan_request *req)
 {
        struct wl1251 *wl = hw->priv;
@@ -1196,6 +1197,66 @@ static const struct ieee80211_ops wl1251_ops = {
        .conf_tx = wl1251_op_conf_tx,
 };
 
+static int wl1251_read_eeprom_byte(struct wl1251 *wl, off_t offset, u8 *data)
+{
+       unsigned long timeout;
+
+       wl1251_reg_write32(wl, EE_ADDR, offset);
+       wl1251_reg_write32(wl, EE_CTL, EE_CTL_READ);
+
+       /* EE_CTL_READ clears when data is ready */
+       timeout = jiffies + msecs_to_jiffies(100);
+       while (1) {
+               if (!(wl1251_reg_read32(wl, EE_CTL) & EE_CTL_READ))
+                       break;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+       }
+
+       *data = wl1251_reg_read32(wl, EE_DATA);
+       return 0;
+}
+
+static int wl1251_read_eeprom(struct wl1251 *wl, off_t offset,
+                             u8 *data, size_t len)
+{
+       size_t i;
+       int ret;
+
+       wl1251_reg_write32(wl, EE_START, 0);
+
+       for (i = 0; i < len; i++) {
+               ret = wl1251_read_eeprom_byte(wl, offset + i, &data[i]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int wl1251_read_eeprom_mac(struct wl1251 *wl)
+{
+       u8 mac[ETH_ALEN];
+       int i, ret;
+
+       wl1251_set_partition(wl, 0, 0, REGISTERS_BASE, REGISTERS_DOWN_SIZE);
+
+       ret = wl1251_read_eeprom(wl, 0x1c, mac, sizeof(mac));
+       if (ret < 0) {
+               wl1251_warning("failed to read MAC address from EEPROM");
+               return ret;
+       }
+
+       /* MAC is stored in reverse order */
+       for (i = 0; i < ETH_ALEN; i++)
+               wl->mac_addr[i] = mac[ETH_ALEN - i - 1];
+
+       return 0;
+}
+
 static int wl1251_register_hw(struct wl1251 *wl)
 {
        int ret;
@@ -1231,7 +1292,6 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
        wl->hw->channel_change_time = 10000;
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_NOISE_DBM |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_BEACON_FILTER |
                IEEE80211_HW_SUPPORTS_UAPSD;
@@ -1242,6 +1302,9 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
 
        wl->hw->queues = 4;
 
+       if (wl->use_eeprom)
+               wl1251_read_eeprom_mac(wl);
+
        ret = wl1251_register_hw(wl);
        if (ret)
                goto out;
index 851dfb65e474eb80a916a802a42b5e0d38b42a20..b55cb2bd459aa0d278556f3b81d5ca7701fe209d 100644 (file)
@@ -45,7 +45,7 @@ void wl1251_elp_work(struct work_struct *work)
                goto out;
 
        wl1251_debug(DEBUG_PSM, "chip to elp");
-       wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+       wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
        wl->elp = true;
 
 out:
@@ -79,9 +79,9 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
        start = jiffies;
        timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
 
-       wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+       wl1251_write_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
 
-       elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+       elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
 
        /*
         * FIXME: we should wait for irq from chip but, as a temporary
@@ -93,7 +93,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
                        return -ETIMEDOUT;
                }
                msleep(1);
-               elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+               elp_reg = wl1251_read_elp(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
        }
 
        wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
index 0ca3b4326056896f5c3e970df26afb44a4ffe58e..d16edd9bf06c1bf9e61cb397068ba381f1da22ca 100644 (file)
 #define SOR_CFG                        (REGISTERS_BASE + 0x0800)
 #define ECPU_CTRL                      (REGISTERS_BASE + 0x0804)
 #define HI_CFG                         (REGISTERS_BASE + 0x0808)
+
+/* EEPROM registers */
 #define EE_START                       (REGISTERS_BASE + 0x080C)
+#define EE_CTL                         (REGISTERS_BASE + 0x2000)
+#define EE_DATA                        (REGISTERS_BASE + 0x2004)
+#define EE_ADDR                        (REGISTERS_BASE + 0x2008)
+
+#define EE_CTL_READ                   2
 
 #define CHIP_ID_B                      (REGISTERS_BASE + 0x5674)
 
index 6f229e0990f4efc45d3a54facaad939d994cbf3c..851515836a7f6217085ccbd5f32bf38798ab63ac 100644 (file)
@@ -74,12 +74,6 @@ static void wl1251_rx_status(struct wl1251 *wl,
 
        status->signal = desc->rssi;
 
-       /*
-        * FIXME: guessing that snr needs to be divided by two, otherwise
-        * the values don't make any sense
-        */
-       status->noise = desc->rssi - desc->snr / 2;
-
        status->freq = ieee80211_channel_to_frequency(desc->channel);
 
        status->flag |= RX_FLAG_TSFT;
@@ -189,6 +183,4 @@ void wl1251_rx(struct wl1251 *wl)
 
        /* Finally, we need to ACK the RX */
        wl1251_rx_ack(wl);
-
-       return;
 }
index 9423f22bdcedcda262bde981d9b8da6698412179..d234285c2c81186fc096044dcfa309236e7e2d51 100644 (file)
  * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com)
  */
 #include <linux/module.h>
-#include <linux/crc7.h>
 #include <linux/mod_devicetable.h>
-#include <linux/irq.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/platform_device.h>
+#include <linux/spi/wl12xx.h>
+#include <linux/irq.h>
 
 #include "wl1251.h"
-#include "wl12xx_80211.h"
-#include "wl1251_reg.h"
-#include "wl1251_ps.h"
-#include "wl1251_io.h"
-#include "wl1251_tx.h"
-#include "wl1251_debugfs.h"
 
 #ifndef SDIO_VENDOR_ID_TI
 #define SDIO_VENDOR_ID_TI              0x104c
@@ -43,6 +37,8 @@
 #define SDIO_DEVICE_ID_TI_WL1251       0x9066
 #endif
 
+static struct wl12xx_platform_data *wl12xx_board_data;
+
 static struct sdio_func *wl_to_func(struct wl1251 *wl)
 {
        return wl->if_priv;
@@ -65,7 +61,8 @@ static const struct sdio_device_id wl1251_devices[] = {
 MODULE_DEVICE_TABLE(sdio, wl1251_devices);
 
 
-void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len)
+static void wl1251_sdio_read(struct wl1251 *wl, int addr,
+                            void *buf, size_t len)
 {
        int ret;
        struct sdio_func *func = wl_to_func(wl);
@@ -77,7 +74,8 @@ void wl1251_sdio_read(struct wl1251 *wl, int addr, void *buf, size_t len)
        sdio_release_host(func);
 }
 
-void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len)
+static void wl1251_sdio_write(struct wl1251 *wl, int addr,
+                             void *buf, size_t len)
 {
        int ret;
        struct sdio_func *func = wl_to_func(wl);
@@ -89,7 +87,33 @@ void wl1251_sdio_write(struct wl1251 *wl, int addr, void *buf, size_t len)
        sdio_release_host(func);
 }
 
-void wl1251_sdio_reset(struct wl1251 *wl)
+static void wl1251_sdio_read_elp(struct wl1251 *wl, int addr, u32 *val)
+{
+       int ret = 0;
+       struct sdio_func *func = wl_to_func(wl);
+
+       sdio_claim_host(func);
+       *val = sdio_readb(func, addr, &ret);
+       sdio_release_host(func);
+
+       if (ret)
+               wl1251_error("sdio_readb failed (%d)", ret);
+}
+
+static void wl1251_sdio_write_elp(struct wl1251 *wl, int addr, u32 val)
+{
+       int ret = 0;
+       struct sdio_func *func = wl_to_func(wl);
+
+       sdio_claim_host(func);
+       sdio_writeb(func, val, addr, &ret);
+       sdio_release_host(func);
+
+       if (ret)
+               wl1251_error("sdio_writeb failed (%d)", ret);
+}
+
+static void wl1251_sdio_reset(struct wl1251 *wl)
 {
 }
 
@@ -111,19 +135,64 @@ static void wl1251_sdio_disable_irq(struct wl1251 *wl)
        sdio_release_host(func);
 }
 
-void wl1251_sdio_set_power(bool enable)
+/* Interrupts when using dedicated WLAN_IRQ pin */
+static irqreturn_t wl1251_line_irq(int irq, void *cookie)
+{
+       struct wl1251 *wl = cookie;
+
+       ieee80211_queue_work(wl->hw, &wl->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static void wl1251_enable_line_irq(struct wl1251 *wl)
 {
+       return enable_irq(wl->irq);
 }
 
-struct wl1251_if_operations wl1251_sdio_ops = {
+static void wl1251_disable_line_irq(struct wl1251 *wl)
+{
+       return disable_irq(wl->irq);
+}
+
+static void wl1251_sdio_set_power(bool enable)
+{
+}
+
+static struct wl1251_if_operations wl1251_sdio_ops = {
        .read = wl1251_sdio_read,
        .write = wl1251_sdio_write,
+       .write_elp = wl1251_sdio_write_elp,
+       .read_elp = wl1251_sdio_read_elp,
        .reset = wl1251_sdio_reset,
-       .enable_irq = wl1251_sdio_enable_irq,
-       .disable_irq = wl1251_sdio_disable_irq,
 };
 
-int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+static int wl1251_platform_probe(struct platform_device *pdev)
+{
+       if (pdev->id != -1) {
+               wl1251_error("can only handle single device");
+               return -ENODEV;
+       }
+
+       wl12xx_board_data = pdev->dev.platform_data;
+       return 0;
+}
+
+/*
+ * Dummy platform_driver for passing platform_data to this driver,
+ * until we have a way to pass this through SDIO subsystem or
+ * some other way.
+ */
+static struct platform_driver wl1251_platform_driver = {
+       .driver = {
+               .name   = "wl1251_data",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = wl1251_platform_probe,
+};
+
+static int wl1251_sdio_probe(struct sdio_func *func,
+                            const struct sdio_device_id *id)
 {
        int ret;
        struct wl1251 *wl;
@@ -141,20 +210,50 @@ int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
                goto release;
 
        sdio_set_block_size(func, 512);
+       sdio_release_host(func);
 
        SET_IEEE80211_DEV(hw, &func->dev);
        wl->if_priv = func;
        wl->if_ops = &wl1251_sdio_ops;
        wl->set_power = wl1251_sdio_set_power;
 
-       sdio_release_host(func);
+       if (wl12xx_board_data != NULL) {
+               wl->set_power = wl12xx_board_data->set_power;
+               wl->irq = wl12xx_board_data->irq;
+               wl->use_eeprom = wl12xx_board_data->use_eeprom;
+       }
+
+       if (wl->irq) {
+               ret = request_irq(wl->irq, wl1251_line_irq, 0, "wl1251", wl);
+               if (ret < 0) {
+                       wl1251_error("request_irq() failed: %d", ret);
+                       goto disable;
+               }
+
+               set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+               disable_irq(wl->irq);
+
+               wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq;
+               wl1251_sdio_ops.disable_irq = wl1251_disable_line_irq;
+
+               wl1251_info("using dedicated interrupt line");
+       } else {
+               wl1251_sdio_ops.enable_irq = wl1251_sdio_enable_irq;
+               wl1251_sdio_ops.disable_irq = wl1251_sdio_disable_irq;
+
+               wl1251_info("using SDIO interrupt");
+       }
+
        ret = wl1251_init_ieee80211(wl);
        if (ret)
-               goto disable;
+               goto out_free_irq;
 
        sdio_set_drvdata(func, wl);
        return ret;
 
+out_free_irq:
+       if (wl->irq)
+               free_irq(wl->irq, wl);
 disable:
        sdio_claim_host(func);
        sdio_disable_func(func);
@@ -167,6 +266,8 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func)
 {
        struct wl1251 *wl = sdio_get_drvdata(func);
 
+       if (wl->irq)
+               free_irq(wl->irq, wl);
        wl1251_free_hw(wl);
 
        sdio_claim_host(func);
@@ -186,6 +287,12 @@ static int __init wl1251_sdio_init(void)
 {
        int err;
 
+       err = platform_driver_register(&wl1251_platform_driver);
+       if (err) {
+               wl1251_error("failed to register platform driver: %d", err);
+               return err;
+       }
+
        err = sdio_register_driver(&wl1251_sdio_driver);
        if (err)
                wl1251_error("failed to register sdio driver: %d", err);
@@ -195,6 +302,7 @@ static int __init wl1251_sdio_init(void)
 static void __exit wl1251_sdio_exit(void)
 {
        sdio_unregister_driver(&wl1251_sdio_driver);
+       platform_driver_unregister(&wl1251_platform_driver);
        wl1251_notice("unloaded");
 }
 
index 3bfb59bd4635413422c3031625c5fb89c090ab0d..e81474203a23a9df145f9e27178d0fc26aadc225 100644 (file)
@@ -310,7 +310,7 @@ static int __devexit wl1251_spi_remove(struct spi_device *spi)
 
 static struct spi_driver wl1251_spi_driver = {
        .driver = {
-               .name           = "wl1251",
+               .name           = DRIVER_NAME,
                .bus            = &spi_bus_type,
                .owner          = THIS_MODULE,
        },
index 97ea5096bc8c96dfa974d2754e247051357edd00..6f1b6b5640c00182f4f178d950aa270111ea4fdb 100644 (file)
@@ -53,6 +53,9 @@ enum {
        DEBUG_MAC80211  = BIT(11),
        DEBUG_CMD       = BIT(12),
        DEBUG_ACX       = BIT(13),
+       DEBUG_SDIO      = BIT(14),
+       DEBUG_FILTERS   = BIT(15),
+       DEBUG_ADHOC     = BIT(16),
        DEBUG_ALL       = ~0,
 };
 
@@ -110,6 +113,9 @@ enum {
 #define WL1271_FW_NAME "wl1271-fw.bin"
 #define WL1271_NVS_NAME "wl1271-nvs.bin"
 
+#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
+#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
+
 /* NVS data structure */
 #define WL1271_NVS_SECTION_SIZE                  468
 
@@ -142,14 +148,7 @@ struct wl1271_nvs_file {
  */
 #undef WL1271_80211A_ENABLED
 
-/*
- * FIXME: for the wl1271, a busy word count of 1 here will result in a more
- * optimal SPI interface. There is some SPI bug however, causing RXS time outs
- * with this mode occasionally on boot, so lets have three for now. A value of
- * three should make sure, that the chipset will always be ready, though this
- * will impact throughput and latencies slightly.
- */
-#define WL1271_BUSY_WORD_CNT 3
+#define WL1271_BUSY_WORD_CNT 1
 #define WL1271_BUSY_WORD_LEN (WL1271_BUSY_WORD_CNT * sizeof(u32))
 
 #define WL1271_ELP_HW_STATE_ASLEEP 0
@@ -334,11 +333,27 @@ struct wl1271_scan {
        u8 probe_requests;
 };
 
+struct wl1271_if_operations {
+       void (*read)(struct wl1271 *wl, int addr, void *buf, size_t len,
+                    bool fixed);
+       void (*write)(struct wl1271 *wl, int addr, void *buf, size_t len,
+                    bool fixed);
+       void (*reset)(struct wl1271 *wl);
+       void (*init)(struct wl1271 *wl);
+       void (*power)(struct wl1271 *wl, bool enable);
+       struct device* (*dev)(struct wl1271 *wl);
+       void (*enable_irq)(struct wl1271 *wl);
+       void (*disable_irq)(struct wl1271 *wl);
+};
+
 struct wl1271 {
+       struct platform_device *plat_dev;
        struct ieee80211_hw *hw;
        bool mac80211_registered;
 
-       struct spi_device *spi;
+       void *if_priv;
+
+       struct wl1271_if_operations *if_ops;
 
        void (*set_power)(bool enable);
        int irq;
@@ -357,6 +372,9 @@ struct wl1271 {
 #define WL1271_FLAG_IN_ELP             (6)
 #define WL1271_FLAG_PSM                (7)
 #define WL1271_FLAG_PSM_REQUESTED      (8)
+#define WL1271_FLAG_IRQ_PENDING        (9)
+#define WL1271_FLAG_IRQ_RUNNING       (10)
+#define WL1271_FLAG_IDLE              (11)
        unsigned long flags;
 
        struct wl1271_partition_set part;
@@ -370,9 +388,12 @@ struct wl1271 {
        size_t fw_len;
        struct wl1271_nvs_file *nvs;
 
+       s8 hw_pg_ver;
+
        u8 bssid[ETH_ALEN];
        u8 mac_addr[ETH_ALEN];
        u8 bss_type;
+       u8 set_bss_type;
        u8 ssid[IW_ESSID_MAX_SIZE + 1];
        u8 ssid_len;
        int channel;
@@ -382,13 +403,13 @@ struct wl1271 {
        /* Accounting for allocated / available TX blocks on HW */
        u32 tx_blocks_freed[NUM_TX_QUEUES];
        u32 tx_blocks_available;
-       u8 tx_results_count;
+       u32 tx_results_count;
 
        /* Transmitted TX packets counter for chipset interface */
-       int tx_packets_count;
+       u32 tx_packets_count;
 
        /* Time-offset between host and chipset clocks */
-       int time_offset;
+       s64 time_offset;
 
        /* Session counter for the chipset */
        int session_counter;
@@ -403,8 +424,7 @@ struct wl1271 {
 
        /* Security sequence number counters */
        u8 tx_security_last_seq;
-       u16 tx_security_seq_16;
-       u32 tx_security_seq_32;
+       s64 tx_security_seq;
 
        /* FW Rx counter */
        u32 rx_counter;
@@ -430,14 +450,19 @@ struct wl1271 {
        /* currently configured rate set */
        u32 sta_rate_set;
        u32 basic_rate_set;
+       u32 basic_rate;
        u32 rate_set;
 
        /* The current band */
        enum ieee80211_band band;
 
+       /* Beaconing interval (needed for ad-hoc) */
+       u32 beacon_int;
+
        /* Default key (for WEP) */
        u32 default_key;
 
+       unsigned int filters;
        unsigned int rx_config;
        unsigned int rx_filter;
 
@@ -450,10 +475,13 @@ struct wl1271 {
        /* in dBm */
        int power_level;
 
+       int rssi_thold;
+       int last_rssi_event;
+
        struct wl1271_stats stats;
        struct wl1271_debugfs debugfs;
 
-       u32 buffer_32;
+       __le32 buffer_32;
        u32 buffer_cmd;
        u32 buffer_busyword[WL1271_BUSY_WORD_CNT];
 
@@ -465,6 +493,8 @@ struct wl1271 {
        /* Current chipset configuration */
        struct conf_drv_settings conf;
 
+       bool sg_enabled;
+
        struct list_head list;
 };
 
@@ -477,7 +507,8 @@ int wl1271_plt_stop(struct wl1271 *wl);
 
 #define WL1271_DEFAULT_POWER_LEVEL 0
 
-#define WL1271_TX_QUEUE_MAX_LENGTH 20
+#define WL1271_TX_QUEUE_LOW_WATERMARK  10
+#define WL1271_TX_QUEUE_HIGH_WATERMARK 25
 
 /* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
    on in case is has been shut down shortly before */
index 308782421fce5afb777b22caa755e2c395e6fc9f..e19e2f8f1e522d7806fcde6224a35bfa90a4b65a 100644 (file)
@@ -32,7 +32,6 @@
 #include "wl1271.h"
 #include "wl12xx_80211.h"
 #include "wl1271_reg.h"
-#include "wl1271_spi.h"
 #include "wl1271_ps.h"
 
 int wl1271_acx_wake_up_conditions(struct wl1271 *wl)
@@ -137,12 +136,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power)
                goto out;
        }
 
-       /*
-        * FIXME: This is a workaround needed while we don't the correct
-        * calibration, to avoid distortions
-        */
-       /* acx->current_tx_power = power * 10; */
-       acx->current_tx_power = 120;
+       acx->current_tx_power = power * 10;
 
        ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
        if (ret < 0) {
@@ -511,12 +505,17 @@ out:
        return ret;
 }
 
-int wl1271_acx_conn_monit_params(struct wl1271 *wl)
+#define ACX_CONN_MONIT_DISABLE_VALUE  0xffffffff
+
+int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable)
 {
        struct acx_conn_monit_params *acx;
+       u32 threshold = ACX_CONN_MONIT_DISABLE_VALUE;
+       u32 timeout = ACX_CONN_MONIT_DISABLE_VALUE;
        int ret;
 
-       wl1271_debug(DEBUG_ACX, "acx connection monitor parameters");
+       wl1271_debug(DEBUG_ACX, "acx connection monitor parameters: %s",
+                    enable ? "enabled" : "disabled");
 
        acx = kzalloc(sizeof(*acx), GFP_KERNEL);
        if (!acx) {
@@ -524,8 +523,13 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl)
                goto out;
        }
 
-       acx->synch_fail_thold = cpu_to_le32(wl->conf.conn.synch_fail_thold);
-       acx->bss_lose_timeout = cpu_to_le32(wl->conf.conn.bss_lose_timeout);
+       if (enable) {
+               threshold = wl->conf.conn.synch_fail_thold;
+               timeout = wl->conf.conn.bss_lose_timeout;
+       }
+
+       acx->synch_fail_thold = cpu_to_le32(threshold);
+       acx->bss_lose_timeout = cpu_to_le32(timeout);
 
        ret = wl1271_cmd_configure(wl, ACX_CONN_MONIT_PARAMS,
                                   acx, sizeof(*acx));
@@ -541,7 +545,7 @@ out:
 }
 
 
-int wl1271_acx_sg_enable(struct wl1271 *wl)
+int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable)
 {
        struct acx_bt_wlan_coex *pta;
        int ret;
@@ -554,7 +558,10 @@ int wl1271_acx_sg_enable(struct wl1271 *wl)
                goto out;
        }
 
-       pta->enable = SG_ENABLE;
+       if (enable)
+               pta->enable = wl->conf.sg.state;
+       else
+               pta->enable = CONF_SG_DISABLE;
 
        ret = wl1271_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
        if (ret < 0) {
@@ -571,7 +578,7 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
 {
        struct acx_bt_wlan_coex_param *param;
        struct conf_sg_settings *c = &wl->conf.sg;
-       int ret;
+       int i, ret;
 
        wl1271_debug(DEBUG_ACX, "acx sg cfg");
 
@@ -582,19 +589,9 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
        }
 
        /* BT-WLAN coext parameters */
-       param->per_threshold = cpu_to_le32(c->per_threshold);
-       param->max_scan_compensation_time =
-               cpu_to_le32(c->max_scan_compensation_time);
-       param->nfs_sample_interval = cpu_to_le16(c->nfs_sample_interval);
-       param->load_ratio = c->load_ratio;
-       param->auto_ps_mode = c->auto_ps_mode;
-       param->probe_req_compensation = c->probe_req_compensation;
-       param->scan_window_compensation = c->scan_window_compensation;
-       param->antenna_config = c->antenna_config;
-       param->beacon_miss_threshold = c->beacon_miss_threshold;
-       param->rate_adaptation_threshold =
-               cpu_to_le32(c->rate_adaptation_threshold);
-       param->rate_adaptation_snr = c->rate_adaptation_snr;
+       for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
+               param->params[i] = cpu_to_le32(c->params[i]);
+       param->param_idx = CONF_SG_PARAMS_ALL;
 
        ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
        if (ret < 0) {
@@ -806,7 +803,7 @@ int wl1271_acx_rate_policies(struct wl1271 *wl)
 
        /* 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].enabled_rates = cpu_to_le32(wl->basic_rate);
        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;
@@ -1143,3 +1140,129 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable)
+{
+       struct wl1271_acx_keep_alive_mode *acx = NULL;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx keep alive mode: %d", enable);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->enabled = enable;
+
+       ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx keep alive mode failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid)
+{
+       struct wl1271_acx_keep_alive_config *acx = NULL;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx keep alive config");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval);
+       acx->index = index;
+       acx->tpl_validation = tpl_valid;
+       acx->trigger = ACX_KEEP_ALIVE_NO_TX;
+
+       ret = wl1271_cmd_configure(wl, ACX_SET_KEEP_ALIVE_CONFIG,
+                                  acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx keep alive config failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
+                               s16 thold, u8 hyst)
+{
+       struct wl1271_acx_rssi_snr_trigger *acx = NULL;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx rssi snr trigger");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wl->last_rssi_event = -1;
+
+       acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing);
+       acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON;
+       acx->type = WL1271_ACX_TRIG_TYPE_EDGE;
+       if (enable)
+               acx->enable = WL1271_ACX_TRIG_ENABLE;
+       else
+               acx->enable = WL1271_ACX_TRIG_DISABLE;
+
+       acx->index = WL1271_ACX_TRIG_IDX_RSSI;
+       acx->dir = WL1271_ACX_TRIG_DIR_BIDIR;
+       acx->threshold = cpu_to_le16(thold);
+       acx->hysteresis = hyst;
+
+       ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_TRIGGER, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx rssi snr trigger setting failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
+
+int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl)
+{
+       struct wl1271_acx_rssi_snr_avg_weights *acx = NULL;
+       struct conf_roam_trigger_settings *c = &wl->conf.roam_trigger;
+       int ret = 0;
+
+       wl1271_debug(DEBUG_ACX, "acx rssi snr avg weights");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->rssi_beacon = c->avg_weight_rssi_beacon;
+       acx->rssi_data = c->avg_weight_rssi_data;
+       acx->snr_beacon = c->avg_weight_snr_beacon;
+       acx->snr_data = c->avg_weight_snr_data;
+
+       ret = wl1271_cmd_configure(wl, ACX_RSSI_SNR_WEIGHTS, acx, sizeof(*acx));
+       if (ret < 0) {
+               wl1271_warning("acx rssi snr trigger weights failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+}
index aeccc98581eb04598826f428ba3b6fd930ca6502..420e7e2fc021b357032a861b67acd2bb82007eff 100644 (file)
@@ -392,81 +392,27 @@ struct acx_conn_monit_params {
        __le32 bss_lose_timeout; /* number of TU's from synch fail */
 } __attribute__ ((packed));
 
-enum {
-       SG_ENABLE = 0,
-       SG_DISABLE,
-       SG_SENSE_NO_ACTIVITY,
-       SG_SENSE_ACTIVE
-};
-
 struct acx_bt_wlan_coex {
        struct acx_header header;
 
-       /*
-        * 0 -> PTA enabled
-        * 1 -> PTA disabled
-        * 2 -> sense no active mode, i.e.
-        *      an interrupt is sent upon
-        *      BT activity.
-        * 3 -> PTA is switched on in response
-        *      to the interrupt sending.
-        */
        u8 enable;
        u8 pad[3];
 } __attribute__ ((packed));
 
-struct acx_dco_itrim_params {
+struct acx_bt_wlan_coex_param {
        struct acx_header header;
 
-       u8 enable;
+       __le32 params[CONF_SG_PARAMS_MAX];
+       u8 param_idx;
        u8 padding[3];
-       __le32 timeout;
 } __attribute__ ((packed));
 
-#define PTA_ANTENNA_TYPE_DEF             (0)
-#define PTA_BT_HP_MAXTIME_DEF            (2000)
-#define PTA_WLAN_HP_MAX_TIME_DEF         (5000)
-#define PTA_SENSE_DISABLE_TIMER_DEF      (1350)
-#define PTA_PROTECTIVE_RX_TIME_DEF       (1500)
-#define PTA_PROTECTIVE_TX_TIME_DEF       (1500)
-#define PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF (3000)
-#define PTA_SIGNALING_TYPE_DEF           (1)
-#define PTA_AFH_LEVERAGE_ON_DEF                  (0)
-#define PTA_NUMBER_QUIET_CYCLE_DEF       (0)
-#define PTA_MAX_NUM_CTS_DEF              (3)
-#define PTA_NUMBER_OF_WLAN_PACKETS_DEF   (2)
-#define PTA_NUMBER_OF_BT_PACKETS_DEF     (2)
-#define PTA_PROTECTIVE_RX_TIME_FAST_DEF          (1500)
-#define PTA_PROTECTIVE_TX_TIME_FAST_DEF          (3000)
-#define PTA_CYCLE_TIME_FAST_DEF                  (8700)
-#define PTA_RX_FOR_AVALANCHE_DEF         (5)
-#define PTA_ELP_HP_DEF                   (0)
-#define PTA_ANTI_STARVE_PERIOD_DEF       (500)
-#define PTA_ANTI_STARVE_NUM_CYCLE_DEF    (4)
-#define PTA_ALLOW_PA_SD_DEF              (1)
-#define PTA_TIME_BEFORE_BEACON_DEF       (6300)
-#define PTA_HPDM_MAX_TIME_DEF            (1600)
-#define PTA_TIME_OUT_NEXT_WLAN_DEF       (2550)
-#define PTA_AUTO_MODE_NO_CTS_DEF         (0)
-#define PTA_BT_HP_RESPECTED_DEF                  (3)
-#define PTA_WLAN_RX_MIN_RATE_DEF         (24)
-#define PTA_ACK_MODE_DEF                 (1)
-
-struct acx_bt_wlan_coex_param {
+struct acx_dco_itrim_params {
        struct acx_header header;
 
-       __le32 per_threshold;
-       __le32 max_scan_compensation_time;
-       __le16 nfs_sample_interval;
-       u8 load_ratio;
-       u8 auto_ps_mode;
-       u8 probe_req_compensation;
-       u8 scan_window_compensation;
-       u8 antenna_config;
-       u8 beacon_miss_threshold;
-       __le32 rate_adaptation_threshold;
-       s8 rate_adaptation_snr;
+       u8 enable;
        u8 padding[3];
+       __le32 timeout;
 } __attribute__ ((packed));
 
 struct acx_energy_detection {
@@ -969,6 +915,84 @@ struct wl1271_acx_pm_config {
        u8 padding[3];
 } __attribute__ ((packed));
 
+struct wl1271_acx_keep_alive_mode {
+       struct acx_header header;
+
+       u8 enabled;
+       u8 padding[3];
+} __attribute__ ((packed));
+
+enum {
+       ACX_KEEP_ALIVE_NO_TX = 0,
+       ACX_KEEP_ALIVE_PERIOD_ONLY
+};
+
+enum {
+       ACX_KEEP_ALIVE_TPL_INVALID = 0,
+       ACX_KEEP_ALIVE_TPL_VALID
+};
+
+struct wl1271_acx_keep_alive_config {
+       struct acx_header header;
+
+       __le32 period;
+       u8 index;
+       u8 tpl_validation;
+       u8 trigger;
+       u8 padding;
+} __attribute__ ((packed));
+
+enum {
+       WL1271_ACX_TRIG_TYPE_LEVEL = 0,
+       WL1271_ACX_TRIG_TYPE_EDGE,
+};
+
+enum {
+       WL1271_ACX_TRIG_DIR_LOW = 0,
+       WL1271_ACX_TRIG_DIR_HIGH,
+       WL1271_ACX_TRIG_DIR_BIDIR,
+};
+
+enum {
+       WL1271_ACX_TRIG_ENABLE = 1,
+       WL1271_ACX_TRIG_DISABLE,
+};
+
+enum {
+       WL1271_ACX_TRIG_METRIC_RSSI_BEACON = 0,
+       WL1271_ACX_TRIG_METRIC_RSSI_DATA,
+       WL1271_ACX_TRIG_METRIC_SNR_BEACON,
+       WL1271_ACX_TRIG_METRIC_SNR_DATA,
+};
+
+enum {
+       WL1271_ACX_TRIG_IDX_RSSI = 0,
+       WL1271_ACX_TRIG_COUNT = 8,
+};
+
+struct wl1271_acx_rssi_snr_trigger {
+       struct acx_header header;
+
+       __le16 threshold;
+       __le16 pacing; /* 0 - 60000 ms */
+       u8 metric;
+       u8 type;
+       u8 dir;
+       u8 hysteresis;
+       u8 index;
+       u8 enable;
+       u8 padding[2];
+};
+
+struct wl1271_acx_rssi_snr_avg_weights {
+       struct acx_header header;
+
+       u8 rssi_beacon;
+       u8 rssi_data;
+       u8 snr_beacon;
+       u8 snr_data;
+};
+
 enum {
        ACX_WAKE_UP_CONDITIONS      = 0x0002,
        ACX_MEM_CFG                 = 0x0003,
@@ -1017,8 +1041,8 @@ enum {
        ACX_FRAG_CFG                = 0x004F,
        ACX_BET_ENABLE              = 0x0050,
        ACX_RSSI_SNR_TRIGGER        = 0x0051,
-       ACX_RSSI_SNR_WEIGHTS        = 0x0051,
-       ACX_KEEP_ALIVE_MODE         = 0x0052,
+       ACX_RSSI_SNR_WEIGHTS        = 0x0052,
+       ACX_KEEP_ALIVE_MODE         = 0x0053,
        ACX_SET_KEEP_ALIVE_CONFIG   = 0x0054,
        ACX_BA_SESSION_RESPONDER_POLICY = 0x0055,
        ACX_BA_SESSION_INITIATOR_POLICY = 0x0056,
@@ -1058,8 +1082,8 @@ 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);
-int wl1271_acx_sg_enable(struct wl1271 *wl);
+int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
+int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
 int wl1271_acx_sg_cfg(struct wl1271 *wl);
 int wl1271_acx_cca_threshold(struct wl1271 *wl);
 int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
@@ -1085,5 +1109,10 @@ 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);
+int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable);
+int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid);
+int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable,
+                               s16 thold, u8 hyst);
+int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl);
 
 #endif /* __WL1271_ACX_H__ */
index 0243562630657098d5b3f05802500f5d151c8704..1a36d8a2196e7c7c19f8b81dd079c9eaa9140461 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of wl1271
  *
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
  *
  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  *
@@ -27,7 +27,6 @@
 #include "wl1271_acx.h"
 #include "wl1271_reg.h"
 #include "wl1271_boot.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 #include "wl1271_event.h"
 
@@ -230,6 +229,14 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
        nvs_len = sizeof(wl->nvs->nvs);
        nvs_ptr = (u8 *)wl->nvs->nvs;
 
+       /* update current MAC address to NVS */
+       nvs_ptr[11] = wl->mac_addr[0];
+       nvs_ptr[10] = wl->mac_addr[1];
+       nvs_ptr[6] = wl->mac_addr[2];
+       nvs_ptr[5] = wl->mac_addr[3];
+       nvs_ptr[4] = wl->mac_addr[4];
+       nvs_ptr[3] = wl->mac_addr[5];
+
        /*
         * Layout before the actual NVS tables:
         * 1 byte : burst length.
@@ -300,7 +307,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
 
 static void wl1271_boot_enable_interrupts(struct wl1271 *wl)
 {
-       enable_irq(wl->irq);
+       wl1271_enable_interrupts(wl);
        wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
                       WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
        wl1271_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
@@ -344,7 +351,7 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl)
 static int wl1271_boot_run_firmware(struct wl1271 *wl)
 {
        int loop, ret;
-       u32 chip_id, interrupt;
+       u32 chip_id, intr;
 
        wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
 
@@ -361,15 +368,15 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        loop = 0;
        while (loop++ < INIT_LOOP) {
                udelay(INIT_LOOP_DELAY);
-               interrupt = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+               intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
 
-               if (interrupt == 0xffffffff) {
+               if (intr == 0xffffffff) {
                        wl1271_error("error reading hardware complete "
                                     "init indication");
                        return -EIO;
                }
                /* check that ACX_INTR_INIT_COMPLETE is enabled */
-               else if (interrupt & WL1271_ACX_INTR_INIT_COMPLETE) {
+               else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) {
                        wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
                                       WL1271_ACX_INTR_INIT_COMPLETE);
                        break;
@@ -404,7 +411,10 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        /* unmask required mbox events  */
        wl->event_mask = BSS_LOSE_EVENT_ID |
                SCAN_COMPLETE_EVENT_ID |
-               PS_REPORT_EVENT_ID;
+               PS_REPORT_EVENT_ID |
+               JOIN_EVENT_COMPLETE_ID |
+               DISCONNECT_EVENT_COMPLETE_ID |
+               RSSI_SNR_TRIGGER_0_EVENT_ID;
 
        ret = wl1271_event_unmask(wl);
        if (ret < 0) {
@@ -431,11 +441,23 @@ static int wl1271_boot_write_irq_polarity(struct wl1271 *wl)
        return 0;
 }
 
+static void wl1271_boot_hw_version(struct wl1271 *wl)
+{
+       u32 fuse;
+
+       fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1);
+       fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET;
+
+       wl->hw_pg_ver = (s8)fuse;
+}
+
 int wl1271_boot(struct wl1271 *wl)
 {
        int ret = 0;
        u32 tmp, clk, pause;
 
+       wl1271_boot_hw_version(wl);
+
        if (REF_CLOCK == 0 || REF_CLOCK == 2 || REF_CLOCK == 4)
                /* ref clk: 19.2/38.4/38.4-XTAL */
                clk = 0x3;
@@ -445,11 +467,15 @@ int wl1271_boot(struct wl1271 *wl)
 
        if (REF_CLOCK != 0) {
                u16 val;
-               /* Set clock type */
+               /* Set clock type (open drain) */
                val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
                val &= FREF_CLK_TYPE_BITS;
-               val |= CLK_REQ_PRCM;
                wl1271_top_reg_write(wl, OCP_REG_CLK_TYPE, val);
+
+               /* Set clock pull mode (no pull) */
+               val = wl1271_top_reg_read(wl, OCP_REG_CLK_PULL);
+               val |= NO_PULL;
+               wl1271_top_reg_write(wl, OCP_REG_CLK_PULL, val);
        } else {
                u16 val;
                /* Set clock polarity */
index 412443ee655a6cf8761190a22efb5d96f9670414..f829699d597e1c00faff1eee7afe9c642e951b40 100644 (file)
@@ -53,10 +53,16 @@ struct wl1271_static_data {
 #define OCP_REG_POLARITY     0x0064
 #define OCP_REG_CLK_TYPE     0x0448
 #define OCP_REG_CLK_POLARITY 0x0cb2
+#define OCP_REG_CLK_PULL     0x0cb4
 
-#define CMD_MBOX_ADDRESS 0x407B4
+#define REG_FUSE_DATA_2_1    0x050a
+#define PG_VER_MASK          0x3c
+#define PG_VER_OFFSET        2
 
-#define POLARITY_LOW BIT(1)
+#define CMD_MBOX_ADDRESS     0x407B4
+
+#define POLARITY_LOW         BIT(1)
+#define NO_PULL              (BIT(14) | BIT(15))
 
 #define FREF_CLK_TYPE_BITS     0xfffffe7f
 #define CLK_REQ_PRCM           0x100
index e7832f3318eba7e38629e3f43adce326c6a6f411..19393e236e2c8426fb4002d4e77038a9b13055c4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of wl1271
  *
- * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2009-2010 Nokia Corporation
  *
  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
  *
 #include <linux/crc7.h>
 #include <linux/spi/spi.h>
 #include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
 #include <linux/slab.h>
 
 #include "wl1271.h"
 #include "wl1271_reg.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 #include "wl1271_acx.h"
 #include "wl12xx_80211.h"
 #include "wl1271_cmd.h"
+#include "wl1271_event.h"
+
+#define WL1271_CMD_FAST_POLL_COUNT       50
 
 /*
  * send command to firmware
@@ -52,6 +55,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
        u32 intr;
        int ret = 0;
        u16 status;
+       u16 poll_count = 0;
 
        cmd = buf;
        cmd->id = cpu_to_le16(id);
@@ -73,7 +77,11 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                        goto out;
                }
 
-               msleep(1);
+               poll_count++;
+               if (poll_count < WL1271_CMD_FAST_POLL_COUNT)
+                       udelay(10);
+               else
+                       msleep(1);
 
                intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
        }
@@ -249,7 +257,36 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
        return ret;
 }
 
-int wl1271_cmd_join(struct wl1271 *wl)
+/*
+ * Poll the mailbox event field until any of the bits in the mask is set or a
+ * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
+ */
+static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
+{
+       u32 events_vector, event;
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
+
+       do {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               msleep(1);
+
+               /* read from both event fields */
+               wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
+                           sizeof(events_vector), false);
+               event = events_vector & mask;
+               wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
+                           sizeof(events_vector), false);
+               event |= events_vector & mask;
+       } while (!event);
+
+       return 0;
+}
+
+int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
 {
        static bool do_cal = true;
        struct wl1271_cmd_join *join;
@@ -280,30 +317,13 @@ int wl1271_cmd_join(struct wl1271 *wl)
 
        join->rx_config_options = cpu_to_le32(wl->rx_config);
        join->rx_filter_options = cpu_to_le32(wl->rx_filter);
-       join->bss_type = wl->bss_type;
+       join->bss_type = bss_type;
+       join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
 
-       /*
-        * FIXME: disable temporarily all filters because after commit
-        * 9cef8737 "mac80211: fix managed mode BSSID handling" broke
-        * association. The filter logic needs to be implemented properly
-        * and once that is done, this hack can be removed.
-        */
-       join->rx_config_options = cpu_to_le32(0);
-       join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER);
-
-       if (wl->band == IEEE80211_BAND_2GHZ)
-               join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS   |
-                                                  CONF_HW_BIT_RATE_2MBPS   |
-                                                  CONF_HW_BIT_RATE_5_5MBPS |
-                                                  CONF_HW_BIT_RATE_11MBPS);
-       else {
+       if (wl->band == IEEE80211_BAND_5GHZ)
                join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
-               join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS  |
-                                                  CONF_HW_BIT_RATE_12MBPS |
-                                                  CONF_HW_BIT_RATE_24MBPS);
-       }
 
-       join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT);
+       join->beacon_interval = cpu_to_le16(wl->beacon_int);
        join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
 
        join->channel = wl->channel;
@@ -320,8 +340,7 @@ int wl1271_cmd_join(struct wl1271 *wl)
 
        /* reset TX security counters */
        wl->tx_security_last_seq = 0;
-       wl->tx_security_seq_16 = 0;
-       wl->tx_security_seq_32 = 0;
+       wl->tx_security_seq = 0;
 
        ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
        if (ret < 0) {
@@ -329,11 +348,9 @@ int wl1271_cmd_join(struct wl1271 *wl)
                goto out_free;
        }
 
-       /*
-        * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
-        * simplify locking we just sleep instead, for now
-        */
-       msleep(10);
+       ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
+       if (ret < 0)
+               wl1271_error("cmd join event completion error");
 
 out_free:
        kfree(join);
@@ -465,7 +482,7 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
        if (ret < 0) {
                wl1271_error("tx %s cmd for channel %d failed",
                             enable ? "start" : "stop", cmd->channel);
-               return ret;
+               goto out;
        }
 
        wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
@@ -499,7 +516,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
        ps_params->ps_mode = ps_mode;
        ps_params->send_null_data = send;
        ps_params->retries = 5;
-       ps_params->hang_over_period = 128;
+       ps_params->hang_over_period = 1;
        ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
 
        ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
@@ -549,25 +566,29 @@ out:
        return ret;
 }
 
-int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
-                   u8 active_scan, u8 high_prio, u8 band,
-                   u8 probe_requests)
+int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
+                   const u8 *ie, size_t ie_len, u8 active_scan,
+                   u8 high_prio, u8 band, u8 probe_requests)
 {
 
        struct wl1271_cmd_trigger_scan_to *trigger = NULL;
        struct wl1271_cmd_scan *params = NULL;
        struct ieee80211_channel *channels;
+       u32 rate;
        int i, j, n_ch, ret;
        u16 scan_options = 0;
        u8 ieee_band;
 
-       if (band == WL1271_SCAN_BAND_2_4_GHZ)
+       if (band == WL1271_SCAN_BAND_2_4_GHZ) {
                ieee_band = IEEE80211_BAND_2GHZ;
-       else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled())
+               rate = wl->conf.tx.basic_rate;
+       } else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) {
                ieee_band = IEEE80211_BAND_2GHZ;
-       else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled())
+               rate = wl->conf.tx.basic_rate;
+       } else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) {
                ieee_band = IEEE80211_BAND_5GHZ;
-       else
+               rate = wl->conf.tx.basic_rate_5;
+       } else
                return -EINVAL;
 
        if (wl->hw->wiphy->bands[ieee_band]->channels == NULL)
@@ -594,8 +615,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
        params->params.scan_options = cpu_to_le16(scan_options);
 
        params->params.num_probe_requests = probe_requests;
-       /* Let the fw autodetect suitable tx_rate for probes */
-       params->params.tx_rate = 0;
+       params->params.tx_rate = cpu_to_le32(rate);
        params->params.tid_trigger = 0;
        params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG;
 
@@ -622,12 +642,13 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 
        params->params.num_channels = j;
 
-       if (len && ssid) {
-               params->params.ssid_len = len;
-               memcpy(params->params.ssid, ssid, len);
+       if (ssid_len && ssid) {
+               params->params.ssid_len = ssid_len;
+               memcpy(params->params.ssid, ssid, ssid_len);
        }
 
-       ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band);
+       ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
+                                        ie, ie_len, ieee_band);
        if (ret < 0) {
                wl1271_error("PROBE request template failed");
                goto out;
@@ -658,9 +679,9 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
                        wl->scan.active = active_scan;
                        wl->scan.high_prio = high_prio;
                        wl->scan.probe_requests = probe_requests;
-                       if (len && ssid) {
-                               wl->scan.ssid_len = len;
-                               memcpy(wl->scan.ssid, ssid, len);
+                       if (ssid_len && ssid) {
+                               wl->scan.ssid_len = ssid_len;
+                               memcpy(wl->scan.ssid, ssid, ssid_len);
                        } else
                                wl->scan.ssid_len = 0;
                }
@@ -675,11 +696,12 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
 
 out:
        kfree(params);
+       kfree(trigger);
        return ret;
 }
 
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-                           void *buf, size_t buf_len)
+                           void *buf, size_t buf_len, int index, u32 rates)
 {
        struct wl1271_cmd_template_set *cmd;
        int ret = 0;
@@ -697,9 +719,10 @@ int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
 
        cmd->len = cpu_to_le16(buf_len);
        cmd->template_type = template_id;
-       cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates);
+       cmd->enabled_rates = cpu_to_le32(rates);
        cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit;
        cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit;
+       cmd->index = index;
 
        if (buf)
                memcpy(cmd->template_data, buf, buf_len);
@@ -717,155 +740,129 @@ out:
        return ret;
 }
 
-static int wl1271_build_basic_rates(u8 *rates, u8 band)
+int wl1271_cmd_build_null_data(struct wl1271 *wl)
 {
-       u8 index = 0;
-
-       if (band == IEEE80211_BAND_2GHZ) {
-               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;
-       } else if (band == IEEE80211_BAND_5GHZ) {
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
-       } else {
-               wl1271_error("build_basic_rates invalid band: %d", band);
-       }
+       struct sk_buff *skb = NULL;
+       int size;
+       void *ptr;
+       int ret = -ENOMEM;
 
-       return index;
-}
 
-static int wl1271_build_extended_rates(u8 *rates, u8 band)
-{
-       u8 index = 0;
-
-       if (band == IEEE80211_BAND_2GHZ) {
-               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;
-       } else if (band == IEEE80211_BAND_5GHZ) {
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB;
-               rates[index++] =
-                       IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB;
+       if (wl->bss_type == BSS_TYPE_IBSS) {
+               size = sizeof(struct wl12xx_null_data_template);
+               ptr = NULL;
        } else {
-               wl1271_error("build_basic_rates invalid band: %d", band);
+               skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
+               if (!skb)
+                       goto out;
+               size = skb->len;
+               ptr = skb->data;
        }
 
-       return index;
+       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
+                                     WL1271_RATE_AUTOMATIC);
+
+out:
+       dev_kfree_skb(skb);
+       if (ret)
+               wl1271_warning("cmd buld null data failed %d", ret);
+
+       return ret;
+
 }
 
-int wl1271_cmd_build_null_data(struct wl1271 *wl)
+int wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
 {
-       struct wl12xx_null_data_template template;
+       struct sk_buff *skb = NULL;
+       int ret = -ENOMEM;
 
-       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);
-       }
+       skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
+       if (!skb)
+               goto out;
+
+       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
+                                     skb->data, skb->len,
+                                     CMD_TEMPL_KLV_IDX_NULL_DATA,
+                                     WL1271_RATE_AUTOMATIC);
 
-       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);
+out:
+       dev_kfree_skb(skb);
+       if (ret)
+               wl1271_warning("cmd build klv null data failed %d", ret);
 
-       return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template,
-                                      sizeof(template));
+       return ret;
 
 }
 
 int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
 {
-       struct wl12xx_ps_poll_template template;
-
-       memcpy(template.bssid, wl->bssid, ETH_ALEN);
-       memcpy(template.ta, wl->mac_addr, ETH_ALEN);
-
-       /* aid in PS-Poll has its two MSBs each set to 1 */
-       template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid);
+       struct sk_buff *skb;
+       int ret = 0;
 
-       template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
+       skb = ieee80211_pspoll_get(wl->hw, wl->vif);
+       if (!skb)
+               goto out;
 
-       return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template,
-                                      sizeof(template));
+       ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
+                                     skb->len, 0, wl->basic_rate);
 
+out:
+       dev_kfree_skb(skb);
+       return ret;
 }
 
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
-                              u8 band)
+int wl1271_cmd_build_probe_req(struct wl1271 *wl,
+                              const u8 *ssid, size_t ssid_len,
+                              const u8 *ie, size_t ie_len, u8 band)
 {
-       struct wl12xx_probe_req_template template;
-       struct wl12xx_ie_rates *rates;
-       char *ptr;
-       u16 size;
+       struct sk_buff *skb;
        int ret;
 
-       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 = wl1271_build_basic_rates(rates->rates, band);
-       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 = wl1271_build_extended_rates(rates->rates, band);
-       size += sizeof(struct wl12xx_ie_header) + rates->header.len;
-
-       wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+       skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
+                                    ie, ie_len);
+       if (!skb) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
 
        if (band == IEEE80211_BAND_2GHZ)
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                             &template, size);
+                                             skb->data, skb->len, 0,
+                                             wl->conf.tx.basic_rate);
        else
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             &template, size);
+                                             skb->data, skb->len, 0,
+                                             wl->conf.tx.basic_rate_5);
+
+out:
+       dev_kfree_skb(skb);
        return ret;
 }
 
+int wl1271_build_qos_null_data(struct wl1271 *wl)
+{
+       struct ieee80211_qos_hdr template;
+
+       memset(&template, 0, sizeof(template));
+
+       memcpy(template.addr1, wl->bssid, ETH_ALEN);
+       memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
+       memcpy(template.addr3, wl->bssid, ETH_ALEN);
+
+       template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                            IEEE80211_STYPE_QOS_NULLFUNC |
+                                            IEEE80211_FCTL_TODS);
+
+       /* FIXME: not sure what priority to use here */
+       template.qos_ctrl = cpu_to_le16(0);
+
+       return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
+                                      sizeof(template), 0,
+                                      WL1271_RATE_AUTOMATIC);
+}
+
 int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id)
 {
        struct wl1271_cmd_set_keys *cmd;
@@ -976,6 +973,10 @@ int wl1271_cmd_disconnect(struct wl1271 *wl)
                goto out_free;
        }
 
+       ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
+       if (ret < 0)
+               wl1271_error("cmd disconnect event completion error");
+
 out_free:
        kfree(cmd);
 
index 2dc06c73532b8be497daf62fcc308b869a1ab4ba..f2820b42a943f8e952a54410d1adc566e65484ae 100644 (file)
@@ -33,7 +33,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
                    size_t res_len);
 int wl1271_cmd_general_parms(struct wl1271 *wl);
 int wl1271_cmd_radio_parms(struct wl1271 *wl);
-int wl1271_cmd_join(struct wl1271 *wl);
+int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
 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);
@@ -41,15 +41,18 @@ int wl1271_cmd_data_path(struct wl1271 *wl, bool enable);
 int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
 int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
                           size_t len);
-int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len,
-                   u8 active_scan, u8 high_prio, u8 band,
-                   u8 probe_requests);
+int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
+                   const u8 *ie, size_t ie_len, u8 active_scan,
+                   u8 high_prio, u8 band, u8 probe_requests);
 int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
-                           void *buf, size_t buf_len);
+                           void *buf, size_t buf_len, int index, u32 rates);
 int wl1271_cmd_build_null_data(struct wl1271 *wl);
 int wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid);
-int wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len,
-                              u8 band);
+int wl1271_cmd_build_probe_req(struct wl1271 *wl,
+                              const u8 *ssid, size_t ssid_len,
+                              const u8 *ie, size_t ie_len, u8 band);
+int wl1271_build_qos_null_data(struct wl1271 *wl);
+int wl1271_cmd_build_klv_null_data(struct wl1271 *wl);
 int wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id);
 int wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
                       u8 key_size, const u8 *key, const u8 *addr,
@@ -99,6 +102,11 @@ enum wl1271_commands {
 
 #define MAX_CMD_PARAMS 572
 
+enum {
+       CMD_TEMPL_KLV_IDX_NULL_DATA = 0,
+       CMD_TEMPL_KLV_IDX_MAX = 4
+};
+
 enum cmd_templ {
        CMD_TEMPL_NULL_DATA = 0,
        CMD_TEMPL_BEACON,
@@ -121,6 +129,7 @@ enum cmd_templ {
 /* unit ms */
 #define WL1271_COMMAND_TIMEOUT     2000
 #define WL1271_CMD_TEMPL_MAX_SIZE  252
+#define WL1271_EVENT_TIMEOUT       750
 
 struct wl1271_cmd_header {
        __le16 id;
@@ -243,6 +252,8 @@ struct cmd_enabledisable_path {
        u8 padding[3];
 } __attribute__ ((packed));
 
+#define WL1271_RATE_AUTOMATIC  0
+
 struct wl1271_cmd_template_set {
        struct wl1271_cmd_header header;
 
@@ -509,6 +520,8 @@ enum wl1271_disconnect_type {
 };
 
 struct wl1271_cmd_disconnect {
+       struct wl1271_cmd_header header;
+
        __le32 rx_config_options;
        __le32 rx_filter_options;
 
index 6f9e75cc5640b5c772d66fb47a2a2bdd21897b09..d046d044b5bd8a640acb99bfcc08259e2654b1f6 100644 (file)
@@ -65,110 +65,344 @@ enum {
        CONF_HW_RATE_INDEX_MAX     = CONF_HW_RATE_INDEX_54MBPS,
 };
 
-struct conf_sg_settings {
+enum {
+       CONF_HW_RXTX_RATE_MCS7 = 0,
+       CONF_HW_RXTX_RATE_MCS6,
+       CONF_HW_RXTX_RATE_MCS5,
+       CONF_HW_RXTX_RATE_MCS4,
+       CONF_HW_RXTX_RATE_MCS3,
+       CONF_HW_RXTX_RATE_MCS2,
+       CONF_HW_RXTX_RATE_MCS1,
+       CONF_HW_RXTX_RATE_MCS0,
+       CONF_HW_RXTX_RATE_54,
+       CONF_HW_RXTX_RATE_48,
+       CONF_HW_RXTX_RATE_36,
+       CONF_HW_RXTX_RATE_24,
+       CONF_HW_RXTX_RATE_22,
+       CONF_HW_RXTX_RATE_18,
+       CONF_HW_RXTX_RATE_12,
+       CONF_HW_RXTX_RATE_11,
+       CONF_HW_RXTX_RATE_9,
+       CONF_HW_RXTX_RATE_6,
+       CONF_HW_RXTX_RATE_5_5,
+       CONF_HW_RXTX_RATE_2,
+       CONF_HW_RXTX_RATE_1,
+       CONF_HW_RXTX_RATE_MAX,
+       CONF_HW_RXTX_RATE_UNSUPPORTED = 0xff
+};
+
+enum {
+       CONF_SG_DISABLE = 0,
+       CONF_SG_PROTECTIVE,
+       CONF_SG_OPPORTUNISTIC
+};
+
+enum {
        /*
-        * Defines the PER threshold in PPM of the BT voice of which reaching
-        * this value will trigger raising the priority of the BT voice by
-        * the BT IP until next NFS sample interval time as defined in
-        * nfs_sample_interval.
+        * PER threshold in PPM of the BT voice
         *
-        * Unit: PER value in PPM (parts per million)
-        * #Error_packets / #Total_packets
+        * Range: 0 - 10000000
+        */
+       CONF_SG_BT_PER_THRESHOLD = 0,
 
-        * Range: u32
+       /*
+        * Number of consequent RX_ACTIVE activities to override BT voice
+        * frames to ensure WLAN connection
+        *
+        * Range: 0 - 100
+        */
+       CONF_SG_HV3_MAX_OVERRIDE,
+
+       /*
+        * Defines the PER threshold of the BT voice
+        *
+        * Range: 0 - 65000
+        */
+       CONF_SG_BT_NFS_SAMPLE_INTERVAL,
+
+       /*
+        * Defines the load ratio of BT
+        *
+        * Range: 0 - 100 (%)
+        */
+       CONF_SG_BT_LOAD_RATIO,
+
+       /*
+        * Defines whether the SG will force WLAN host to enter/exit PSM
+        *
+        * Range: 1 - SG can force, 0 - host handles PSM
+        */
+       CONF_SG_AUTO_PS_MODE,
+
+       /*
+        * Compensation percentage of probe requests when scan initiated
+        * during BT voice/ACL link.
+        *
+        * Range: 0 - 255 (%)
+        */
+       CONF_SG_AUTO_SCAN_PROBE_REQ,
+
+       /*
+        * Compensation percentage of probe requests when active scan initiated
+        * during BT voice
+        *
+        * Range: 0 - 255 (%)
+        */
+       CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3,
+
+       /*
+        * Defines antenna configuration (single/dual antenna)
+        *
+        * Range: 0 - single antenna, 1 - dual antenna
+        */
+       CONF_SG_ANTENNA_CONFIGURATION,
+
+       /*
+        * The threshold (percent) of max consequtive beacon misses before
+        * increasing priority of beacon reception.
+        *
+        * Range: 0 - 100 (%)
+        */
+       CONF_SG_BEACON_MISS_PERCENT,
+
+       /*
+        * The rate threshold below which receiving a data frame from the AP
+        * will increase the priority of the data frame above BT traffic.
+        *
+        * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54
+        */
+       CONF_SG_RATE_ADAPT_THRESH,
+
+       /*
+        * Not used currently.
+        *
+        * Range: 0
+        */
+       CONF_SG_RATE_ADAPT_SNR,
+
+       /*
+        * Configure the min and max time BT gains the antenna
+        * in WLAN PSM / BT master basic rate
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR,
+       CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR,
+
+       /*
+        * The time after it expires no new WLAN trigger frame is trasmitted
+        * in WLAN PSM / BT master basic rate
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR,
+
+       /*
+        * Configure the min and max time BT gains the antenna
+        * in WLAN PSM / BT slave basic rate
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR,
+       CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR,
+
+       /*
+        * The time after it expires no new WLAN trigger frame is trasmitted
+        * in WLAN PSM / BT slave basic rate
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR,
+
+       /*
+        * Configure the min and max time BT gains the antenna
+        * in WLAN PSM / BT master EDR
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR,
+       CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR,
+
+       /*
+        * The time after it expires no new WLAN trigger frame is trasmitted
+        * in WLAN PSM / BT master EDR
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR,
+
+       /*
+        * Configure the min and max time BT gains the antenna
+        * in WLAN PSM / BT slave EDR
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR,
+       CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR,
+
+       /*
+        * The time after it expires no new WLAN trigger frame is trasmitted
+        * in WLAN PSM / BT slave EDR
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR,
+
+       /*
+        * RX guard time before the beginning of a new BT voice frame during
+        * which no new WLAN trigger frame is transmitted.
+        *
+        * Range: 0 - 100000 (us)
+        */
+       CONF_SG_RXT,
+
+       /*
+        * TX guard time before the beginning of a new BT voice frame during
+        * which no new WLAN frame is transmitted.
+        *
+        * Range: 0 - 100000 (us)
+        */
+
+       CONF_SG_TXT,
+
+       /*
+        * Enable adaptive RXT/TXT algorithm. If disabled, the host values
+        * will be utilized.
+        *
+        * Range: 0 - disable, 1 - enable
+        */
+       CONF_SG_ADAPTIVE_RXT_TXT,
+
+       /*
+        * The used WLAN legacy service period during active BT ACL link
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_PS_POLL_TIMEOUT,
+
+       /*
+        * The used WLAN UPSD service period during active BT ACL link
+        *
+        * Range: 0 - 255 (ms)
         */
-       u32 per_threshold;
+       CONF_SG_UPSD_TIMEOUT,
 
        /*
-        * This value is an absolute time in micro-seconds to limit the
-        * maximum scan duration compensation while in SG
+        * Configure the min and max time BT gains the antenna
+        * in WLAN Active / BT master EDR
+        *
+        * Range: 0 - 255 (ms)
         */
-       u32 max_scan_compensation_time;
+       CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR,
+       CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR,
 
-       /* Defines the PER threshold of the BT voice of which reaching this
-        * value will trigger raising the priority of the BT voice until next
-        * NFS sample interval time as defined in sample_interval.
+       /*
+        * The maximum time WLAN can gain the antenna for
+        * in WLAN Active / BT master EDR
         *
-        * Unit: msec
-        * Range: 1-65000
+        * Range: 0 - 255 (ms)
         */
-       u16 nfs_sample_interval;
+       CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR,
 
        /*
-        * Defines the load ratio for the BT.
-        * The WLAN ratio is: 100 - load_ratio
+        * Configure the min and max time BT gains the antenna
+        * in WLAN Active / BT slave EDR
         *
-        * Unit: Percent
-        * Range: 0-100
+        * Range: 0 - 255 (ms)
         */
-       u8 load_ratio;
+       CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR,
+       CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR,
 
        /*
-        * true - Co-ex is allowed to enter/exit P.S automatically and
-        *        transparently to the host
+        * The maximum time WLAN can gain the antenna for
+        * in WLAN Active / BT slave EDR
         *
-        * false - Co-ex is disallowed to enter/exit P.S and will trigger an
-        *         event to the host to notify for the need to enter/exit P.S
-        *         due to BT change state
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR,
+
+       /*
+        * Configure the min and max time BT gains the antenna
+        * in WLAN Active / BT basic rate
+        *
+        * Range: 0 - 255 (ms)
+        */
+       CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR,
+       CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR,
+
+       /*
+        * The maximum time WLAN can gain the antenna for
+        * in WLAN Active / BT basic rate
         *
+        * Range: 0 - 255 (ms)
         */
-       u8 auto_ps_mode;
+       CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR,
 
        /*
-        * This parameter defines the compensation percentage of num of probe
-        * requests in case scan is initiated during BT voice/BT ACL
-        * guaranteed link.
+        * Compensation percentage of WLAN passive scan window if initiated
+        * during BT voice
         *
-        * Unit: Percent
-        * Range: 0-255 (0 - No compensation)
+        * Range: 0 - 1000 (%)
         */
-       u8 probe_req_compensation;
+       CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3,
 
        /*
-        * This parameter defines the compensation percentage of scan window
-        * size in case scan is initiated during BT voice/BT ACL Guaranteed
-        * link.
+        * Compensation percentage of WLAN passive scan window if initiated
+        * during BT A2DP
         *
-        * Unit: Percent
-        * Range: 0-255 (0 - No compensation)
+        * Range: 0 - 1000 (%)
         */
-       u8 scan_window_compensation;
+       CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP,
 
        /*
-        * Defines the antenna configuration.
+        * Fixed time ensured for BT traffic to gain the antenna during WLAN
+        * passive scan.
         *
-        * Range: 0 - Single Antenna; 1 - Dual Antenna
+        * Range: 0 - 1000 ms
         */
-       u8 antenna_config;
+       CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME,
 
        /*
-        * The percent out of the Max consecutive beacon miss roaming trigger
-        * which is the threshold for raising the priority of beacon
-        * reception.
+        * Fixed time ensured for WLAN traffic to gain the antenna during WLAN
+        * passive scan.
         *
-        * Range: 1-100
-        * N = MaxConsecutiveBeaconMiss
-        * P = coexMaxConsecutiveBeaconMissPrecent
-        * Threshold = MIN( N-1, round(N * P / 100))
+        * Range: 0 - 1000 ms
         */
-       u8 beacon_miss_threshold;
+       CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME,
 
        /*
-        * The RX rate threshold below which rate adaptation is assumed to be
-        * occurring at the AP which will raise priority for ACTIVE_RX and RX
-        * SP.
+        * Number of consequent BT voice frames not interrupted by WLAN
         *
-        * Range: HW_BIT_RATE_*
+        * Range: 0 - 100
         */
-       u32 rate_adaptation_threshold;
+       CONF_SG_HV3_MAX_SERVED,
 
        /*
-        * The SNR above which the RX rate threshold indicating AP rate
-        * adaptation is valid
+        * Protection time of the DHCP procedure.
         *
-        * Range: -128 - 127
+        * Range: 0 - 100000 (ms)
         */
-       s8 rate_adaptation_snr;
+       CONF_SG_DHCP_TIME,
+
+       /*
+        * Compensation percentage of WLAN active scan window if initiated
+        * during BT A2DP
+        *
+        * Range: 0 - 1000 (%)
+        */
+       CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP,
+       CONF_SG_TEMP_PARAM_1,
+       CONF_SG_TEMP_PARAM_2,
+       CONF_SG_TEMP_PARAM_3,
+       CONF_SG_TEMP_PARAM_4,
+       CONF_SG_TEMP_PARAM_5,
+       CONF_SG_PARAMS_MAX,
+       CONF_SG_PARAMS_ALL = 0xff
+};
+
+struct conf_sg_settings {
+       u32 params[CONF_SG_PARAMS_MAX];
+       u8 state;
 };
 
 enum conf_rx_queue_type {
@@ -440,6 +674,19 @@ struct conf_tx_settings {
         */
        u16 tx_compl_threshold;
 
+       /*
+        * The rate used for control messages and scanning on the 2.4GHz band
+        *
+        * Range: CONF_HW_BIT_RATE_* bit mask
+        */
+       u32 basic_rate;
+
+       /*
+        * The rate used for control messages and scanning on the 5GHz band
+        *
+        * Range: CONF_HW_BIT_RATE_* bit mask
+        */
+       u32 basic_rate_5;
 };
 
 enum {
@@ -509,65 +756,6 @@ enum {
        CONF_TRIG_EVENT_DIR_BIDIR
 };
 
-
-struct conf_sig_trigger {
-       /*
-        * The RSSI / SNR threshold value.
-        *
-        * FIXME: what is the range?
-        */
-       s16 threshold;
-
-       /*
-        * Minimum delay between two trigger events for this trigger in ms.
-        *
-        * Range: 0 - 60000
-        */
-       u16 pacing;
-
-       /*
-        * The measurement data source for this trigger.
-        *
-        * Range: CONF_TRIG_METRIC_*
-        */
-       u8 metric;
-
-       /*
-        * The trigger type of this trigger.
-        *
-        * Range: CONF_TRIG_EVENT_TYPE_*
-        */
-       u8 type;
-
-       /*
-        * The direction of the trigger.
-        *
-        * Range: CONF_TRIG_EVENT_DIR_*
-        */
-       u8 direction;
-
-       /*
-        * Hysteresis range of the trigger around the threshold (in dB)
-        *
-        * Range: u8
-        */
-       u8 hysteresis;
-
-       /*
-        * Index of the trigger rule.
-        *
-        * Range: 0 - CONF_MAX_RSSI_SNR_TRIGGERS-1
-        */
-       u8 index;
-
-       /*
-        * Enable / disable this rule (to use for clearing rules.)
-        *
-        * Range: 1 - Enabled, 2 - Not enabled
-        */
-       u8 enable;
-};
-
 struct conf_sig_weights {
 
        /*
@@ -685,12 +873,6 @@ struct conf_conn_settings {
         */
        u8 ps_poll_threshold;
 
-       /*
-        * Configuration of signal (rssi/snr) triggers.
-        */
-       u8 sig_trigger_count;
-       struct conf_sig_trigger sig_trigger[CONF_MAX_RSSI_SNR_TRIGGERS];
-
        /*
         * Configuration of signal average weights.
         */
@@ -721,6 +903,22 @@ struct conf_conn_settings {
         * Range 0 - 255
         */
        u8 psm_entry_retries;
+
+       /*
+        *
+        * Specifies the interval of the connection keep-alive null-func
+        * frame in ms.
+        *
+        * Range: 1000 - 3600000
+        */
+       u32 keep_alive_interval;
+
+       /*
+        * Maximum listen interval supported by the driver in units of beacons.
+        *
+        * Range: u16
+        */
+       u8 max_listen_interval;
 };
 
 enum {
@@ -782,6 +980,43 @@ struct conf_pm_config_settings {
        bool host_fast_wakeup_support;
 };
 
+struct conf_roam_trigger_settings {
+       /*
+        * The minimum interval between two trigger events.
+        *
+        * Range: 0 - 60000 ms
+        */
+       u16 trigger_pacing;
+
+       /*
+        * The weight for rssi/beacon average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_rssi_beacon;
+
+       /*
+        * The weight for rssi/data frame average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_rssi_data;
+
+       /*
+        * The weight for snr/beacon average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_snr_beacon;
+
+       /*
+        * The weight for snr/data frame average calculation
+        *
+        * Range: 0 - 255
+        */
+       u8 avg_weight_snr_data;
+};
+
 struct conf_drv_settings {
        struct conf_sg_settings sg;
        struct conf_rx_settings rx;
@@ -790,6 +1025,7 @@ struct conf_drv_settings {
        struct conf_init_settings init;
        struct conf_itrim_settings itrim;
        struct conf_pm_config_settings pm_config;
+       struct conf_roam_trigger_settings roam_trigger;
 };
 
 #endif
index 3f7ff8d0cf5acc3f2c48e7eb820bc034aff6bb05..c239ef4d0b8dedf5932eac4c041073e05a90e782 100644 (file)
@@ -29,6 +29,7 @@
 #include "wl1271.h"
 #include "wl1271_acx.h"
 #include "wl1271_ps.h"
+#include "wl1271_io.h"
 
 /* ms */
 #define WL1271_DEBUGFS_STATS_LIFETIME 1000
@@ -277,13 +278,10 @@ static ssize_t gpio_power_write(struct file *file,
                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);
-       }
+       if (value)
+               wl1271_power_on(wl);
+       else
+               wl1271_power_off(wl);
 
 out:
        mutex_unlock(&wl->mutex);
index 7468ef10194bef9a1974f84b09036e3954a831ed..cf37aa6eb13725cd1f0ef2cb1dd5d70bd1ed69f2 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "wl1271.h"
 #include "wl1271_reg.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 #include "wl1271_event.h"
 #include "wl1271_ps.h"
 static int wl1271_event_scan_complete(struct wl1271 *wl,
                                      struct event_mailbox *mbox)
 {
-       int size = sizeof(struct wl12xx_probe_req_template);
        wl1271_debug(DEBUG_EVENT, "status: 0x%x",
                     mbox->scheduled_scan_status);
 
        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);
                        /* 2.4 GHz band scanned, scan 5 GHz band, pretend
                         * to the wl1271_cmd_scan function that we are not
                         * scanning as it checks that.
                         */
                        clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
+                       /* FIXME: ie missing! */
                        wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
+                                               NULL, 0,
                                                wl->scan.active,
                                                wl->scan.high_prio,
                                                WL1271_SCAN_BAND_5_GHZ,
                                                wl->scan.probe_requests);
                } else {
-                       if (wl->scan.state == WL1271_SCAN_BAND_2_4_GHZ)
-                               wl1271_cmd_template_set(wl,
-                                               CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                               NULL, size);
-                       else
-                               wl1271_cmd_template_set(wl,
-                                               CMD_TEMPL_CFG_PROBE_REQ_5,
-                                               NULL, size);
-
                        mutex_unlock(&wl->mutex);
                        ieee80211_scan_completed(wl->hw, false);
                        mutex_lock(&wl->mutex);
@@ -92,16 +81,9 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
                        ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
                                                 true);
                } else {
-                       wl1271_error("PSM entry failed, giving up.\n");
-                       /* FIXME: this may need to be reconsidered. for now it
-                          is not possible to indicate to the mac80211
-                          afterwards that PSM entry failed. To maximize
-                          functionality (receiving data and remaining
-                          associated) make sure that we are in sync with the
-                          AP in regard of PSM mode. */
-                       ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
-                                                false);
+                       wl1271_info("No ack to nullfunc from AP.");
                        wl->psm_entry_retry = 0;
+                       *beacon_loss = true;
                }
                break;
        case EVENT_ENTER_POWER_SAVE_SUCCESS:
@@ -143,6 +125,24 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
        return ret;
 }
 
+static void wl1271_event_rssi_trigger(struct wl1271 *wl,
+                                     struct event_mailbox *mbox)
+{
+       enum nl80211_cqm_rssi_threshold_event event;
+       s8 metric = mbox->rssi_snr_trigger_metric[0];
+
+       wl1271_debug(DEBUG_EVENT, "RSSI trigger metric: %d", metric);
+
+       if (metric <= wl->rssi_thold)
+               event = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
+       else
+               event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
+
+       if (event != wl->last_rssi_event)
+               ieee80211_cqm_rssi_notify(wl->vif, event, GFP_KERNEL);
+       wl->last_rssi_event = event;
+}
+
 static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
 {
        wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
@@ -172,10 +172,13 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
         * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
         * filtering) is enabled. Without PSM, the stack will receive all
         * beacons and can detect beacon loss by itself.
+        *
+        * As there's possibility that the driver disables PSM before receiving
+        * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
+        *
         */
-       if (vector & BSS_LOSE_EVENT_ID &&
-           test_bit(WL1271_FLAG_PSM, &wl->flags)) {
-               wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+       if (vector & BSS_LOSE_EVENT_ID) {
+               wl1271_info("Beacon loss detected.");
 
                /* indicate to the stack, that beacons have been lost */
                beacon_loss = true;
@@ -188,17 +191,15 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        return ret;
        }
 
-       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
-                  be taken that nothing more is done after this function
-                  returns. */
-               mutex_unlock(&wl->mutex);
-               ieee80211_beacon_loss(wl->vif);
-               mutex_lock(&wl->mutex);
+       if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
+               wl1271_debug(DEBUG_EVENT, "RSSI_SNR_TRIGGER_0_EVENT");
+               if (wl->vif)
+                       wl1271_event_rssi_trigger(wl, mbox);
        }
 
+       if (wl->vif && beacon_loss)
+               ieee80211_connection_loss(wl->vif);
+
        return 0;
 }
 
index 278f9206aa5623ad6d9b08a93b066bec8d97de91..58371008f270f29b375151570d8dd597e02a350a 100644 (file)
  */
 
 enum {
+       RSSI_SNR_TRIGGER_0_EVENT_ID              = BIT(0),
+       RSSI_SNR_TRIGGER_1_EVENT_ID              = BIT(1),
+       RSSI_SNR_TRIGGER_2_EVENT_ID              = BIT(2),
+       RSSI_SNR_TRIGGER_3_EVENT_ID              = BIT(3),
+       RSSI_SNR_TRIGGER_4_EVENT_ID              = BIT(4),
+       RSSI_SNR_TRIGGER_5_EVENT_ID              = BIT(5),
+       RSSI_SNR_TRIGGER_6_EVENT_ID              = BIT(6),
+       RSSI_SNR_TRIGGER_7_EVENT_ID              = BIT(7),
        MEASUREMENT_START_EVENT_ID               = BIT(8),
        MEASUREMENT_COMPLETE_EVENT_ID            = BIT(9),
        SCAN_COMPLETE_EVENT_ID                   = BIT(10),
index d189e8fe05a645a268f4a315b5b0798b44ca04af..4447af1557f5c2af3d95ff7576118e543b8e0ea1 100644 (file)
@@ -52,50 +52,65 @@ static int wl1271_init_hwenc_config(struct wl1271 *wl)
 
 int wl1271_init_templates_config(struct wl1271 *wl)
 {
-       int ret;
+       int ret, i;
 
        /* send empty templates for fw memory reservation */
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
-                                     sizeof(struct wl12xx_probe_req_template));
+                                     sizeof(struct wl12xx_probe_req_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        if (wl1271_11a_enabled()) {
+               size_t size = sizeof(struct wl12xx_probe_req_template);
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                               NULL,
-                               sizeof(struct wl12xx_probe_req_template));
+                                             NULL, size, 0,
+                                             WL1271_RATE_AUTOMATIC);
                if (ret < 0)
                        return ret;
        }
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
-                                     sizeof(struct wl12xx_null_data_template));
+                                     sizeof(struct wl12xx_null_data_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
-                                     sizeof(struct wl12xx_ps_poll_template));
+                                     sizeof(struct wl12xx_ps_poll_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
                                      sizeof
-                                     (struct wl12xx_qos_null_data_template));
+                                     (struct wl12xx_qos_null_data_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
                                      sizeof
-                                     (struct wl12xx_probe_resp_template));
+                                     (struct wl12xx_probe_resp_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
                                      sizeof
-                                     (struct wl12xx_beacon_template));
+                                     (struct wl12xx_beacon_template),
+                                     0, WL1271_RATE_AUTOMATIC);
        if (ret < 0)
                return ret;
 
+       for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
+               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
+                                             WL1271_CMD_TEMPL_MAX_SIZE, i,
+                                             WL1271_RATE_AUTOMATIC);
+               if (ret < 0)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -161,11 +176,11 @@ int wl1271_init_pta(struct wl1271 *wl)
 {
        int ret;
 
-       ret = wl1271_acx_sg_enable(wl);
+       ret = wl1271_acx_sg_cfg(wl);
        if (ret < 0)
                return ret;
 
-       ret = wl1271_acx_sg_cfg(wl);
+       ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
        if (ret < 0)
                return ret;
 
@@ -237,7 +252,7 @@ int wl1271_hw_init(struct wl1271 *wl)
                goto out_free_memmap;
 
        /* Initialize connection monitoring thresholds */
-       ret = wl1271_acx_conn_monit_params(wl);
+       ret = wl1271_acx_conn_monit_params(wl, false);
        if (ret < 0)
                goto out_free_memmap;
 
@@ -325,6 +340,24 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
+       /* disable all keep-alive templates */
+       for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
+               ret = wl1271_acx_keep_alive_config(wl, i,
+                                                  ACX_KEEP_ALIVE_TPL_INVALID);
+               if (ret < 0)
+                       goto out_free_memmap;
+       }
+
+       /* disable the keep-alive feature */
+       ret = wl1271_acx_keep_alive_mode(wl, false);
+       if (ret < 0)
+               goto out_free_memmap;
+
+       /* Configure rssi/snr averaging weights */
+       ret = wl1271_acx_rssi_snr_avg_weights(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
        return 0;
 
  out_free_memmap:
index 5cd94d5666c29ac1db5211fbb7af92c526133c25..c8759acef131976d12671bdc3d03d8213824c621 100644 (file)
 
 #include "wl1271.h"
 #include "wl12xx_80211.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 
-static int wl1271_translate_addr(struct wl1271 *wl, int addr)
+#define OCP_CMD_LOOP  32
+
+#define OCP_CMD_WRITE 0x1
+#define OCP_CMD_READ  0x2
+
+#define OCP_READY_MASK  BIT(18)
+#define OCP_STATUS_MASK (BIT(16) | BIT(17))
+
+#define OCP_STATUS_NO_RESP    0x00000
+#define OCP_STATUS_OK         0x10000
+#define OCP_STATUS_REQ_FAILED 0x20000
+#define OCP_STATUS_RESP_ERROR 0x30000
+
+void wl1271_disable_interrupts(struct wl1271 *wl)
 {
-       /*
-        * To translate, first check to which window of addresses the
-        * particular address belongs. Then subtract the starting address
-        * of that window from the address. Then, add offset of the
-        * translated region.
-        *
-        * The translated regions occur next to each other in physical device
-        * memory, so just add the sizes of the preceeding address regions to
-        * get the offset to the new region.
-        *
-        * Currently, only the two first regions are addressed, and the
-        * assumption is that all addresses will fall into either of those
-        * two.
-        */
-       if ((addr >= wl->part.reg.start) &&
-           (addr < wl->part.reg.start + wl->part.reg.size))
-               return addr - wl->part.reg.start + wl->part.mem.size;
-       else
-               return addr - wl->part.mem.start;
+       wl->if_ops->disable_irq(wl);
+}
+
+void wl1271_enable_interrupts(struct wl1271 *wl)
+{
+       wl->if_ops->enable_irq(wl);
 }
 
 /* Set the SPI partitions to access the chip addresses
@@ -117,54 +116,12 @@ int wl1271_set_partition(struct wl1271 *wl,
 
 void wl1271_io_reset(struct wl1271 *wl)
 {
-       wl1271_spi_reset(wl);
+       wl->if_ops->reset(wl);
 }
 
 void wl1271_io_init(struct wl1271 *wl)
 {
-       wl1271_spi_init(wl);
-}
-
-void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
-                     size_t len, bool fixed)
-{
-       wl1271_spi_raw_write(wl, addr, buf, len, fixed);
-}
-
-void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
-                    size_t len, bool fixed)
-{
-       wl1271_spi_raw_read(wl, addr, buf, len, fixed);
-}
-
-void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
-                    bool fixed)
-{
-       int physical;
-
-       physical = wl1271_translate_addr(wl, addr);
-
-       wl1271_spi_raw_read(wl, physical, buf, len, fixed);
-}
-
-void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
-                 bool fixed)
-{
-       int physical;
-
-       physical = wl1271_translate_addr(wl, addr);
-
-       wl1271_spi_raw_write(wl, physical, buf, len, fixed);
-}
-
-u32 wl1271_read32(struct wl1271 *wl, int addr)
-{
-       return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
-}
-
-void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
-{
-       wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
+       wl->if_ops->init(wl);
 }
 
 void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val)
index fa9a0b35788f2e08dfe238a1e07fb852f2f01f0f..bc806c74c63ab4214d70008bb58fa95a22546395 100644 (file)
 #ifndef __WL1271_IO_H__
 #define __WL1271_IO_H__
 
+#include "wl1271_reg.h"
+
+#define HW_ACCESS_MEMORY_MAX_RANGE     0x1FFC0
+
+#define HW_PARTITION_REGISTERS_ADDR     0x1FFC0
+#define HW_PART0_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR)
+#define HW_PART0_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 4)
+#define HW_PART1_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 8)
+#define HW_PART1_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 12)
+#define HW_PART2_SIZE_ADDR              (HW_PARTITION_REGISTERS_ADDR + 16)
+#define HW_PART2_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 20)
+#define HW_PART3_START_ADDR             (HW_PARTITION_REGISTERS_ADDR + 24)
+
+#define HW_ACCESS_REGISTER_SIZE         4
+
+#define HW_ACCESS_PRAM_MAX_RANGE       0x3c000
+
 struct wl1271;
 
+void wl1271_disable_interrupts(struct wl1271 *wl);
+void wl1271_enable_interrupts(struct wl1271 *wl);
+
 void wl1271_io_reset(struct wl1271 *wl);
 void wl1271_io_init(struct wl1271 *wl);
 
-/* Raw target IO, address is not translated */
-void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
-                     size_t len, bool fixed);
-void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
-                    size_t len, bool fixed);
+static inline struct device *wl1271_wl_to_dev(struct wl1271 *wl)
+{
+       return wl->if_ops->dev(wl);
+}
 
-/* Translated target IO */
-void wl1271_read(struct wl1271 *wl, int addr, void *buf, size_t len,
-                    bool fixed);
-void wl1271_write(struct wl1271 *wl, int addr, void *buf, size_t len,
-                     bool fixed);
-u32 wl1271_read32(struct wl1271 *wl, int addr);
-void wl1271_write32(struct wl1271 *wl, int addr, u32 val);
 
-/* Top Register IO */
-void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
-u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
+/* Raw target IO, address is not translated */
+static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf,
+                                   size_t len, bool fixed)
+{
+       wl->if_ops->write(wl, addr, buf, len, fixed);
+}
 
-int wl1271_set_partition(struct wl1271 *wl,
-                        struct wl1271_partition_set *p);
+static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf,
+                                  size_t len, bool fixed)
+{
+       wl->if_ops->read(wl, addr, buf, len, fixed);
+}
 
 static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr)
 {
        wl1271_raw_read(wl, addr, &wl->buffer_32,
                            sizeof(wl->buffer_32), false);
 
-       return wl->buffer_32;
+       return le32_to_cpu(wl->buffer_32);
 }
 
 static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val)
 {
-       wl->buffer_32 = val;
+       wl->buffer_32 = cpu_to_le32(val);
        wl1271_raw_write(wl, addr, &wl->buffer_32,
                             sizeof(wl->buffer_32), false);
 }
+
+/* Translated target IO */
+static inline int wl1271_translate_addr(struct wl1271 *wl, int addr)
+{
+       /*
+        * To translate, first check to which window of addresses the
+        * particular address belongs. Then subtract the starting address
+        * of that window from the address. Then, add offset of the
+        * translated region.
+        *
+        * The translated regions occur next to each other in physical device
+        * memory, so just add the sizes of the preceeding address regions to
+        * get the offset to the new region.
+        *
+        * Currently, only the two first regions are addressed, and the
+        * assumption is that all addresses will fall into either of those
+        * two.
+        */
+       if ((addr >= wl->part.reg.start) &&
+           (addr < wl->part.reg.start + wl->part.reg.size))
+               return addr - wl->part.reg.start + wl->part.mem.size;
+       else
+               return addr - wl->part.mem.start;
+}
+
+static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf,
+                              size_t len, bool fixed)
+{
+       int physical;
+
+       physical = wl1271_translate_addr(wl, addr);
+
+       wl1271_raw_read(wl, physical, buf, len, fixed);
+}
+
+static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf,
+                               size_t len, bool fixed)
+{
+       int physical;
+
+       physical = wl1271_translate_addr(wl, addr);
+
+       wl1271_raw_write(wl, physical, buf, len, fixed);
+}
+
+static inline u32 wl1271_read32(struct wl1271 *wl, int addr)
+{
+       return wl1271_raw_read32(wl, wl1271_translate_addr(wl, addr));
+}
+
+static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val)
+{
+       wl1271_raw_write32(wl, wl1271_translate_addr(wl, addr), val);
+}
+
+static inline void wl1271_power_off(struct wl1271 *wl)
+{
+       wl->if_ops->power(wl, false);
+       clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+}
+
+static inline void wl1271_power_on(struct wl1271 *wl)
+{
+       wl->if_ops->power(wl, true);
+       set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
+}
+
+
+/* Top Register IO */
+void wl1271_top_reg_write(struct wl1271 *wl, int addr, u16 val);
+u16 wl1271_top_reg_read(struct wl1271 *wl, int addr);
+
+int wl1271_set_partition(struct wl1271 *wl,
+                        struct wl1271_partition_set *p);
+
+/* Functions from wl1271_main.c */
+
+int wl1271_register_hw(struct wl1271 *wl);
+void wl1271_unregister_hw(struct wl1271 *wl);
+int wl1271_init_ieee80211(struct wl1271 *wl);
+struct ieee80211_hw *wl1271_alloc_hw(void);
+int wl1271_free_hw(struct wl1271 *wl);
+
 #endif
index 65a1aeba2419116f793a5cfba18ffae7b44839d7..b7d9137851acd1ec71af9fdcb3271a9a773082a0 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
 #include <linux/firmware.h>
 #include <linux/delay.h>
-#include <linux/irq.h>
 #include <linux/spi/spi.h>
 #include <linux/crc32.h>
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
-#include <linux/spi/wl12xx.h>
 #include <linux/inetdevice.h>
+#include <linux/platform_device.h>
 #include <linux/slab.h>
 
 #include "wl1271.h"
 #include "wl12xx_80211.h"
 #include "wl1271_reg.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 #include "wl1271_event.h"
 #include "wl1271_tx.h"
 
 static struct conf_drv_settings default_conf = {
        .sg = {
-               .per_threshold               = 7500,
-               .max_scan_compensation_time  = 120000,
-               .nfs_sample_interval         = 400,
-               .load_ratio                  = 50,
-               .auto_ps_mode                = 0,
-               .probe_req_compensation      = 170,
-               .scan_window_compensation    = 50,
-               .antenna_config              = 0,
-               .beacon_miss_threshold       = 60,
-               .rate_adaptation_threshold   = CONF_HW_BIT_RATE_12MBPS,
-               .rate_adaptation_snr         = 0
+               .params = {
+                       [CONF_SG_BT_PER_THRESHOLD]                  = 7500,
+                       [CONF_SG_HV3_MAX_OVERRIDE]                  = 0,
+                       [CONF_SG_BT_NFS_SAMPLE_INTERVAL]            = 400,
+                       [CONF_SG_BT_LOAD_RATIO]                     = 50,
+                       [CONF_SG_AUTO_PS_MODE]                      = 0,
+                       [CONF_SG_AUTO_SCAN_PROBE_REQ]               = 170,
+                       [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3]   = 50,
+                       [CONF_SG_ANTENNA_CONFIGURATION]             = 0,
+                       [CONF_SG_BEACON_MISS_PERCENT]               = 60,
+                       [CONF_SG_RATE_ADAPT_THRESH]                 = 12,
+                       [CONF_SG_RATE_ADAPT_SNR]                    = 0,
+                       [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR]      = 10,
+                       [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR]      = 30,
+                       [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR]      = 8,
+                       [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR]       = 20,
+                       [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR]       = 50,
+                       /* Note: with UPSD, this should be 4 */
+                       [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR]       = 8,
+                       [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR]     = 7,
+                       [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR]     = 25,
+                       [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR]     = 20,
+                       /* Note: with UPDS, this should be 15 */
+                       [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR]      = 8,
+                       /* Note: with UPDS, this should be 50 */
+                       [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR]      = 40,
+                       /* Note: with UPDS, this should be 10 */
+                       [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR]      = 20,
+                       [CONF_SG_RXT]                               = 1200,
+                       [CONF_SG_TXT]                               = 1000,
+                       [CONF_SG_ADAPTIVE_RXT_TXT]                  = 1,
+                       [CONF_SG_PS_POLL_TIMEOUT]                   = 10,
+                       [CONF_SG_UPSD_TIMEOUT]                      = 10,
+                       [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
+                       [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
+                       [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
+                       [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR]  = 8,
+                       [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR]  = 20,
+                       [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR]  = 15,
+                       [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR]         = 20,
+                       [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR]         = 50,
+                       [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR]         = 10,
+                       [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3]  = 200,
+                       [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
+                       [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME]         = 75,
+                       [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME]       = 15,
+                       [CONF_SG_HV3_MAX_SERVED]                    = 6,
+                       [CONF_SG_DHCP_TIME]                         = 5000,
+                       [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP]  = 100,
+               },
+               .state = CONF_SG_PROTECTIVE,
        },
        .rx = {
                .rx_msdu_life_time           = 512000,
@@ -81,8 +117,7 @@ static struct conf_drv_settings default_conf = {
        .tx = {
                .tx_energy_detection         = 0,
                .rc_conf                     = {
-                       .enabled_rates       = CONF_HW_BIT_RATE_1MBPS |
-                                              CONF_HW_BIT_RATE_2MBPS,
+                       .enabled_rates       = 0,
                        .short_retry_limit   = 10,
                        .long_retry_limit    = 10,
                        .aflags              = 0
@@ -179,11 +214,13 @@ static struct conf_drv_settings default_conf = {
                },
                .frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD,
                .tx_compl_timeout            = 700,
-               .tx_compl_threshold          = 4
+               .tx_compl_threshold          = 4,
+               .basic_rate                  = CONF_HW_BIT_RATE_1MBPS,
+               .basic_rate_5                = CONF_HW_BIT_RATE_6MBPS,
        },
        .conn = {
                .wake_up_event               = CONF_WAKE_UP_EVENT_DTIM,
-               .listen_interval             = 0,
+               .listen_interval             = 1,
                .bcn_filt_mode               = CONF_BCN_FILT_MODE_ENABLED,
                .bcn_filt_ie_count           = 1,
                .bcn_filt_ie = {
@@ -198,38 +235,11 @@ static struct conf_drv_settings default_conf = {
                .broadcast_timeout           = 20000,
                .rx_broadcast_in_ps          = 1,
                .ps_poll_threshold           = 20,
-               .sig_trigger_count           = 2,
-               .sig_trigger = {
-                       [0] = {
-                               .threshold   = -75,
-                               .pacing      = 500,
-                               .metric      = CONF_TRIG_METRIC_RSSI_BEACON,
-                               .type        = CONF_TRIG_EVENT_TYPE_EDGE,
-                               .direction   = CONF_TRIG_EVENT_DIR_LOW,
-                               .hysteresis  = 2,
-                               .index       = 0,
-                               .enable      = 1
-                       },
-                       [1] = {
-                               .threshold   = -75,
-                               .pacing      = 500,
-                               .metric      = CONF_TRIG_METRIC_RSSI_BEACON,
-                               .type        = CONF_TRIG_EVENT_TYPE_EDGE,
-                               .direction   = CONF_TRIG_EVENT_DIR_HIGH,
-                               .hysteresis  = 2,
-                               .index       = 1,
-                               .enable      = 1
-                       }
-               },
-               .sig_weights = {
-                       .rssi_bcn_avg_weight = 10,
-                       .rssi_pkt_avg_weight = 10,
-                       .snr_bcn_avg_weight  = 10,
-                       .snr_pkt_avg_weight  = 10
-               },
                .bet_enable                  = CONF_BET_MODE_ENABLE,
                .bet_max_consecutive         = 10,
-               .psm_entry_retries           = 3
+               .psm_entry_retries           = 3,
+               .keep_alive_interval         = 55000,
+               .max_listen_interval         = 20,
        },
        .init = {
                .radioparam = {
@@ -243,9 +253,32 @@ static struct conf_drv_settings default_conf = {
        .pm_config = {
                .host_clk_settling_time = 5000,
                .host_fast_wakeup_support = false
+       },
+       .roam_trigger = {
+               /* FIXME: due to firmware bug, must use value 1 for now */
+               .trigger_pacing               = 1,
+               .avg_weight_rssi_beacon       = 20,
+               .avg_weight_rssi_data         = 10,
+               .avg_weight_snr_beacon        = 20,
+               .avg_weight_snr_data          = 10
        }
 };
 
+static void wl1271_device_release(struct device *dev)
+{
+
+}
+
+static struct platform_device wl1271_device = {
+       .name           = "wl1271",
+       .id             = -1,
+
+       /* device model insists to have a release function */
+       .dev            = {
+               .release = wl1271_device_release,
+       },
+};
+
 static LIST_HEAD(wl_list);
 
 static void wl1271_conf_init(struct wl1271 *wl)
@@ -298,7 +331,7 @@ static int wl1271_plt_init(struct wl1271 *wl)
                goto out_free_memmap;
 
        /* Initialize connection monitoring thresholds */
-       ret = wl1271_acx_conn_monit_params(wl);
+       ret = wl1271_acx_conn_monit_params(wl, false);
        if (ret < 0)
                goto out_free_memmap;
 
@@ -365,30 +398,14 @@ static int wl1271_plt_init(struct wl1271 *wl)
        return ret;
 }
 
-static void wl1271_disable_interrupts(struct wl1271 *wl)
-{
-       disable_irq(wl->irq);
-}
-
-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,
                             struct wl1271_fw_status *status)
 {
+       struct timespec ts;
        u32 total = 0;
        int i;
 
-       wl1271_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
+       wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false);
 
        wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
                     "drv_rx_counter = %d, tx_results_counter = %d)",
@@ -413,14 +430,19 @@ static void wl1271_fw_status(struct wl1271 *wl,
                ieee80211_queue_work(wl->hw, &wl->tx_work);
 
        /* update the host-chipset time offset */
-       wl->time_offset = jiffies_to_usecs(jiffies) -
-               le32_to_cpu(status->fw_localtime);
+       getnstimeofday(&ts);
+       wl->time_offset = (timespec_to_ns(&ts) >> 10) -
+               (s64)le32_to_cpu(status->fw_localtime);
 }
 
+#define WL1271_IRQ_MAX_LOOPS 10
+
 static void wl1271_irq_work(struct work_struct *work)
 {
        int ret;
        u32 intr;
+       int loopcount = WL1271_IRQ_MAX_LOOPS;
+       unsigned long flags;
        struct wl1271 *wl =
                container_of(work, struct wl1271, irq_work);
 
@@ -428,91 +450,78 @@ static void wl1271_irq_work(struct work_struct *work)
 
        wl1271_debug(DEBUG_IRQ, "IRQ work");
 
-       if (wl->state == WL1271_STATE_OFF)
+       if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
        ret = wl1271_ps_elp_wakeup(wl, true);
        if (ret < 0)
                goto out;
 
-       wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL);
-
-       wl1271_fw_status(wl, wl->fw_status);
-       intr = le32_to_cpu(wl->fw_status->intr);
-       if (!intr) {
-               wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
-               goto out_sleep;
-       }
+       spin_lock_irqsave(&wl->wl_lock, flags);
+       while (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags) && loopcount) {
+               clear_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+               loopcount--;
+
+               wl1271_fw_status(wl, wl->fw_status);
+               intr = le32_to_cpu(wl->fw_status->intr);
+               if (!intr) {
+                       wl1271_debug(DEBUG_IRQ, "Zero interrupt received.");
+                       spin_lock_irqsave(&wl->wl_lock, flags);
+                       continue;
+               }
 
-       intr &= WL1271_INTR_MASK;
+               intr &= WL1271_INTR_MASK;
 
-       if (intr & WL1271_ACX_INTR_EVENT_A) {
-               wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
-               wl1271_event_handle(wl, 0);
-       }
+               if (intr & WL1271_ACX_INTR_DATA) {
+                       wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
 
-       if (intr & WL1271_ACX_INTR_EVENT_B) {
-               wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
-               wl1271_event_handle(wl, 1);
-       }
+                       /* check for tx results */
+                       if (wl->fw_status->tx_results_counter !=
+                           (wl->tx_results_count & 0xff))
+                               wl1271_tx_complete(wl);
 
-       if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
-               wl1271_debug(DEBUG_IRQ,
-                            "WL1271_ACX_INTR_INIT_COMPLETE");
+                       wl1271_rx(wl, wl->fw_status);
+               }
 
-       if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
-               wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
+               if (intr & WL1271_ACX_INTR_EVENT_A) {
+                       wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A");
+                       wl1271_event_handle(wl, 0);
+               }
 
-       if (intr & WL1271_ACX_INTR_DATA) {
-               u8 tx_res_cnt = wl->fw_status->tx_results_counter -
-                       wl->tx_results_count;
+               if (intr & WL1271_ACX_INTR_EVENT_B) {
+                       wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B");
+                       wl1271_event_handle(wl, 1);
+               }
 
-               wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA");
+               if (intr & WL1271_ACX_INTR_INIT_COMPLETE)
+                       wl1271_debug(DEBUG_IRQ,
+                                    "WL1271_ACX_INTR_INIT_COMPLETE");
 
-               /* check for tx results */
-               if (tx_res_cnt)
-                       wl1271_tx_complete(wl, tx_res_cnt);
+               if (intr & WL1271_ACX_INTR_HW_AVAILABLE)
+                       wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE");
 
-               wl1271_rx(wl, wl->fw_status);
+               spin_lock_irqsave(&wl->wl_lock, flags);
        }
 
-out_sleep:
-       wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
-                      WL1271_ACX_INTR_ALL & ~(WL1271_INTR_MASK));
+       if (test_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags))
+               ieee80211_queue_work(wl->hw, &wl->irq_work);
+       else
+               clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+
        wl1271_ps_elp_sleep(wl);
 
 out:
        mutex_unlock(&wl->mutex);
 }
 
-static irqreturn_t wl1271_irq(int irq, void *cookie)
-{
-       struct wl1271 *wl;
-       unsigned long flags;
-
-       wl1271_debug(DEBUG_IRQ, "IRQ");
-
-       wl = cookie;
-
-       /* complete the ELP completion */
-       spin_lock_irqsave(&wl->wl_lock, flags);
-       if (wl->elp_compl) {
-               complete(wl->elp_compl);
-               wl->elp_compl = NULL;
-       }
-
-       ieee80211_queue_work(wl->hw, &wl->irq_work);
-       spin_unlock_irqrestore(&wl->wl_lock, flags);
-
-       return IRQ_HANDLED;
-}
-
 static int wl1271_fetch_firmware(struct wl1271 *wl)
 {
        const struct firmware *fw;
        int ret;
 
-       ret = request_firmware(&fw, WL1271_FW_NAME, &wl->spi->dev);
+       ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
 
        if (ret < 0) {
                wl1271_error("could not get firmware: %d", ret);
@@ -545,46 +554,12 @@ out:
        return ret;
 }
 
-static int wl1271_update_mac_addr(struct wl1271 *wl)
-{
-       int ret = 0;
-       u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
-
-       /* get mac address from the NVS */
-       wl->mac_addr[0] = nvs_ptr[11];
-       wl->mac_addr[1] = nvs_ptr[10];
-       wl->mac_addr[2] = nvs_ptr[6];
-       wl->mac_addr[3] = nvs_ptr[5];
-       wl->mac_addr[4] = nvs_ptr[4];
-       wl->mac_addr[5] = nvs_ptr[3];
-
-       /* FIXME: if it is a zero-address, we should bail out. Now, instead,
-          we randomize an address */
-       if (is_zero_ether_addr(wl->mac_addr)) {
-               static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
-               memcpy(wl->mac_addr, nokia_oui, 3);
-               get_random_bytes(wl->mac_addr + 3, 3);
-
-               /* update this address to the NVS */
-               nvs_ptr[11] = wl->mac_addr[0];
-               nvs_ptr[10] = wl->mac_addr[1];
-               nvs_ptr[6] = wl->mac_addr[2];
-               nvs_ptr[5] = wl->mac_addr[3];
-               nvs_ptr[4] = wl->mac_addr[4];
-               nvs_ptr[3] = wl->mac_addr[5];
-       }
-
-       SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
-
-       return ret;
-}
-
 static int wl1271_fetch_nvs(struct wl1271 *wl)
 {
        const struct firmware *fw;
        int ret;
 
-       ret = request_firmware(&fw, WL1271_NVS_NAME, &wl->spi->dev);
+       ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
 
        if (ret < 0) {
                wl1271_error("could not get nvs file: %d", ret);
@@ -608,8 +583,6 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
 
        memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
 
-       ret = wl1271_update_mac_addr(wl);
-
 out:
        release_firmware(fw);
 
@@ -826,15 +799,13 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
         * The workqueue is slow to process the tx_queue and we need stop
         * the queue here, otherwise the queue will get too long.
         */
-       if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_MAX_LENGTH) {
-               ieee80211_stop_queues(wl->hw);
+       if (skb_queue_len(&wl->tx_queue) >= WL1271_TX_QUEUE_HIGH_WATERMARK) {
+               wl1271_debug(DEBUG_TX, "op_tx: stopping queues");
 
-               /*
-                * FIXME: this is racy, the variable is not properly
-                * protected. Maybe fix this by removing the stupid
-                * variable altogether and checking the real queue state?
-                */
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_stop_queues(wl->hw);
                set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
        }
 
        return NETDEV_TX_OK;
@@ -882,7 +853,7 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
                if (wl == wl_temp)
                        break;
        }
-       if (wl == NULL)
+       if (wl != wl_temp)
                return NOTIFY_DONE;
 
        /* Get the interface IP address for the device. "ifa" will become
@@ -928,14 +899,61 @@ static struct notifier_block wl1271_dev_notifier = {
 
 
 static int wl1271_op_start(struct ieee80211_hw *hw)
+{
+       wl1271_debug(DEBUG_MAC80211, "mac80211 start");
+
+       /*
+        * We have to delay the booting of the hardware because
+        * we need to know the local MAC address before downloading and
+        * initializing the firmware. The MAC address cannot be changed
+        * after boot, and without the proper MAC address, the firmware
+        * will not function properly.
+        *
+        * The MAC address is first known when the corresponding interface
+        * is added. That is where we will initialize the hardware.
+        */
+
+       return 0;
+}
+
+static void wl1271_op_stop(struct ieee80211_hw *hw)
+{
+       wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
+}
+
+static int wl1271_op_add_interface(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
        int retries = WL1271_BOOT_RETRIES;
        int ret = 0;
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 start");
+       wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+                    vif->type, vif->addr);
 
        mutex_lock(&wl->mutex);
+       if (wl->vif) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       wl->vif = vif;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               wl->bss_type = BSS_TYPE_STA_BSS;
+               wl->set_bss_type = BSS_TYPE_STA_BSS;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               wl->bss_type = BSS_TYPE_IBSS;
+               wl->set_bss_type = BSS_TYPE_STA_BSS;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 
        if (wl->state != WL1271_STATE_OFF) {
                wl1271_error("cannot start because not in off state: %d",
@@ -991,19 +1009,20 @@ out:
        return ret;
 }
 
-static void wl1271_op_stop(struct ieee80211_hw *hw)
+static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif)
 {
        struct wl1271 *wl = hw->priv;
        int i;
 
-       wl1271_info("down");
-
-       wl1271_debug(DEBUG_MAC80211, "mac80211 stop");
-
        unregister_inetaddr_notifier(&wl1271_dev_notifier);
-       list_del(&wl->list);
 
        mutex_lock(&wl->mutex);
+       wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
+
+       wl1271_info("down");
+
+       list_del(&wl->list);
 
        WARN_ON(wl->state != WL1271_STATE_ON);
 
@@ -1032,6 +1051,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1);
        wl->ssid_len = 0;
        wl->bss_type = MAX_BSS_TYPE;
+       wl->set_bss_type = MAX_BSS_TYPE;
        wl->band = IEEE80211_BAND_2GHZ;
 
        wl->rx_counter = 0;
@@ -1041,163 +1061,142 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wl->tx_results_count = 0;
        wl->tx_packets_count = 0;
        wl->tx_security_last_seq = 0;
-       wl->tx_security_seq_16 = 0;
-       wl->tx_security_seq_32 = 0;
+       wl->tx_security_seq = 0;
        wl->time_offset = 0;
        wl->session_counter = 0;
        wl->rate_set = CONF_TX_RATE_MASK_BASIC;
        wl->sta_rate_set = 0;
        wl->flags = 0;
+       wl->vif = NULL;
+       wl->filters = 0;
 
        for (i = 0; i < NUM_TX_QUEUES; i++)
                wl->tx_blocks_freed[i] = 0;
 
        wl1271_debugfs_reset(wl);
+
+       kfree(wl->fw_status);
+       wl->fw_status = NULL;
+       kfree(wl->tx_res_if);
+       wl->tx_res_if = NULL;
+       kfree(wl->target_mem_map);
+       wl->target_mem_map = NULL;
+
        mutex_unlock(&wl->mutex);
 }
 
-static int wl1271_op_add_interface(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif)
+static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
 {
-       struct wl1271 *wl = hw->priv;
-       int ret = 0;
+       wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
+       wl->rx_filter = WL1271_DEFAULT_RX_FILTER;
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
-                    vif->type, vif->addr);
+       /* combine requested filters with current filter config */
+       filters = wl->filters | filters;
 
-       mutex_lock(&wl->mutex);
-       if (wl->vif) {
-               ret = -EBUSY;
-               goto out;
+       wl1271_debug(DEBUG_FILTERS, "RX filters set: ");
+
+       if (filters & FIF_PROMISC_IN_BSS) {
+               wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS");
+               wl->rx_config &= ~CFG_UNI_FILTER_EN;
+               wl->rx_config |= CFG_BSSID_FILTER_EN;
+       }
+       if (filters & FIF_BCN_PRBRESP_PROMISC) {
+               wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC");
+               wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+               wl->rx_config &= ~CFG_SSID_FILTER_EN;
+       }
+       if (filters & FIF_OTHER_BSS) {
+               wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS");
+               wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+       }
+       if (filters & FIF_CONTROL) {
+               wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL");
+               wl->rx_filter |= CFG_RX_CTL_EN;
        }
+       if (filters & FIF_FCSFAIL) {
+               wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL");
+               wl->rx_filter |= CFG_RX_FCS_ERROR;
+       }
+}
 
-       wl->vif = vif;
+static int wl1271_dummy_join(struct wl1271 *wl)
+{
+       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 };
 
-       switch (vif->type) {
-       case NL80211_IFTYPE_STATION:
-               wl->bss_type = BSS_TYPE_STA_BSS;
-               break;
-       case NL80211_IFTYPE_ADHOC:
-               wl->bss_type = BSS_TYPE_IBSS;
-               break;
-       default:
-               ret = -EOPNOTSUPP;
+       memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
+
+       /* pass through frames from all BSS */
+       wl1271_configure_filters(wl, FIF_OTHER_BSS);
+
+       ret = wl1271_cmd_join(wl, wl->set_bss_type);
+       if (ret < 0)
                goto out;
-       }
 
-       /* FIXME: what if conf->mac_addr changes? */
+       set_bit(WL1271_FLAG_JOINED, &wl->flags);
 
 out:
-       mutex_unlock(&wl->mutex);
        return ret;
 }
 
-static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
-                                        struct ieee80211_vif *vif)
-{
-       struct wl1271 *wl = hw->priv;
-
-       mutex_lock(&wl->mutex);
-       wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
-       wl->vif = NULL;
-       mutex_unlock(&wl->mutex);
-}
-
-#if 0
-static int wl1271_op_config_interface(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif,
-                                     struct ieee80211_if_conf *conf)
+static int wl1271_join(struct wl1271 *wl, bool set_assoc)
 {
-       struct wl1271 *wl = hw->priv;
-       struct sk_buff *beacon;
        int ret;
 
-       wl1271_debug(DEBUG_MAC80211, "mac80211 config_interface bssid %pM",
-                    conf->bssid);
-       wl1271_dump_ascii(DEBUG_MAC80211, "ssid: ", conf->ssid,
-                         conf->ssid_len);
+       /*
+        * One of the side effects of the JOIN command is that is clears
+        * WPA/WPA2 keys from the chipset. Performing a JOIN while associated
+        * to a WPA/WPA2 access point will therefore kill the data-path.
+        * Currently there is no supported scenario for JOIN during
+        * association - if it becomes a supported scenario, the WPA/WPA2 keys
+        * must be handled somehow.
+        *
+        */
+       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+               wl1271_info("JOIN while associated.");
 
-       mutex_lock(&wl->mutex);
+       if (set_assoc)
+               set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
 
-       ret = wl1271_ps_elp_wakeup(wl, false);
+       ret = wl1271_cmd_join(wl, wl->set_bss_type);
        if (ret < 0)
                goto out;
 
-       if (memcmp(wl->bssid, conf->bssid, ETH_ALEN)) {
-               wl1271_debug(DEBUG_MAC80211, "bssid changed");
-
-               memcpy(wl->bssid, conf->bssid, ETH_ALEN);
-
-               ret = wl1271_cmd_join(wl);
-               if (ret < 0)
-                       goto out_sleep;
-
-               ret = wl1271_cmd_build_null_data(wl);
-               if (ret < 0)
-                       goto out_sleep;
-       }
-
-       wl->ssid_len = conf->ssid_len;
-       if (wl->ssid_len)
-               memcpy(wl->ssid, conf->ssid, wl->ssid_len);
-
-       if (conf->changed & IEEE80211_IFCC_BEACON) {
-               beacon = ieee80211_beacon_get(hw, vif);
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
-                                             beacon->data, beacon->len);
-
-               if (ret < 0) {
-                       dev_kfree_skb(beacon);
-                       goto out_sleep;
-               }
-
-               ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE,
-                                             beacon->data, beacon->len);
-
-               dev_kfree_skb(beacon);
-
-               if (ret < 0)
-                       goto out_sleep;
-       }
-
-out_sleep:
-       wl1271_ps_elp_sleep(wl);
-
-out:
-       mutex_unlock(&wl->mutex);
-
-       return ret;
-}
-#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 };
+       set_bit(WL1271_FLAG_JOINED, &wl->flags);
 
-       /* the dummy join is not required for ad-hoc */
-       if (wl->bss_type == BSS_TYPE_IBSS)
+       if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
                goto out;
 
-       /* disable mac filter, so we hear everything */
-       wl->rx_config &= ~CFG_BSSID_FILTER_EN;
+       /*
+        * The join command disable the keep-alive mode, shut down its process,
+        * and also clear the template config, so we need to reset it all after
+        * the join. The acx_aid starts the keep-alive process, and the order
+        * of the commands below is relevant.
+        */
+       ret = wl1271_acx_keep_alive_mode(wl, true);
+       if (ret < 0)
+               goto out;
 
-       wl->channel = channel;
-       memcpy(wl->bssid, dummy_bssid, ETH_ALEN);
+       ret = wl1271_acx_aid(wl, wl->aid);
+       if (ret < 0)
+               goto out;
 
-       ret = wl1271_cmd_join(wl);
+       ret = wl1271_cmd_build_klv_null_data(wl);
        if (ret < 0)
                goto out;
 
-       set_bit(WL1271_FLAG_JOINED, &wl->flags);
+       ret = wl1271_acx_keep_alive_config(wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+                                          ACX_KEEP_ALIVE_TPL_VALID);
+       if (ret < 0)
+               goto out;
 
 out:
        return ret;
 }
 
-static int wl1271_unjoin_channel(struct wl1271 *wl)
+static int wl1271_unjoin(struct wl1271 *wl)
 {
        int ret;
 
@@ -1207,14 +1206,41 @@ static int wl1271_unjoin_channel(struct wl1271 *wl)
                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;
+
+       /* stop filterting packets based on bssid */
+       wl1271_configure_filters(wl, FIF_OTHER_BSS);
 
 out:
        return ret;
 }
 
+static void wl1271_set_band_rate(struct wl1271 *wl)
+{
+       if (wl->band == IEEE80211_BAND_2GHZ)
+               wl->basic_rate_set = wl->conf.tx.basic_rate;
+       else
+               wl->basic_rate_set = wl->conf.tx.basic_rate_5;
+}
+
+static u32 wl1271_min_rate_get(struct wl1271 *wl)
+{
+       int i;
+       u32 rate = 0;
+
+       if (!wl->basic_rate_set) {
+               WARN_ON(1);
+               wl->basic_rate_set = wl->conf.tx.basic_rate;
+       }
+
+       for (i = 0; !rate; i++) {
+               if ((wl->basic_rate_set >> i) & 0x1)
+                       rate = 1 << i;
+       }
+
+       return rate;
+}
+
 static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct wl1271 *wl = hw->priv;
@@ -1231,38 +1257,62 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&wl->mutex);
 
-       wl->band = conf->channel->band;
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
 
        ret = wl1271_ps_elp_wakeup(wl, false);
        if (ret < 0)
                goto out;
 
-       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+       /* if the channel changes while joined, join again */
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
+           ((wl->band != conf->channel->band) ||
+            (wl->channel != channel))) {
+               wl->band = conf->channel->band;
+               wl->channel = channel;
+
+               /*
+                * FIXME: the mac80211 should really provide a fixed rate
+                * to use here. for now, just use the smallest possible rate
+                * for the band as a fixed rate for association frames and
+                * other control messages.
+                */
+               if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
+                       wl1271_set_band_rate(wl);
+
+               wl->basic_rate = wl1271_min_rate_get(wl);
+               ret = wl1271_acx_rate_policies(wl);
+               if (ret < 0)
+                       wl1271_warning("rate policy for update channel "
+                                      "failed %d", ret);
+
+               if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+                       ret = wl1271_join(wl, false);
+                       if (ret < 0)
+                               wl1271_warning("cmd join to update channel "
+                                              "failed %d", ret);
+               }
+       }
+
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                if (conf->flags & IEEE80211_CONF_IDLE &&
                    test_bit(WL1271_FLAG_JOINED, &wl->flags))
-                       wl1271_unjoin_channel(wl);
+                       wl1271_unjoin(wl);
                else if (!(conf->flags & IEEE80211_CONF_IDLE))
-                       wl1271_join_channel(wl, channel);
+                       wl1271_dummy_join(wl);
 
                if (conf->flags & IEEE80211_CONF_IDLE) {
-                       wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+                       wl->rate_set = wl1271_min_rate_get(wl);
                        wl->sta_rate_set = 0;
                        wl1271_acx_rate_policies(wl);
-               }
+                       wl1271_acx_keep_alive_config(
+                               wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+                               ACX_KEEP_ALIVE_TPL_INVALID);
+                       set_bit(WL1271_FLAG_IDLE, &wl->flags);
+               } else
+                       clear_bit(WL1271_FLAG_IDLE, &wl->flags);
        }
 
-       /* if the channel changes while joined, join again */
-       if (channel != wl->channel &&
-           test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
-               wl->channel = channel;
-               /* FIXME: maybe use CMD_CHANNEL_SWITCH for this? */
-               ret = wl1271_cmd_join(wl);
-               if (ret < 0)
-                       wl1271_warning("cmd join to update channel failed %d",
-                                      ret);
-       } else
-               wl->channel = channel;
-
        if (conf->flags & IEEE80211_CONF_PS &&
            !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
                set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
@@ -1273,13 +1323,13 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                 * through the bss_info_changed() hook.
                 */
                if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) {
-                       wl1271_info("psm enabled");
+                       wl1271_debug(DEBUG_PSM, "psm enabled");
                        ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
                                                 true);
                }
        } else if (!(conf->flags & IEEE80211_CONF_PS) &&
                   test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) {
-               wl1271_info("psm disabled");
+               wl1271_debug(DEBUG_PSM, "psm disabled");
 
                clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags);
 
@@ -1311,11 +1361,15 @@ struct wl1271_filter_params {
        u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
 };
 
-static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
-                                      struct dev_addr_list *mc_list)
+static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw,
+                                      struct netdev_hw_addr_list *mc_list)
 {
        struct wl1271_filter_params *fp;
-       int i;
+       struct netdev_hw_addr *ha;
+       struct wl1271 *wl = hw->priv;
+
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               return 0;
 
        fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
        if (!fp) {
@@ -1324,21 +1378,16 @@ static u64 wl1271_op_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
        }
 
        /* update multicast filtering parameters */
-       fp->enabled = true;
-       if (mc_count > ACX_MC_ADDRESS_GROUP_MAX) {
-               mc_count = 0;
-               fp->enabled = false;
-       }
-
        fp->mc_list_length = 0;
-       for (i = 0; i < mc_count; i++) {
-               if (mc_list->da_addrlen == ETH_ALEN) {
+       if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
+               fp->enabled = false;
+       } else {
+               fp->enabled = true;
+               netdev_hw_addr_list_for_each(ha, mc_list) {
                        memcpy(fp->mc_list[fp->mc_list_length],
-                              mc_list->da_addr, ETH_ALEN);
+                                       ha->addr, ETH_ALEN);
                        fp->mc_list_length++;
-               } else
-                       wl1271_warning("Unknown mc address length.");
-               mc_list = mc_list->next;
+               }
        }
 
        return (u64)(unsigned long)fp;
@@ -1363,15 +1412,16 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
 
        mutex_lock(&wl->mutex);
 
-       if (wl->state == WL1271_STATE_OFF)
+       *total &= WL1271_SUPPORTED_FILTERS;
+       changed &= WL1271_SUPPORTED_FILTERS;
+
+       if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
        ret = wl1271_ps_elp_wakeup(wl, false);
        if (ret < 0)
                goto out;
 
-       *total &= WL1271_SUPPORTED_FILTERS;
-       changed &= WL1271_SUPPORTED_FILTERS;
 
        if (*total & FIF_ALLMULTI)
                ret = wl1271_acx_group_address_tbl(wl, false, NULL, 0);
@@ -1382,14 +1432,14 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out_sleep;
 
-       kfree(fp);
-
-       /* FIXME: We still need to set our filters properly */
-
        /* determine, whether supported filter values have changed */
        if (changed == 0)
                goto out_sleep;
 
+       /* configure filters */
+       wl->filters = *total;
+       wl1271_configure_filters(wl, 0);
+
        /* apply configured filters */
        ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
        if (ret < 0)
@@ -1400,6 +1450,7 @@ out_sleep:
 
 out:
        mutex_unlock(&wl->mutex);
+       kfree(fp);
 }
 
 static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -1450,15 +1501,15 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                key_type = KEY_TKIP;
 
                key_conf->hw_key_idx = key_conf->keyidx;
-               tx_seq_32 = wl->tx_security_seq_32;
-               tx_seq_16 = wl->tx_security_seq_16;
+               tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+               tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
                break;
        case ALG_CCMP:
                key_type = KEY_AES;
 
                key_conf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-               tx_seq_32 = wl->tx_security_seq_32;
-               tx_seq_16 = wl->tx_security_seq_16;
+               tx_seq_32 = WL1271_TX_SECURITY_HI32(wl->tx_security_seq);
+               tx_seq_16 = WL1271_TX_SECURITY_LO16(wl->tx_security_seq);
                break;
        default:
                wl1271_error("Unknown key algo 0x%x", key_conf->alg);
@@ -1508,8 +1559,6 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        default:
                wl1271_error("Unsupported key cmd 0x%x", cmd);
                ret = -EOPNOTSUPP;
-               goto out_sleep;
-
                break;
        }
 
@@ -1524,6 +1573,7 @@ out:
 }
 
 static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif,
                             struct cfg80211_scan_request *req)
 {
        struct wl1271 *wl = hw->priv;
@@ -1545,10 +1595,12 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
                goto out;
 
        if (wl1271_11a_enabled())
-               ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
+               ret = wl1271_cmd_scan(hw->priv, ssid, len,
+                                     req->ie, req->ie_len, 1, 0,
                                      WL1271_SCAN_BAND_DUAL, 3);
        else
-               ret = wl1271_cmd_scan(hw->priv, ssid, len, 1, 0,
+               ret = wl1271_cmd_scan(hw->priv, ssid, len,
+                                     req->ie, req->ie_len, 1, 0,
                                      WL1271_SCAN_BAND_2_4_GHZ, 3);
 
        wl1271_ps_elp_sleep(wl);
@@ -1562,10 +1614,13 @@ out:
 static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 {
        struct wl1271 *wl = hw->priv;
-       int ret;
+       int ret = 0;
 
        mutex_lock(&wl->mutex);
 
+       if (unlikely(wl->state == WL1271_STATE_OFF))
+               goto out;
+
        ret = wl1271_ps_elp_wakeup(wl, false);
        if (ret < 0)
                goto out;
@@ -1607,6 +1662,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        enum wl1271_cmd_ps_mode mode;
        struct wl1271 *wl = hw->priv;
        bool do_join = false;
+       bool set_assoc = false;
        int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1617,20 +1673,29 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
-       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. */
+       if ((changed && BSS_CHANGED_BEACON_INT) &&
+           (wl->bss_type == BSS_TYPE_IBSS)) {
+               wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon interval updated: %d",
+                       bss_conf->beacon_int);
+
+               wl->beacon_int = bss_conf->beacon_int;
+               do_join = true;
+       }
+
+       if ((changed && BSS_CHANGED_BEACON) &&
+           (wl->bss_type == BSS_TYPE_IBSS)) {
                struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);
 
+               wl1271_debug(DEBUG_ADHOC, "ad-hoc beacon updated");
+
                if (beacon) {
                        struct ieee80211_hdr *hdr;
 
                        wl1271_ssid_set(wl, beacon);
                        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON,
                                                      beacon->data,
-                                                     beacon->len);
+                                                     beacon->len, 0,
+                                                     wl1271_min_rate_get(wl));
 
                        if (ret < 0) {
                                dev_kfree_skb(beacon);
@@ -1645,7 +1710,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        ret = wl1271_cmd_template_set(wl,
                                                      CMD_TEMPL_PROBE_RESPONSE,
                                                      beacon->data,
-                                                     beacon->len);
+                                                     beacon->len, 0,
+                                                     wl1271_min_rate_get(wl));
                        dev_kfree_skb(beacon);
                        if (ret < 0)
                                goto out_sleep;
@@ -1655,20 +1721,48 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if ((changed & BSS_CHANGED_BEACON_ENABLED) &&
+           (wl->bss_type == BSS_TYPE_IBSS)) {
+               wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s",
+                            bss_conf->enable_beacon ? "enabled" : "disabled");
+
+               if (bss_conf->enable_beacon)
+                       wl->set_bss_type = BSS_TYPE_IBSS;
+               else
+                       wl->set_bss_type = BSS_TYPE_STA_BSS;
+               do_join = true;
+       }
+
+       if (changed & BSS_CHANGED_CQM) {
+               bool enable = false;
+               if (bss_conf->cqm_rssi_thold)
+                       enable = true;
+               ret = wl1271_acx_rssi_snr_trigger(wl, enable,
+                                                 bss_conf->cqm_rssi_thold,
+                                                 bss_conf->cqm_rssi_hyst);
+               if (ret < 0)
+                       goto out;
+               wl->rssi_thold = bss_conf->cqm_rssi_thold;
+       }
+
        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);
+                       if (ret < 0)
                                goto out_sleep;
-                       }
+
+                       ret = wl1271_build_qos_null_data(wl);
+                       if (ret < 0)
+                               goto out_sleep;
+
+                       /* filter out all packets not from this BSSID */
+                       wl1271_configure_filters(wl, 0);
 
                        /* Need to update the BSSID (for filtering etc) */
                        do_join = true;
@@ -1676,8 +1770,21 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_ASSOC) {
                if (bss_conf->assoc) {
+                       u32 rates;
                        wl->aid = bss_conf->aid;
-                       set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
+                       set_assoc = true;
+
+                       /*
+                        * use basic rates from AP, and determine lowest rate
+                        * to use with control frames.
+                        */
+                       rates = bss_conf->basic_rates;
+                       wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
+                                                                        rates);
+                       wl->basic_rate = wl1271_min_rate_get(wl);
+                       ret = wl1271_acx_rate_policies(wl);
+                       if (ret < 0)
+                               goto out_sleep;
 
                        /*
                         * with wl1271, we don't need to update the
@@ -1689,7 +1796,17 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        if (ret < 0)
                                goto out_sleep;
 
-                       ret = wl1271_acx_aid(wl, wl->aid);
+                       /*
+                        * The SSID is intentionally set to NULL here - the
+                        * firmware will set the probe request with a
+                        * broadcast SSID regardless of what we set in the
+                        * template.
+                        */
+                       ret = wl1271_cmd_build_probe_req(wl, NULL, 0,
+                                                        NULL, 0, wl->band);
+
+                       /* enable the connection monitoring feature */
+                       ret = wl1271_acx_conn_monit_params(wl, true);
                        if (ret < 0)
                                goto out_sleep;
 
@@ -1705,6 +1822,22 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
                        /* use defaults when not associated */
                        clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
                        wl->aid = 0;
+
+                       /* revert back to minimum rates for the current band */
+                       wl1271_set_band_rate(wl);
+                       wl->basic_rate = wl1271_min_rate_get(wl);
+                       ret = wl1271_acx_rate_policies(wl);
+                       if (ret < 0)
+                               goto out_sleep;
+
+                       /* disable connection monitor features */
+                       ret = wl1271_acx_conn_monit_params(wl, false);
+
+                       /* Disable the keep-alive feature */
+                       ret = wl1271_acx_keep_alive_mode(wl, false);
+
+                       if (ret < 0)
+                               goto out_sleep;
                }
 
        }
@@ -1739,12 +1872,11 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (do_join) {
-               ret = wl1271_cmd_join(wl);
+               ret = wl1271_join(wl, set_assoc);
                if (ret < 0) {
                        wl1271_warning("cmd join failed %d", ret);
                        goto out_sleep;
                }
-               set_bit(WL1271_FLAG_JOINED, &wl->flags);
        }
 
 out_sleep:
@@ -1758,6 +1890,7 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
                             const struct ieee80211_tx_queue_params *params)
 {
        struct wl1271 *wl = hw->priv;
+       u8 ps_scheme;
        int ret;
 
        mutex_lock(&wl->mutex);
@@ -1768,17 +1901,22 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
        if (ret < 0)
                goto out;
 
+       /* the txop is confed in units of 32us by the mac80211, we need us */
        ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
                                params->cw_min, params->cw_max,
-                               params->aifs, params->txop);
+                               params->aifs, params->txop << 5);
        if (ret < 0)
                goto out_sleep;
 
+       if (params->uapsd)
+               ps_scheme = CONF_PS_SCHEME_UPSD_TRIGGER;
+       else
+               ps_scheme = CONF_PS_SCHEME_LEGACY;
+
        ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
                                 CONF_CHANNEL_TYPE_EDCF,
                                 wl1271_tx_get_queue(queue),
-                                CONF_PS_SCHEME_LEGACY_PSPOLL,
-                                CONF_ACK_POLICY_LEGACY, 0, 0);
+                                ps_scheme, CONF_ACK_POLICY_LEGACY, 0, 0);
        if (ret < 0)
                goto out_sleep;
 
@@ -1852,6 +1990,36 @@ static struct ieee80211_channel wl1271_channels[] = {
        { .hw_value = 13, .center_freq = 2472, .max_power = 25 },
 };
 
+/* mapping to indexes for wl1271_rates */
+const static u8 wl1271_rate_to_idx_2ghz[] = {
+       /* MCS rates are used only with 11n */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
+
+       11,                            /* CONF_HW_RXTX_RATE_54   */
+       10,                            /* CONF_HW_RXTX_RATE_48   */
+       9,                             /* CONF_HW_RXTX_RATE_36   */
+       8,                             /* CONF_HW_RXTX_RATE_24   */
+
+       /* TI-specific rate */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22   */
+
+       7,                             /* CONF_HW_RXTX_RATE_18   */
+       6,                             /* CONF_HW_RXTX_RATE_12   */
+       3,                             /* CONF_HW_RXTX_RATE_11   */
+       5,                             /* CONF_HW_RXTX_RATE_9    */
+       4,                             /* CONF_HW_RXTX_RATE_6    */
+       2,                             /* CONF_HW_RXTX_RATE_5_5  */
+       1,                             /* CONF_HW_RXTX_RATE_2    */
+       0                              /* CONF_HW_RXTX_RATE_1    */
+};
+
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1271_band_2ghz = {
        .channels = wl1271_channels,
@@ -1934,6 +2102,35 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
        { .hw_value = 165, .center_freq = 5825},
 };
 
+/* mapping to indexes for wl1271_rates_5ghz */
+const static u8 wl1271_rate_to_idx_5ghz[] = {
+       /* MCS rates are used only with 11n */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */
+
+       7,                             /* CONF_HW_RXTX_RATE_54   */
+       6,                             /* CONF_HW_RXTX_RATE_48   */
+       5,                             /* CONF_HW_RXTX_RATE_36   */
+       4,                             /* CONF_HW_RXTX_RATE_24   */
+
+       /* TI-specific rate */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_22   */
+
+       3,                             /* CONF_HW_RXTX_RATE_18   */
+       2,                             /* CONF_HW_RXTX_RATE_12   */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_11   */
+       1,                             /* CONF_HW_RXTX_RATE_9    */
+       0,                             /* CONF_HW_RXTX_RATE_6    */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_5_5  */
+       CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_2    */
+       CONF_HW_RXTX_RATE_UNSUPPORTED  /* CONF_HW_RXTX_RATE_1    */
+};
 
 static struct ieee80211_supported_band wl1271_band_5ghz = {
        .channels = wl1271_channels_5ghz,
@@ -1942,13 +2139,17 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
        .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
 };
 
+const static u8 *wl1271_band_rate_to_idx[] = {
+       [IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
+       [IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
+};
+
 static const struct ieee80211_ops wl1271_ops = {
        .start = wl1271_op_start,
        .stop = wl1271_op_stop,
        .add_interface = wl1271_op_add_interface,
        .remove_interface = wl1271_op_remove_interface,
        .config = wl1271_op_config,
-/*     .config_interface = wl1271_op_config_interface, */
        .prepare_multicast = wl1271_op_prepare_multicast,
        .configure_filter = wl1271_op_configure_filter,
        .tx = wl1271_op_tx,
@@ -1960,7 +2161,113 @@ static const struct ieee80211_ops wl1271_ops = {
        CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
-static int wl1271_register_hw(struct wl1271 *wl)
+
+u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate)
+{
+       u8 idx;
+
+       BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *));
+
+       if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) {
+               wl1271_error("Illegal RX rate from HW: %d", rate);
+               return 0;
+       }
+
+       idx = wl1271_band_rate_to_idx[wl->band][rate];
+       if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) {
+               wl1271_error("Unsupported RX rate from HW: %d", rate);
+               return 0;
+       }
+
+       return idx;
+}
+
+static ssize_t wl1271_sysfs_show_bt_coex_state(struct device *dev,
+                                              struct device_attribute *attr,
+                                              char *buf)
+{
+       struct wl1271 *wl = dev_get_drvdata(dev);
+       ssize_t len;
+
+       /* FIXME: what's the maximum length of buf? page size?*/
+       len = 500;
+
+       mutex_lock(&wl->mutex);
+       len = snprintf(buf, len, "%d\n\n0 - off\n1 - on\n",
+                      wl->sg_enabled);
+       mutex_unlock(&wl->mutex);
+
+       return len;
+
+}
+
+static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       struct wl1271 *wl = dev_get_drvdata(dev);
+       unsigned long res;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &res);
+
+       if (ret < 0) {
+               wl1271_warning("incorrect value written to bt_coex_mode");
+               return count;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       res = !!res;
+
+       if (res == wl->sg_enabled)
+               goto out;
+
+       wl->sg_enabled = res;
+
+       if (wl->state == WL1271_STATE_OFF)
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl, false);
+       if (ret < 0)
+               goto out;
+
+       wl1271_acx_sg_enable(wl, wl->sg_enabled);
+       wl1271_ps_elp_sleep(wl);
+
+ out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR,
+                  wl1271_sysfs_show_bt_coex_state,
+                  wl1271_sysfs_store_bt_coex_state);
+
+static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct wl1271 *wl = dev_get_drvdata(dev);
+       ssize_t len;
+
+       /* FIXME: what's the maximum length of buf? page size?*/
+       len = 500;
+
+       mutex_lock(&wl->mutex);
+       if (wl->hw_pg_ver >= 0)
+               len = snprintf(buf, len, "%d\n", wl->hw_pg_ver);
+       else
+               len = snprintf(buf, len, "n/a\n");
+       mutex_unlock(&wl->mutex);
+
+       return len;
+}
+
+static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR,
+                  wl1271_sysfs_show_hw_pg_ver, NULL);
+
+int wl1271_register_hw(struct wl1271 *wl)
 {
        int ret;
 
@@ -1981,8 +2288,17 @@ static int wl1271_register_hw(struct wl1271 *wl)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(wl1271_register_hw);
 
-static int wl1271_init_ieee80211(struct wl1271 *wl)
+void wl1271_unregister_hw(struct wl1271 *wl)
+{
+       ieee80211_unregister_hw(wl->hw);
+       wl->mac80211_registered = false;
+
+}
+EXPORT_SYMBOL_GPL(wl1271_unregister_hw);
+
+int wl1271_init_ieee80211(struct wl1271 *wl)
 {
        /* The tx descriptor buffer and the TKIP space. */
        wl->hw->extra_tx_headroom = WL1271_TKIP_IV_SPACE +
@@ -1991,11 +2307,15 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
        /* unit us */
        /* FIXME: find a proper value */
        wl->hw->channel_change_time = 10000;
+       wl->hw->max_listen_interval = wl->conf.conn.max_listen_interval;
 
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_NOISE_DBM |
                IEEE80211_HW_BEACON_FILTER |
-               IEEE80211_HW_SUPPORTS_PS;
+               IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_SUPPORTS_UAPSD |
+               IEEE80211_HW_HAS_RATE_CONTROL |
+               IEEE80211_HW_CONNECTION_MONITOR |
+               IEEE80211_HW_SUPPORTS_CQM_RSSI;
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                BIT(NL80211_IFTYPE_ADHOC);
@@ -2005,51 +2325,53 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
        if (wl1271_11a_enabled())
                wl->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wl1271_band_5ghz;
 
-       SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
-
-       return 0;
-}
+       wl->hw->queues = 4;
+       wl->hw->max_rates = 1;
 
-static void wl1271_device_release(struct device *dev)
-{
+       SET_IEEE80211_DEV(wl->hw, wl1271_wl_to_dev(wl));
 
+       return 0;
 }
-
-static struct platform_device wl1271_device = {
-       .name           = "wl1271",
-       .id             = -1,
-
-       /* device model insists to have a release function */
-       .dev            = {
-               .release = wl1271_device_release,
-       },
-};
+EXPORT_SYMBOL_GPL(wl1271_init_ieee80211);
 
 #define WL1271_DEFAULT_CHANNEL 0
 
-static struct ieee80211_hw *wl1271_alloc_hw(void)
+struct ieee80211_hw *wl1271_alloc_hw(void)
 {
        struct ieee80211_hw *hw;
+       struct platform_device *plat_dev = NULL;
        struct wl1271 *wl;
-       int i;
+       int i, ret;
 
        hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
        if (!hw) {
                wl1271_error("could not alloc ieee80211_hw");
-               return ERR_PTR(-ENOMEM);
+               ret = -ENOMEM;
+               goto err_hw_alloc;
+       }
+
+       plat_dev = kmalloc(sizeof(wl1271_device), GFP_KERNEL);
+       if (!plat_dev) {
+               wl1271_error("could not allocate platform_device");
+               ret = -ENOMEM;
+               goto err_plat_alloc;
        }
 
+       memcpy(plat_dev, &wl1271_device, sizeof(wl1271_device));
+
        wl = hw->priv;
        memset(wl, 0, sizeof(*wl));
 
        INIT_LIST_HEAD(&wl->list);
 
        wl->hw = hw;
+       wl->plat_dev = plat_dev;
 
        skb_queue_head_init(&wl->tx_queue);
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work);
        wl->channel = WL1271_DEFAULT_CHANNEL;
+       wl->beacon_int = WL1271_DEFAULT_BEACON_INT;
        wl->default_key = 0;
        wl->rx_counter = 0;
        wl->rx_config = WL1271_DEFAULT_RX_CONFIG;
@@ -2057,11 +2379,14 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->psm_entry_retry = 0;
        wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
        wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->basic_rate = 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->flags = 0;
+       wl->sg_enabled = true;
+       wl->hw_pg_ver = -1;
 
        for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
                wl->tx_frames[i] = NULL;
@@ -2074,167 +2399,72 @@ static struct ieee80211_hw *wl1271_alloc_hw(void)
        /* Apply default driver configuration. */
        wl1271_conf_init(wl);
 
-       return hw;
-}
-
-int wl1271_free_hw(struct wl1271 *wl)
-{
-       ieee80211_unregister_hw(wl->hw);
-
-       wl1271_debugfs_exit(wl);
-
-       kfree(wl->target_mem_map);
-       vfree(wl->fw);
-       wl->fw = NULL;
-       kfree(wl->nvs);
-       wl->nvs = NULL;
-
-       kfree(wl->fw_status);
-       kfree(wl->tx_res_if);
-
-       ieee80211_free_hw(wl->hw);
-
-       return 0;
-}
-
-static int __devinit wl1271_probe(struct spi_device *spi)
-{
-       struct wl12xx_platform_data *pdata;
-       struct ieee80211_hw *hw;
-       struct wl1271 *wl;
-       int ret;
+       wl1271_debugfs_init(wl);
 
-       pdata = spi->dev.platform_data;
-       if (!pdata) {
-               wl1271_error("no platform data");
-               return -ENODEV;
+       /* Register platform device */
+       ret = platform_device_register(wl->plat_dev);
+       if (ret) {
+               wl1271_error("couldn't register platform device");
+               goto err_hw;
        }
+       dev_set_drvdata(&wl->plat_dev->dev, wl);
 
-       hw = wl1271_alloc_hw();
-       if (IS_ERR(hw))
-               return PTR_ERR(hw);
-
-       wl = hw->priv;
-
-       dev_set_drvdata(&spi->dev, wl);
-       wl->spi = spi;
-
-       /* This is the only SPI value that we need to set here, the rest
-        * comes from the board-peripherals file */
-       spi->bits_per_word = 32;
-
-       ret = spi_setup(spi);
+       /* Create sysfs file to control bt coex state */
+       ret = device_create_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
        if (ret < 0) {
-               wl1271_error("spi_setup failed");
-               goto out_free;
-       }
-
-       wl->set_power = pdata->set_power;
-       if (!wl->set_power) {
-               wl1271_error("set power function missing in platform data");
-               ret = -ENODEV;
-               goto out_free;
+               wl1271_error("failed to create sysfs file bt_coex_state");
+               goto err_platform;
        }
 
-       wl->irq = spi->irq;
-       if (wl->irq < 0) {
-               wl1271_error("irq missing in platform data");
-               ret = -ENODEV;
-               goto out_free;
-       }
-
-       ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
+       /* Create sysfs file to get HW PG version */
+       ret = device_create_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver);
        if (ret < 0) {
-               wl1271_error("request_irq() failed: %d", ret);
-               goto out_free;
-       }
-
-       set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
-
-       disable_irq(wl->irq);
-
-       ret = platform_device_register(&wl1271_device);
-       if (ret) {
-               wl1271_error("couldn't register platform device");
-               goto out_irq;
+               wl1271_error("failed to create sysfs file hw_pg_ver");
+               goto err_bt_coex_state;
        }
-       dev_set_drvdata(&wl1271_device.dev, wl);
-
-       ret = wl1271_init_ieee80211(wl);
-       if (ret)
-               goto out_platform;
-
-       ret = wl1271_register_hw(wl);
-       if (ret)
-               goto out_platform;
-
-       wl1271_debugfs_init(wl);
 
-       wl1271_notice("initialized");
+       return hw;
 
-       return 0;
+err_bt_coex_state:
+       device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state);
 
- out_platform:
-       platform_device_unregister(&wl1271_device);
+err_platform:
+       platform_device_unregister(wl->plat_dev);
 
- out_irq:
-       free_irq(wl->irq, wl);
+err_hw:
+       wl1271_debugfs_exit(wl);
+       kfree(plat_dev);
 
- out_free:
+err_plat_alloc:
        ieee80211_free_hw(hw);
 
-       return ret;
-}
-
-static int __devexit wl1271_remove(struct spi_device *spi)
-{
-       struct wl1271 *wl = dev_get_drvdata(&spi->dev);
+err_hw_alloc:
 
-       platform_device_unregister(&wl1271_device);
-       free_irq(wl->irq, wl);
-
-       wl1271_free_hw(wl);
-
-       return 0;
+       return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
 
-
-static struct spi_driver wl1271_spi_driver = {
-       .driver = {
-               .name           = "wl1271",
-               .bus            = &spi_bus_type,
-               .owner          = THIS_MODULE,
-       },
-
-       .probe          = wl1271_probe,
-       .remove         = __devexit_p(wl1271_remove),
-};
-
-static int __init wl1271_init(void)
+int wl1271_free_hw(struct wl1271 *wl)
 {
-       int ret;
+       platform_device_unregister(wl->plat_dev);
+       kfree(wl->plat_dev);
 
-       ret = spi_register_driver(&wl1271_spi_driver);
-       if (ret < 0) {
-               wl1271_error("failed to register spi driver: %d", ret);
-               goto out;
-       }
+       wl1271_debugfs_exit(wl);
 
-out:
-       return ret;
-}
+       vfree(wl->fw);
+       wl->fw = NULL;
+       kfree(wl->nvs);
+       wl->nvs = NULL;
 
-static void __exit wl1271_exit(void)
-{
-       spi_unregister_driver(&wl1271_spi_driver);
+       kfree(wl->fw_status);
+       kfree(wl->tx_res_if);
 
-       wl1271_notice("unloaded");
-}
+       ieee80211_free_hw(wl->hw);
 
-module_init(wl1271_init);
-module_exit(wl1271_exit);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wl1271_free_hw);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
-MODULE_FIRMWARE(WL1271_FW_NAME);
index e2b1ebf096e84ffa838ccf4613d29a4230f88d70..a5e60e0403e5ad90f2b35f6900dbfa71aafe52ea 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "wl1271_reg.h"
 #include "wl1271_ps.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 
 #define WL1271_WAKEUP_TIMEOUT 500
@@ -41,7 +40,8 @@ void wl1271_elp_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
 
        if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
-           !test_bit(WL1271_FLAG_PSM, &wl->flags))
+           (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
+            !test_bit(WL1271_FLAG_IDLE, &wl->flags)))
                goto out;
 
        wl1271_debug(DEBUG_PSM, "chip to elp");
@@ -57,7 +57,8 @@ out:
 /* Routines to toggle sleep mode while in ELP */
 void wl1271_ps_elp_sleep(struct wl1271 *wl)
 {
-       if (test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+       if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
+           test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
                cancel_delayed_work(&wl->elp_work);
                ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
                                        msecs_to_jiffies(ELP_ENTRY_DELAY));
index c723d9c7e1310c4eb7f263f4405786832b6ef80b..57f4bfd959c8d46519fbe375901d3d2f3de2864f 100644 (file)
@@ -27,7 +27,6 @@
 #include "wl1271_acx.h"
 #include "wl1271_reg.h"
 #include "wl1271_rx.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 
 static u8 wl1271_rx_get_mem_block(struct wl1271_fw_status *status,
@@ -44,66 +43,6 @@ static u32 wl1271_rx_get_buf_size(struct wl1271_fw_status *status,
                RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV;
 }
 
-/* The values of this table must match the wl1271_rates[] array */
-static u8 wl1271_rx_rate_to_idx[] = {
-       /* MCS rates are used only with 11n */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
-
-       11,                         /* WL1271_RATE_54   */
-       10,                         /* WL1271_RATE_48   */
-       9,                          /* WL1271_RATE_36   */
-       8,                          /* WL1271_RATE_24   */
-
-       /* TI-specific rate */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22   */
-
-       7,                          /* WL1271_RATE_18   */
-       6,                          /* WL1271_RATE_12   */
-       3,                          /* WL1271_RATE_11   */
-       5,                          /* WL1271_RATE_9    */
-       4,                          /* WL1271_RATE_6    */
-       2,                          /* WL1271_RATE_5_5  */
-       1,                          /* WL1271_RATE_2    */
-       0                           /* WL1271_RATE_1    */
-};
-
-/* The values of this table must match the wl1271_rates[] array */
-static u8 wl1271_5_ghz_rx_rate_to_idx[] = {
-       /* MCS rates are used only with 11n */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS7 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS6 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS5 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS4 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS3 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS2 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS1 */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_MCS0 */
-
-       7,                          /* WL1271_RATE_54   */
-       6,                          /* WL1271_RATE_48   */
-       5,                          /* WL1271_RATE_36   */
-       4,                          /* WL1271_RATE_24   */
-
-       /* TI-specific rate */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_22   */
-
-       3,                          /* WL1271_RATE_18   */
-       2,                          /* WL1271_RATE_12   */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_11   */
-       1,                          /* WL1271_RATE_9    */
-       0,                          /* WL1271_RATE_6    */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_5_5  */
-       WL1271_RX_RATE_UNSUPPORTED, /* WL1271_RATE_2    */
-       WL1271_RX_RATE_UNSUPPORTED  /* WL1271_RATE_1    */
-};
-
 static void wl1271_rx_status(struct wl1271 *wl,
                             struct wl1271_rx_descriptor *desc,
                             struct ieee80211_rx_status *status,
@@ -111,20 +50,8 @@ static void wl1271_rx_status(struct wl1271 *wl,
 {
        memset(status, 0, sizeof(struct ieee80211_rx_status));
 
-       if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
-           WL1271_RX_DESC_BAND_BG) {
-               status->band = IEEE80211_BAND_2GHZ;
-               status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];
-       } else if ((desc->flags & WL1271_RX_DESC_BAND_MASK) ==
-                WL1271_RX_DESC_BAND_A) {
-               status->band = IEEE80211_BAND_5GHZ;
-               status->rate_idx = wl1271_5_ghz_rx_rate_to_idx[desc->rate];
-       } else
-               wl1271_warning("unsupported band 0x%x",
-                              desc->flags & WL1271_RX_DESC_BAND_MASK);
-
-       if (unlikely(status->rate_idx == WL1271_RX_RATE_UNSUPPORTED))
-               wl1271_warning("unsupported rate");
+       status->band = wl->band;
+       status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);
 
        /*
         * FIXME: Add mactime handling.  For IBSS (ad-hoc) we need to get the
@@ -134,13 +61,6 @@ static void wl1271_rx_status(struct wl1271 *wl,
         */
        status->signal = desc->rssi;
 
-       /*
-        * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
-        * need to divide by two for now, but TI has been discussing about
-        * changing it.  This needs to be rechecked.
-        */
-       status->noise = desc->rssi - (desc->snr >> 1);
-
        status->freq = ieee80211_channel_to_frequency(desc->channel);
 
        if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
@@ -162,6 +82,13 @@ static void wl1271_rx_handle_data(struct wl1271 *wl, u32 length)
        u8 *buf;
        u8 beacon = 0;
 
+       /*
+        * In PLT mode we seem to get frames and mac80211 warns about them,
+        * workaround this by not retrieving them at all.
+        */
+       if (unlikely(wl->state == WL1271_STATE_PLT))
+               return;
+
        skb = __dev_alloc_skb(length, GFP_KERNEL);
        if (!skb) {
                wl1271_error("Couldn't allocate RX frame");
@@ -220,6 +147,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status)
 
                wl->rx_counter++;
                drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK;
-               wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
        }
+
+       wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter);
 }
index 1ae6d1783ed478a24360658ad22be5caff13040a..b89be4758e7884b78718295de7554906d9b9518e 100644 (file)
@@ -43,7 +43,6 @@
 #define RX_MAX_PACKET_ID 3
 
 #define NUM_RX_PKT_DESC_MOD_MASK   7
-#define WL1271_RX_RATE_UNSUPPORTED 0xFF
 
 #define RX_DESC_VALID_FCS         0x0001
 #define RX_DESC_MATCH_RXADDR1     0x0002
@@ -117,5 +116,6 @@ struct wl1271_rx_descriptor {
 } __attribute__ ((packed));
 
 void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
+u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
 
 #endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
new file mode 100644 (file)
index 0000000..d3d6f30
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2009-2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * 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
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/vmalloc.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/card.h>
+#include <plat/gpio.h>
+
+#include "wl1271.h"
+#include "wl12xx_80211.h"
+#include "wl1271_io.h"
+
+
+#define RX71_WL1271_IRQ_GPIO           42
+
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI              0x0097
+#endif
+
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271       0x4076
+#endif
+
+static const struct sdio_device_id wl1271_devices[] = {
+       { SDIO_DEVICE(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271) },
+       {}
+};
+MODULE_DEVICE_TABLE(sdio, wl1271_devices);
+
+static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
+{
+       return wl->if_priv;
+}
+
+static struct device *wl1271_sdio_wl_to_dev(struct wl1271 *wl)
+{
+       return &(wl_to_func(wl)->dev);
+}
+
+static irqreturn_t wl1271_irq(int irq, void *cookie)
+{
+       struct wl1271 *wl = cookie;
+       unsigned long flags;
+
+       wl1271_debug(DEBUG_IRQ, "IRQ");
+
+       /* complete the ELP completion */
+       spin_lock_irqsave(&wl->wl_lock, flags);
+       if (wl->elp_compl) {
+               complete(wl->elp_compl);
+               wl->elp_compl = NULL;
+       }
+
+       if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
+               ieee80211_queue_work(wl->hw, &wl->irq_work);
+       set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static void wl1271_sdio_disable_interrupts(struct wl1271 *wl)
+{
+       disable_irq(wl->irq);
+}
+
+static void wl1271_sdio_enable_interrupts(struct wl1271 *wl)
+{
+       enable_irq(wl->irq);
+}
+
+static void wl1271_sdio_reset(struct wl1271 *wl)
+{
+}
+
+static void wl1271_sdio_init(struct wl1271 *wl)
+{
+}
+
+static void wl1271_sdio_raw_read(struct wl1271 *wl, int addr, void *buf,
+                                size_t len, bool fixed)
+{
+       int ret;
+       struct sdio_func *func = wl_to_func(wl);
+
+       if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
+               ((u8 *)buf)[0] = sdio_f0_readb(func, addr, &ret);
+               wl1271_debug(DEBUG_SDIO, "sdio read 52 addr 0x%x, byte 0x%02x",
+                            addr, ((u8 *)buf)[0]);
+       } else {
+               if (fixed)
+                       ret = sdio_readsb(func, buf, addr, len);
+               else
+                       ret = sdio_memcpy_fromio(func, buf, addr, len);
+
+               wl1271_debug(DEBUG_SDIO, "sdio read 53 addr 0x%x, %zu bytes",
+                            addr, len);
+               wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
+       }
+
+       if (ret)
+               wl1271_error("sdio read failed (%d)", ret);
+
+}
+
+static void wl1271_sdio_raw_write(struct wl1271 *wl, int addr, void *buf,
+                                 size_t len, bool fixed)
+{
+       int ret;
+       struct sdio_func *func = wl_to_func(wl);
+
+       if (unlikely(addr == HW_ACCESS_ELP_CTRL_REG_ADDR)) {
+               sdio_f0_writeb(func, ((u8 *)buf)[0], addr, &ret);
+               wl1271_debug(DEBUG_SDIO, "sdio write 52 addr 0x%x, byte 0x%02x",
+                            addr, ((u8 *)buf)[0]);
+       } else {
+               wl1271_debug(DEBUG_SDIO, "sdio write 53 addr 0x%x, %zu bytes",
+                            addr, len);
+               wl1271_dump_ascii(DEBUG_SDIO, "data: ", buf, len);
+
+               if (fixed)
+                       ret = sdio_writesb(func, addr, buf, len);
+               else
+                       ret = sdio_memcpy_toio(func, addr, buf, len);
+       }
+       if (ret)
+               wl1271_error("sdio write failed (%d)", ret);
+
+}
+
+static void wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
+{
+       struct sdio_func *func = wl_to_func(wl);
+
+       /* Let the SDIO stack handle wlan_enable control, so we
+        * keep host claimed while wlan is in use to keep wl1271
+        * alive.
+        */
+       if (enable) {
+               sdio_claim_host(func);
+               sdio_enable_func(func);
+       } else {
+               sdio_disable_func(func);
+               sdio_release_host(func);
+       }
+}
+
+static struct wl1271_if_operations sdio_ops = {
+       .read           = wl1271_sdio_raw_read,
+       .write          = wl1271_sdio_raw_write,
+       .reset          = wl1271_sdio_reset,
+       .init           = wl1271_sdio_init,
+       .power          = wl1271_sdio_set_power,
+       .dev            = wl1271_sdio_wl_to_dev,
+       .enable_irq     = wl1271_sdio_enable_interrupts,
+       .disable_irq    = wl1271_sdio_disable_interrupts
+};
+
+static int __devinit wl1271_probe(struct sdio_func *func,
+                                 const struct sdio_device_id *id)
+{
+       struct ieee80211_hw *hw;
+       struct wl1271 *wl;
+       int ret;
+
+       /* We are only able to handle the wlan function */
+       if (func->num != 0x02)
+               return -ENODEV;
+
+       hw = wl1271_alloc_hw();
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
+
+       wl = hw->priv;
+
+       wl->if_priv = func;
+       wl->if_ops = &sdio_ops;
+
+       /* Grab access to FN0 for ELP reg. */
+       func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+
+       wl->irq = gpio_to_irq(RX71_WL1271_IRQ_GPIO);
+       if (wl->irq < 0) {
+               ret = wl->irq;
+               wl1271_error("could not get irq!");
+               goto out_free;
+       }
+
+       ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
+       if (ret < 0) {
+               wl1271_error("request_irq() failed: %d", ret);
+               goto out_free;
+       }
+
+       set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+       disable_irq(wl->irq);
+
+       ret = wl1271_init_ieee80211(wl);
+       if (ret)
+               goto out_irq;
+
+       ret = wl1271_register_hw(wl);
+       if (ret)
+               goto out_irq;
+
+       sdio_set_drvdata(func, wl);
+
+       wl1271_notice("initialized");
+
+       return 0;
+
+ out_irq:
+       free_irq(wl->irq, wl);
+
+
+ out_free:
+       wl1271_free_hw(wl);
+
+       return ret;
+}
+
+static void __devexit wl1271_remove(struct sdio_func *func)
+{
+       struct wl1271 *wl = sdio_get_drvdata(func);
+
+       free_irq(wl->irq, wl);
+
+       wl1271_unregister_hw(wl);
+       wl1271_free_hw(wl);
+}
+
+static struct sdio_driver wl1271_sdio_driver = {
+       .name           = "wl1271_sdio",
+       .id_table       = wl1271_devices,
+       .probe          = wl1271_probe,
+       .remove         = __devexit_p(wl1271_remove),
+};
+
+static int __init wl1271_init(void)
+{
+       int ret;
+
+       ret = sdio_register_driver(&wl1271_sdio_driver);
+       if (ret < 0) {
+               wl1271_error("failed to register sdio driver: %d", ret);
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+static void __exit wl1271_exit(void)
+{
+       sdio_unregister_driver(&wl1271_sdio_driver);
+
+       wl1271_notice("unloaded");
+}
+
+module_init(wl1271_init);
+module_exit(wl1271_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
+MODULE_FIRMWARE(WL1271_FW_NAME);
index 053c84aceb4900263ddcd40b188467bfd4e73ce7..5189b812f939e4744b60b46ad637bd7332d1c11e 100644 (file)
  *
  */
 
+#include <linux/irq.h>
 #include <linux/module.h>
-#include <linux/platform_device.h>
 #include <linux/crc7.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/wl12xx.h>
 #include <linux/slab.h>
 
 #include "wl1271.h"
 #include "wl12xx_80211.h"
-#include "wl1271_spi.h"
+#include "wl1271_io.h"
+
+#include "wl1271_reg.h"
+
+#define WSPI_CMD_READ                 0x40000000
+#define WSPI_CMD_WRITE                0x00000000
+#define WSPI_CMD_FIXED                0x20000000
+#define WSPI_CMD_BYTE_LENGTH          0x1FFE0000
+#define WSPI_CMD_BYTE_LENGTH_OFFSET   17
+#define WSPI_CMD_BYTE_ADDR            0x0001FFFF
+
+#define WSPI_INIT_CMD_CRC_LEN       5
+
+#define WSPI_INIT_CMD_START         0x00
+#define WSPI_INIT_CMD_TX            0x40
+/* the extra bypass bit is sampled by the TNET as '1' */
+#define WSPI_INIT_CMD_BYPASS_BIT    0x80
+#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07
+#define WSPI_INIT_CMD_EN_FIXEDBUSY  0x80
+#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00
+#define WSPI_INIT_CMD_IOD           0x40
+#define WSPI_INIT_CMD_IP            0x20
+#define WSPI_INIT_CMD_CS            0x10
+#define WSPI_INIT_CMD_WS            0x08
+#define WSPI_INIT_CMD_WSPI          0x01
+#define WSPI_INIT_CMD_END           0x01
+
+#define WSPI_INIT_CMD_LEN           8
+
+#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
+               ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
+#define HW_ACCESS_WSPI_INIT_CMD_MASK  0
+
+static inline struct spi_device *wl_to_spi(struct wl1271 *wl)
+{
+       return wl->if_priv;
+}
 
+static struct device *wl1271_spi_wl_to_dev(struct wl1271 *wl)
+{
+       return &(wl_to_spi(wl)->dev);
+}
 
-void wl1271_spi_reset(struct wl1271 *wl)
+static void wl1271_spi_disable_interrupts(struct wl1271 *wl)
+{
+       disable_irq(wl->irq);
+}
+
+static void wl1271_spi_enable_interrupts(struct wl1271 *wl)
+{
+       enable_irq(wl->irq);
+}
+
+static void wl1271_spi_reset(struct wl1271 *wl)
 {
        u8 *cmd;
        struct spi_transfer t;
@@ -53,12 +104,13 @@ void wl1271_spi_reset(struct wl1271 *wl)
        t.len = WSPI_INIT_CMD_LEN;
        spi_message_add_tail(&t, &m);
 
-       spi_sync(wl->spi, &m);
+       spi_sync(wl_to_spi(wl), &m);
+       kfree(cmd);
 
        wl1271_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
 }
 
-void wl1271_spi_init(struct wl1271 *wl)
+static void wl1271_spi_init(struct wl1271 *wl)
 {
        u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
        struct spi_transfer t;
@@ -107,48 +159,25 @@ void wl1271_spi_init(struct wl1271 *wl)
        t.len = WSPI_INIT_CMD_LEN;
        spi_message_add_tail(&t, &m);
 
-       spi_sync(wl->spi, &m);
+       spi_sync(wl_to_spi(wl), &m);
+       kfree(cmd);
 
        wl1271_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
 }
 
 #define WL1271_BUSY_WORD_TIMEOUT 1000
 
-/* FIXME: Check busy words, removed due to SPI bug */
-#if 0
-static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
+static int wl1271_spi_read_busy(struct wl1271 *wl)
 {
        struct spi_transfer t[1];
        struct spi_message m;
        u32 *busy_buf;
        int num_busy_bytes = 0;
 
-       wl1271_info("spi read BUSY!");
-
-       /*
-        * Look for the non-busy word in the read buffer, and if found,
-        * read in the remaining data into the buffer.
-        */
-       busy_buf = (u32 *)buf;
-       for (; (u32)busy_buf < (u32)buf + len; busy_buf++) {
-               num_busy_bytes += sizeof(u32);
-               if (*busy_buf & 0x1) {
-                       spi_message_init(&m);
-                       memset(t, 0, sizeof(t));
-                       memmove(buf, busy_buf, len - num_busy_bytes);
-                       t[0].rx_buf = buf + (len - num_busy_bytes);
-                       t[0].len = num_busy_bytes;
-                       spi_message_add_tail(&t[0], &m);
-                       spi_sync(wl->spi, &m);
-                       return;
-               }
-       }
-
        /*
         * Read further busy words from SPI until a non-busy word is
         * encountered, then read the data itself into the buffer.
         */
-       wl1271_info("spi read BUSY-polling needed!");
 
        num_busy_bytes = WL1271_BUSY_WORD_TIMEOUT;
        busy_buf = wl->buffer_busyword;
@@ -158,28 +187,21 @@ static void wl1271_spi_read_busy(struct wl1271 *wl, void *buf, size_t len)
                memset(t, 0, sizeof(t));
                t[0].rx_buf = busy_buf;
                t[0].len = sizeof(u32);
+               t[0].cs_change = true;
                spi_message_add_tail(&t[0], &m);
-               spi_sync(wl->spi, &m);
-
-               if (*busy_buf & 0x1) {
-                       spi_message_init(&m);
-                       memset(t, 0, sizeof(t));
-                       t[0].rx_buf = buf;
-                       t[0].len = len;
-                       spi_message_add_tail(&t[0], &m);
-                       spi_sync(wl->spi, &m);
-                       return;
-               }
+               spi_sync(wl_to_spi(wl), &m);
+
+               if (*busy_buf & 0x1)
+                       return 0;
        }
 
        /* The SPI bus is unresponsive, the read failed. */
-       memset(buf, 0, len);
        wl1271_error("SPI read busy-word timeout!\n");
+       return -ETIMEDOUT;
 }
-#endif
 
-void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
-                        size_t len, bool fixed)
+static void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
+                               size_t len, bool fixed)
 {
        struct spi_transfer t[3];
        struct spi_message m;
@@ -202,28 +224,38 @@ void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
 
        t[0].tx_buf = cmd;
        t[0].len = 4;
+       t[0].cs_change = true;
        spi_message_add_tail(&t[0], &m);
 
        /* Busy and non busy words read */
        t[1].rx_buf = busy_buf;
        t[1].len = WL1271_BUSY_WORD_LEN;
+       t[1].cs_change = true;
        spi_message_add_tail(&t[1], &m);
 
-       t[2].rx_buf = buf;
-       t[2].len = len;
-       spi_message_add_tail(&t[2], &m);
+       spi_sync(wl_to_spi(wl), &m);
 
-       spi_sync(wl->spi, &m);
+       if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) &&
+           wl1271_spi_read_busy(wl)) {
+               memset(buf, 0, len);
+               return;
+       }
 
-       /* FIXME: Check busy words, removed due to SPI bug */
-       /* if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1))
-          wl1271_spi_read_busy(wl, buf, len); */
+       spi_message_init(&m);
+       memset(t, 0, sizeof(t));
+
+       t[0].rx_buf = buf;
+       t[0].len = len;
+       t[0].cs_change = true;
+       spi_message_add_tail(&t[0], &m);
+
+       spi_sync(wl_to_spi(wl), &m);
 
        wl1271_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
        wl1271_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
 }
 
-void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
+static void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
                          size_t len, bool fixed)
 {
        struct spi_transfer t[2];
@@ -251,8 +283,181 @@ void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
        t[1].len = len;
        spi_message_add_tail(&t[1], &m);
 
-       spi_sync(wl->spi, &m);
+       spi_sync(wl_to_spi(wl), &m);
 
        wl1271_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
        wl1271_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
 }
+
+static irqreturn_t wl1271_irq(int irq, void *cookie)
+{
+       struct wl1271 *wl;
+       unsigned long flags;
+
+       wl1271_debug(DEBUG_IRQ, "IRQ");
+
+       wl = cookie;
+
+       /* complete the ELP completion */
+       spin_lock_irqsave(&wl->wl_lock, flags);
+       if (wl->elp_compl) {
+               complete(wl->elp_compl);
+               wl->elp_compl = NULL;
+       }
+
+       if (!test_and_set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags))
+               ieee80211_queue_work(wl->hw, &wl->irq_work);
+       set_bit(WL1271_FLAG_IRQ_PENDING, &wl->flags);
+       spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static void wl1271_spi_set_power(struct wl1271 *wl, bool enable)
+{
+       if (wl->set_power)
+               wl->set_power(enable);
+}
+
+static struct wl1271_if_operations spi_ops = {
+       .read           = wl1271_spi_raw_read,
+       .write          = wl1271_spi_raw_write,
+       .reset          = wl1271_spi_reset,
+       .init           = wl1271_spi_init,
+       .power          = wl1271_spi_set_power,
+       .dev            = wl1271_spi_wl_to_dev,
+       .enable_irq     = wl1271_spi_enable_interrupts,
+       .disable_irq    = wl1271_spi_disable_interrupts
+};
+
+static int __devinit wl1271_probe(struct spi_device *spi)
+{
+       struct wl12xx_platform_data *pdata;
+       struct ieee80211_hw *hw;
+       struct wl1271 *wl;
+       int ret;
+
+       pdata = spi->dev.platform_data;
+       if (!pdata) {
+               wl1271_error("no platform data");
+               return -ENODEV;
+       }
+
+       hw = wl1271_alloc_hw();
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
+
+       wl = hw->priv;
+
+       dev_set_drvdata(&spi->dev, wl);
+       wl->if_priv = spi;
+
+       wl->if_ops = &spi_ops;
+
+       /* This is the only SPI value that we need to set here, the rest
+        * comes from the board-peripherals file */
+       spi->bits_per_word = 32;
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               wl1271_error("spi_setup failed");
+               goto out_free;
+       }
+
+       wl->set_power = pdata->set_power;
+       if (!wl->set_power) {
+               wl1271_error("set power function missing in platform data");
+               ret = -ENODEV;
+               goto out_free;
+       }
+
+       wl->irq = spi->irq;
+       if (wl->irq < 0) {
+               wl1271_error("irq missing in platform data");
+               ret = -ENODEV;
+               goto out_free;
+       }
+
+       ret = request_irq(wl->irq, wl1271_irq, 0, DRIVER_NAME, wl);
+       if (ret < 0) {
+               wl1271_error("request_irq() failed: %d", ret);
+               goto out_free;
+       }
+
+       set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING);
+
+       disable_irq(wl->irq);
+
+       ret = wl1271_init_ieee80211(wl);
+       if (ret)
+               goto out_irq;
+
+       ret = wl1271_register_hw(wl);
+       if (ret)
+               goto out_irq;
+
+       wl1271_notice("initialized");
+
+       return 0;
+
+ out_irq:
+       free_irq(wl->irq, wl);
+
+ out_free:
+       wl1271_free_hw(wl);
+
+       return ret;
+}
+
+static int __devexit wl1271_remove(struct spi_device *spi)
+{
+       struct wl1271 *wl = dev_get_drvdata(&spi->dev);
+
+       free_irq(wl->irq, wl);
+
+       wl1271_unregister_hw(wl);
+       wl1271_free_hw(wl);
+
+       return 0;
+}
+
+
+static struct spi_driver wl1271_spi_driver = {
+       .driver = {
+               .name           = "wl1271_spi",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+
+       .probe          = wl1271_probe,
+       .remove         = __devexit_p(wl1271_remove),
+};
+
+static int __init wl1271_init(void)
+{
+       int ret;
+
+       ret = spi_register_driver(&wl1271_spi_driver);
+       if (ret < 0) {
+               wl1271_error("failed to register spi driver: %d", ret);
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+static void __exit wl1271_exit(void)
+{
+       spi_unregister_driver(&wl1271_spi_driver);
+
+       wl1271_notice("unloaded");
+}
+
+module_init(wl1271_init);
+module_exit(wl1271_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luciano Coelho <luciano.coelho@nokia.com>");
+MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
+MODULE_FIRMWARE(WL1271_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/wl1271_spi.h b/drivers/net/wireless/wl12xx/wl1271_spi.h
deleted file mode 100644 (file)
index a803596..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * This file is part of wl1271
- *
- * Copyright (C) 1998-2009 Texas Instruments. All rights reserved.
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Luciano Coelho <luciano.coelho@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * 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
- *
- */
-
-#ifndef __WL1271_SPI_H__
-#define __WL1271_SPI_H__
-
-#include "wl1271_reg.h"
-
-#define HW_ACCESS_MEMORY_MAX_RANGE             0x1FFC0
-
-#define HW_PARTITION_REGISTERS_ADDR         0x1ffc0
-#define HW_PART0_SIZE_ADDR                  (HW_PARTITION_REGISTERS_ADDR)
-#define HW_PART0_START_ADDR                 (HW_PARTITION_REGISTERS_ADDR + 4)
-#define HW_PART1_SIZE_ADDR                  (HW_PARTITION_REGISTERS_ADDR + 8)
-#define HW_PART1_START_ADDR                 (HW_PARTITION_REGISTERS_ADDR + 12)
-#define HW_PART2_SIZE_ADDR                  (HW_PARTITION_REGISTERS_ADDR + 16)
-#define HW_PART2_START_ADDR                 (HW_PARTITION_REGISTERS_ADDR + 20)
-#define HW_PART3_START_ADDR                 (HW_PARTITION_REGISTERS_ADDR + 24)
-
-#define HW_ACCESS_REGISTER_SIZE             4
-
-#define HW_ACCESS_PRAM_MAX_RANGE               0x3c000
-
-#define WSPI_CMD_READ                 0x40000000
-#define WSPI_CMD_WRITE                0x00000000
-#define WSPI_CMD_FIXED                0x20000000
-#define WSPI_CMD_BYTE_LENGTH          0x1FFE0000
-#define WSPI_CMD_BYTE_LENGTH_OFFSET   17
-#define WSPI_CMD_BYTE_ADDR            0x0001FFFF
-
-#define WSPI_INIT_CMD_CRC_LEN       5
-
-#define WSPI_INIT_CMD_START         0x00
-#define WSPI_INIT_CMD_TX            0x40
-/* the extra bypass bit is sampled by the TNET as '1' */
-#define WSPI_INIT_CMD_BYPASS_BIT    0x80
-#define WSPI_INIT_CMD_FIXEDBUSY_LEN 0x07
-#define WSPI_INIT_CMD_EN_FIXEDBUSY  0x80
-#define WSPI_INIT_CMD_DIS_FIXEDBUSY 0x00
-#define WSPI_INIT_CMD_IOD           0x40
-#define WSPI_INIT_CMD_IP            0x20
-#define WSPI_INIT_CMD_CS            0x10
-#define WSPI_INIT_CMD_WS            0x08
-#define WSPI_INIT_CMD_WSPI          0x01
-#define WSPI_INIT_CMD_END           0x01
-
-#define WSPI_INIT_CMD_LEN           8
-
-#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
-               ((WL1271_BUSY_WORD_LEN - 4) / sizeof(u32))
-#define HW_ACCESS_WSPI_INIT_CMD_MASK  0
-
-#define OCP_CMD_LOOP  32
-
-#define OCP_CMD_WRITE 0x1
-#define OCP_CMD_READ  0x2
-
-#define OCP_READY_MASK  BIT(18)
-#define OCP_STATUS_MASK (BIT(16) | BIT(17))
-
-#define OCP_STATUS_NO_RESP    0x00000
-#define OCP_STATUS_OK         0x10000
-#define OCP_STATUS_REQ_FAILED 0x20000
-#define OCP_STATUS_RESP_ERROR 0x30000
-
-/* Raw target IO, address is not translated */
-void wl1271_spi_raw_write(struct wl1271 *wl, int addr, void *buf,
-                     size_t len, bool fixed);
-void wl1271_spi_raw_read(struct wl1271 *wl, int addr, void *buf,
-                    size_t len, bool fixed);
-
-/* INIT and RESET words */
-void wl1271_spi_reset(struct wl1271 *wl);
-void wl1271_spi_init(struct wl1271 *wl);
-#endif /* __WL1271_SPI_H__ */
index 5c1c4f565fd8be475f3665316a1a6b931bd31497..554deb4d024eae483d6895a5da9b86868d26c158 100644 (file)
@@ -26,7 +26,6 @@
 #include <net/genetlink.h>
 
 #include "wl1271.h"
-#include "wl1271_spi.h"
 #include "wl1271_acx.h"
 
 #define WL1271_TM_MAX_DATA_LENGTH 1024
index 811e739d05bffa2315bbd5c8d9ac77225d102430..62db79508ddfa812b7b96f01cd355a0928b9d97c 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 
 #include "wl1271.h"
-#include "wl1271_spi.h"
 #include "wl1271_io.h"
 #include "wl1271_reg.h"
 #include "wl1271_ps.h"
@@ -47,7 +46,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
 {
        struct wl1271_tx_hw_descr *desc;
        u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
-       u32 total_blocks, excluded;
+       u32 total_blocks;
        int id, ret = -EBUSY;
 
        /* allocate free identifier for the packet */
@@ -57,12 +56,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
 
        /* approximate the number of blocks required for this packet
           in the firmware */
-       /* FIXME: try to figure out what is done here and make it cleaner */
-       total_blocks = (total_len + 20) >> TX_HW_BLOCK_SHIFT_DIV;
-       excluded = (total_blocks << 2) + ((total_len + 20) & 0xff) + 34;
-       total_blocks += (excluded > 252) ? 2 : 1;
-       total_blocks += TX_HW_BLOCK_SPARE;
-
+       total_blocks = total_len + TX_HW_BLOCK_SIZE - 1;
+       total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE;
        if (total_blocks <= wl->tx_blocks_available) {
                desc = (struct wl1271_tx_hw_descr *)skb_push(
                        skb, total_len - skb->len);
@@ -87,8 +82,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
 static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
                              u32 extra, struct ieee80211_tx_info *control)
 {
+       struct timespec ts;
        struct wl1271_tx_hw_descr *desc;
        int pad, ac;
+       s64 hosttime;
        u16 tx_attr;
 
        desc = (struct wl1271_tx_hw_descr *) skb->data;
@@ -102,8 +99,9 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
        }
 
        /* configure packet life time */
-       desc->start_time = cpu_to_le32(jiffies_to_usecs(jiffies) -
-                                      wl->time_offset);
+       getnstimeofday(&ts);
+       hosttime = (timespec_to_ns(&ts) >> 10);
+       desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
        desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
 
        /* configure the tx attributes */
@@ -170,7 +168,6 @@ static int wl1271_tx_send_packet(struct wl1271 *wl, struct sk_buff *skb,
 
        /* write packet new counter into the write access register */
        wl->tx_packets_count++;
-       wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
 
        desc = (struct wl1271_tx_hw_descr *) skb->data;
        wl1271_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u (%u words)",
@@ -223,7 +220,7 @@ 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)
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
 {
        struct ieee80211_supported_band *band;
        u32 enabled_rates = 0;
@@ -245,6 +242,7 @@ void wl1271_tx_work(struct work_struct *work)
        struct sk_buff *skb;
        bool woken_up = false;
        u32 sta_rates = 0;
+       u32 prev_tx_packets_count;
        int ret;
 
        /* check if the rates supported by the AP have changed */
@@ -261,6 +259,8 @@ void wl1271_tx_work(struct work_struct *work)
        if (unlikely(wl->state == WL1271_STATE_OFF))
                goto out;
 
+       prev_tx_packets_count = wl->tx_packets_count;
+
        /* if rates have changed, re-configure the rate policy */
        if (unlikely(sta_rates)) {
                wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates);
@@ -271,31 +271,26 @@ void wl1271_tx_work(struct work_struct *work)
                if (!woken_up) {
                        ret = wl1271_ps_elp_wakeup(wl, false);
                        if (ret < 0)
-                               goto out;
+                               goto out_ack;
                        woken_up = true;
                }
 
                ret = wl1271_tx_frame(wl, skb);
                if (ret == -EBUSY) {
-                       /* firmware buffer is full, stop queues */
-                       wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, "
-                                    "stop queues");
-                       ieee80211_stop_queues(wl->hw);
-                       set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+                       /* firmware buffer is full, lets stop transmitting. */
                        skb_queue_head(&wl->tx_queue, skb);
-                       goto out;
+                       goto out_ack;
                } else if (ret < 0) {
                        dev_kfree_skb(skb);
-                       goto out;
-               } 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);
+                       goto out_ack;
                }
        }
 
+out_ack:
+       /* interrupt the firmware with the new packets */
+       if (prev_tx_packets_count != wl->tx_packets_count)
+               wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count);
+
 out:
        if (woken_up)
                wl1271_ps_elp_sleep(wl);
@@ -308,11 +303,12 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 {
        struct ieee80211_tx_info *info;
        struct sk_buff *skb;
-       u16 seq;
        int id = result->id;
+       int rate = -1;
+       u8 retries = 0;
 
        /* check for id legality */
-       if (id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL) {
+       if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) {
                wl1271_warning("TX result illegal id: %d", id);
                return;
        }
@@ -320,31 +316,29 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
        skb = wl->tx_frames[id];
        info = IEEE80211_SKB_CB(skb);
 
-       /* update packet status */
-       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-               if (result->status == TX_SUCCESS)
+       /* update the TX status info */
+       if (result->status == TX_SUCCESS) {
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                        info->flags |= IEEE80211_TX_STAT_ACK;
-               if (result->status & TX_RETRY_EXCEEDED) {
-                       /* FIXME */
-                       /* info->status.excessive_retries = 1; */
-                       wl->stats.excessive_retries++;
-               }
+               rate = wl1271_rate_to_idx(wl, result->rate_class_index);
+               retries = result->ack_failures;
+       } else if (result->status == TX_RETRY_EXCEEDED) {
+               wl->stats.excessive_retries++;
+               retries = result->ack_failures;
        }
 
-       /* FIXME */
-       /* info->status.retry_count = result->ack_failures; */
+       info->status.rates[0].idx = rate;
+       info->status.rates[0].count = retries;
+       info->status.rates[0].flags = 0;
+       info->status.ack_signal = -1;
+
        wl->stats.retry_count += result->ack_failures;
 
        /* update security sequence number */
-       seq = wl->tx_security_seq_16 +
-               (result->lsb_security_sequence_number -
-                wl->tx_security_last_seq);
+       wl->tx_security_seq += (result->lsb_security_sequence_number -
+                               wl->tx_security_last_seq);
        wl->tx_security_last_seq = result->lsb_security_sequence_number;
 
-       if (seq < wl->tx_security_seq_16)
-               wl->tx_security_seq_32++;
-       wl->tx_security_seq_16 = seq;
-
        /* remove private header from packet */
        skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
 
@@ -367,23 +361,29 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
 }
 
 /* Called upon reception of a TX complete interrupt */
-void wl1271_tx_complete(struct wl1271 *wl, u32 count)
+void wl1271_tx_complete(struct wl1271 *wl)
 {
        struct wl1271_acx_mem_map *memmap =
                (struct wl1271_acx_mem_map *)wl->target_mem_map;
+       u32 count, fw_counter;
        u32 i;
 
-       wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
-
        /* read the tx results from the chipset */
        wl1271_read(wl, le32_to_cpu(memmap->tx_result),
                    wl->tx_res_if, sizeof(*wl->tx_res_if), false);
+       fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
+
+       /* write host counter to chipset (to ack) */
+       wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
+                      offsetof(struct wl1271_tx_hw_res_if,
+                               tx_result_host_counter), fw_counter);
+
+       count = fw_counter - wl->tx_results_count;
+       wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
 
        /* verify that the result buffer is not getting overrun */
-       if (count > TX_HW_RESULT_QUEUE_LEN) {
+       if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
                wl1271_warning("TX result overflow from chipset: %d", count);
-               count = TX_HW_RESULT_QUEUE_LEN;
-       }
 
        /* process the results */
        for (i = 0; i < count; i++) {
@@ -397,11 +397,18 @@ void wl1271_tx_complete(struct wl1271 *wl, u32 count)
                wl->tx_results_count++;
        }
 
-       /* write host counter to chipset (to ack) */
-       wl1271_write32(wl, le32_to_cpu(memmap->tx_result) +
-                      offsetof(struct wl1271_tx_hw_res_if,
-                      tx_result_host_counter),
-                      le32_to_cpu(wl->tx_res_if->tx_result_fw_counter));
+       if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) &&
+           skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) {
+               unsigned long flags;
+
+               /* firmware buffer has space, restart queues */
+               wl1271_debug(DEBUG_TX, "tx_complete: waking queues");
+               spin_lock_irqsave(&wl->wl_lock, flags);
+               ieee80211_wake_queues(wl->hw);
+               clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags);
+               spin_unlock_irqrestore(&wl->wl_lock, flags);
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+       }
 }
 
 /* caller must hold wl->mutex */
@@ -409,31 +416,19 @@ void wl1271_tx_flush(struct wl1271 *wl)
 {
        int i;
        struct sk_buff *skb;
-       struct ieee80211_tx_info *info;
 
        /* TX failure */
 /*     control->flags = 0; FIXME */
 
        while ((skb = skb_dequeue(&wl->tx_queue))) {
-               info = IEEE80211_SKB_CB(skb);
-
                wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb);
-
-               if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
-                               continue;
-
                ieee80211_tx_status(wl->hw, skb);
        }
 
        for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
                if (wl->tx_frames[i] != NULL) {
                        skb = wl->tx_frames[i];
-                       info = IEEE80211_SKB_CB(skb);
-
-                       if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
-                               continue;
-
-                       ieee80211_tx_status(wl->hw, skb);
                        wl->tx_frames[i] = NULL;
+                       ieee80211_tx_status(wl->hw, skb);
                }
 }
index 17e405a09caaed632ea308f18c6703ff82e4538f..3b8b7ac253fd544ed594d45f9ea7e74f51e59486 100644 (file)
@@ -26,7 +26,7 @@
 #define __WL1271_TX_H__
 
 #define TX_HW_BLOCK_SPARE                2
-#define TX_HW_BLOCK_SHIFT_DIV            8
+#define TX_HW_BLOCK_SIZE                 252
 
 #define TX_HW_MGMT_PKT_LIFETIME_TU       2000
 /* The chipset reference driver states, that the "aid" value 1
@@ -125,9 +125,6 @@ struct wl1271_tx_hw_res_if {
 
 static inline int wl1271_tx_get_queue(int queue)
 {
-       /* FIXME: use best effort until WMM is enabled */
-       return CONF_TX_AC_BE;
-
        switch (queue) {
        case 0:
                return CONF_TX_AC_VO;
@@ -160,7 +157,9 @@ static inline int wl1271_tx_ac_to_tid(int ac)
 }
 
 void wl1271_tx_work(struct work_struct *work);
-void wl1271_tx_complete(struct wl1271 *wl, u32 count);
+void wl1271_tx_complete(struct wl1271 *wl);
 void wl1271_tx_flush(struct wl1271 *wl);
+u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
 
 #endif
index 5e5d24c1ce2b60f9ec6eb31ea7290fa70d725c4e..376c6b964a9ce31f652fce6524f944d2ee2e3d55 100644 (file)
@@ -1307,7 +1307,7 @@ static void wl3501_tx_timeout(struct net_device *dev)
                printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
                       dev->name, rc);
        else {
-               dev->trans_start = jiffies;
+               dev->trans_start = jiffies; /* prevent tx timeout */
                netif_wake_queue(dev);
        }
 }
@@ -1326,7 +1326,6 @@ static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb,
 
        spin_lock_irqsave(&this->lock, flags);
        enabled = wl3501_block_interrupt(this);
-       dev->trans_start = jiffies;
        rc = wl3501_send_pkt(this, skb->data, skb->len);
        if (enabled)
                wl3501_unblock_interrupt(this);
@@ -1455,8 +1454,6 @@ static void wl3501_detach(struct pcmcia_device *link)
 
        if (link->priv)
                free_netdev(link->priv);
-
-       return;
 }
 
 static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info,
@@ -1836,32 +1833,32 @@ out:
 }
 
 static const iw_handler        wl3501_handler[] = {
-       [SIOCGIWNAME    - SIOCIWFIRST] = wl3501_get_name,
-       [SIOCSIWFREQ    - SIOCIWFIRST] = wl3501_set_freq,
-       [SIOCGIWFREQ    - SIOCIWFIRST] = wl3501_get_freq,
-       [SIOCSIWMODE    - SIOCIWFIRST] = wl3501_set_mode,
-       [SIOCGIWMODE    - SIOCIWFIRST] = wl3501_get_mode,
-       [SIOCGIWSENS    - SIOCIWFIRST] = wl3501_get_sens,
-       [SIOCGIWRANGE   - SIOCIWFIRST] = wl3501_get_range,
-       [SIOCSIWSPY     - SIOCIWFIRST] = iw_handler_set_spy,
-       [SIOCGIWSPY     - SIOCIWFIRST] = iw_handler_get_spy,
-       [SIOCSIWTHRSPY  - SIOCIWFIRST] = iw_handler_set_thrspy,
-       [SIOCGIWTHRSPY  - SIOCIWFIRST] = iw_handler_get_thrspy,
-       [SIOCSIWAP      - SIOCIWFIRST] = wl3501_set_wap,
-       [SIOCGIWAP      - SIOCIWFIRST] = wl3501_get_wap,
-       [SIOCSIWSCAN    - SIOCIWFIRST] = wl3501_set_scan,
-       [SIOCGIWSCAN    - SIOCIWFIRST] = wl3501_get_scan,
-       [SIOCSIWESSID   - SIOCIWFIRST] = wl3501_set_essid,
-       [SIOCGIWESSID   - SIOCIWFIRST] = wl3501_get_essid,
-       [SIOCSIWNICKN   - SIOCIWFIRST] = wl3501_set_nick,
-       [SIOCGIWNICKN   - SIOCIWFIRST] = wl3501_get_nick,
-       [SIOCGIWRATE    - SIOCIWFIRST] = wl3501_get_rate,
-       [SIOCGIWRTS     - SIOCIWFIRST] = wl3501_get_rts_threshold,
-       [SIOCGIWFRAG    - SIOCIWFIRST] = wl3501_get_frag_threshold,
-       [SIOCGIWTXPOW   - SIOCIWFIRST] = wl3501_get_txpow,
-       [SIOCGIWRETRY   - SIOCIWFIRST] = wl3501_get_retry,
-       [SIOCGIWENCODE  - SIOCIWFIRST] = wl3501_get_encode,
-       [SIOCGIWPOWER   - SIOCIWFIRST] = wl3501_get_power,
+       IW_HANDLER(SIOCGIWNAME, wl3501_get_name),
+       IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq),
+       IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq),
+       IW_HANDLER(SIOCSIWMODE, wl3501_set_mode),
+       IW_HANDLER(SIOCGIWMODE, wl3501_get_mode),
+       IW_HANDLER(SIOCGIWSENS, wl3501_get_sens),
+       IW_HANDLER(SIOCGIWRANGE, wl3501_get_range),
+       IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
+       IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
+       IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
+       IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
+       IW_HANDLER(SIOCSIWAP, wl3501_set_wap),
+       IW_HANDLER(SIOCGIWAP, wl3501_get_wap),
+       IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan),
+       IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan),
+       IW_HANDLER(SIOCSIWESSID, wl3501_set_essid),
+       IW_HANDLER(SIOCGIWESSID, wl3501_get_essid),
+       IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick),
+       IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick),
+       IW_HANDLER(SIOCGIWRATE, wl3501_get_rate),
+       IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold),
+       IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold),
+       IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow),
+       IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry),
+       IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode),
+       IW_HANDLER(SIOCGIWPOWER, wl3501_get_power),
 };
 
 static const struct iw_handler_def wl3501_handler_def = {
index 9d12778746452161990e55363487b312dc449be8..390d77f762c49fc9c2d9e4889f282d3efba40212 100644 (file)
@@ -134,7 +134,6 @@ static void zd1201_usbfree(struct urb *urb)
 
        kfree(urb->transfer_buffer);
        usb_free_urb(urb);
-       return;
 }
 
 /* cmdreq message: 
@@ -185,7 +184,6 @@ static void zd1201_usbtx(struct urb *urb)
 {
        struct zd1201 *zd = urb->context;
        netif_wake_queue(zd->dev);
-       return;
 }
 
 /* Incoming data */
@@ -407,7 +405,6 @@ exit:
                wake_up(&zd->rxdataq);
                kfree(urb->transfer_buffer);
        }
-       return;
 }
 
 static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
@@ -827,7 +824,6 @@ static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb,
        } else {
                dev->stats.tx_packets++;
                dev->stats.tx_bytes += skb->len;
-               dev->trans_start = jiffies;
        }
        kfree_skb(skb);
 
@@ -845,7 +841,7 @@ static void zd1201_tx_timeout(struct net_device *dev)
        usb_unlink_urb(zd->tx_urb);
        dev->stats.tx_errors++;
        /* Restart the timeout to quiet the watchdog: */
-       dev->trans_start = jiffies;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 static int zd1201_set_mac_address(struct net_device *dev, void *p)
@@ -876,7 +872,7 @@ static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
 static void zd1201_set_multicast(struct net_device *dev)
 {
        struct zd1201 *zd = netdev_priv(dev);
-       struct dev_mc_list *mc;
+       struct netdev_hw_addr *ha;
        unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
        int i;
 
@@ -884,8 +880,8 @@ static void zd1201_set_multicast(struct net_device *dev)
                return;
 
        i = 0;
-       netdev_for_each_mc_addr(mc, dev)
-               memcpy(reqbuf + i++ * ETH_ALEN, mc->dmi_addr, ETH_ALEN);
+       netdev_for_each_mc_addr(ha, dev)
+               memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
        zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
                         netdev_mc_count(dev) * ETH_ALEN, 0);
 }
index 16fa289ad77b20367aeff3cd9f1327eb66b25f0c..b0b666019a9321752bb8f69ff4fa8ecca567b01f 100644 (file)
@@ -948,20 +948,17 @@ static void set_rx_filter_handler(struct work_struct *work)
 }
 
 static u64 zd_op_prepare_multicast(struct ieee80211_hw *hw,
-                                  int mc_count, struct dev_addr_list *mclist)
+                                  struct netdev_hw_addr_list *mc_list)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
        struct zd_mc_hash hash;
-       int i;
+       struct netdev_hw_addr *ha;
 
        zd_mc_clear(&hash);
 
-       for (i = 0; i < mc_count; i++) {
-               if (!mclist)
-                       break;
-               dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", mclist->dmi_addr);
-               zd_mc_add_addr(&hash, mclist->dmi_addr);
-               mclist = mclist->next;
+       netdev_hw_addr_list_for_each(ha, mc_list) {
+               dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", ha->addr);
+               zd_mc_add_addr(&hash, ha->addr);
        }
 
        return hash.low | ((u64)hash.high << 32);
index 1e783ccc306ebe7866de609f2df0c4ff5a277ca3..a7db68d37ee98c3e3359507ad31630110a55d8f4 100644 (file)
@@ -558,7 +558,7 @@ static void xemaclite_tx_timeout(struct net_device *dev)
        }
 
        /* To exclude tx timeout */
-       dev->trans_start = 0xffffffff - TX_TIMEOUT - TX_TIMEOUT;
+       dev->trans_start = jiffies; /* prevent tx timeout */
 
        /* We're all ready to go. Start the queue */
        netif_wake_queue(dev);
@@ -590,7 +590,7 @@ static void xemaclite_tx_handler(struct net_device *dev)
                        dev->stats.tx_bytes += lp->deferred_skb->len;
                        dev_kfree_skb_irq(lp->deferred_skb);
                        lp->deferred_skb = NULL;
-                       dev->trans_start = jiffies;
+                       dev->trans_start = jiffies; /* prevent tx timeout */
                        netif_wake_queue(dev);
                }
        }
@@ -639,7 +639,6 @@ static void xemaclite_rx_handler(struct net_device *dev)
        }
 
        skb_put(skb, len);      /* Tell the skb how much data we got */
-       skb->dev = dev;         /* Fill out required meta-data */
 
        skb->protocol = eth_type_trans(skb, dev);
        skb->ip_summed = CHECKSUM_NONE;
@@ -1055,7 +1054,6 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
 
        dev->stats.tx_bytes += len;
        dev_kfree_skb(new_skb);
-       dev->trans_start = jiffies;
 
        return 0;
 }
@@ -1172,7 +1170,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
        }
 
        /* Get the virtual base address for the device */
-       lp->base_addr = ioremap(r_mem.start, r_mem.end - r_mem.start + 1);
+       lp->base_addr = ioremap(r_mem.start, resource_size(&r_mem));
        if (NULL == lp->base_addr) {
                dev_err(dev, "EmacLite: Could not allocate iomem\n");
                rc = -EIO;
@@ -1225,7 +1223,7 @@ static int __devinit xemaclite_of_probe(struct of_device *ofdev,
        return 0;
 
 error1:
-       release_mem_region(ndev->mem_start, r_mem.end - r_mem.start + 1);
+       release_mem_region(ndev->mem_start, resource_size(&r_mem));
 
 error2:
        xemaclite_remove_ndev(ndev);
index ede5b2436f2271f31743cd1efa285b281bf1a6c2..4eb67aed68ddaf020d8e0f61020bb3bab7f55a67 100644 (file)
@@ -564,7 +564,6 @@ static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value
        for (i = 10000; i >= 0; i--)
                if ((ioread16(ioaddr + MII_Status) & 1) == 0)
                        break;
-       return;
 }
 
 
@@ -1299,25 +1298,25 @@ static void set_rx_mode(struct net_device *dev)
                /* Too many to filter well, or accept all multicasts. */
                iowrite16(0x000B, ioaddr + AddrMode);
        } else if (!netdev_mc_empty(dev)) { /* Must use the multicast hash table. */
-               struct dev_mc_list *mclist;
+               struct netdev_hw_addr *ha;
                u16 hash_table[4];
                int i;
 
                memset(hash_table, 0, sizeof(hash_table));
-               netdev_for_each_mc_addr(mclist, dev) {
+               netdev_for_each_mc_addr(ha, dev) {
                        unsigned int bit;
 
                        /* Due to a bug in the early chip versions, multiple filter
                           slots must be set for each address. */
                        if (yp->drv_flags & HasMulticastBug) {
-                               bit = (ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f;
+                               bit = (ether_crc_le(3, ha->addr) >> 3) & 0x3f;
                                hash_table[bit >> 4] |= (1 << bit);
-                               bit = (ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f;
+                               bit = (ether_crc_le(4, ha->addr) >> 3) & 0x3f;
                                hash_table[bit >> 4] |= (1 << bit);
-                               bit = (ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f;
+                               bit = (ether_crc_le(5, ha->addr) >> 3) & 0x3f;
                                hash_table[bit >> 4] |= (1 << bit);
                        }
-                       bit = (ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f;
+                       bit = (ether_crc_le(6, ha->addr) >> 3) & 0x3f;
                        hash_table[bit >> 4] |= (1 << bit);
                }
                /* Copy the hash table to the chip. */
index dbfef8d70f2dfdf7660496c473308b5302f1b1d9..c3a3292045114bf86a285622ad7b75efeef89fa3 100644 (file)
@@ -587,7 +587,6 @@ static netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev)
                }
                spin_unlock_irqrestore (&znet->lock, flags);
 
-               dev->trans_start = jiffies;
                netif_start_queue (dev);
 
                if (znet_debug > 4)
@@ -802,7 +801,6 @@ static void znet_rx(struct net_device *dev)
        /* If any worth-while packets have been received, dev_rint()
           has done a mark_bh(INET_BH) for us and will work on them
           when we get to the bottom-half routine. */
-       return;
 }
 
 /* The inverse routine to znet_open(). */
index 9548cbb5012a69305b799d6fc68664f072fc3bd5..b78a38d9172a52d8517faba9df5cb914d5215e1c 100644 (file)
@@ -431,7 +431,6 @@ static void zorro8390_block_output(struct net_device *dev, int count,
 
     z_writeb(ENISR_RDC, nic_base + NE_EN0_ISR);        /* Ack intr. */
     ei_status.dmaing &= ~0x01;
-    return;
 }
 
 static void __devexit zorro8390_remove_one(struct zorro_dev *z)
index e35713dd05040d6ef75e26f18833bf447469db27..4ecafbf91211b72775315a95e20a322e0e11e834 100644 (file)
@@ -1364,8 +1364,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type,
 
        ch->protocol = priv->protocol;
        if (IS_MPC(priv)) {
-               ch->discontact_th = (struct th_header *)
-                               kzalloc(TH_HEADER_LENGTH, gfp_type());
+               ch->discontact_th = kzalloc(TH_HEADER_LENGTH, gfp_type());
                if (ch->discontact_th == NULL)
                                        goto nomem_return;
 
@@ -1379,8 +1378,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type,
        } else
                ccw_num = 8;
 
-       ch->ccw = (struct ccw1 *)
-               kzalloc(ccw_num * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+       ch->ccw = kzalloc(ccw_num * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
        if (ch->ccw == NULL)
                                        goto nomem_return;
 
index 5978b390153f82210a67650852643518c9fd0dae..87c24d2936d6e34d1de09da7ebe27aff148d8f61 100644 (file)
@@ -669,8 +669,7 @@ static void ctcmpc_send_sweep_resp(struct channel *rch)
                                goto done;
        }
 
-       header = (struct th_sweep *)
-                       kmalloc(sizeof(struct th_sweep), gfp_type());
+       header = kmalloc(sizeof(struct th_sweep), gfp_type());
 
        if (!header) {
                dev_kfree_skb_any(sweep_skb);
@@ -1191,8 +1190,7 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
                        skb_pull(pskb, new_len); /* point to next PDU */
                }
        } else {
-               mpcginfo = (struct mpcg_info *)
-                               kmalloc(sizeof(struct mpcg_info), gfp_type());
+               mpcginfo = kmalloc(sizeof(struct mpcg_info), gfp_type());
                if (mpcginfo == NULL)
                                        goto done;
 
index 9b19ea13b4d8593302620a60da62bf8c653abdef..0f19d540b655be900be7e946fd0838c77d95bb03 100644 (file)
@@ -1238,8 +1238,7 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev)
                ipm = lcs_check_addr_entry(card, im4, buf);
                if (ipm != NULL)
                        continue;       /* Address already in list. */
-               ipm = (struct lcs_ipm_list *)
-                       kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);
+               ipm = kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);
                if (ipm == NULL) {
                        pr_info("Not enough memory to add"
                                " new multicast entry!\n");
index fcd005aad98919897f09051e3c461f92f9fa0c2e..7a44c38aaf65bdbd7fcc8c69c2712a21c053deeb 100644 (file)
@@ -179,25 +179,23 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa,
         ((prot == QETH_PROT_IPV6) ? \
                qeth_is_enabled6(c, f) : qeth_is_enabled(c, f))
 
-#define QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT 0x0101
-#define QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT 0x0101
+#define QETH_IDX_FUNC_LEVEL_OSD                 0x0101
 #define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
 #define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
 
 #define QETH_MODELLIST_ARRAY \
-       {{0x1731, 0x01, 0x1732, 0x01, QETH_CARD_TYPE_OSAE, 1, \
-       QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
-       QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
-       QETH_MAX_QUEUES, 0}, \
-       {0x1731, 0x05, 0x1732, 0x05, QETH_CARD_TYPE_IQD, 0, \
-       QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \
-       QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \
-       QETH_MAX_QUEUES, 0x103}, \
-       {0x1731, 0x06, 0x1732, 0x06, QETH_CARD_TYPE_OSN, 0, \
-       QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
-       QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
-       QETH_MAX_QUEUES, 0}, \
-       {0, 0, 0, 0, 0, 0, 0, 0, 0} }
+       {{0x1731, 0x01, 0x1732, QETH_CARD_TYPE_OSD, QETH_MAX_QUEUES, 0}, \
+        {0x1731, 0x05, 0x1732, QETH_CARD_TYPE_IQD, QETH_MAX_QUEUES, 0x103}, \
+        {0x1731, 0x06, 0x1732, QETH_CARD_TYPE_OSN, QETH_MAX_QUEUES, 0}, \
+        {0x1731, 0x02, 0x1732, QETH_CARD_TYPE_OSM, QETH_MAX_QUEUES, 0}, \
+        {0x1731, 0x02, 0x1732, QETH_CARD_TYPE_OSX, QETH_MAX_QUEUES, 0}, \
+        {0, 0, 0, 0, 0, 0} }
+#define QETH_CU_TYPE_IND       0
+#define QETH_CU_MODEL_IND      1
+#define QETH_DEV_TYPE_IND      2
+#define QETH_DEV_MODEL_IND     3
+#define QETH_QUEUE_NO_IND      4
+#define QETH_MULTICAST_IND     5
 
 #define QETH_REAL_CARD         1
 #define QETH_VLAN_CARD         2
@@ -351,7 +349,7 @@ enum qeth_header_ids {
 #define QETH_HDR_EXT_SRC_MAC_ADDR     0x08
 #define QETH_HDR_EXT_CSUM_HDR_REQ     0x10
 #define QETH_HDR_EXT_CSUM_TRANSP_REQ  0x20
-#define QETH_HDR_EXT_UDP_TSO          0x40 /*bit off for TCP*/
+#define QETH_HDR_EXT_UDP             0x40 /*bit off for TCP*/
 
 static inline int qeth_is_last_sbale(struct qdio_buffer_element *sbale)
 {
@@ -630,6 +628,7 @@ struct qeth_card_info {
        int unique_id;
        struct qeth_card_blkt blkt;
        __u32 csum_mask;
+       __u32 tx_csum_mask;
        enum qeth_ipa_promisc_modes promisc_mode;
 };
 
@@ -739,6 +738,7 @@ struct qeth_card {
        atomic_t force_alloc_skb;
        struct service_level qeth_service_level;
        struct qdio_ssqd_desc ssqd;
+       struct mutex conf_mutex;
 };
 
 struct qeth_card_list_struct {
index 28f71349fdeca9355a01be3fa10b742d66ba714c..13ef46b9d388714abb3c72efaa1dcffc6f259a43 100644 (file)
@@ -53,7 +53,7 @@ struct kmem_cache *qeth_core_header_cache;
 EXPORT_SYMBOL_GPL(qeth_core_header_cache);
 
 static struct device *qeth_core_root_dev;
-static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY;
+static unsigned int known_devices[][6] = QETH_MODELLIST_ARRAY;
 static struct lock_class_key qdio_out_skb_queue_key;
 
 static void qeth_send_control_data_cb(struct qeth_channel *,
@@ -111,21 +111,29 @@ static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
        if (card->info.guestlan) {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        return " Guest LAN QDIO";
                case QETH_CARD_TYPE_IQD:
                        return " Guest LAN Hiper";
+               case QETH_CARD_TYPE_OSM:
+                       return " Guest LAN QDIO - OSM";
+               case QETH_CARD_TYPE_OSX:
+                       return " Guest LAN QDIO - OSX";
                default:
                        return " unknown";
                }
        } else {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        return " OSD Express";
                case QETH_CARD_TYPE_IQD:
                        return " HiperSockets";
                case QETH_CARD_TYPE_OSN:
                        return " OSN QDIO";
+               case QETH_CARD_TYPE_OSM:
+                       return " OSM QDIO";
+               case QETH_CARD_TYPE_OSX:
+                       return " OSX QDIO";
                default:
                        return " unknown";
                }
@@ -138,16 +146,20 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
 {
        if (card->info.guestlan) {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        return "GuestLAN QDIO";
                case QETH_CARD_TYPE_IQD:
                        return "GuestLAN Hiper";
+               case QETH_CARD_TYPE_OSM:
+                       return "GuestLAN OSM";
+               case QETH_CARD_TYPE_OSX:
+                       return "GuestLAN OSX";
                default:
                        return "unknown";
                }
        } else {
                switch (card->info.type) {
-               case QETH_CARD_TYPE_OSAE:
+               case QETH_CARD_TYPE_OSD:
                        switch (card->info.link_type) {
                        case QETH_LINK_TYPE_FAST_ETH:
                                return "OSD_100";
@@ -172,6 +184,10 @@ const char *qeth_get_cardname_short(struct qeth_card *card)
                        return "HiperSockets";
                case QETH_CARD_TYPE_OSN:
                        return "OSN";
+               case QETH_CARD_TYPE_OSM:
+                       return "OSM_1000";
+               case QETH_CARD_TYPE_OSX:
+                       return "OSX_10GIG";
                default:
                        return "unknown";
                }
@@ -419,7 +435,8 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
 
-static int qeth_check_idx_response(unsigned char *buffer)
+static int qeth_check_idx_response(struct qeth_card *card,
+       unsigned char *buffer)
 {
        if (!buffer)
                return 0;
@@ -434,6 +451,12 @@ static int qeth_check_idx_response(unsigned char *buffer)
                QETH_DBF_TEXT(TRACE, 2, "ckidxres");
                QETH_DBF_TEXT(TRACE, 2, " idxterm");
                QETH_DBF_TEXT_(TRACE, 2, "  rc%d", -EIO);
+               if (buffer[4] == 0xf6) {
+                       dev_err(&card->gdev->dev,
+                       "The qeth device is not configured "
+                       "for the OSI layer required by z/VM\n");
+                       return -EPERM;
+               }
                return -EIO;
        }
        return 0;
@@ -528,18 +551,19 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
        struct qeth_ipa_cmd *cmd;
        unsigned long flags;
        int keep_reply;
+       int rc = 0;
 
        QETH_DBF_TEXT(TRACE, 4, "sndctlcb");
 
        card = CARD_FROM_CDEV(channel->ccwdev);
-       if (qeth_check_idx_response(iob->data)) {
+       rc = qeth_check_idx_response(card, iob->data);
+       switch (rc) {
+       case 0:
+               break;
+       case -EIO:
                qeth_clear_ipacmd_list(card);
-               if (((iob->data[2] & 0xc0) == 0xc0) && iob->data[4] == 0xf6)
-                       dev_err(&card->gdev->dev,
-                               "The qeth device is not configured "
-                               "for the OSI layer required by z/VM\n");
-               else
-                       qeth_schedule_recovery(card);
+               qeth_schedule_recovery(card);
+       default:
                goto out;
        }
 
@@ -606,7 +630,7 @@ static int qeth_setup_channel(struct qeth_channel *channel)
 
        QETH_DBF_TEXT(SETUP, 2, "setupch");
        for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) {
-               channel->iob[cnt].data = (char *)
+               channel->iob[cnt].data =
                        kmalloc(QETH_BUFSIZE, GFP_DMA|GFP_KERNEL);
                if (channel->iob[cnt].data == NULL)
                        break;
@@ -719,7 +743,7 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb)
                QETH_DBF_TEXT(TRACE, 2, "CGENCHK");
                dev_warn(&cdev->dev, "The qeth device driver "
                        "failed to recover an error on the device\n");
-               QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x ",
+               QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x\n",
                        dev_name(&cdev->dev), dstat, cstat);
                print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET,
                                16, 1, irb, 64, 1);
@@ -998,9 +1022,8 @@ static void qeth_clean_channel(struct qeth_channel *channel)
                kfree(channel->iob[cnt].data);
 }
 
-static int qeth_is_1920_device(struct qeth_card *card)
+static void qeth_get_channel_path_desc(struct qeth_card *card)
 {
-       int single_queue = 0;
        struct ccw_device *ccwdev;
        struct channelPath_dsc {
                u8 flags;
@@ -1013,17 +1036,25 @@ static int qeth_is_1920_device(struct qeth_card *card)
                u8 chpp;
        } *chp_dsc;
 
-       QETH_DBF_TEXT(SETUP, 2, "chk_1920");
+       QETH_DBF_TEXT(SETUP, 2, "chp_desc");
 
        ccwdev = card->data.ccwdev;
        chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0);
        if (chp_dsc != NULL) {
                /* CHPP field bit 6 == 1 -> single queue */
-               single_queue = ((chp_dsc->chpp & 0x02) == 0x02);
+               if ((chp_dsc->chpp & 0x02) == 0x02)
+                       card->qdio.no_out_queues = 1;
+               card->info.func_level = 0x4100 + chp_dsc->desc;
                kfree(chp_dsc);
        }
-       QETH_DBF_TEXT_(SETUP, 2, "rc:%x", single_queue);
-       return single_queue;
+       if (card->qdio.no_out_queues == 1) {
+               card->qdio.default_out_queue = 0;
+               dev_info(&card->gdev->dev,
+                       "Priority Queueing not supported\n");
+       }
+       QETH_DBF_TEXT_(SETUP, 2, "nr:%x", card->qdio.no_out_queues);
+       QETH_DBF_TEXT_(SETUP, 2, "lvl:%02x", card->info.func_level);
+       return;
 }
 
 static void qeth_init_qdio_info(struct qeth_card *card)
@@ -1100,6 +1131,7 @@ static int qeth_setup_card(struct qeth_card *card)
        spin_lock_init(&card->lock);
        spin_lock_init(&card->ip_lock);
        spin_lock_init(&card->thread_mask_lock);
+       mutex_init(&card->conf_mutex);
        card->thread_start_mask = 0;
        card->thread_allowed_mask = 0;
        card->thread_running_mask = 0;
@@ -1170,18 +1202,17 @@ static int qeth_determine_card_type(struct qeth_card *card)
 
        card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
        card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
-       while (known_devices[i][4]) {
-               if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) &&
-                   (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) {
-                       card->info.type = known_devices[i][4];
-                       card->qdio.no_out_queues = known_devices[i][8];
-                       card->info.is_multicast_different = known_devices[i][9];
-                       if (qeth_is_1920_device(card)) {
-                               dev_info(&card->gdev->dev,
-                                       "Priority Queueing not supported\n");
-                               card->qdio.no_out_queues = 1;
-                               card->qdio.default_out_queue = 0;
-                       }
+       while (known_devices[i][QETH_DEV_MODEL_IND]) {
+               if ((CARD_RDEV(card)->id.dev_type ==
+                               known_devices[i][QETH_DEV_TYPE_IND]) &&
+                   (CARD_RDEV(card)->id.dev_model ==
+                               known_devices[i][QETH_DEV_MODEL_IND])) {
+                       card->info.type = known_devices[i][QETH_DEV_MODEL_IND];
+                       card->qdio.no_out_queues =
+                               known_devices[i][QETH_QUEUE_NO_IND];
+                       card->info.is_multicast_different =
+                               known_devices[i][QETH_MULTICAST_IND];
+                       qeth_get_channel_path_desc(card);
                        return 0;
                }
                i++;
@@ -1399,22 +1430,20 @@ static void qeth_init_tokens(struct qeth_card *card)
 
 static void qeth_init_func_level(struct qeth_card *card)
 {
-       if (card->ipato.enabled) {
-               if (card->info.type == QETH_CARD_TYPE_IQD)
-                               card->info.func_level =
-                                       QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
-               else
-                               card->info.func_level =
-                                       QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT;
-       } else {
-               if (card->info.type == QETH_CARD_TYPE_IQD)
-               /*FIXME:why do we have same values for  dis and ena for
-                 osae??? */
+       switch (card->info.type) {
+       case QETH_CARD_TYPE_IQD:
+               if (card->ipato.enabled)
                        card->info.func_level =
-                               QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
+                               QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT;
                else
                        card->info.func_level =
-                               QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT;
+                               QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT;
+               break;
+       case QETH_CARD_TYPE_OSD:
+               card->info.func_level = QETH_IDX_FUNC_LEVEL_OSD;
+               break;
+       default:
+               break;
        }
 }
 
@@ -1561,7 +1590,7 @@ static void qeth_idx_write_cb(struct qeth_channel *channel,
        card = CARD_FROM_CDEV(channel->ccwdev);
 
        if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
-               if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+               if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == QETH_IDX_ACT_ERR_EXCL)
                        dev_err(&card->write.ccwdev->dev,
                                "The adapter is used exclusively by another "
                                "host\n");
@@ -1597,27 +1626,35 @@ static void qeth_idx_read_cb(struct qeth_channel *channel,
        }
 
        card = CARD_FROM_CDEV(channel->ccwdev);
-       if (qeth_check_idx_response(iob->data))
+       if (qeth_check_idx_response(card, iob->data))
                        goto out;
 
        if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
-               if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+               switch (QETH_IDX_ACT_CAUSE_CODE(iob->data)) {
+               case QETH_IDX_ACT_ERR_EXCL:
                        dev_err(&card->write.ccwdev->dev,
                                "The adapter is used exclusively by another "
                                "host\n");
-               else
+                       break;
+               case QETH_IDX_ACT_ERR_AUTH:
+                       dev_err(&card->read.ccwdev->dev,
+                               "Setting the device online failed because of "
+                               "insufficient LPAR authorization\n");
+                       break;
+               default:
                        QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:"
                                " negative reply\n",
                                dev_name(&card->read.ccwdev->dev));
+               }
                goto out;
        }
 
 /**
- * temporary fix for microcode bug
- * to revert it,replace OR by AND
- */
+ *  * temporary fix for microcode bug
+ *   * to revert it,replace OR by AND
+ *    */
        if ((!QETH_IDX_NO_PORTNAME_REQUIRED(iob->data)) ||
-            (card->info.type == QETH_CARD_TYPE_OSAE))
+            (card->info.type == QETH_CARD_TYPE_OSD))
                card->info.portname_required = 1;
 
        memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
@@ -1826,7 +1863,7 @@ static inline int qeth_get_initial_mtu_for_card(struct qeth_card *card)
                return 1500;
        case QETH_CARD_TYPE_IQD:
                return card->info.max_mtu;
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
                switch (card->info.link_type) {
                case QETH_LINK_TYPE_HSTR:
                case QETH_LINK_TYPE_LANE_TR:
@@ -1834,6 +1871,9 @@ static inline int qeth_get_initial_mtu_for_card(struct qeth_card *card)
                default:
                        return 1492;
                }
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
+               return 1492;
        default:
                return 1500;
        }
@@ -1844,8 +1884,10 @@ static inline int qeth_get_max_mtu_for_card(int cardtype)
        switch (cardtype) {
 
        case QETH_CARD_TYPE_UNKNOWN:
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
        case QETH_CARD_TYPE_OSN:
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
                return 61440;
        case QETH_CARD_TYPE_IQD:
                return 57344;
@@ -1883,7 +1925,9 @@ static inline int qeth_get_mtu_outof_framesize(int framesize)
 static inline int qeth_mtu_is_valid(struct qeth_card *card, int mtu)
 {
        switch (card->info.type) {
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
                return ((mtu >= 576) && (mtu <= 61440));
        case QETH_CARD_TYPE_IQD:
                return ((mtu >= 576) &&
@@ -1934,6 +1978,7 @@ static int qeth_ulp_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
                card->info.link_type = link_type;
        } else
                card->info.link_type = 0;
+       QETH_DBF_TEXT_(SETUP, 2, "link%d", link_type);
        QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
        return 0;
 }
@@ -1977,6 +2022,7 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
                unsigned long data)
 {
        struct qeth_cmd_buffer *iob;
+       int rc = 0;
 
        QETH_DBF_TEXT(SETUP, 2, "ulpstpcb");
 
@@ -1984,8 +2030,15 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
        memcpy(&card->token.ulp_connection_r,
               QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data),
               QETH_MPC_TOKEN_LENGTH);
+       if (!strncmp("00S", QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(iob->data),
+                    3)) {
+               QETH_DBF_TEXT(SETUP, 2, "olmlimit");
+               dev_err(&card->gdev->dev, "A connection could not be "
+                       "established because of an OLM limit\n");
+               rc = -EMLINK;
+       }
        QETH_DBF_TEXT_(SETUP, 2, "  rc%d", iob->rc);
-       return 0;
+       return rc;
 }
 
 static int qeth_ulp_setup(struct qeth_card *card)
@@ -2238,7 +2291,9 @@ static void qeth_print_status_no_portname(struct qeth_card *card)
 void qeth_print_status_message(struct qeth_card *card)
 {
        switch (card->info.type) {
-       case QETH_CARD_TYPE_OSAE:
+       case QETH_CARD_TYPE_OSD:
+       case QETH_CARD_TYPE_OSM:
+       case QETH_CARD_TYPE_OSX:
                /* VM will use a non-zero first character
                 * to indicate a HiperSockets like reporting
                 * of the level OSA sets the first character to zero
@@ -2545,9 +2600,11 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
        QETH_DBF_TEXT(TRACE, 3, "quyadpcb");
 
        cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f)
+       if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
                card->info.link_type =
                      cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
+               QETH_DBF_TEXT_(SETUP, 2, "lnk %d", card->info.link_type);
+       }
        card->options.adp.supported_funcs =
                cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
        return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
@@ -2937,7 +2994,8 @@ EXPORT_SYMBOL_GPL(qeth_qdio_output_handler);
 int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
                        int ipv, int cast_type)
 {
-       if (!ipv && (card->info.type == QETH_CARD_TYPE_OSAE))
+       if (!ipv && (card->info.type == QETH_CARD_TYPE_OSD ||
+                    card->info.type == QETH_CARD_TYPE_OSX))
                return card->qdio.default_out_queue;
        switch (card->qdio.no_out_queues) {
        case 4:
@@ -3499,13 +3557,14 @@ int qeth_set_access_ctrl_online(struct qeth_card *card)
 
        QETH_DBF_TEXT(TRACE, 4, "setactlo");
 
-       if (card->info.type == QETH_CARD_TYPE_OSAE &&
-           qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
+       if ((card->info.type == QETH_CARD_TYPE_OSD ||
+            card->info.type == QETH_CARD_TYPE_OSX) &&
+            qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
                rc = qeth_setadpparms_set_access_ctrl(card,
                        card->options.isolation);
                if (rc) {
                        QETH_DBF_MESSAGE(3,
-                               "IPA(SET_ACCESS_CTRL,%s,%d) sent failed",
+                               "IPA(SET_ACCESS_CTRL,%s,%d) sent failed\n",
                                card->gdev->dev.kobj.name,
                                rc);
                }
@@ -3845,9 +3904,16 @@ static void qeth_core_free_card(struct qeth_card *card)
 }
 
 static struct ccw_device_id qeth_ids[] = {
-       {CCW_DEVICE(0x1731, 0x01), .driver_info = QETH_CARD_TYPE_OSAE},
-       {CCW_DEVICE(0x1731, 0x05), .driver_info = QETH_CARD_TYPE_IQD},
-       {CCW_DEVICE(0x1731, 0x06), .driver_info = QETH_CARD_TYPE_OSN},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x01, 0x1732, 0x01),
+                                       .driver_info = QETH_CARD_TYPE_OSD},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x05, 0x1732, 0x05),
+                                       .driver_info = QETH_CARD_TYPE_IQD},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x06, 0x1732, 0x06),
+                                       .driver_info = QETH_CARD_TYPE_OSN},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x03),
+                                       .driver_info = QETH_CARD_TYPE_OSM},
+       {CCW_DEVICE_DEVTYPE(0x1731, 0x02, 0x1732, 0x02),
+                                       .driver_info = QETH_CARD_TYPE_OSX},
        {},
 };
 MODULE_DEVICE_TABLE(ccw, qeth_ids);
@@ -4251,25 +4317,25 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
                goto err_card;
        }
 
-       if (card->info.type == QETH_CARD_TYPE_OSN) {
+       if (card->info.type == QETH_CARD_TYPE_OSN)
                rc = qeth_core_create_osn_attributes(dev);
-               if (rc)
-                       goto err_card;
+       else
+               rc = qeth_core_create_device_attributes(dev);
+       if (rc)
+               goto err_card;
+       switch (card->info.type) {
+       case QETH_CARD_TYPE_OSN:
+       case QETH_CARD_TYPE_OSM:
                rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2);
-               if (rc) {
-                       qeth_core_remove_osn_attributes(dev);
-                       goto err_card;
-               }
+               if (rc)
+                       goto err_attr;
                rc = card->discipline.ccwgdriver->probe(card->gdev);
-               if (rc) {
-                       qeth_core_free_discipline(card);
-                       qeth_core_remove_osn_attributes(dev);
-                       goto err_card;
-               }
-       } else {
-               rc = qeth_core_create_device_attributes(dev);
                if (rc)
-                       goto err_card;
+                       goto err_disc;
+       case QETH_CARD_TYPE_OSD:
+       case QETH_CARD_TYPE_OSX:
+       default:
+               break;
        }
 
        write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
@@ -4279,6 +4345,13 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
        qeth_determine_capabilities(card);
        return 0;
 
+err_disc:
+       qeth_core_free_discipline(card);
+err_attr:
+       if (card->info.type == QETH_CARD_TYPE_OSN)
+               qeth_core_remove_osn_attributes(dev);
+       else
+               qeth_core_remove_device_attributes(dev);
 err_card:
        qeth_core_free_card(card);
 err_dev:
index 104a3351e02b163519dfc34f2e885a681cc446fa..f9ed24de75140e41630b638458acf22e404f8cbd 100644 (file)
@@ -48,9 +48,11 @@ extern unsigned char IPA_PDU_HEADER[];
 
 enum qeth_card_types {
        QETH_CARD_TYPE_UNKNOWN = 0,
-       QETH_CARD_TYPE_OSAE    = 10,
-       QETH_CARD_TYPE_IQD     = 1234,
-       QETH_CARD_TYPE_OSN     = 11,
+       QETH_CARD_TYPE_OSD     = 1,
+       QETH_CARD_TYPE_IQD     = 5,
+       QETH_CARD_TYPE_OSN     = 6,
+       QETH_CARD_TYPE_OSM     = 3,
+       QETH_CARD_TYPE_OSX     = 2,
 };
 
 #define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
@@ -614,6 +616,8 @@ extern unsigned char IDX_ACTIVATE_WRITE[];
 #define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08] & 3) == 2)
 #define QETH_IDX_REPLY_LEVEL(buffer) (buffer + 0x12)
 #define QETH_IDX_ACT_CAUSE_CODE(buffer) (buffer)[0x09]
+#define QETH_IDX_ACT_ERR_EXCL  0x19
+#define QETH_IDX_ACT_ERR_AUTH  0x1E
 
 #define PDU_ENCAPSULATION(buffer) \
        (buffer + *(buffer + (*(buffer + 0x0b)) + \
index 25dfd5abd19bb9a0fbbd20ee584548a925b3a328..2eb022ff2610f725bad556a6d67c47371dae13d8 100644 (file)
@@ -122,23 +122,32 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
        unsigned int portno, limit;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        portno = simple_strtoul(buf, &tmp, 16);
-       if (portno > QETH_MAX_PORTNO)
-               return -EINVAL;
+       if (portno > QETH_MAX_PORTNO) {
+               rc = -EINVAL;
+               goto out;
+       }
        limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
-       if (portno > limit)
-               return -EINVAL;
-
+       if (portno > limit) {
+               rc = -EINVAL;
+               goto out;
+       }
        card->info.portno = portno;
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(portno, 0644, qeth_dev_portno_show, qeth_dev_portno_store);
@@ -165,18 +174,23 @@ static ssize_t qeth_dev_portname_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
-       int i;
+       int i, rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        tmp = strsep((char **) &buf, "\n");
-       if ((strlen(tmp) > 8) || (strlen(tmp) == 0))
-               return -EINVAL;
+       if ((strlen(tmp) > 8) || (strlen(tmp) == 0)) {
+               rc = -EINVAL;
+               goto out;
+       }
 
        card->info.portname[0] = strlen(tmp);
        /* for beauty reasons */
@@ -184,8 +198,9 @@ static ssize_t qeth_dev_portname_store(struct device *dev,
                card->info.portname[i] = ' ';
        strcpy(card->info.portname + 1, tmp);
        ASCEBC(card->info.portname + 1, 8);
-
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(portname, 0644, qeth_dev_portname_show,
@@ -215,20 +230,25 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        /* check if 1920 devices are supported ,
         * if though we have to permit priority queueing
         */
        if (card->qdio.no_out_queues == 1) {
                card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
-               return -EPERM;
+               rc = -EPERM;
+               goto out;
        }
 
        tmp = strsep((char **) &buf, "\n");
@@ -251,10 +271,11 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
        } else if (!strcmp(tmp, "no_prio_queueing")) {
                card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
                card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       } else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(priority_queueing, 0644, qeth_dev_prioqing_show,
@@ -277,14 +298,17 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
        int cnt, old_cnt;
-       int rc;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        old_cnt = card->qdio.in_buf_pool.buf_count;
        cnt = simple_strtoul(buf, &tmp, 10);
@@ -293,7 +317,9 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
        if (old_cnt != cnt) {
                rc = qeth_realloc_buffer_pool(card, cnt);
        }
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
@@ -337,25 +363,27 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
-       int i;
+       int i, rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        i = simple_strtoul(buf, &tmp, 16);
        if ((i == 0) || (i == 1)) {
                if (i == card->options.performance_stats)
-                       return count;
+                       goto out;;
                card->options.performance_stats = i;
                if (i == 0)
                        memset(&card->perf_stats, 0,
                                sizeof(struct qeth_perf_stats));
                card->perf_stats.initial_rx_packets = card->stats.rx_packets;
                card->perf_stats.initial_tx_packets = card->stats.tx_packets;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       } else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(performance_stats, 0644, qeth_dev_performance_stats_show,
@@ -377,15 +405,17 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
-       int i, rc;
+       int i, rc = 0;
        enum qeth_discipline_id newdis;
 
        if (!card)
                return -EINVAL;
 
-       if (((card->state != CARD_STATE_DOWN) &&
-            (card->state != CARD_STATE_RECOVER)))
-               return -EPERM;
+       mutex_lock(&card->conf_mutex);
+       if (card->state != CARD_STATE_DOWN) {
+               rc = -EPERM;
+               goto out;
+       }
 
        i = simple_strtoul(buf, &tmp, 16);
        switch (i) {
@@ -396,12 +426,13 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
                newdis = QETH_DISCIPLINE_LAYER2;
                break;
        default:
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out;
        }
 
-       if (card->options.layer2 == newdis) {
-               return count;
-       else {
+       if (card->options.layer2 == newdis)
+               goto out;
+       else {
                if (card->discipline.ccwgdriver) {
                        card->discipline.ccwgdriver->remove(card->gdev);
                        qeth_core_free_discipline(card);
@@ -410,12 +441,12 @@ static ssize_t qeth_dev_layer2_store(struct device *dev,
 
        rc = qeth_core_load_discipline(card, newdis);
        if (rc)
-               return rc;
+               goto out;
 
        rc = card->discipline.ccwgdriver->probe(card->gdev);
-       if (rc)
-               return rc;
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show,
@@ -454,13 +485,13 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
        char *tmp, *curtoken;
        curtoken = (char *) buf;
 
-       if (!card) {
-               rc = -EINVAL;
-               goto out;
-       }
+       if (!card)
+               return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        /* check for unknown, too, in case we do not yet know who we are */
-       if (card->info.type != QETH_CARD_TYPE_OSAE &&
+       if (card->info.type != QETH_CARD_TYPE_OSD &&
+           card->info.type != QETH_CARD_TYPE_OSX &&
            card->info.type != QETH_CARD_TYPE_UNKNOWN) {
                rc = -EOPNOTSUPP;
                dev_err(&card->gdev->dev, "Adapter does not "
@@ -491,6 +522,7 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
                        rc = ipa_rc;
        }
 out:
+       mutex_unlock(&card->conf_mutex);
        return rc;
 }
 
@@ -510,22 +542,25 @@ static ssize_t qeth_dev_blkt_store(struct qeth_card *card,
                const char *buf, size_t count, int *value, int max_value)
 {
        char *tmp;
-       int i;
+       int i, rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
-
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
        i = simple_strtoul(buf, &tmp, 10);
-       if (i <= max_value) {
+       if (i <= max_value)
                *value = i;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_dev_blkt_total_show(struct device *dev,
index 6a801dc3bf8eb6546ccb3bc6960ca8b6c632ac4c..d43f57a4ac6614b2d8924b9381a4ab77d814390f 100644 (file)
@@ -56,7 +56,9 @@ static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data);
                break;
        case SIOC_QETH_GET_CARD_TYPE:
-               if ((card->info.type == QETH_CARD_TYPE_OSAE) &&
+               if ((card->info.type == QETH_CARD_TYPE_OSD ||
+                    card->info.type == QETH_CARD_TYPE_OSM ||
+                    card->info.type == QETH_CARD_TYPE_OSX) &&
                    !card->info.guestlan)
                        return 1;
                return 0;
@@ -309,6 +311,10 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
        struct qeth_vlan_vid *id;
 
        QETH_DBF_TEXT_(TRACE, 4, "aid:%d", vid);
+       if (card->info.type == QETH_CARD_TYPE_OSM) {
+               QETH_DBF_TEXT(TRACE, 3, "aidOSM");
+               return;
+       }
        if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
                QETH_DBF_TEXT(TRACE, 3, "aidREC");
                return;
@@ -329,6 +335,10 @@ static void qeth_l2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
        struct qeth_card *card = dev->ml_priv;
 
        QETH_DBF_TEXT_(TRACE, 4, "kid:%d", vid);
+       if (card->info.type == QETH_CARD_TYPE_OSM) {
+               QETH_DBF_TEXT(TRACE, 3, "kidOSM");
+               return;
+       }
        if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
                QETH_DBF_TEXT(TRACE, 3, "kidREC");
                return;
@@ -559,8 +569,10 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
                        "device %s: x%x\n", CARD_BUS_ID(card), rc);
        }
 
-       if ((card->info.type == QETH_CARD_TYPE_IQD) || 
-           (card->info.guestlan)) {
+       if (card->info.type == QETH_CARD_TYPE_IQD ||
+           card->info.type == QETH_CARD_TYPE_OSM ||
+           card->info.type == QETH_CARD_TYPE_OSX ||
+           card->info.guestlan) {
                rc = qeth_setadpparms_change_macaddr(card);
                if (rc) {
                        QETH_DBF_MESSAGE(2, "couldn't get MAC address on "
@@ -589,8 +601,10 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
                return -EOPNOTSUPP;
        }
 
-       if (card->info.type == QETH_CARD_TYPE_OSN) {
-               QETH_DBF_TEXT(TRACE, 3, "setmcOSN");
+       if (card->info.type == QETH_CARD_TYPE_OSN ||
+           card->info.type == QETH_CARD_TYPE_OSM ||
+           card->info.type == QETH_CARD_TYPE_OSX) {
+               QETH_DBF_TEXT(TRACE, 3, "setmcTYP");
                return -EOPNOTSUPP;
        }
        QETH_DBF_TEXT_(TRACE, 3, "%s", CARD_BUS_ID(card));
@@ -608,7 +622,6 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
 static void qeth_l2_set_multicast_list(struct net_device *dev)
 {
        struct qeth_card *card = dev->ml_priv;
-       struct dev_addr_list *dm;
        struct netdev_hw_addr *ha;
 
        if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -620,8 +633,8 @@ static void qeth_l2_set_multicast_list(struct net_device *dev)
                return;
        qeth_l2_del_all_mc(card);
        spin_lock_bh(&card->mclock);
-       for (dm = dev->mc_list; dm; dm = dm->next)
-               qeth_l2_add_mc(card, dm->da_addr, 0);
+       netdev_for_each_mc_addr(ha, dev)
+               qeth_l2_add_mc(card, ha->addr, 0);
 
        netdev_for_each_uc_addr(ha, dev)
                qeth_l2_add_mc(card, ha->addr, 1);
@@ -886,9 +899,6 @@ static const struct net_device_ops qeth_l2_netdev_ops = {
 static int qeth_l2_setup_netdev(struct qeth_card *card)
 {
        switch (card->info.type) {
-       case QETH_CARD_TYPE_OSAE:
-               card->dev = alloc_etherdev(0);
-               break;
        case QETH_CARD_TYPE_IQD:
                card->dev = alloc_netdev(0, "hsi%d", ether_setup);
                break;
@@ -925,6 +935,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        enum qeth_card_states recover_flag;
 
        BUG_ON(!card);
+       mutex_lock(&card->conf_mutex);
        QETH_DBF_TEXT(SETUP, 2, "setonlin");
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
@@ -957,18 +968,21 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                        dev_warn(&card->gdev->dev,
                                "The LAN is offline\n");
                        card->lan_online = 0;
-                       return 0;
+                       goto out;
                }
                rc = -ENODEV;
                goto out_remove;
        } else
                card->lan_online = 1;
 
-       if (card->info.type != QETH_CARD_TYPE_OSN) {
+       if ((card->info.type == QETH_CARD_TYPE_OSD) ||
+           (card->info.type == QETH_CARD_TYPE_OSX))
                /* configure isolation level */
                qeth_set_access_ctrl_online(card);
+
+       if (card->info.type != QETH_CARD_TYPE_OSN &&
+           card->info.type != QETH_CARD_TYPE_OSM)
                qeth_l2_process_vlans(card, 0);
-       }
 
        netif_tx_disable(card->dev);
 
@@ -996,6 +1010,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        }
        /* let user_space know that device is online */
        kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
+out:
+       mutex_unlock(&card->conf_mutex);
        return 0;
 
 out_remove:
@@ -1008,6 +1024,7 @@ out_remove:
                card->state = CARD_STATE_RECOVER;
        else
                card->state = CARD_STATE_DOWN;
+       mutex_unlock(&card->conf_mutex);
        return rc;
 }
 
@@ -1023,6 +1040,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
        int rc = 0, rc2 = 0, rc3 = 0;
        enum qeth_card_states recover_flag;
 
+       mutex_lock(&card->conf_mutex);
        QETH_DBF_TEXT(SETUP, 3, "setoffl");
        QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
 
@@ -1041,6 +1059,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
        kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
+       mutex_unlock(&card->conf_mutex);
        return 0;
 }
 
index fc6ca1da8b983b568d49271f4ec2914d72b76a1f..61adae21a464c5d950c1f4d2b09b11dba10773e0 100644 (file)
@@ -54,16 +54,16 @@ int qeth_l3_set_large_send(struct qeth_card *card,
        if (card->options.large_send == QETH_LARGE_SEND_TSO) {
                if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
                        card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
-                                       NETIF_F_HW_CSUM;
+                                       NETIF_F_IP_CSUM;
                } else {
                        card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
-                                       NETIF_F_HW_CSUM);
+                                       NETIF_F_IP_CSUM);
                        card->options.large_send = QETH_LARGE_SEND_NO;
                        rc = -EOPNOTSUPP;
                }
        } else {
                card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
-                                       NETIF_F_HW_CSUM);
+                                       NETIF_F_IP_CSUM);
                card->options.large_send = QETH_LARGE_SEND_NO;
        }
        return rc;
@@ -1108,6 +1108,13 @@ static int qeth_l3_default_setassparms_cb(struct qeth_card *card,
                card->info.csum_mask = cmd->data.setassparms.data.flags_32bit;
                QETH_DBF_TEXT_(TRACE, 3, "csum:%d", card->info.csum_mask);
        }
+       if (cmd->data.setassparms.hdr.assist_no == IPA_OUTBOUND_CHECKSUM &&
+           cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
+               card->info.tx_csum_mask =
+                       cmd->data.setassparms.data.flags_32bit;
+               QETH_DBF_TEXT_(TRACE, 3, "tcsu:%d", card->info.tx_csum_mask);
+       }
+
        return 0;
 }
 
@@ -1536,6 +1543,28 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card)
        return rc;
 }
 
+static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card)
+{
+       int rc = 0;
+
+       if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
+               return rc;
+       rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
+                         IPA_CMD_ASS_START, 0);
+       if (rc)
+               goto err_out;
+       rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_CHECKSUM,
+                         IPA_CMD_ASS_ENABLE, card->info.tx_csum_mask);
+       if (rc)
+               goto err_out;
+       dev_info(&card->gdev->dev, "HW TX Checksumming enabled\n");
+       return rc;
+err_out:
+       dev_warn(&card->gdev->dev, "Enabling HW TX checksumming for %s "
+               "failed, using SW TX checksumming\n", QETH_CARD_IFNAME(card));
+       return rc;
+}
+
 static int qeth_l3_start_ipa_tso(struct qeth_card *card)
 {
        int rc;
@@ -1578,6 +1607,7 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)
        qeth_l3_start_ipa_ipv6(card);           /* go on*/
        qeth_l3_start_ipa_broadcast(card);              /* go on*/
        qeth_l3_start_ipa_checksum(card);               /* go on*/
+       qeth_l3_start_ipa_tx_checksum(card);
        qeth_l3_start_ipa_tso(card);            /* go on*/
        return 0;
 }
@@ -1929,7 +1959,7 @@ static void qeth_l3_free_vlan_addresses6(struct qeth_card *card,
        in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid));
        if (!in6_dev)
                return;
-       for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next) {
+       list_for_each_entry(ifa, &in6_dev->addr_list, if_list) {
                addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
                if (addr) {
                        memcpy(&addr->u.a6.addr, &ifa->addr,
@@ -2681,7 +2711,8 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
                rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data);
                break;
        case SIOC_QETH_GET_CARD_TYPE:
-               if ((card->info.type == QETH_CARD_TYPE_OSAE) &&
+               if ((card->info.type == QETH_CARD_TYPE_OSD ||
+                    card->info.type == QETH_CARD_TYPE_OSX) &&
                    !card->info.guestlan)
                        return 1;
                return 0;
@@ -2817,6 +2848,21 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
        }
 }
 
+static inline void qeth_l3_hdr_csum(struct qeth_card *card,
+               struct qeth_hdr *hdr, struct sk_buff *skb)
+{
+       struct iphdr *iph = ip_hdr(skb);
+
+       /* tcph->check contains already the pseudo hdr checksum
+        * so just set the header flags
+        */
+       if (iph->protocol == IPPROTO_UDP)
+               hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_UDP;
+       hdr->hdr.l3.ext_flags |= QETH_HDR_EXT_CSUM_TRANSP_REQ;
+       if (card->options.performance_stats)
+               card->perf_stats.tx_csum++;
+}
+
 static void qeth_tso_fill_header(struct qeth_card *card,
                struct qeth_hdr *qhdr, struct sk_buff *skb)
 {
@@ -2852,21 +2898,6 @@ static void qeth_tso_fill_header(struct qeth_card *card,
        }
 }
 
-static void qeth_tx_csum(struct sk_buff *skb)
-{
-       __wsum csum;
-       int offset;
-
-       skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));
-       offset = skb->csum_start - skb_headroom(skb);
-       BUG_ON(offset >= skb_headlen(skb));
-       csum = skb_checksum(skb, offset, skb->len - offset, 0);
-
-       offset += skb->csum_offset;
-       BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb));
-       *(__sum16 *)(skb->data + offset) = csum_fold(csum);
-}
-
 static inline int qeth_l3_tso_elements(struct sk_buff *skb)
 {
        unsigned long tcpd = (unsigned long)tcp_hdr(skb) +
@@ -2923,12 +2954,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (skb_is_gso(skb))
                large_send = card->options.large_send;
-       else
-               if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       qeth_tx_csum(skb);
-                       if (card->options.performance_stats)
-                               card->perf_stats.tx_csum++;
-               }
 
        if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
            (skb_shinfo(skb)->nr_frags == 0)) {
@@ -3007,6 +3032,9 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                cast_type);
                        hdr->hdr.l3.length = new_skb->len - data_offset;
                }
+
+               if (skb->ip_summed == CHECKSUM_PARTIAL)
+                       qeth_l3_hdr_csum(card, hdr, new_skb);
        }
 
        elems = qeth_get_elements_no(card, (void *)hdr, new_skb,
@@ -3132,10 +3160,25 @@ static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data)
        return rc;
 }
 
+static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data)
+{
+       struct qeth_card *card = dev->ml_priv;
+
+       if (data) {
+               if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
+                       dev->features |= NETIF_F_IP_CSUM;
+               else
+                       return -EPERM;
+       } else
+               dev->features &= ~NETIF_F_IP_CSUM;
+
+       return 0;
+}
+
 static const struct ethtool_ops qeth_l3_ethtool_ops = {
        .get_link = ethtool_op_get_link,
        .get_tx_csum = ethtool_op_get_tx_csum,
-       .set_tx_csum = ethtool_op_set_tx_hw_csum,
+       .set_tx_csum = qeth_l3_ethtool_set_tx_csum,
        .get_rx_csum = qeth_l3_ethtool_get_rx_csum,
        .set_rx_csum = qeth_l3_ethtool_set_rx_csum,
        .get_sg      = ethtool_op_get_sg,
@@ -3206,7 +3249,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
 
 static int qeth_l3_setup_netdev(struct qeth_card *card)
 {
-       if (card->info.type == QETH_CARD_TYPE_OSAE) {
+       if (card->info.type == QETH_CARD_TYPE_OSD ||
+           card->info.type == QETH_CARD_TYPE_OSX) {
                if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
                    (card->info.link_type == QETH_LINK_TYPE_HSTR)) {
 #ifdef CONFIG_TR
@@ -3336,6 +3380,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        enum qeth_card_states recover_flag;
 
        BUG_ON(!card);
+       mutex_lock(&card->conf_mutex);
        QETH_DBF_TEXT(SETUP, 2, "setonlin");
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
 
@@ -3367,7 +3412,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                        dev_warn(&card->gdev->dev,
                                "The LAN is offline\n");
                        card->lan_online = 0;
-                       return 0;
+                       goto out;
                }
                rc = -ENODEV;
                goto out_remove;
@@ -3414,6 +3459,8 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        }
        /* let user_space know that device is online */
        kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
+out:
+       mutex_unlock(&card->conf_mutex);
        return 0;
 out_remove:
        card->use_hard_stop = 1;
@@ -3425,6 +3472,7 @@ out_remove:
                card->state = CARD_STATE_RECOVER;
        else
                card->state = CARD_STATE_DOWN;
+       mutex_unlock(&card->conf_mutex);
        return rc;
 }
 
@@ -3440,6 +3488,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
        int rc = 0, rc2 = 0, rc3 = 0;
        enum qeth_card_states recover_flag;
 
+       mutex_lock(&card->conf_mutex);
        QETH_DBF_TEXT(SETUP, 3, "setoffl");
        QETH_DBF_HEX(SETUP, 3, &card, sizeof(void *));
 
@@ -3458,6 +3507,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
        kobject_uevent(&cgdev->dev.kobj, KOBJ_CHANGE);
+       mutex_unlock(&card->conf_mutex);
        return 0;
 }
 
index 25b3e7aae44f336ce9d354f8a99c37cfced240f6..fb5318b30e99bfe849602fa127bbf1a1ffe83336 100644 (file)
@@ -70,10 +70,10 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
 {
        enum qeth_routing_types old_route_type = route->type;
        char *tmp;
-       int rc;
+       int rc = 0;
 
        tmp = strsep((char **) &buf, "\n");
-
+       mutex_lock(&card->conf_mutex);
        if (!strcmp(tmp, "no_router")) {
                route->type = NO_ROUTER;
        } else if (!strcmp(tmp, "primary_connector")) {
@@ -87,7 +87,8 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
        } else if (!strcmp(tmp, "multicast_router")) {
                route->type = MULTICAST_ROUTER;
        } else {
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out;
        }
        if (((card->state == CARD_STATE_SOFTSETUP) ||
             (card->state == CARD_STATE_UP)) &&
@@ -97,7 +98,9 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
                else if (prot == QETH_PROT_IPV6)
                        rc = qeth_l3_setrouting_v6(card);
        }
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_route4_store(struct device *dev,
@@ -157,22 +160,26 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
-       int i;
+       int i, rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        i = simple_strtoul(buf, &tmp, 16);
        if ((i == 0) || (i == 1))
                card->options.fake_broadcast = i;
-       else {
-               return -EINVAL;
-       }
-       return count;
+       else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(fake_broadcast, 0644, qeth_l3_dev_fake_broadcast_show,
@@ -200,31 +207,35 @@ static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
              (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out;
        }
 
        tmp = strsep((char **) &buf, "\n");
 
-       if (!strcmp(tmp, "local")) {
+       if (!strcmp(tmp, "local"))
                card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL;
-               return count;
-       } else if (!strcmp(tmp, "all_rings")) {
+       else if (!strcmp(tmp, "all_rings"))
                card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
-               return count;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(broadcast_mode, 0644, qeth_l3_dev_broadcast_mode_show,
@@ -251,18 +262,22 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
-       int i;
+       int i, rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
              (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) {
-               return -EINVAL;
+               rc = -EINVAL;
+               goto out;
        }
 
        i = simple_strtoul(buf, &tmp, 16);
@@ -270,10 +285,11 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev,
                card->options.macaddr_mode = i?
                        QETH_TR_MACADDR_CANONICAL :
                        QETH_TR_MACADDR_NONCANONICAL;
-       else {
-               return -EINVAL;
-       }
-       return count;
+       else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show,
@@ -297,11 +313,12 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
        struct qeth_card *card = dev_get_drvdata(dev);
        enum qeth_checksum_types csum_type;
        char *tmp;
-       int rc;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        tmp = strsep((char **) &buf, "\n");
        if (!strcmp(tmp, "sw_checksumming"))
                csum_type = SW_CHECKSUMMING;
@@ -309,13 +326,15 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
                csum_type = HW_CHECKSUMMING;
        else if (!strcmp(tmp, "no_checksumming"))
                csum_type = NO_CHECKSUMMING;
-       else
-               return -EINVAL;
+       else {
+               rc = -EINVAL;
+               goto out;
+       }
 
        rc = qeth_l3_set_rx_csum(card, csum_type);
-       if (rc)
-               return rc;
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
@@ -336,7 +355,7 @@ 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;
+       int rc = 0;
        unsigned long i;
 
        if (!card)
@@ -345,19 +364,24 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
        if (card->info.type != QETH_CARD_TYPE_IQD)
                return -EPERM;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
-       ret = strict_strtoul(buf, 16, &i);
-       if (ret)
-               return -EINVAL;
+       rc = strict_strtoul(buf, 16, &i);
+       if (rc) {
+               rc = -EINVAL;
+               goto out;
+       }
        switch (i) {
        case 0:
                card->options.sniffer = i;
                break;
        case 1:
-               ret = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
+               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 !=
@@ -366,11 +390,13 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
                                        QETH_IN_BUF_COUNT_MAX);
                        break;
                } else
-                       return -EPERM;
+                       rc = -EPERM;
        default:   /* fall through */
-               return -EINVAL;
+               rc = -EINVAL;
        }
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
@@ -412,12 +438,11 @@ static ssize_t qeth_l3_dev_large_send_store(struct device *dev,
        else
                return -EINVAL;
 
-       if (card->options.large_send == type)
-               return count;
-       rc = qeth_l3_set_large_send(card, type);
-       if (rc)
-               return rc;
-       return count;
+       mutex_lock(&card->conf_mutex);
+       if (card->options.large_send != type)
+               rc = qeth_l3_set_large_send(card, type);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show,
@@ -455,13 +480,17 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        if ((card->state != CARD_STATE_DOWN) &&
-           (card->state != CARD_STATE_RECOVER))
-               return -EPERM;
+           (card->state != CARD_STATE_RECOVER)) {
+               rc = -EPERM;
+               goto out;
+       }
 
        tmp = strsep((char **) &buf, "\n");
        if (!strcmp(tmp, "toggle")) {
@@ -470,10 +499,11 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
                card->ipato.enabled = 1;
        } else if (!strcmp(tmp, "0")) {
                card->ipato.enabled = 0;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       } else
+               rc = -EINVAL;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
@@ -497,10 +527,12 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        tmp = strsep((char **) &buf, "\n");
        if (!strcmp(tmp, "toggle")) {
                card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
@@ -508,10 +540,10 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
                card->ipato.invert4 = 1;
        } else if (!strcmp(tmp, "0")) {
                card->ipato.invert4 = 0;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       } else
+               rc = -EINVAL;
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
@@ -593,27 +625,28 @@ static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count,
        struct qeth_ipato_entry *ipatoe;
        u8 addr[16];
        int mask_bits;
-       int rc;
+       int rc = 0;
 
+       mutex_lock(&card->conf_mutex);
        rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
        if (rc)
-               return rc;
+               goto out;
 
        ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL);
        if (!ipatoe) {
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto out;
        }
        ipatoe->proto = proto;
        memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
        ipatoe->mask_bits = mask_bits;
 
        rc = qeth_l3_add_ipato_entry(card, ipatoe);
-       if (rc) {
+       if (rc)
                kfree(ipatoe);
-               return rc;
-       }
-
-       return count;
+out:
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_ipato_add4_store(struct device *dev,
@@ -636,15 +669,14 @@ static ssize_t qeth_l3_dev_ipato_del_store(const char *buf, size_t count,
 {
        u8 addr[16];
        int mask_bits;
-       int rc;
+       int rc = 0;
 
+       mutex_lock(&card->conf_mutex);
        rc = qeth_l3_parse_ipatoe(buf, proto, addr, &mask_bits);
-       if (rc)
-               return rc;
-
-       qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
-
-       return count;
+       if (!rc)
+               qeth_l3_del_ipato_entry(card, proto, addr, mask_bits);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_ipato_del4_store(struct device *dev,
@@ -677,10 +709,12 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
 {
        struct qeth_card *card = dev_get_drvdata(dev);
        char *tmp;
+       int rc = 0;
 
        if (!card)
                return -EINVAL;
 
+       mutex_lock(&card->conf_mutex);
        tmp = strsep((char **) &buf, "\n");
        if (!strcmp(tmp, "toggle")) {
                card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
@@ -688,10 +722,10 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
                card->ipato.invert6 = 1;
        } else if (!strcmp(tmp, "0")) {
                card->ipato.invert6 = 0;
-       } else {
-               return -EINVAL;
-       }
-       return count;
+       } else
+               rc = -EINVAL;
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
@@ -813,15 +847,12 @@ static ssize_t qeth_l3_dev_vipa_add_store(const char *buf, size_t count,
        u8 addr[16] = {0, };
        int rc;
 
+       mutex_lock(&card->conf_mutex);
        rc = qeth_l3_parse_vipae(buf, proto, addr);
-       if (rc)
-               return rc;
-
-       rc = qeth_l3_add_vipa(card, proto, addr);
-       if (rc)
-               return rc;
-
-       return count;
+       if (!rc)
+               rc = qeth_l3_add_vipa(card, proto, addr);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_vipa_add4_store(struct device *dev,
@@ -845,13 +876,12 @@ static ssize_t qeth_l3_dev_vipa_del_store(const char *buf, size_t count,
        u8 addr[16];
        int rc;
 
+       mutex_lock(&card->conf_mutex);
        rc = qeth_l3_parse_vipae(buf, proto, addr);
-       if (rc)
-               return rc;
-
-       qeth_l3_del_vipa(card, proto, addr);
-
-       return count;
+       if (!rc)
+               qeth_l3_del_vipa(card, proto, addr);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_vipa_del4_store(struct device *dev,
@@ -979,15 +1009,12 @@ static ssize_t qeth_l3_dev_rxip_add_store(const char *buf, size_t count,
        u8 addr[16] = {0, };
        int rc;
 
+       mutex_lock(&card->conf_mutex);
        rc = qeth_l3_parse_rxipe(buf, proto, addr);
-       if (rc)
-               return rc;
-
-       rc = qeth_l3_add_rxip(card, proto, addr);
-       if (rc)
-               return rc;
-
-       return count;
+       if (!rc)
+               rc = qeth_l3_add_rxip(card, proto, addr);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_rxip_add4_store(struct device *dev,
@@ -1011,13 +1038,12 @@ static ssize_t qeth_l3_dev_rxip_del_store(const char *buf, size_t count,
        u8 addr[16];
        int rc;
 
+       mutex_lock(&card->conf_mutex);
        rc = qeth_l3_parse_rxipe(buf, proto, addr);
-       if (rc)
-               return rc;
-
-       qeth_l3_del_rxip(card, proto, addr);
-
-       return count;
+       if (!rc)
+               qeth_l3_del_rxip(card, proto, addr);
+       mutex_unlock(&card->conf_mutex);
+       return rc ? rc : count;
 }
 
 static ssize_t qeth_l3_dev_rxip_del4_store(struct device *dev,
index f01b9b44e8aa8a6ab387a969e7b7701400a4d1cf..54c870b8c328f4002d01067c957e03b2f1f5cd4b 100644 (file)
@@ -309,10 +309,10 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
         * for multiple unicast MACs.
         */
        memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_add(netdev, flogi_maddr);
+       dev_uc_add(netdev, flogi_maddr);
        if (fip->spma)
-               dev_unicast_add(netdev, fip->ctl_src_addr);
-       dev_mc_add(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+               dev_uc_add(netdev, fip->ctl_src_addr);
+       dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
 
        /*
         * setup the receive function from ethernet driver
@@ -395,10 +395,10 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
 
        /* Delete secondary MAC addresses */
        memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN);
-       dev_unicast_delete(netdev, flogi_maddr);
+       dev_uc_del(netdev, flogi_maddr);
        if (fip->spma)
-               dev_unicast_delete(netdev, fip->ctl_src_addr);
-       dev_mc_delete(netdev, FIP_ALL_ENODE_MACS, ETH_ALEN, 0);
+               dev_uc_del(netdev, fip->ctl_src_addr);
+       dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
 
        /* Tell the LLD we are done w/ FCoE */
        ops = netdev->netdev_ops;
@@ -491,9 +491,9 @@ static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr)
 
        rtnl_lock();
        if (!is_zero_ether_addr(port->data_src_addr))
-               dev_unicast_delete(fcoe->netdev, port->data_src_addr);
+               dev_uc_del(fcoe->netdev, port->data_src_addr);
        if (!is_zero_ether_addr(addr))
-               dev_unicast_add(fcoe->netdev, addr);
+               dev_uc_add(fcoe->netdev, addr);
        memcpy(port->data_src_addr, addr, ETH_ALEN);
        rtnl_unlock();
 }
@@ -820,7 +820,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)
 
        rtnl_lock();
        if (!is_zero_ether_addr(port->data_src_addr))
-               dev_unicast_delete(netdev, port->data_src_addr);
+               dev_uc_del(netdev, port->data_src_addr);
        rtnl_unlock();
 
        /* receives may not be stopped until after this */
index 02143af7c1af6234a27d416b6e5e8a3df370c057..9eae04afa9a09c998daa82f0941c62276139414b 100644 (file)
@@ -599,9 +599,9 @@ static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
        set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
        write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
 
-       if (sock->sk->sk_sleep) {
+       if (sk_sleep(sock->sk) && waitqueue_active(sk_sleep(sock->sk))) {
                sock->sk->sk_err = EIO;
-               wake_up_interruptible(sock->sk->sk_sleep);
+               wake_up_interruptible(sk_sleep(sock->sk));
        }
 
        iscsi_conn_stop(cls_conn, flag);
index 9681536163caa5bdf7a36fc1dcfff9f8da3a66ec..59ae76bace14cb740483484b1a6a21b08157f259 100644 (file)
@@ -233,6 +233,8 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
 {
        if (!cc->dev)
                return; /* We don't have a ChipCommon */
+       if (cc->dev->id.revision >= 11)
+               cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
        ssb_pmu_init(cc);
        chipco_powercontrol_init(cc);
        ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
@@ -370,6 +372,7 @@ u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
        return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
 }
+EXPORT_SYMBOL(ssb_chipco_gpio_control);
 
 u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
 {
index bc9bdb277bec6f23372e70c56b56d6b80eb38d2f..51275aac5b34df0040ff02781a5f308dadc32753 100644 (file)
@@ -834,6 +834,9 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus,
        if (!err) {
                ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
                           "PCI device %s\n", dev_name(&host_pci->dev));
+       } else {
+               ssb_printk(KERN_ERR PFX "Failed to register PCI version"
+                          " of SSB with error %d\n", err);
        }
 
        return err;
index a8dbb06623c96f17e61ad996df9647ab699a6740..989e2752cc36d8abb9613b6c77b50936be85184c 100644 (file)
@@ -168,7 +168,7 @@ err_pci:
 }
 
 /* Get the word-offset for a SSB_SPROM_XXX define. */
-#define SPOFF(offset)  (((offset) - SSB_SPROM_BASE) / sizeof(u16))
+#define SPOFF(offset)  ((offset) / sizeof(u16))
 /* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
 #define SPEX16(_outvar, _offset, _mask, _shift)        \
        out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
@@ -254,7 +254,7 @@ static int sprom_do_read(struct ssb_bus *bus, u16 *sprom)
        int i;
 
        for (i = 0; i < bus->sprom_size; i++)
-               sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2));
+               sprom[i] = ioread16(bus->mmio + bus->sprom_offset + (i * 2));
 
        return 0;
 }
@@ -285,7 +285,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
                        ssb_printk("75%%");
                else if (i % 2)
                        ssb_printk(".");
-               writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
+               writew(sprom[i], bus->mmio + bus->sprom_offset + (i * 2));
                mmiowb();
                msleep(20);
        }
@@ -621,6 +621,14 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
        int err = -ENOMEM;
        u16 *buf;
 
+       if (!ssb_is_sprom_available(bus)) {
+               ssb_printk(KERN_ERR PFX "No SPROM available!\n");
+               return -ENODEV;
+       }
+
+       bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
+               SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
+
        buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
        if (!buf)
                goto out;
index f2f920fef10df9f2d0f5845fcf7ff70875c12350..007bc3a03486b621034134f33a1c3029cb8e0b29 100644 (file)
@@ -176,3 +176,17 @@ const struct ssb_sprom *ssb_get_fallback_sprom(void)
 {
        return fallback_sprom;
 }
+
+/* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
+bool ssb_is_sprom_available(struct ssb_bus *bus)
+{
+       /* status register only exists on chipcomon rev >= 11 and we need check
+          for >= 31 only */
+       /* this routine differs from specs as we do not access SPROM directly
+          on PCMCIA */
+       if (bus->bustype == SSB_BUSTYPE_PCI &&
+           bus->chipco.dev->id.revision >= 31)
+               return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
+
+       return true;
+}
index 88fdd53cf5d3668fbbf2dd4b59f0a89ed9678ac2..80284522c42b5a4fb84c7d82ab9c543151a7c8fd 100644 (file)
@@ -1458,7 +1458,7 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
                                !netdev_mc_empty(dev))
                        {
                                char hw_dst_addr[6];
-                               struct dev_mc_list *dmi;
+                               struct netdev_hw_addr *ha;
                                int i;
 
                                memcpy_fromio(hw_dst_addr, arlan->ultimateDestAddress, 6);
@@ -1469,12 +1469,13 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short
                                                        printk(KERN_ERR "%s mcast 0x0100 \n", dev->name);
                                                else if (hw_dst_addr[1] == 0x40)
                                                        printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name);
-                                       netdev_for_each_mc_entry(dmi, dev) {
+                                       netdev_for_each_mc_entry(ha, dev) {
                                                if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
                                                        printk(KERN_ERR "%s mcl %pM\n",
-                                                              dev->name, dmi->dmi_addr);
+                                                              dev->name,
+                                                              ha->addr);
                                                for (i = 0; i < 6; i++)
-                                                       if (dmi->dmi_addr[i] != hw_dst_addr[i])
+                                                       if (ha->addr[i] != hw_dst_addr[i])
                                                                break;
                                                if (i == 6)
                                                        break;
index ab047f2ff72cd10e1a3a17e34803f4e8f04b1893..abc82c3dad21dc45819c46c01f908d4b9cb0cc7f 100644 (file)
@@ -404,7 +404,7 @@ void et131x_multicast(struct net_device *netdev)
        struct et131x_adapter *adapter = netdev_priv(netdev);
        uint32_t PacketFilter = 0;
        unsigned long flags;
-       struct dev_mc_list *mclist;
+       struct netdev_hw_addr *ha;
        int i;
 
        spin_lock_irqsave(&adapter->Lock, flags);
@@ -449,10 +449,10 @@ void et131x_multicast(struct net_device *netdev)
 
        /* Set values in the private adapter struct */
        i = 0;
-       netdev_for_each_mc_addr(mclist, netdev) {
+       netdev_for_each_mc_addr(ha, netdev) {
                if (i == NIC_MAX_MCAST_LIST)
                        break;
-               memcpy(adapter->MCList[i++], mclist->dmi_addr, ETH_ALEN);
+               memcpy(adapter->MCList[i++], ha->addr, ETH_ALEN);
        }
        adapter->MCAddressCount = i;
 
index 7daeced317c4ac050701cd8ab653e8f665ffc32a..bebf0fd2af859a6b98f55915d2fcb84b05df8d40 100644 (file)
@@ -1367,12 +1367,12 @@ static void slic_mcast_set_list(struct net_device *dev)
        struct adapter *adapter = netdev_priv(dev);
        int status = STATUS_SUCCESS;
        char *addresses;
-       struct dev_mc_list *mc_list;
+       struct netdev_hw_addr *ha;
 
        ASSERT(adapter);
 
-       netdev_for_each_mc_addr(mc_list, dev) {
-               addresses = (char *) &mc_list->dmi_addr;
+       netdev_for_each_mc_addr(ha, dev) {
+               addresses = (char *) &ha->addr;
                status = slic_mcast_add_list(adapter, addresses);
                if (status != STATUS_SUCCESS)
                        break;
index e40a2e990f4f6e389da82b567026ba00871da29f..18f4dfed997fb3929fd371bead09893c7a3c34bb 100644 (file)
@@ -3080,7 +3080,7 @@ static void device_set_multi(struct net_device *dev) {
 
     PSMgmtObject     pMgmt = pDevice->pMgmt;
     u32              mc_filter[2];
-    struct dev_mc_list *mclist;
+    struct netdev_hw_addr *ha;
 
 
     VNSvInPortB(pDevice->PortOffset + MAC_REG_RCR, &(pDevice->byRxMode));
@@ -3100,8 +3100,8 @@ static void device_set_multi(struct net_device *dev) {
     }
     else {
         memset(mc_filter, 0, sizeof(mc_filter));
-       netdev_for_each_mc_addr(mclist, dev) {
-            int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+       netdev_for_each_mc_addr(ha, dev) {
+            int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
             mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
         }
         MACvSelectPage1(pDevice->PortOffset);
index a8e1adbc9592daea1e114c147f6c2116477680db..49270db98fbb64d01225e3c3b1f2c8c789485c51 100644 (file)
@@ -1596,7 +1596,7 @@ static void device_set_multi(struct net_device *dev) {
     PSMgmtObject     pMgmt = &(pDevice->sMgmtObj);
     u32              mc_filter[2];
     int              ii;
-    struct dev_mc_list *mclist;
+    struct netdev_hw_addr *ha;
     BYTE             pbyData[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
     BYTE             byTmpMode = 0;
     int              rc;
@@ -1632,8 +1632,8 @@ static void device_set_multi(struct net_device *dev) {
     }
     else {
         memset(mc_filter, 0, sizeof(mc_filter));
-       netdev_for_each_mc_addr(mclist, dev) {
-            int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+       netdev_for_each_mc_addr(ha, dev) {
+            int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
             mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
         }
         for (ii = 0; ii < 4; ii++) {
index 54ca63196fdd7e2e599b483397c50ce3d5296660..f44ef351647b8c5884a29b44931b1b080111e8e9 100644 (file)
@@ -3419,7 +3419,7 @@ static void wv_82586_config(struct net_device * dev)
        ac_cfg_t cfg;           /* Configure action */
        ac_ias_t ias;           /* IA-setup action */
        ac_mcs_t mcs;           /* Multicast setup */
-       struct dev_mc_list *dmi;
+       struct netdev_hw_addr *ha;
 
 #ifdef DEBUG_CONFIG_TRACE
        printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name);
@@ -3531,16 +3531,16 @@ static void wv_82586_config(struct net_device * dev)
 
        /* Any address to set? */
        if (lp->mc_count) {
-               netdev_for_each_mc_addr(dmi, dev)
-                       outsw(PIOP1(ioaddr), (u16 *) dmi->dmi_addr,
+               netdev_for_each_mc_addr(ha, dev)
+                       outsw(PIOP1(ioaddr), (u16 *) ha->addr,
                              WAVELAN_ADDR_SIZE >> 1);
 
 #ifdef DEBUG_CONFIG_INFO
                printk(KERN_DEBUG
                       "%s: wv_82586_config(): set %d multicast addresses:\n",
                       dev->name, lp->mc_count);
-               netdev_for_each_mc_addr(dmi, dev)
-                       printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev)
+                       printk(KERN_DEBUG " %pM\n", ha->addr);
 #endif
        }
 
index 37fa85517a588232772162193ac1a4aca0194891..e3bb40be4306e5de35a8744945ef0713143e7e49 100644 (file)
@@ -3591,20 +3591,20 @@ wv_82593_config(struct net_device *     dev)
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
     /* But only if it's not in there already! */
   if(do_roaming)
-    dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1);
+    dev_mc_add(dev, WAVELAN_BEACON_ADDRESS);
 #endif /* WAVELAN_ROAMING */
 
   /* If any multicast address to set */
   if(lp->mc_count)
     {
-      struct dev_mc_list *dmi;
+      struct netdev_hw_addr *ha;
       int                      addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
             dev->name, lp->mc_count);
-      netdev_for_each_mc_addr(dmi, dev)
-       printk(KERN_DEBUG " %pM\n", dmi->dmi_addr);
+      netdev_for_each_mc_addr(ha, dev)
+       printk(KERN_DEBUG " %pM\n", ha->addr);
 #endif
 
       /* Initialize adapter's ethernet multicast addresses */
@@ -3612,8 +3612,8 @@ wv_82593_config(struct net_device *       dev)
       outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
       outb(addrs_len & 0xff, PIOP(base));      /* byte count lsb */
       outb((addrs_len >> 8), PIOP(base));      /* byte count msb */
-      netdev_for_each_mc_addr(dmi, dev)
-       outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen);
+      netdev_for_each_mc_addr(ha, dev)
+       outsb(PIOP(base), ha->addr, dev->addr_len);
 
       /* reset transmit DMA pointer */
       hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
index 3482eec186516930725bb11a3bb51d2ee83cc782..5d9499bba9cc786a3501d93ecea728f6cc7278f1 100644 (file)
@@ -92,10 +92,10 @@ static int wbsoft_get_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
-static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
-                                   struct dev_addr_list *mc_list)
+static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw,
+                                   struct netdev_hw_addr_list *mc_list)
 {
-       return mc_count;
+       return netdev_hw_addr_list_count(mc_list);
 }
 
 static void wbsoft_configure_filter(struct ieee80211_hw *dev,
index 1db73ebcae28798407b9e02eb65a6ca2cc27c409..ca8c8b134c4efb102bf3b62c787c1f8e2803ef69 100644 (file)
@@ -1050,7 +1050,7 @@ void wl_multicast( struct net_device *dev )
 //;?seems reasonable that even an AP-only driver could afford this small additional footprint
 
     int                 x;
-    struct dev_mc_list *mclist;
+    struct netdev_hw_addr *ha;
     struct wl_private   *lp = wl_priv(dev);
     unsigned long       flags;
     /*------------------------------------------------------------------------*/
@@ -1073,9 +1073,9 @@ void wl_multicast( struct net_device *dev )
 
         DBG_PRINT( "  mc_count: %d\n", netdev_mc_count(dev));
 
-       netdev_for_each_mc_addr(mclist, dev)
-            DBG_PRINT( "    %s (%d)\n", DbgHwAddr(mclist->dmi_addr),
-                       mclist->dmi_addrlen );
+       netdev_for_each_mc_addr(ha, dev)
+            DBG_PRINT("    %s (%d)\n", DbgHwAddr(ha->addr),
+                     dev->addr_len);
     }
 #endif /* DBG */
 
@@ -1120,9 +1120,9 @@ void wl_multicast( struct net_device *dev )
                 lp->ltvRecord.typ = CFG_GROUP_ADDR;
 
                x = 0;
-               netdev_for_each_mc_addr(mclist, dev)
+               netdev_for_each_mc_addr(ha, dev)
                     memcpy(&(lp->ltvRecord.u.u8[x++ * ETH_ALEN]),
-                           mclist->dmi_addr, ETH_ALEN);
+                          ha->addr, ETH_ALEN);
                 DBG_PRINT( "Setting multicast list\n" );
                 hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord ));
             } else {
index 9777583218ff9fa4abaa7be5896de223b92f77ab..aa88911c95045d10e1089ae477b1f43eab7de614 100644 (file)
@@ -642,7 +642,7 @@ static struct miscdevice vhost_net_misc = {
        &vhost_net_fops,
 };
 
-int vhost_net_init(void)
+static int vhost_net_init(void)
 {
        int r = vhost_init();
        if (r)
@@ -659,7 +659,7 @@ err_init:
 }
 module_init(vhost_net_init);
 
-void vhost_net_exit(void)
+static void vhost_net_exit(void)
 {
        misc_deregister(&vhost_net_misc);
        vhost_cleanup();
index 49fa953aaf6e354be77e47ff708f8677cc58026b..750effe0f98b61f7134b69d7b14a85a54723cc45 100644 (file)
@@ -715,8 +715,8 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
        return 0;
 }
 
-int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
-                  struct iovec iov[], int iov_size)
+static 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;
@@ -741,7 +741,7 @@ int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
                _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)
+               _iov->iov_base = (void __user *)(unsigned long)
                        (reg->userspace_addr + addr - reg->guest_phys_addr);
                s += size;
                addr += size;
@@ -995,7 +995,7 @@ void vhost_discard_vq_desc(struct vhost_virtqueue *vq)
  * 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;
+       struct vring_used_elem __user *used;
 
        /* The virtqueue contains a ring of used buffers.  Get a pointer to the
         * next entry in that used ring. */
@@ -1019,7 +1019,8 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
                smp_wmb();
                /* Log used ring entry write. */
                log_write(vq->log_base,
-                         vq->log_addr + ((void *)used - (void *)vq->used),
+                         vq->log_addr +
+                          ((void __user *)used - (void __user *)vq->used),
                          sizeof *used);
                /* Log used index update. */
                log_write(vq->log_base,
index 8af0fc7210b1fe70616a066775ee2bd5672b5df0..243409f5240d1a00541ebe8824e103c88d932c6f 100644 (file)
@@ -33,7 +33,7 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \
 fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin
 fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw
 fw-shipped-$(CONFIG_BNX2X) += bnx2x-e1-5.2.13.0.fw bnx2x-e1h-5.2.13.0.fw
-fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-5.0.0.j9.fw \
+fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-5.0.0.j15.fw \
                             bnx2/bnx2-rv2p-09-5.0.0.j10.fw \
                             bnx2/bnx2-rv2p-09ax-5.0.0.j10.fw \
                             bnx2/bnx2-mips-06-5.0.0.j6.fw \
diff --git a/firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex b/firmware/bnx2/bnx2-mips-09-5.0.0.j15.fw.ihex
new file mode 100644 (file)
index 0000000..627baec
--- /dev/null
@@ -0,0 +1,6081 @@
+:100000000800011008000000000051F8000000C8BE
+:10001000000000000000000000000000080051F88F
+:1000200000000038000052C00800008808000000EE
+:100030000000528C000052F8080054800000008438
+:100040000000A5840800528C000001C00000A60832
+:10005000080031D808000000000081080000A7C88F
+:1000600000000000000000000000000008008108FF
+:1000700000000124000128D00800048808000400C2
+:10008000000017EC000129F400000000000000004F
+:100090000000000008001BEC00000004000141E02B
+:1000A000080000A808000000000038D0000141E46A
+:1000B000000000000000000000000000080038D030
+:0800C0000000003000017AB4D9
+:0800C8000A00004400000000E2
+:1000D000000000000000000D636F6D352E302E30E3
+:1000E0006A31350005000002000000000000000336
+:1000F00000000014000000320000000300000000B7
+:1001000000000000000000000000000000000000EF
+:1001100000000010000001360000EA600000000549
+:1001200000000000000000000000000000000008C7
+:1001300000000000000000000000000000000000BF
+:1001400000000000000000000000000000000000AF
+:10015000000000000000000000000000000000009F
+:10016000000000020000000000000000000000008D
+:10017000000000000000000000000000000000007F
+:10018000000000000000000000000010000000005F
+:10019000000000000000000000000000000000005F
+:1001A000000000000000000000000000000000004F
+:1001B000000000000000000000000000000000003F
+:1001C000000000000000000000000000000000002F
+:1001D000000000000000000000000000100000030C
+:1001E000000000000000000D0000000D3C020800AF
+:1001F000244252603C0308002463539CAC4000003E
+:100200000043202B1480FFFD244200043C1D080005
+:1002100037BD9FFC03A0F0213C1008002610011000
+:100220003C1C0800279C52600E00026B000000007E
+:100230000000000D27BDFFE0AFBF0018AFB10014F4
+:10024000AFB000103C04800094820108304370007D
+:10025000240220001062000B2862200114400036A6
+:1002600000001021240240001062002C0000000059
+:10027000240260001062002D000010210A00009D81
+:100280008FBF001834910100922400098E300018AD
+:1002900010800020240300012402000914820006BB
+:1002A0008F8200243C0280089442001A000214004D
+:1002B000020280258F8200248C42000C1040001521
+:1002C000000018210E000D52000000008F83002452
+:1002D000962400088F8200209463001E9625000C4F
+:1002E0000004240000832025AC500000AC4500042D
+:1002F000AC400008AC40000CAC400010AC40001416
+:10030000AC400018AC44001C0E000D862404000113
+:10031000000018210A00009C006010210E00043B20
+:10032000000000000A00009C000010210E000C726A
+:1003300000000000000010218FBF00188FB10014D2
+:100340008FB0001003E0000827BD00208F8200243A
+:1003500027BDFFE0AFB00010AFBF0018AFB1001471
+:100360008C42000C3C1080008E11010010400034C3
+:100370008FBF00180E000D52000000008F85002076
+:1003800024047FFF0091202BACB100008E030104F8
+:100390009602010800031C003042FFFF006218258E
+:1003A000ACA300049202010A96030114304200FF3C
+:1003B0003063FFFF0002140000431025ACA20008C8
+:1003C0009603010C9602010E00031C003042FFFF51
+:1003D00000621825ACA3000C9603011096020112CE
+:1003E00000031C003042FFFF00621825ACA3001080
+:1003F0008E020118ACA200148E02011CACA20018DF
+:10040000148000088F820024978200003C0420059D
+:100410000044182524420001ACA3001C0A0000DBA4
+:10042000A78200003C0340189442001E00431025A0
+:10043000ACA2001C0E000D86240400018FBF001822
+:100440008FB100148FB000100000102103E00008ED
+:1004500027BD00203C0680008CC202B824030001A6
+:1004600004410008008028213C0208008C42006002
+:10047000244200013C010800AC22006003E00008B7
+:10048000006010218C83002094820016ACC302808F
+:100490002442FFFCA4C202843C0208008C42005C9F
+:1004A0008C84000494A3000E244200013C01080047
+:1004B000AC22005C3C021000A4C30286ACC40288DB
+:1004C00000001821ACC202B803E00008006010214F
+:1004D00027BDFFE0AFB000103C108000AFB20018A5
+:1004E000AFBF001CAFB10014361201009243000BE5
+:1004F0002402001A965100081462005A00002821B4
+:1005000032220001104000188F8200248E42000029
+:10051000000223403C02003F3442FFFF0044102B06
+:10052000104000043C030040964200140A000124DD
+:10053000008320218E030100240201005462000682
+:10054000964200143C028008904200043042000FA2
+:10055000000225009642001400821025AE020080A1
+:100560000A000157000000008C42000C10400028D7
+:10057000000000000E000D5200000000960201086D
+:100580009603010C8F8500203042003E3063FFFF50
+:100590000002140000431025ACA200008E020100EE
+:1005A000ACA20004960301169604010E8F8200246B
+:1005B00000031C003084FFFF00641825ACA3000872
+:1005C00096030110960401129446001E00031C00BD
+:1005D0003084FFFF00641825ACA3000C3C0220000F
+:1005E00000C2302596020114240400013042FFFFAE
+:1005F000ACA200108E020118ACA200149202010BF2
+:10060000304200FFACA200180E000D86ACA6001C04
+:100610003C0208008C420040244200013C010800DA
+:10062000AC2200403C0308008C63004432220002EC
+:1006300032240004246300013C010800AC23004480
+:10064000108000080002282B024020218FBF001CD0
+:100650008FB200188FB100148FB000100A0000E3B1
+:1006600027BD00208FBF001C8FB200188FB100146F
+:100670008FB0001000A0102103E0000827BD00206B
+:1006800027BDFFE0AFB000103C108000AFB20018F3
+:10069000AFBF001CAFB10014361201009243000B33
+:1006A00024020003965100081462007500002821FE
+:1006B00032220001104000178F8200248E43000078
+:1006C0003C02003F3442FFFF000323400044102B54
+:1006D0005040000524020100964200143C030040F3
+:1006E0000A00018F00832021546200069642001404
+:1006F0003C028008904200043042000F00022500B6
+:100700009642001400821025AE0200800A0001BF4C
+:10071000000000008C42000C10400025000000008A
+:100720000E000D5200000000960201089603010C15
+:100730008F8500203042003E3063FFFF000214002E
+:1007400000431025ACA200008E020100ACA2000400
+:10075000960301169604010E8F82002400031C00EC
+:100760003084FFFF00641825ACA300089603011035
+:10077000960401129446001E00031C003084FFFF03
+:1007800000641825ACA3000C3C02200000C23025F8
+:1007900096020114240400013042FFFFACA20010B5
+:1007A000ACA00014ACA000180E000D86ACA6001C76
+:1007B0003C0208008C420040244200013C01080039
+:1007C000AC2200403C0208008C420044322300046A
+:1007D000244200013C010800AC22004410600008E3
+:1007E00032220002024020218FBF001C8FB200186D
+:1007F0008FB100148FB000100A0000E327BD002065
+:100800001040001F000028213C05800034A2007029
+:100810008C4400008F82000C008210232C43012C9A
+:1008200010600004AF820010240500010A0001EEF0
+:10083000AF84000C8CA301043C026020AC43001484
+:100840008C420004240301FE304203FF1443000BDA
+:10085000AF84000C8CA20100000219C22462FFFCCC
+:100860002C42000810400003240400022462FFFD13
+:10087000004420043C026000AC44691400002821BC
+:100880008FBF001C8FB200188FB100148FB0001002
+:1008900000A0102103E0000827BD00203C048000D8
+:1008A0008C83010024020100506200033C02800896
+:1008B0000000000D3C02800890430004000010215D
+:1008C0003063000F00031D0003E00008AC830080CC
+:1008D0002C8407811080000A000028213C0280003F
+:1008E00094420108240320003042700014430005A4
+:1008F0002783FFA43C02800890420005304500FF9A
+:100900002783FFA40005208000832021000510C05C
+:10091000004510238C8400003C0308002463532C02
+:10092000000210C0004310213C038000AC64009022
+:1009300003E00008AF82002403E00008000010215B
+:1009400003E00008000010212402010014820008C6
+:10095000000000003C0208008C4200FC2442000120
+:100960003C010800AC2200FC0A00023030A200204A
+:100970003C0208008C420084244200013C01080033
+:10098000AC22008430A200201040000830A30010E8
+:100990003C0208008C420108244200013C0108008E
+:1009A000AC22010803E0000800000000106000080D
+:1009B000000000003C0208008C42010424420001B7
+:1009C0003C010800AC22010403E000080000000024
+:1009D0003C0208008C420100244200013C01080056
+:1009E000AC22010003E000080000000027BDFFE882
+:1009F000AFB000103C108000AFBF001436040100FF
+:100A00009483000830620004104000053066000244
+:100A10008FBF00148FB000100A0000E327BD00183C
+:100A200010C00006006028218E0401000E00022084
+:100A3000000000000A000267240200018F82000803
+:100A40008E03010410430007000010218E040100F2
+:100A50000E000220000000008E020104AF82000898
+:100A6000000010218FBF00148FB0001003E00008B9
+:100A700027BD001827BDFFD83C036010AFB3001C92
+:100A8000AFBF0020AFB20018AFB10014AFB000107C
+:100A90008C6450002402FF7F3C13080026735290A0
+:100AA000008220243484380CAC6450003C02800066
+:100AB00024030037AC4300083C06080024C6087035
+:100AC000026010212404001C2484FFFFAC460000B7
+:100AD0000481FFFD244200043C0208002442016C12
+:100AE0003C010800AC2252983C020800244205B8A0
+:100AF0003C010800AC22529C3C02080024420284C3
+:100B00003C010800AC2252D83C02080024420408F0
+:100B10003C030800246308783C040800248409246A
+:100B20003C05080024A52C803C010800AC2252F8AA
+:100B30003C020800244207D43C010800AC2652E0E5
+:100B40003C010800AC2552EC3C010800AC2352F4F7
+:100B50003C010800AC2452FC3C010800AC225300CC
+:100B60003C010800AC2352943C010800AC2052A088
+:100B70003C010800AC2052A43C010800AC2052A863
+:100B80003C010800AC2052AC3C010800AC2052B043
+:100B90003C010800AC2052B43C010800AC2052B823
+:100BA0003C010800AC2452BC3C010800AC2052C0FF
+:100BB0003C010800AC2052C43C010800AC2052C8E3
+:100BC0003C010800AC2052CC3C010800AC2052D0C3
+:100BD0003C010800AC2652D43C010800AC2652DC93
+:100BE0003C010800AC2052E43C010800AC2552E86E
+:100BF0003C010800AC2352F00E0005670000000025
+:100C0000AF80000C8F8300043C0208008C4200205F
+:100C10001062001F000088212792FFA43C100800EA
+:100C20002610532C3C0208008C42002024050001B1
+:100C300002251804004320248F820004004310245E
+:100C40005044000C2631000110800008AF900024B1
+:100C50008E4300003C028000AC4300900E000D1952
+:100C6000AE05000C0A0002EB26310001AE00000CBC
+:100C7000263100012E220002261000381440FFE920
+:100C8000265200043C0208008C420020AF8200047F
+:100C90003C1080008E110000322200071040FFDA65
+:100CA0008F83000432220001104000213222000212
+:100CB0008E020100AE0200208E020104AE0200A8E6
+:100CC0000E0002028E0401009202010B304300FF6D
+:100CD0002C62001D54400004000310800E00021C12
+:100CE0000A00030C00000000005310218C42000099
+:100CF0000040F80900000000104000043C028000A1
+:100D00008C4301043C026020AC4300143C02080008
+:100D10008C4200343C0440003C038000244200012B
+:100D2000AC6401383C010800AC22003432220002DD
+:100D300010400010322200043C1080008E0201405E
+:100D4000AE0200200E0002028E0401400E0003A439
+:100D5000000000003C024000AE0201783C020800A6
+:100D60008C420038244200013C010800AC220038CB
+:100D7000322200041040FFA48F8300043C10800046
+:100D80008E020180AE0200200E0002028E0401805D
+:100D90008E03018024020F00146200073C028008C9
+:100DA0008E0201883C0300E03042FFFF0043102523
+:100DB0000A000348AE0200803442008090420000E6
+:100DC00024030050304200FF1443000700000000DD
+:100DD0000E0003810000000014400003000000002A
+:100DE0000E00096A000000003C0208008C42003C32
+:100DF0003C0440003C03800024420001AC6401B884
+:100E00003C010800AC22003C0A0002D08F830004A1
+:100E10003C02900034420001008220253C02800008
+:100E2000AC4400203C0380008C6200200440FFFEA4
+:100E30000000000003E00008000000003C02800009
+:100E4000344300010083202503E00008AC44002067
+:100E500027BDFFE0AFB10014AFB0001000808821C3
+:100E6000AFBF00180E00035230B000FF8F83FF9C0D
+:100E7000022020219062002502028025A07000251A
+:100E80008C7000183C0280000E00035D020280247A
+:100E90001600000A8FBF00183C0380008C6201F826
+:100EA0000440FFFE24020002AC7101C0A06201C434
+:100EB0003C021000AC6201F88FBF00188FB1001423
+:100EC0008FB0001003E0000827BD002027BDFFE819
+:100ED000AFBF00103C0380009462018430420200E6
+:100EE00010400005000020210E000FDA0000000075
+:100EF0000A000397240400018C6201880440000A60
+:100F00008FBF00108C6201883C03FF000043102457
+:100F10003C03040014430004240400018F82FF9C5E
+:100F2000904200088FBF00100080102103E00008ED
+:100F300027BD00188F82FFA02403000124050001B3
+:100F4000A040001A8F82FF9CA44300163C02800040
+:100F50000A0003628C4401408F85FF9C27BDFFE09F
+:100F6000AFBF001CAFB20018AFB10014AFB000109B
+:100F700090A20000304400FF388300203882003007
+:100F80000003182B0002102B0062182410600005CB
+:100F90003C02800024020050148200818FBF001C9C
+:100FA0003C02800090420148304200FF2443FFFF92
+:100FB0002C6200051040007A8FBF001C00031080D7
+:100FC0003C03080024635210004310218C420000AF
+:100FD00000400008000000003C1180008E24014009
+:100FE0000E0003528F92FF9C8E50000C8E22014403
+:100FF0001602000224020001AE42000C0E00035D46
+:101000008E2401408E220144145000068FBF001C24
+:101010008FB200188FB100148FB000100A000F4675
+:1010200027BD00208E42000C0A00042F00000000A3
+:1010300094A200103C0480008C8301443042FFFFE6
+:10104000146200090000000024020001A4A20010A4
+:101050008C820140AC8202003C021000AC8202385B
+:101060000A0004368FBF001C94A200100A00042F4F
+:1010700000000000240200201482000E3C118000B9
+:1010800094A200123C0380008C6301443042FFFFB5
+:10109000146200050000000024020001A4A2001256
+:1010A0000A0004098FBF001C94A200120A00042F3A
+:1010B000000000008E2401400E0003528F92FF9C1E
+:1010C000964200128E2301443050FFFF16030002A7
+:1010D00024020001A64200120E00035D8E2401408E
+:1010E0008E220144160200068FBF001C8FB200182A
+:1010F0008FB100148FB000100A00039B27BD0020A1
+:10110000964200120A00042F0000000094A200146E
+:101110003C0380008C6301443042FFFF14620008EE
+:101120008FBF001C240200018FB200188FB1001481
+:101130008FB00010A4A200140A00143127BD0020B3
+:1011400094A200140A00042F0000000094A20016CC
+:101150003C0380008C6301443042FFFF14620008AE
+:10116000240200018FBF001C8FB200188FB1001441
+:101170008FB00010A4A200160A000B0D27BD00209E
+:1011800094A20016144000068FBF001C3C02080009
+:101190008C420070244200013C010800AC22007027
+:1011A0008FB200188FB100148FB0001003E0000858
+:1011B00027BD002027BDFFD8AFB200188F92FF9C3B
+:1011C000AFB10014AFBF0020AFB3001CAFB0001030
+:1011D0003C028000345101008C500100924200001A
+:1011E00092230009304400FF2402001F106200AB6C
+:1011F0002862002010400019240200382862000AEA
+:101200001040000D2402000B286200081040002E40
+:101210008F82002404600103286200021440002A27
+:101220008F82002424020006106200268FBF002057
+:101230000A0005598FB3001C106200602862000B81
+:10124000144000F98FBF00202402000E10620078C5
+:101250008F8200240A0005598FB3001C106200D150
+:10126000286200391040000A24020080240200365F
+:10127000106200E428620037104000C224020035EA
+:10128000106200D88FBF00200A0005598FB3001CE0
+:101290001062002D2862008110400006240200C860
+:1012A00024020039106200C88FBF00200A000559CF
+:1012B0008FB3001C106200A28FBF00200A000559E6
+:1012C0008FB3001C8F8200248C42000C104000D68B
+:1012D0008FBF00200E000D52000000003C03800074
+:1012E000346301008C6200008F8500209467000841
+:1012F0009466000CACA200008C6400048F82002471
+:1013000000063400ACA400049448001E8C6200184F
+:1013100000073C0000E83825ACA200088C62001CE5
+:1013200024040001ACA2000C9062000A00C2302527
+:10133000ACA60010ACA00014ACA00018ACA7001C18
+:101340000A0005188FBF00208F8200248C42000CF9
+:10135000104000B58FBF00200E000D5200000000AD
+:101360008F820024962400089625000C9443001ECA
+:10137000000422029626000E8F8200200004260020
+:101380000083202500052C003C03008000A62825B2
+:1013900000832025AC400000AC400004AC400008B5
+:1013A000AC40000CAC450010AC400014AC40001840
+:1013B000AC44001C0A000517240400019622000C0E
+:1013C0001440001800000000924200053042001056
+:1013D00014400014000000000E00035202002021FF
+:1013E0009242000502002021344200100E00035DED
+:1013F000A24200059242000024030020304200FF78
+:1014000010430088020020218FBF00208FB3001CF2
+:101410008FB200188FB100148FB000100A00104373
+:1014200027BD00280000000D0A0005588FBF0020CE
+:101430008C42000C1040007C8FBF00200E000D522B
+:10144000000000008E2200048F8400209623000CF0
+:10145000AC8200003C0280089445002C8F8200245E
+:1014600000031C0030A5FFFF9446001E3C02400E06
+:101470000065182500C23025AC830004AC8000084C
+:10148000AC80000CAC800010AC800014AC80001864
+:10149000AC86001C0A000517240400010E0003524C
+:1014A000020020218F93FFA0020020210E00035D87
+:1014B000A660000C020020210E000362240500013A
+:1014C0008F8200248C42000C104000578FBF0020F8
+:1014D0000E000D52000000009622000C8F830020A9
+:1014E00000021400AC700000AC620004AC600008A4
+:1014F0008E4400388F820024AC64000C8E46003C81
+:101500009445001E3C02401FAC66001000A2282536
+:101510008E62000424040001AC620014AC60001868
+:10152000AC65001C8FBF00208FB3001C8FB2001869
+:101530008FB100148FB000100A000D8627BD00285F
+:1015400024020020108200398FB3001C0E000F2CE3
+:1015500000000000104000348FBF00203C038000DA
+:101560008C6201F80440FFFE24020002AC7001C04E
+:10157000A06201C43C021000AC6201F80A000558E8
+:101580008FBF0020020020218FBF00208FB3001CDE
+:101590008FB200188FB100148FB000100A000E75C2
+:1015A00027BD00289625000C020020218FBF0020B7
+:1015B0008FB3001C8FB200188FB100148FB00010D1
+:1015C0000A000E9A27BD0028020020218FB3001CBC
+:1015D0008FB200188FB100148FB000100A000EC532
+:1015E00027BD00289225000D020020218FB3001C8A
+:1015F0008FB200188FB100148FB000100A000F16C0
+:1016000027BD0028020020218FBF00208FB3001CBF
+:101610008FB200188FB100148FB000100A000EEDC9
+:1016200027BD00288FBF00208FB3001C8FB2001889
+:101630008FB100148FB0001003E0000827BD002810
+:101640003C0380008C6202780440FFFE240200020A
+:10165000AC640240A06202443C02100003E00008B7
+:10166000AC620278A380001803E00008A380001990
+:101670003C0380008C6202780440FFFE8F82001CD5
+:10168000AC62024024020002A06202443C0210004C
+:1016900003E00008AC6202783C02600003E000084E
+:1016A0008C425404908300302402000500804021C5
+:1016B0003063003F00004821146200050000502103
+:1016C0009082004C9483004E304900FF306AFFFF47
+:1016D000AD00000CAD000010AD0000249502001418
+:1016E0008D05001C8D0400183042FFFF00491023B7
+:1016F00000021100000237C3004038210086202379
+:1017000000A2102B0082202300A72823AD05001C77
+:10171000AD040018A5090014A5090020A50A0016AB
+:1017200003E00008A50A002203E000080000000012
+:1017300027BDFFD8AFB200183C128008AFB400201C
+:10174000AFB3001CAFB10014AFBF0024AFB00010A6
+:10175000365101003C0260008C4254049222000C7D
+:101760003C140800929400F7304300FF240200016B
+:1017700010620032008098212402000214620035B9
+:10178000365000800E00140B000000009202004C46
+:101790002403FF803C0480003042007F000211C01F
+:1017A000244202400262102100431824AC830094BA
+:1017B000924500089204004C3042007F3C038006B2
+:1017C00014850007004380212402FFFFA22200119C
+:1017D0002402FFFFA62200120A0005CB2402FFFF0D
+:1017E00096020020A222001196020022A6220012D8
+:1017F0008E0200243C048008AE2200143485008050
+:1018000090A2004C34830100A06200108CA2003C26
+:10181000AC6200188C820068AC6200E48C820064C8
+:10182000AC6200E08C82006CAC6200E82402000133
+:10183000A0A200680A0005E73C0480080E001424FA
+:101840000000000036420080A04000680A0005E762
+:101850003C048008A2000068A20000690A00062279
+:101860003C028008348300808C620038348501009B
+:10187000AC62006C24020001A062006990A200C565
+:1018800090830008305100FF3072007F123200193F
+:10189000001111C024420240026210212403FF8083
+:1018A000004318243C048000AC8300943042007F45
+:1018B0003C038006004380218E02000C1040000D86
+:1018C000020020210E000577000000002622000102
+:1018D000305100FF9203003C023410260002102B0E
+:1018E000000210233063007F022288240A0005F1E1
+:1018F000A203003C3C088008350401008C8200D023
+:1019000035070080ACE2003C8C8200D0AD020000C4
+:1019100090E5004C908600C590E3004C908400C593
+:101920002402FF8000A228243063007F308400FF5F
+:1019300000A628250064182A1060000230A500FFC8
+:1019400038A50080A0E5004CA10500093C028008F4
+:101950009043000E344400803C058000A043000A00
+:101960008C8300183C027FFF3442FFFF0062182482
+:10197000AC8300188CA201F80440FFFE00000000B8
+:10198000ACB301C08FBF00248FB400208FB3001C04
+:101990008FB200188FB100148FB000102402000223
+:1019A000A0A201C427BD00283C02100003E00008EB
+:1019B000ACA201F890A2000024420001A0A2000005
+:1019C0003C0308008C6300F4304200FF1443000223
+:1019D00000803021A0A0000090A200008F84001C95
+:1019E000000211C0244202402483004000822021D2
+:1019F0002402FF80008220243063007F3C02800AA2
+:101A0000006218213C028000AC44002403E000087E
+:101A1000ACC3000094820006908300058C85000C06
+:101A20008C8600108C8700188C88001C8C84002009
+:101A30003C010800A422530E3C010800A023530DD2
+:101A40003C010800AC2553143C010800AC26531897
+:101A50003C010800AC2753203C010800AC2853246B
+:101A60003C010800AC24532803E0000800000000FB
+:101A70003C028008344201008C4400343C03800066
+:101A800034650400AC6400388C420038AF8500280F
+:101A9000AC62003C3C020005AC620030000000007B
+:101AA0000000000003E00008000000003C02000607
+:101AB000308400FF008220253C028000AC440030CE
+:101AC0000000000000000000000000003C03800057
+:101AD0008C620000304200101040FFFD34620400B0
+:101AE00003E00008AF82002894C200003C08080010
+:101AF000950800CA30E7FFFF00804821010210214D
+:101B0000A4C2000094C200003042FFFF00E2102B8C
+:101B100054400001A4C7000094A200003C03080048
+:101B20008C6300CC24420001A4A2000094A2000017
+:101B30003042FFFF144300073C0280080107102BCE
+:101B4000A4A000005440000101003821A4C70000F7
+:101B50003C028008344601008CC3002894A2000097
+:101B60003C0480003042FFFE000210C000621021E1
+:101B7000AC82003C8C82003C006218231860000498
+:101B8000000000008CC200240A0006B324420001B9
+:101B90008CC20024AC8200383C0200503442001059
+:101BA0003C038000AC620030000000000000000038
+:101BB000000000008C620000304200201040FFFD59
+:101BC0000000000094A200003C04800030420001AC
+:101BD000000210C0004410218C430400AD2300001B
+:101BE0008C420404AD2200043C02002003E0000803
+:101BF000AC82003027BDFFE0AFB20018AFB10014D7
+:101C0000AFB00010AFBF001C94C2000000C0802124
+:101C10003C120800965200C624420001A6020000B1
+:101C20009603000094E2000000E030211443000518
+:101C30008FB100300E000688024038210A0006EA03
+:101C4000000000008C8300048C82000424420040C9
+:101C500004610007AC8200048C820004044000048C
+:101C6000000000008C82000024420001AC820000D1
+:101C7000960200003042FFFF50520001A600000013
+:101C80009622000024420001A62200003C028008A7
+:101C900034420100962300009442003C14430004A7
+:101CA0008FBF001C24020001A62200008FBF001C71
+:101CB0008FB200188FB100148FB0001003E000083D
+:101CC00027BD002027BDFFE03C028008AFBF001801
+:101CD000344201008C4800343C0380003469040025
+:101CE000AC6800388C42003830E700FFAF8900282C
+:101CF000AC62003C3C020005AC6200300000000019
+:101D000000000000000000000000000000000000D3
+:101D1000000000008C82000C8C82000C978300165F
+:101D2000AD2200008C82001000604021AD22000432
+:101D30008C820018AD2200088C82001CAD22000CA1
+:101D40008CA20014AD2200108C820020AD22001461
+:101D500090820005304200FF00021200AD22001800
+:101D60008CA20018AD22001C8CA2000CAD22002019
+:101D70008CA20010AD2200248CA2001CAD220028F1
+:101D80008CA20020AD22002C3402FFFFAD260030D3
+:101D9000AD200034506200013408FFFFAD28003848
+:101DA00050E000113C0280083C04800834840100AB
+:101DB000948200503042FFFFAD22003C94830044E7
+:101DC00094850044240200013063FFFF000318C221
+:101DD000006418219064005430A5000700A210048C
+:101DE0000A0007550044102534420100AD20003C94
+:101DF00094430044944400443063FFFF000318C23E
+:101E0000006218213084000790650054240200010C
+:101E1000008210040002102700451024A062005424
+:101E20000000000000000000000000003C0200066E
+:101E3000344200403C038000AC62003000000000EF
+:101E400000000000000000008C6200003042001022
+:101E50001040FFFD3C06800834C20150346304008A
+:101E600034C7014A34C4013434C5014034C6014486
+:101E7000AFA200100E0006CBAF8300288FBF001862
+:101E800003E0000827BD00208F8300143C060800F3
+:101E90008CC600E88F82001C30633FFF000319806E
+:101EA00000461021004310212403FF800043182422
+:101EB0003C068000ACC300283042007F3C03800C0D
+:101EC0000043302190C2000D30A500FF00003821F2
+:101ED00034420010A0C2000D8F8900143C0280081B
+:101EE0003442010094430044000913823048000347
+:101EF00024020001A4C3000E1102000B29020002FB
+:101F000010400005240200021100000C240300010F
+:101F10000A00079D000018211102000600000000C1
+:101F20000A00079D000018218CC2002C0A00079DA2
+:101F3000244300018CC20014244300018CC2001809
+:101F40000043102B5040000A240700012402002700
+:101F500014A200033C0380080A0007AA240700011A
+:101F6000346301009462004C24420001A462004CDE
+:101F700000091382304300032C6200021040000964
+:101F800000802821146000040000000094C2003486
+:101F90000A0007BA3046FFFF8CC600380A0007BAAD
+:101FA00000802821000030213C04080024845308CC
+:101FB0000A0006FF0000000027BDFF90AFB60068D2
+:101FC000AFB50064AFB40060AFB3005CAFB200580F
+:101FD000AFB10054AFBF006CAFB000508C900000A8
+:101FE0000080B0213C0208008C4200E896040032D8
+:101FF0008F83001C2414FF8030843FFF006218216F
+:102000000004218000641821007410243C13800017
+:1020100000A0902190A50000AE620028920400323A
+:102020003C02800C3063007F00628821308400C055
+:1020300024020040148200320000A8218E350038AE
+:102040008E2200181440000224020001AE22001863
+:102050009202003C304200201440000E8F83001C8E
+:10206000000511C02442024000621821306400784B
+:102070003C0200800082202500741824AE63080012
+:10208000AE6408108E2200188E0300080043102151
+:10209000AE2200188E22002C8E230018244200014C
+:1020A0000062182B10600043000000009242000004
+:1020B00024420001A24200003C0308008C6300F4AB
+:1020C000304200FF50430001A24000009242000055
+:1020D0008F84001C000211C024420240248300406F
+:1020E0003063007F008220213C02800A009420247B
+:1020F00000621821AE6400240A0008CBAEC30000C1
+:10210000920300322402FFC000431024304200FF3B
+:102110001440000524020001AE220018962200346B
+:102120000A00083B3055FFFF8E22001424420001B4
+:10213000AE220018920200300002160000021603C0
+:102140000441001C000000009602003227A4001089
+:1021500000802821A7A2001696020032000030213C
+:10216000240700013042FFFFAF8200140E0006FF7B
+:10217000AFA0001C960200328F83001C3C040800B4
+:102180008C8400E830423FFF000211800064182177
+:102190000062182100741024AE62002C3063007FAE
+:1021A0003C02800E006218219062000D3042007FD8
+:1021B000A062000D9222000D3042001050400078C5
+:1021C000924200003C028008344401009482004C9A
+:1021D0008EC300003C130800967300C62442FFFF24
+:1021E000A482004C946200329623000E3054FFFF0C
+:1021F0003070FFFF3C0308008C6300D000701807AC
+:10220000A7A300389482003E3063FFFF3042FFFFF7
+:1022100014620007000000008C8200303C03800044
+:1022200024420030AC62003C0A0008638C82002C1F
+:10223000948200403042FFFF5462000927A400400E
+:102240008C8200383C03800024420030AC62003CA9
+:102250008C820034AC6200380A0008723C038000B3
+:1022600027A5003827A60048026038210E000688FE
+:10227000A7A000488FA300403C02800024630030E8
+:10228000AC4300388FA30044AC43003C3C038000C7
+:102290003C020005AC6200303C028008344401007E
+:1022A00094820042346304003042FFFF0202102B8C
+:1022B00014400007AF8300289482004E94830042AC
+:1022C00002021021004310230A0008883043FFFF58
+:1022D0009483004E94820042026318210050102320
+:1022E000006218233063FFFF3C0280083444010081
+:1022F0009482003C3042FFFF1443000300000000C2
+:102300000A000898240300019482003C3042FFFF39
+:102310000062102B144000058F8200289482003C3C
+:10232000006210233043FFFF8F820028AC5500006D
+:10233000AC400004AC540008AC43000C3C02000666
+:10234000344200103C038000AC620030000000000A
+:1023500000000000000000008C620000304200100D
+:102360001040FFFD3C04800834840100001018C2B6
+:102370000064182190650054320200072406000111
+:102380000046100400451025A062005494830042CA
+:102390009622000E50430001A386001892420000CE
+:1023A00024420001A24200003C0308008C6300F4B8
+:1023B000304200FF50430001A24000009242000062
+:1023C0008F84001C000211C024420240248300407C
+:1023D000008220212402FF80008220243063007FBD
+:1023E0003C02800A006218213C028000AC440024B8
+:1023F000AEC300008FBF006C8FB600688FB500645D
+:102400008FB400608FB3005C8FB200588FB100545E
+:102410008FB0005003E0000827BD007027BDFFD833
+:10242000AFB3001CAFB20018AFB10014AFB00010D2
+:10243000AFBF00200080982100E0802130B1FFFF75
+:102440000E000D5230D200FF00000000000000001E
+:10245000000000008F8200208F830024AC51000018
+:10246000AC520004AC530008AC40000CAC4000106F
+:10247000AC400014AC4000189463001E0203802599
+:10248000AC50001C00000000000000000000000034
+:10249000240400018FBF00208FB3001C8FB20018EE
+:1024A0008FB100148FB000100A000D8627BD0028E0
+:1024B00030A5FFFF0A0008D530C600FF3C028008A7
+:1024C000344301009462000E3C080800950800C6E1
+:1024D0003046FFFF14C000043402FFFF946500DAA9
+:1024E0000A0009228F84001C10C20027000000008F
+:1024F0009462004E9464003C3045FFFF00A6102318
+:1025000000A6182B3087FFFF106000043044FFFF47
+:1025100000C5102300E210233044FFFF0088102B79
+:102520001040000E00E810233C02800834440100F3
+:102530002403000134420080A44300162402FFFF5C
+:10254000A482000E948500DA8F84001C00003021E4
+:1025500030A5FFFF0A0008FA3C0760200044102A5B
+:10256000104000093C028008344300809462001649
+:1025700030420001104000043C0280009442007E82
+:1025800024420014A462001603E0000800000000CA
+:1025900027BDFFE03C028008AFBF001CAFB00018B1
+:1025A00034420100944300429442004C1040001910
+:1025B0003068FFFF93830018240200011462002991
+:1025C0008FBF001C3C06800834D00100000810C2F8
+:1025D00000501021904200543103000734C70148D5
+:1025E000304200FF006210073042000134C9014E42
+:1025F00034C4012C34C5013E1040001634C60142DB
+:102600000E0006CBAFA90010960200420A00093F57
+:102610003048FFFF3C0280083444010094830044AA
+:10262000948200421043000F8FBF001C948200442C
+:10263000A482004294820050A482004E8C82003812
+:10264000AC82003094820040A482003E9482004A12
+:10265000A48200488FBF001C8FB000180A0008FD3C
+:1026600027BD00208FB0001803E0000827BD002020
+:1026700027BDFFA0AFB1004C3C118000AFBF005898
+:10268000AFB30054AFB20050AFB000483626018857
+:1026900090C200033044007FA3A400108E3201805A
+:1026A00090C200003043007F240200031062003B10
+:1026B000AF92001C286200041040000624020004AF
+:1026C00024020002106200098FBF00580A000B08A4
+:1026D0008FB300541062004D240200051062014EB9
+:1026E0008FBF00580A000B088FB30054000411C0BC
+:1026F000024210212404FF8024420240004410249E
+:1027000026430040AE2200243063007F3C02800A52
+:10271000006218219062003CAFA3003C00441025E9
+:10272000A062003C8FA3003C9062003C304200401D
+:102730001040016C8FBF00583C108008A380001827
+:10274000361001008E0200D08C63003427A4003CB8
+:1027500027A50010004310210E0007BCAE0200D0D8
+:1027600093A200103C038000A20200C58C62027894
+:102770000440FFFE8F82001CAC6202402402000273
+:10278000A06202443C021000AC6202780E000932E2
+:10279000000000000A000B078FBF00583C058008AE
+:1027A00090C3000190A2000B1443014E8FBF00584C
+:1027B00034A400808C8200189082004C90A2000803
+:1027C0003C0260008C4254048C8300183C027FFF62
+:1027D0003442FFFF006218243C0208008C4200B41F
+:1027E000AC8300183C038000244200013C01080037
+:1027F000AC2200B48C6201F80440FFFE8F82001C02
+:10280000AC6201C00A000ACF240200023C1080081A
+:1028100090C300019202000B144301328FBF005895
+:1028200027A4001836050110240600033C026000AE
+:102830008C4254040E000E150000000027A400284E
+:10284000360501E00E000E15240600038FA20028B5
+:1028500036030100AE0200648FA2002CAE020068B5
+:102860008FA20030AE02006C93A40018906300C5E4
+:102870002402FF800082102400431025304900FF0D
+:102880003084007F3122007F0082102A54400001F2
+:1028900039290080000411C0244202402403FF8033
+:1028A0000242102100431024AE2200942642004030
+:1028B0003042007F3C038006004340218FA3001C70
+:1028C0002402FFFFAFA800403C130800927300F7FA
+:1028D0001062003393A2001995030014304400FFE6
+:1028E0003063FFFF0064182B106000100000000030
+:1028F000950400148D07001C8D0600183084FFFF1E
+:10290000004420230004210000E4382100001021AD
+:1029100000E4202B00C2302100C43021AD07001C90
+:10292000AD0600180A000A2893A2001995040014A5
+:102930008D07001C8D0600183084FFFF00822023C5
+:1029400000042100000010210080182100C2302363
+:1029500000E4202B00C4302300E33823AD07001C23
+:10296000AD06001893A200198FA30040A4620014C2
+:1029700097A2001AA46200168FA2001CAC6200107D
+:102980008FA2001CAC62000C93A20019A46200206C
+:1029900097A2001AA46200228FA2001CAC6200243D
+:1029A0003C048008348300808C6200388FA20020B1
+:1029B00001208821AC62003C8FA20020AC82000084
+:1029C00093A20018A062004C93A20018A0820009F4
+:1029D000A060006893A20018105100512407FF80E6
+:1029E0003229007F000911C0244202400242102116
+:1029F0003046007F3C03800000471024AC62009406
+:102A00003C02800600C2302190C2003CAFA60040CC
+:102A10000000202100471025A0C2003C8FA80040E4
+:102A200095020002950300148D07001C3042FFFF41
+:102A30003063FFFF8D0600180043102300021100D1
+:102A400000E2382100E2102B00C4302100C2302106
+:102A5000AD07001CAD06001895020002A502001487
+:102A6000A50000168D020008AD0200108D020008BE
+:102A7000AD02000C95020002A5020020A500002274
+:102A80008D020008AD0200249102003C304200405B
+:102A90001040001A262200013C108008A3A900382B
+:102AA000A3800018361001008E0200D08D03003480
+:102AB00027A4004027A50038004310210E0007BCC2
+:102AC000AE0200D093A200383C038000A20200C5F1
+:102AD0008C6202780440FFFE8F82001CAC620240D0
+:102AE00024020002A06202443C021000AC620278A0
+:102AF0000E00093200000000262200013043007F52
+:102B000014730004004020212403FF8002231024BA
+:102B10000043202693A200180A000A44309100FFC7
+:102B200093A400188FA3001C2402FFFF1062000A68
+:102B3000308900FF24820001248300013042007F9D
+:102B400014530005306900FF2403FF800083102424
+:102B500000431026304900FF3C02800890420008E4
+:102B600001208821305000FF123000193222007FEE
+:102B7000000211C002421021244202402403FF80BF
+:102B8000004318243C048000AC8300943042007F52
+:102B90003C038006004310218C43000C00402021A0
+:102BA0001060000BAFA200400E000577000000008F
+:102BB000262300012405FF803062007F14530002A9
+:102BC00002252024008518260A000AA8307100FF7B
+:102BD0003C048008348400808C8300183C027FFF12
+:102BE0003442FFFF00621824AC8300183C038000CD
+:102BF0008C6201F80440FFFE00000000AC7201C0CE
+:102C000024020002A06201C43C021000AC6201F880
+:102C10000A000B078FBF00583C04800890C30001D6
+:102C20009082000B1443002F8FBF00583490008017
+:102C300092020008304200401040002000000000D6
+:102C4000920200080002160000021603044100056B
+:102C5000024020210E000E9A240500930A000B0763
+:102C60008FBF00589202000924030018304200FF71
+:102C70001443000D02402021240500390E000E32BD
+:102C8000000030210E0003528F84001C8F82FF9CB5
+:102C900024030012A04300090E00035D8F84001C72
+:102CA0000A000B078FBF0058240500360E000E32B5
+:102CB000000030210A000B078FBF00580E0003529E
+:102CC00002402021920200058F84001C3442002023
+:102CD0000E00035DA20200050E0010438F84001C4D
+:102CE0008FBF00588FB300548FB200508FB1004C8B
+:102CF0008FB0004803E0000827BD00603C02800858
+:102D0000344501003C0280008C42014094A3000E37
+:102D10000000302100402021AF82001C3063FFFF03
+:102D20003402FFFF106200063C0760202402FFFF10
+:102D3000A4A2000E94A500DA0A0008FA30A5FFFF4D
+:102D400003E000080000000027BDFFC83C0280002F
+:102D50003C068008AFB5002CAFB1001CAFBF0030FF
+:102D6000AFB40028AFB30024AFB20020AFB000185A
+:102D70003451010034C501008C4301008E2200143F
+:102D80008CA400D40000A821AF83001C00441023B1
+:102D900018400052A38000188E2200140000502119
+:102DA000ACA200D490C3000890A200C53073007F8D
+:102DB000A3A200108CB200D08CB400D4304200FF2B
+:102DC0001053003B93A200108F83001C2407FF8048
+:102DD000000211C00062102124420240246300401E
+:102DE000004710243063007F3C0980003C08800AC3
+:102DF00000681821AD2200248C62003427A400143E
+:102E000027A50010024280210290102304400028D0
+:102E1000AFA300149062003C00E21024304200FF97
+:102E200014400019020090219062003C344200409E
+:102E3000A062003C8F86001C93A3001024C20040B7
+:102E40003042007F004828213C0208008C4200F4F8
+:102E500024630001306400FF14820002A3A3001069
+:102E6000A3A0001093A20010AFA50014000211C08F
+:102E70002442024000C2102100471024AD22002449
+:102E80000A000B3E93A200100E0007BC00000000D9
+:102E90003C02800834420100AC5000D093A30010E3
+:102EA000240A0001A04300C50A000B3E93A20010B3
+:102EB00024020001154200093C0380008C62027864
+:102EC0000440FFFE8F82001CAC620240240200021C
+:102ED000A06202443C021000AC6202789222000B15
+:102EE00024030002304200FF14430072000000007F
+:102EF00096220008304300FF240200821462004042
+:102F0000240200843C028000344901008D22000C20
+:102F100095230006000216023063FFFF3045003F94
+:102F20002402002710A2000FAF83001428A200285B
+:102F300010400008240200312402002110A20009E0
+:102F40002402002510A20007938200190A000BB684
+:102F50000000000010A20007938200190A000BB6BF
+:102F6000000000000E000770012020210A000C362E
+:102F7000000000003C0380008C6202780440FFFEE9
+:102F80008F82001CAC62024024020002A062024454
+:102F90003C021000AC6202780A000C36000000000F
+:102FA00095230006912400058D25000C8D26001028
+:102FB0008D2700188D28001C8D2900202442000137
+:102FC0003C010800A423530E3C010800A024530D2B
+:102FD0003C010800AC2553143C010800AC265318F2
+:102FE0003C010800AC2753203C010800AC285324C6
+:102FF0003C010800AC2953280A000C36A3820019B2
+:103000001462000A240200813C028008344201005C
+:10301000944500DA922600058F84001C30A5FFFF3E
+:1030200030C600FF0A000BF73C0760211462005C09
+:10303000000000009222000A304300FF30620020AE
+:1030400010400007306200403C028008344201001A
+:10305000944500DA8F84001C0A000BF5240600401A
+:1030600010400007000316003C02800834420100B3
+:10307000944500DA8F84001C0A000BF524060041F9
+:1030800000021603044100463C028008344201005D
+:10309000944500DA8F84001C2406004230A5FFFF0F
+:1030A0003C0760190E0008FA000000000A000C3608
+:1030B000000000009222000B24040016304200FFA2
+:1030C000104400063C0680009222000B24030017E7
+:1030D000304200FF144300320000000034C50100FC
+:1030E00090A2000B304200FF1444000B000080212E
+:1030F0008CA200208CA400202403FF800043102415
+:10310000000211403084007F004410253C03200061
+:1031100000431025ACC2083094A20008000214003D
+:1031200000021403044200012410000194A20008CC
+:10313000304200805040001A0200A82194A20008EA
+:1031400030422000504000160200A8218CA3001835
+:103150003C021C2D344219ED106200110200A8211E
+:103160003C0208008C4200D4104000053C0280085C
+:103170002403000434420100A04300EC3C02800818
+:1031800034420100944500DA8F84001C24060006B6
+:1031900030A5FFFF0E0008FA3C0760210200A821BD
+:1031A0000E000932000000009222000A304200089E
+:1031B0001040000402A010210E0013470000000080
+:1031C00002A010218FBF00308FB5002C8FB40028D3
+:1031D0008FB300248FB200208FB1001C8FB0001875
+:1031E00003E0000827BD00382402FF80008220246D
+:1031F0003C02900034420007008220253C028000FF
+:10320000AC4400203C0380008C6200200440FFFEA0
+:103210000000000003E00008000000003C03800004
+:103220002402FF80008220243462000700822025CF
+:10323000AC6400208C6200200440FFFE000000000F
+:1032400003E00008000000003C02800824030005A1
+:1032500034420100A04300EC3C0280008C4201009B
+:103260003C038000AF82001C8C6202780440FFFEA9
+:103270008F82001CAC62024024020002A062024461
+:103280003C021000AC62027803E00008000000007D
+:1032900027BDFFE83C068000AFBF001034C7010027
+:1032A00094E20008304400FF3883008238820084B2
+:1032B0002C6300012C420001006218251060002DD3
+:1032C0002402008393820019504000368FBF001003
+:1032D0003C020800904253148CC401003C060800D4
+:1032E00094C6530E3045003F38A3003238A2003F49
+:1032F0002C6300012C42000100621825AF84001CE1
+:10330000AF860014A38000191460000700E020219C
+:103310002402002014A20012000000003402FFFF6B
+:1033200014C2000F000000002402002014A20005B7
+:1033300000E028218CE300142402FFFF5062000B00
+:103340008FBF00103C040800248453080000302183
+:103350000E0006FF240700010A000CA98FBF001011
+:103360000E000770000000008FBF00100A00093235
+:1033700027BD0018148200062482FF808CC301043C
+:103380003C026020AC4300140A000CDF8FBF001029
+:10339000304200FF2C4200021040000424020022B0
+:1033A0008FBF00100A000B2027BD001814820004F4
+:1033B0008F8200248FBF00100A000C6027BD001808
+:1033C0008C42000C1040001E00E0282190E3000910
+:1033D0002402001814620003240200160A000CCA1A
+:1033E00024030008146200072402001724030012BB
+:1033F0003C02800834420080A04300090A000CD738
+:1034000094A700085462000794A700088F82FF9CCD
+:103410002404FFFE9043000500641824A043000527
+:1034200094A7000890A6001B8CA4000094A5000699
+:103430008FBF001000073C000A0008D527BD001808
+:103440008FBF001003E0000827BD00188F850024FF
+:103450003C04800094A2002A8CA30034000230C0F7
+:103460002402FFF000C2102400621821AC83003C4B
+:103470008CA200303C038000AC8200383C0200503B
+:1034800034420010AC620030000000000000000078
+:10349000000000008C620000304200201040FFFD60
+:1034A00030C20008104000063C0280008C62040814
+:1034B000ACA200208C62040C0A000D02ACA2002415
+:1034C0008C430400ACA300208C420404ACA2002472
+:1034D0003C0300203C028000AC4300303C048000F0
+:1034E0008C820030004310241440FFFD8F8600249E
+:1034F0003C020040AC82003094C3002A94C20028F1
+:1035000094C4002C94C5002E2463000100441021B3
+:103510003064FFFFA4C2002814850002A4C3002A5F
+:10352000A4C0002A03E00008000000008F840024EB
+:1035300027BDFFE83C05800424840010AFBF0010C5
+:103540000E000E152406000A8F84002494820012B7
+:103550009483002E3042000F2442000300431804DD
+:1035600024027FFF0043102B10400002AC830000B8
+:103570000000000D0E000CE1000000008F8300240D
+:103580008FBF001027BD0018946200149463001AC6
+:103590003042000F00021500006218253C02800036
+:1035A00003E00008AC4300A08F8300243C028004A9
+:1035B000944400069462001A8C650000A46400160E
+:1035C000004410233042FFFF0045102B03E00008A9
+:1035D000384200018F8400243C0780049486001A3E
+:1035E0008C85000094E20006A482001694E3000695
+:1035F00000C310233042FFFF0045102B384200016A
+:103600001440FFF8A483001603E000080000000047
+:103610008F8400243C028004944200069483001AA4
+:103620008C850000A4820016006210233042FFFF48
+:103630000045102B384200015040000D8F850024BA
+:10364000006030213C07800494E20006A48200164A
+:1036500094E3000600C310233042FFFF0045102B07
+:10366000384200011440FFF8A48300168F8500241F
+:103670003C038000346204008CA40020AF82002050
+:10368000AC6400388CA20024AC62003C3C02000513
+:10369000AC62003003E00008ACA000048F8400247A
+:1036A0003C0300068C8200040002114000431025F8
+:1036B0003C038000AC62003000000000000000000D
+:1036C000000000008C620000304200101040FFFD3E
+:1036D00034620400AC80000403E00008AF820020E4
+:1036E0008F86002427BDFFE0AFB10014AFB00010FB
+:1036F000AFBF00188CC300048CC500248F8200204B
+:10370000309000FF94C4001A24630001244200207A
+:103710002484000124A70020ACC30004AF82002051
+:10372000A4C4001AACC7002404A10006000088212C
+:1037300004E2000594C2001A8CC200202442000159
+:10374000ACC2002094C2001A94C300282E040001C9
+:10375000004310262C420001004410245040000574
+:1037600094C2001A24020001ACC2000894C2001ADC
+:1037700094C300280010202B004310262C42000187
+:103780000044102514400007000000008CC200080F
+:1037900014400004240200108CC300041462000FC3
+:1037A0008F8500240E000D75241100018F820024E6
+:1037B000944300289442001A1443000300000000C0
+:1037C0000E000CE100000000160000048F850024AC
+:1037D0000E000D52000000008F85002494A2001EF0
+:1037E00094A4001C244200013043FFFF1464000233
+:1037F000A4A2001EA4A0001E1200000A3C02800425
+:1038000094A2001494A3001A3042000F0002150085
+:10381000006218253C028000AC4300A00A000DECB9
+:10382000ACA000089442000694A3001A8CA40000E7
+:10383000A4A20016006210233042FFFF0044102BA8
+:10384000384200011040000D02201021006030219C
+:103850003C07800494E20006A4A2001694E300064C
+:1038600000C310233042FFFF0044102B38420001F8
+:103870001440FFF8A4A30016022010218FBF0018E7
+:103880008FB100148FB0001003E0000827BD0020A6
+:1038900003E00008000000008F82002C3C030006BB
+:1038A00000021140004310253C038000AC62003050
+:1038B0000000000000000000000000008C6200001A
+:1038C000304200101040FFFD34620400AF82002837
+:1038D00003E00008AF80002C03E000080000102186
+:1038E00003E00008000000003084FFFF30A5FFFF68
+:1038F0000000182110800007000000003082000145
+:103900001040000200042042006518210A000E0B3E
+:103910000005284003E000080060102110C00006E8
+:1039200024C6FFFF8CA2000024A50004AC82000086
+:103930000A000E152484000403E0000800000000C3
+:1039400010A0000824A3FFFFAC86000000000000C8
+:10395000000000002402FFFF2463FFFF1462FFFA4F
+:103960002484000403E00008000000003C028008FA
+:103970003442008024030001AC43000CA443001037
+:10398000A4430012A443001403E00008A44300165B
+:103990008F82002427BDFFD8AFB3001CAFB2001840
+:1039A000AFB10014AFB00010AFBF00208C47000CC7
+:1039B000248200802409FF803C08800E3043007F71
+:1039C000008080213C0A80000049202400681821E2
+:1039D00030B100FF30D200FF10E000290000982134
+:1039E00026020100AD44002C004928243042007F0B
+:1039F000004820219062000024030050304200FF64
+:103A00001443000400000000AD45002C948200DA4D
+:103A10003053FFFF0E000D52000000008F82002483
+:103A20008F83002000112C009442001E00122400FD
+:103A30003484000100A228253C02400000A2282571
+:103A4000AC7000008FBF0020AC6000048FB2001883
+:103A5000AC7300088FB10014AC60000C8FB3001C75
+:103A6000AC6400108FB00010AC600014240400019E
+:103A7000AC60001827BD00280A000D86AC65001C4C
+:103A80008FBF00208FB3001C8FB200188FB10014BD
+:103A90008FB0001003E0000827BD00283C0680001E
+:103AA00034C201009043000F240200101062000E87
+:103AB0002865001110A0000724020012240200084B
+:103AC0002405003A106200060000302103E00008DF
+:103AD00000000000240500351462FFFC00003021C6
+:103AE0000A000E32000000008CC200748F83FF9C1D
+:103AF00024420FA003E00008AC62000C27BDFFE8E1
+:103B0000AFBF00100E000362240500013C048008D2
+:103B10008FBF00102402000134830080A4620012D1
+:103B200027BD00182402000103E00008A080001A4D
+:103B300027BDFFE0AFB20018AFB10014AFB0001066
+:103B4000AFBF001C30B2FFFF0E000352008088217F
+:103B50003C028008345000809202000924030004D3
+:103B6000304200FF1443000C3C0280081240000861
+:103B70002402000A0E000E29000000009202000537
+:103B80002403FFFE00431024A202000524020012B9
+:103B9000A20200093C028008344200800220202159
+:103BA0000E00035DA04000271640000302202021E4
+:103BB0000E000E8D0000000002202021324600FF82
+:103BC0008FBF001C8FB200188FB100148FB000108F
+:103BD000240500380A000E3227BD002027BDFFE073
+:103BE000AFBF001CAFB20018AFB10014AFB00010EF
+:103BF0000E000352008080210E000E2900000000FC
+:103C00003C0280083445008090A20009241200186C
+:103C1000305100FF12320003020020212402001262
+:103C2000A0A2000990A200052403FFFE0043102477
+:103C30000E00035DA0A20005020020212405002043
+:103C400016320007000030218FBF001C8FB2001811
+:103C50008FB100148FB000100A00036227BD00204E
+:103C60008FBF001C8FB200188FB100148FB00010EE
+:103C7000240500390A000E3227BD002027BDFFE8C9
+:103C80003C028000AFB00010AFBF0014344201000E
+:103C90009442000C2405003600808021144000125C
+:103CA000304600FF0E000352000000003C02800876
+:103CB0003442008024030012A04300099043000511
+:103CC000346300100E000E29A04300050E00035DB2
+:103CD00002002021020020210E00036224050020A2
+:103CE0000A000F0A000000000E000E320000000063
+:103CF0000E000352020020213C0280089043001B6A
+:103D00002405FF9F02002021006518248FBF0014A6
+:103D10008FB00010A043001B0A00035D27BD0018F0
+:103D200027BDFFE0AFBF0018AFB10014AFB0001067
+:103D300030B100FF0E000352008080213C02800859
+:103D400024030012344200800E000E29A043000913
+:103D50000E00035D020020210200202102203021FC
+:103D60008FBF00188FB100148FB0001024050035EC
+:103D70000A000E3227BD00203C0480089083000E0C
+:103D80009082000A1443000B000028218F82FF9CC0
+:103D9000240300502405000190420000304200FF3F
+:103DA00014430004000000009082000E2442000131
+:103DB000A082000E03E0000800A010213C03800058
+:103DC0008C6201F80440FFFE24020002AC6401C0D2
+:103DD000A06201C43C02100003E00008AC6201F8DC
+:103DE00027BDFFE0AFB200183C128008AFB100144D
+:103DF000AFBF001CAFB00010365100809222000906
+:103E00002403000A304200FF1443003E000000007B
+:103E10008E4300048E220038506200808FBF001C49
+:103E20009222000024030050304200FF144300257A
+:103E30003C0280008C4201408E4300043642010067
+:103E400002202821AC43001C9622005C8E230038FF
+:103E50003042FFFF0002104000621821AE23001C18
+:103E60008E4300048E2400389622005C00641823E0
+:103E70003042FFFF00031843000210400043102AA5
+:103E800010400006000000008E4200048E2300381F
+:103E9000004310230A000F78000220439622005CA2
+:103EA0003042FFFF000220403C0280083443010002
+:103EB00034420080ACA4002CA04000242402000165
+:103EC000A062000C0E000F2C0000000010400053F8
+:103ED0008FBF001C3C0280008C4401403C038000EA
+:103EE0008C6201F80440FFFE24020002AC6401C0B1
+:103EF000A06201C43C021000AC6201F80A000FD5B8
+:103F00008FBF001C9222000924030010304200FFE2
+:103F1000144300043C0280008C4401400A000FBCA2
+:103F2000000028219222000924030016304200FFDD
+:103F30001443000624020014A22200093C0280005F
+:103F40008C4401400A000FCF8FBF001C8E22003826
+:103F50008E23003C00431023044100308FBF001C1F
+:103F60009222002724420001A22200279222002749
+:103F70002C420004144000163C10800092220009DC
+:103F800024030004304200FF144300093C02800077
+:103F90008C4401408FBF001C8FB200188FB10014F9
+:103FA0008FB00010240500930A000E9A27BD002050
+:103FB0008C440140240500938FBF001C8FB2001871
+:103FC0008FB100148FB000100A000F1627BD00201B
+:103FD0008E0401400E000352000000008E420004D7
+:103FE0002442FFFFAE4200048E22003C2442FFFF29
+:103FF000AE22003C0E00035D8E0401408E040140A1
+:104000008FBF001C8FB200188FB100148FB000104A
+:10401000240500040A00036227BD00208FB20018A7
+:104020008FB100148FB0001003E0000827BD0020FE
+:104030003C0680008CC201883C0380083465008007
+:104040009063000E00021402304400FF306300FF52
+:104050001464000E3C02800890A20026304200FF4B
+:10406000104400098F82FF9CA0A400262403005066
+:1040700090420000304200FF1443000600000000A0
+:104080000A00059A8CC401803C02800834420080FA
+:10409000A044002603E000080000000027BDFFE068
+:1040A00030E700FFAFB20018AFBF001CAFB1001483
+:1040B000AFB000100080902114E0000630C600FF71
+:1040C000000000000000000D000000000A00102E9B
+:1040D0002400010E3C0380089062000E304200FF75
+:1040E000144600233462008090420026304200FFD4
+:1040F0001446001F000000009062000F304200FFD5
+:104100001446001B000000009062000A304200FFCD
+:10411000144600038F90FF9C0000000D8F90FF9CC1
+:104120008F82FFA03C118000AE05003CAC45000032
+:10413000A066000A0E0003528E240100A200002493
+:104140000E00035D8E2401003C0380008C6201F8A8
+:104150000440FFFE24020002AC7201C0A06201C450
+:104160003C021000AC6201F80A00102F8FBF001C47
+:10417000000000000000000D0000000024000137D6
+:104180008FBF001C8FB200188FB100148FB00010C9
+:1041900003E0000827BD00208F83FF9C3C028000C5
+:1041A0008C440100344201008C65003C9046001BA9
+:1041B0000A000FF5240700013C0280089043000E1E
+:1041C0009042000A00431026304200FF03E000083E
+:1041D0000002102B27BDFFE03C028008AFB10014A5
+:1041E000AFB00010AFBF001834500080920200053D
+:1041F00024030030304200301443008500808821C1
+:104200008F8200248C42000C104000828FBF001867
+:104210000E000D52000000008F860020ACD100007F
+:104220009202000892030009304200FF00021200CF
+:10423000306300FF00431025ACC200049202004D21
+:1042400000021600000216030441000500000000F1
+:104250003C0308008C6300480A00106D3C10800885
+:104260009202000830420040144000030000182170
+:1042700092020027304300FF3C1080083611008076
+:104280009222004D00031E00304200FF0002140085
+:1042900000621825ACC300088E2400308F820024F1
+:1042A000ACC4000C8E2500349443001E3C02C00BAD
+:1042B000ACC50010006218258E22003800002021B5
+:1042C000ACC200148E22003CACC200180E000D8659
+:1042D000ACC3001C8E0200048F8400203C058000CB
+:1042E000AC8200008E220020AC8200048E22001CD2
+:1042F000AC8200088E2200588CA300740043102169
+:10430000AC82000C8E22002CAC8200108E22004069
+:104310008E2300440002140000431025AC820014D8
+:104320009222004D24030080304200FF1443000419
+:1043300000000000AC8000180A0010B18F82002439
+:104340008E23000C240200011062000E2402FFFFE5
+:1043500092220008304200401440000A2402FFFF6D
+:104360008E23000C8CA20074006218233C0208000B
+:10437000006210241440000200002821006028215F
+:1043800000051043AC8200188F8200240000202119
+:104390009443001E3C02C00C006218258F8200204E
+:1043A0000E000D86AC43001C3C0380083462010003
+:1043B0008C4200008F850020346300808FBF00187E
+:1043C000ACA20000ACA000048C6400488F820024E2
+:1043D0008FB10014ACA40008ACA0000CACA000107D
+:1043E000906300059446001E3C02400D00031E0031
+:1043F00000C23025ACA300148FB00010ACA0001890
+:1044000024040001ACA6001C0A000D8627BD002074
+:104410008FBF00188FB100148FB0001003E00008A8
+:1044200027BD00203C0280009443007C3C028008B1
+:1044300034460100308400FF3065FFFF2402000590
+:1044400024A34650A0C4000C5482000C3065FFFF2A
+:1044500090C2000D2C4200071040000724A30A0060
+:1044600090C3000D240200140062100400A2102169
+:104470000A0010ED3045FFFF3065FFFF3C02800869
+:104480003442008003E00008A44500143C03800887
+:1044900034680080AD050038346701008CE2001CF0
+:1044A000308400FF00A210231840000330C600FF34
+:1044B00024A2FFFCACE2001C308200015040000846
+:1044C0003C0380088D02003C00A21023044100122E
+:1044D000240400058C62000410A2000F3C03800835
+:1044E0008C62000414A2001E000000003C020800C0
+:1044F0008C4200D830420020104000093C02800865
+:1045000034620080906300089042004C1443000421
+:104510003C028008240400040A0010D700000000B8
+:104520003443008034420100A040000C240200010A
+:10453000A462001410C0000A3C0280008C440100F8
+:104540003C0380008C6201F80440FFFE240200025C
+:10455000AC6401C0A06201C43C021000AC6201F86E
+:1045600003E000080000000027BDFFE800A61823B4
+:10457000AFBF001018600080308800FF3C02800848
+:1045800034470080A0E0002434440100A0E000276C
+:104590008C82001C00A21023044000560000000082
+:1045A0008CE2003C94E3005C8CE4002C004530235A
+:1045B0003063FFFF00C318210083202B108000040C
+:1045C00000E018218CE2002C0A00114600A2102104
+:1045D00094E2005C3042FFFF00C2102100A21021D3
+:1045E000AC62001C3C028008344400809482005C71
+:1045F0008C83001C3042FFFF0002104000A21021FB
+:104600000043102B10400004000000008C82001CAE
+:104610000A0011593C0680089482005C3042FFFF7A
+:104620000002104000A210213C06800834C30100A3
+:1046300034C70080AC82001CA060000CACE50038E0
+:104640008C62001C00A210231840000224A2FFFC70
+:10465000AC62001C31020001104000083C038008DD
+:104660008CE2003C00A21023044100122404000547
+:104670008CC2000410A200108FBF00108C620004D6
+:1046800014A2004F8FBF00103C0208008C4200D8DB
+:10469000304200201040000A3C0280083462008052
+:1046A000906300089042004C144300053C028008CF
+:1046B000240400048FBF00100A0010D727BD001883
+:1046C0003443008034420100A040000C2402000169
+:1046D000A46200143C0280008C4401003C03800072
+:1046E0008C6201F80440FFFE240200020A0011A6B9
+:1046F000000000008CE2001C004610230043102B39
+:1047000054400001ACE5001C94E2005C3042FFFF25
+:104710000062102B144000072402000294E2005CA7
+:104720008CE3001C3042FFFF00621821ACE3001C48
+:1047300024020002ACE500380E000F2CA082000C11
+:104740001040001F8FBF00103C0280008C4401000D
+:104750003C0380008C6201F80440FFFE240200024A
+:10476000AC6401C0A06201C43C021000AC6201F85C
+:104770000A0011BE8FBF001031020010104000105F
+:104780008FBF00103C028008344500808CA3001CC1
+:1047900094A2005C006618233042FFFF00621821DB
+:1047A0003C023FFF3444FFFF0083102B54400001C4
+:1047B0000080182100C31021ACA2001C8FBF001084
+:1047C00003E0000827BD001827BDFFE800C0402116
+:1047D00000A63023AFBF001018C00026308A00FFAB
+:1047E0003C028008344900808D24001C8D23002C5D
+:1047F000008820230064182B1060000F344701004C
+:104800008CE2002000461021ACE200208CE2002067
+:104810000044102B1440000B3C023FFF8CE20020B0
+:1048200000441023ACE200209522005C3042FFFFE0
+:104830000A0011DE00822021ACE000200086202149
+:104840003C023FFF3443FFFF0064102B5440000143
+:10485000006020213C02800834420080008518213D
+:10486000AC43001CA0400024A04000270A001230E6
+:104870003C03800831420010104000433C03800894
+:104880003C06800834C400808C82003C0048102321
+:104890005840003E3466008090820024244200018B
+:1048A000A0820024908200243C0308008C63002432
+:1048B000304200FF0043102B144000688FBF0010EF
+:1048C00034C201008C42001C00A210231840006377
+:1048D000000000008CC300049482005C0068182370
+:1048E0003042FFFF00031843000210400043102A2B
+:1048F00010400005000000008CC200040048102396
+:104900000A001213000210439482005C3042FFFF41
+:10491000000210403C068008AC82002C34C50080A8
+:1049200094A2005C8CA4002C94A3005C3042FFFF96
+:1049300000021040008220213063FFFF008320210D
+:1049400001041021ACA2001C8CC2000434C601007A
+:10495000ACC2001C240200020E000F2CA0C2000CEE
+:104960001040003E8FBF00103C0280008C440100CC
+:104970003C0380008C6201F80440FFFE2402000228
+:104980000A0012600000000034660080ACC50038E8
+:10499000346401008C82001C00A210231840000225
+:1049A00024A2FFFCAC82001C314200015040000AEE
+:1049B0003C0380088CC2003C00A210230443001476
+:1049C000240400058C62000414A200033C03800848
+:1049D0000A001252240400058C62000414A2001F75
+:1049E0008FBF00103C0208008C4200D830420020EB
+:1049F0001040000A3C028008346200809063000886
+:104A00009042004C144300053C028008240400043A
+:104A10008FBF00100A0010D727BD00183443008054
+:104A200034420100A040000C24020001A4620014E2
+:104A30003C0280008C4401003C0380008C6201F841
+:104A40000440FFFE24020002AC6401C0A06201C465
+:104A50003C021000AC6201F88FBF001003E00008B8
+:104A600027BD001827BDFFE83C0A8008AFBF001033
+:104A7000354900808D22003C00C04021308400FF79
+:104A8000004610231840009D30E700FF3547010025
+:104A90002402000100A63023A0E0000CA0E0000DDD
+:104AA000A522001418C00024308200108D23001CA1
+:104AB0008D22002C006818230043102B1040000F9B
+:104AC000000000008CE2002000461021ACE2002033
+:104AD0008CE200200043102B1440000B3C023FFFEF
+:104AE0008CE2002000431023ACE200209522005C01
+:104AF0003042FFFF0A00128F00621821ACE0002054
+:104B0000006618213C023FFF3446FFFF00C3102B14
+:104B10005440000100C018213C028008344200804B
+:104B200000651821AC43001CA0400024A0400027D1
+:104B30000A0012DD3C038008104000403C0380085E
+:104B40008D22003C004810235840003D346700800F
+:104B50009122002424420001A12200249122002459
+:104B60003C0308008C630024304200FF0043102BFC
+:104B70001440009A8FBF00108CE2001C00A210238A
+:104B800018400096000000008D4300049522005C50
+:104B9000006818233042FFFF000318430002104052
+:104BA0000043102A10400005012020218D420004FE
+:104BB000004810230A0012C0000210439522005C36
+:104BC0003042FFFF000210403C068008AC82002CFF
+:104BD00034C5008094A2005C8CA4002C94A3005CDB
+:104BE0003042FFFF00021040008220213063FFFFAF
+:104BF0000083182101031021ACA2001C8CC2000408
+:104C000034C60100ACC2001C240200020E000F2CAE
+:104C1000A0C2000C104000718FBF00103C02800049
+:104C20008C4401003C0380008C6201F80440FFFECC
+:104C3000240200020A00130700000000346700800D
+:104C4000ACE50038346601008CC2001C00A21023C1
+:104C50001840000224A2FFFCACC2001C30820001FC
+:104C6000504000083C0380088CE2003C00A2102366
+:104C700004430051240400058C62000410A2003E8D
+:104C80003C0380088C62000454A200548FBF0010C3
+:104C90003C0208008C4200D8304200201040000640
+:104CA0003C02800834620080906300089042004C0F
+:104CB000104300403C02800834430080344201002D
+:104CC000A040000C24020001A46200143C028000F9
+:104CD0008C4401003C0380008C6201F80440FFFE1C
+:104CE00024020002AC6401C0A06201C43C021000B6
+:104CF000AC6201F80A0013458FBF001024020005C2
+:104D0000A120002714E2000A3C038008354301007B
+:104D10009062000D2C420006504000053C038008C4
+:104D20009062000D24420001A062000D3C03800847
+:104D300034670080ACE50038346601008CC2001C8A
+:104D400000A210231840000224A2FFFCACC2001CE9
+:104D5000308200015040000A3C0380088CE2003C95
+:104D600000A2102304410014240400058C620004F6
+:104D700014A200033C0380080A00133C240400052D
+:104D80008C62000414A200158FBF00103C020800C2
+:104D90008C4200D8304200201040000A3C028008BB
+:104DA00034620080906300089042004C1443000578
+:104DB0003C028008240400048FBF00100A0010D7B2
+:104DC00027BD00183443008034420100A040000C8D
+:104DD00024020001A46200148FBF001003E0000849
+:104DE00027BD00183C0B800827BDFFE83C0280006F
+:104DF000AFBF001034420100356A00809044000AC1
+:104E0000356901008C4500148D4800389123000C51
+:104E1000308400FF010510231C4000B3306700FF01
+:104E20002CE20006504000B18FBF001024020001A8
+:104E300000E2300430C200035440000800A83023D0
+:104E400030C2000C144000A130C20030144000A356
+:104E50008FBF00100A0014090000000018C00024D1
+:104E6000308200108D43001C8D42002C00681823F6
+:104E70000043102B1040000F000000008D22002086
+:104E800000461021AD2200208D2200200043102B6F
+:104E90001440000B3C023FFF8D22002000431023F2
+:104EA000AD2200209542005C3042FFFF0A00137DD6
+:104EB00000621821AD200020006618213C023FFF4F
+:104EC0003446FFFF00C3102B5440000100C01821DE
+:104ED0003C0280083442008000651821AC43001C6D
+:104EE000A0400024A04000270A0013CB3C03800808
+:104EF000104000403C0380088D42003C00481023D5
+:104F00001840003D34670080914200242442000193
+:104F1000A1420024914200243C0308008C63002439
+:104F2000304200FF0043102B144000708FBF001070
+:104F30008D22001C00A210231840006C000000000D
+:104F40008D6300049542005C006818233042FFFF27
+:104F500000031843000210400043102A10400005CF
+:104F6000014020218D620004004810230A0013AE86
+:104F7000000210439542005C3042FFFF00021040E7
+:104F80003C068008AC82002C34C5008094A2005CF2
+:104F90008CA4002C94A3005C3042FFFF0002104060
+:104FA000008220213063FFFF0083182101031021BC
+:104FB000ACA2001C8CC2000434C60100ACC2001CB0
+:104FC000240200020E000F2CA0C2000C104000476B
+:104FD0008FBF00103C0280008C4401003C03800025
+:104FE0008C6201F80440FFFE240200020A0013FB59
+:104FF0000000000034670080ACE500383466010032
+:105000008CC2001C00A210231840000224A2FFFC46
+:10501000ACC2001C308200015040000A3C038008F2
+:105020008CE2003C00A21023044300142404000579
+:105030008C62000414A200033C0380080A0013EDF4
+:10504000240400058C62000414A200288FBF001005
+:105050003C0208008C4200D8304200201040000A78
+:105060003C02800834620080906300089042004C4B
+:10507000144300053C028008240400048FBF001084
+:105080000A0010D727BD00183443008034420100C5
+:10509000A040000C24020001A46200143C02800025
+:1050A0008C4401003C0380008C6201F80440FFFE48
+:1050B00024020002AC6401C0A06201C43C021000E2
+:1050C000AC6201F80A0014098FBF00108FBF0010F6
+:1050D000010030210A00112827BD001801003021ED
+:1050E0000A00126727BD00188FBF001003E00008F8
+:1050F00027BD00183C03800834640100240200032B
+:10510000A082000C8C62000403E00008AC82001C4A
+:105110003C05800834A300809062002734A501007C
+:105120002406004324420001A06200279063002768
+:105130003C0208008C420048306300FF1462000407
+:105140003C07602194A500DA0A0008FA30A5FFFFA9
+:1051500003E000080000000027BDFFE8AFBF00101B
+:105160003C0280000E0014128C4401803C02800836
+:1051700034430100A060000C8C4200048FBF00107B
+:1051800027BD001803E00008AC62001C27BDFFE04B
+:105190003C028008AFBF0018AFB10014AFB00010E0
+:1051A00034450080344601003C0880008D090140F0
+:1051B00090C3000C8CA4003C8CA200381482003BED
+:1051C000306700FF9502007C90A30027146000095F
+:1051D0003045FFFF2402000554E200083C0480082B
+:1051E00090C2000D24420001A0C2000D0A00144D1F
+:1051F0003C048008A0C0000D3C04800834820100FB
+:105200009042000C24030005304200FF1443000AC2
+:1052100024A205DC34830080906200272C42000722
+:105220005040000524A20A009063002724020014C5
+:105230000062100400A210213C108008361000808B
+:105240003045FFFF012020210E001412A605001496
+:105250009602005C8E0300383C1180003042FFFF54
+:105260000002104000621821AE03001C0E00035221
+:105270008E2401409202002534420040A202002503
+:105280000E00035D8E2401408E2401403C0380000B
+:105290008C6201F80440FFFE24020002AC6401C0ED
+:1052A000A06201C43C021000AC6201F88FBF00187C
+:1052B0008FB100148FB0001003E0000827BD00205C
+:1052C00080080100800800808008000000000C8039
+:1052D000000032008008024008000F1008000F682C
+:1052E00008000FAC0800104408001084800801007A
+:0852F000800800808008000026
+:0852F8000A0000220000000082
+:10530000000000000000000D6370352E302E306A62
+:10531000313500000500000400000000000000001E
+:1053200000000000000000000000000038003C0009
+:10533000000000000000000000000000000000006D
+:10534000000000200000000000000000000000003D
+:10535000000000000000000000000000000000004D
+:1053600000000000000000000000000021003800E4
+:10537000000000010000002B000000000000000001
+:105380000000000010000003000000000000000DFD
+:105390000000000D3C020800244255043C030800B4
+:1053A00024635744AC4000000043202B1480FFFDD1
+:1053B000244200043C1D080037BD9FFC03A0F021DF
+:1053C0003C100800261000883C1C0800279C55044F
+:1053D0000E00029A000000000000000D00A018213D
+:1053E00000801021008028213C0460003C07600000
+:1053F0002406000810600006348420788C420000E7
+:10540000ACE220088C63000003E00008ACE3200C51
+:105410000A000E6000000000240300403C0260000F
+:1054200003E00008AC4320003C0760008F860004C6
+:105430008CE520740086102100A2182B1460000750
+:10544000000028218F8AFD9024050001A14400134B
+:105450008F89000401244021AF88000403E0000884
+:1054600000A010218F84FD908F850004908600138A
+:1054700030C300FF00A31023AF82000403E0000844
+:10548000A08000138F84FD9027BDFFE8AFB000100F
+:10549000AFBF0014908900119087001124020028EA
+:1054A000312800FF3906002830E300FF2485002C56
+:1054B0002CD00001106200162484001C0E0000395C
+:1054C000000000008F8FFD903C0560002402020464
+:1054D00095EE003E95ED003C000E5C0031ACFFFF08
+:1054E000016C5025ACAA20105200000124020004D7
+:1054F000ACA220000000000000000000000000003E
+:105500008FBF00148FB0001003E0000827BD001803
+:105510000A000071000028218F85FD9027BDFFD86B
+:10552000AFBF0020AFB3001CAFB20018AFB1001482
+:10553000AFB000100080982190A4001124B0001C8E
+:1055400024B1002C308300FF386200280E00005B7D
+:105550002C5200010E000063000000000200202118
+:105560001240000202202821000028210E000039EC
+:10557000000000008F8DFD903C0880003C0560001D
+:1055800095AC003E95AB003C02683025000C4C0009
+:10559000316AFFFF012A3825ACA72010240202023D
+:1055A000ACA6201452400001240200028FBF00204C
+:1055B0008FB3001C8FB200188FB100148FB0001091
+:1055C00027BD002803E00008ACA2200027BDFFE0B3
+:1055D000AFB20018AFB10014AFB00010AFBF001CE5
+:1055E0003C1160008E2320748F82000430D0FFFFB6
+:1055F00030F2FFFF1062000C2406008F0E0000390D
+:10560000000000003C06801F0010440034C5FF006D
+:105610000112382524040002AE272010000030219A
+:10562000AE252014AE2420008FBF001C8FB20018BE
+:105630008FB100148FB0001000C0102103E00008EB
+:1056400027BD002027BDFFE0AFB0001030D0FFFF26
+:10565000AFBF0018AFB100140E00003930F1FFFFEA
+:1056600000102400009180253C036000AC702010E5
+:105670008FBF00188FB100148FB0001024020004F7
+:10568000AC62200027BD002003E0000800001021CC
+:1056900027BDFFE83C0B6018AFBF00108D6F5000B6
+:1056A0002418FF7F340C807101F8702435CD380C3C
+:1056B000240A00313C098000AD6D50003C08800A8E
+:1056C000AD6C53BCAD2A00080E0004D1AF88004079
+:1056D0000E00048F000000000E00004800000000D3
+:1056E0003C0760008CE508082406FFF03C035709DE
+:1056F00000A620243462F000108200622419000108
+:10570000AF80004C0E000BF2000000003C0660165B
+:105710003C0760148CC400008CE500A03C03FFFF34
+:10572000008310243C1F535300052FC2105F004F0D
+:1057300034C77C0094E201F2A780006410400003AB
+:10574000A7800074384B1E1EA78B006494E201F8FA
+:10575000104000048F8D004C384C1E1EA78C007426
+:105760008F8D004C11A0000497840074240E00203B
+:10577000A78E0064978400742C8F008151E0000193
+:1057800024040080978600642CD804015300000193
+:10579000240604003C0260008C4504382419103CA7
+:1057A00030BFFFFF13F900033083FFFF10600018C4
+:1057B00024080050A38000769389007651200019B8
+:1057C000A7840074A7800074978C00748FBF0010AA
+:1057D0003C0A600E24EB0388354600100000382197
+:1057E0000000202127BD0018A78000643C010800AC
+:1057F000AC2C0080AF8B0010AF860048A780006CF7
+:10580000A780008AAF87001803E00008AF84001467
+:10581000A3880076938900765520FFEBA78000745B
+:10582000A7840074978C00748FBF00103C0A600E30
+:1058300024EB0388A7860064000038213546001059
+:105840000000202127BD00183C010800AC2C00807E
+:10585000AF8B0010AF860048A780006CA780008A3D
+:10586000AF87001803E00008AF84001400055080E3
+:10587000014648218D2800043C0660000A00010F03
+:10588000010638210A000103AF99004C3083FFFF65
+:105890008F8800408F87003C000321403C0580003A
+:1058A0003C020050008248253C0660003C0A010092
+:1058B00034AC04008CCD08E001AA58241160000526
+:1058C000000000008CCF08E024E7000101EA702509
+:1058D000ACCE08E08D19001001805821ACB9003819
+:1058E0008D180014ACB8003CACA9003000000000DA
+:1058F00000000000000000000000000000000000A8
+:105900000000000000000000000000003C038000D8
+:105910008C640000308200201040FFFD3C0F6000CE
+:105920008DED08E03C0E010001AE18241460FFE18B
+:1059300000000000AF87003C03E00008AF8B005080
+:105940008F850040240BFFF03C06800094A7001ACE
+:105950008CA9002430ECFFFF000C38C000EB502471
+:10596000012A4021ACC8003C8CA400248CC3003C1C
+:105970000083102318400033000000008CAD00208D
+:1059800025A200013C0F0050ACC2003835EE0010DB
+:105990003C068000ACCE003000000000000000009B
+:1059A00000000000000000000000000000000000F7
+:1059B00000000000000000003C0480008C99000002
+:1059C000333800201300FFFD30E2000810400017BC
+:1059D0003C0980008C880408ACA800108C83040C5F
+:1059E000ACA300143C1900203C188000AF19003013
+:1059F00094AE001894AF001C01CF3021A4A600186B
+:105A000094AD001A25A70001A4A7001A94AB001AB0
+:105A100094AC001E118B00030000000003E000089E
+:105A20000000000003E00008A4A0001A8D2A040072
+:105A3000ACAA00108D240404ACA400140A0001BC1C
+:105A40003C1900208CA200200A0001A43C0F005049
+:105A50000A0001920000000027BDFFE8AFBF001060
+:105A60000E0001D6000000008F8900408FBF00109B
+:105A70003C038000A520000A9528000A9527000411
+:105A800027BD00183105FFFF30E6000F00061500A6
+:105A900000A2202503E00008AC6400803C0508005B
+:105AA0008CA500208F83000C27BDFFE8AFB000104D
+:105AB000AFBF001410A300100000802124040001D7
+:105AC0000204300400A6202400C310245044000621
+:105AD00026100001001018802787FD941480000A0A
+:105AE00000671821261000012E0900025520FFF33F
+:105AF0008F83000CAF85000C8FBF00148FB0001097
+:105B000003E0000827BD00188C6800003C058000F9
+:105B1000ACA800240E0001D8261000013C050800A6
+:105B20008CA500200A0001FD2E09000224050001B9
+:105B3000008518043C0408008C84002027BDFFC8A1
+:105B4000AFBF003400831024AFBE0030AFB7002CCD
+:105B5000AFB60028AFB50024AFB40020AFB3001C2F
+:105B6000AFB20018AFB1001410400051AFB0001038
+:105B70008F840040948700069488000A00E8302350
+:105B800030D5FFFF12A0004B8FBF0034948B00185C
+:105B9000948C000A016C50233142FFFF02A2482B73
+:105BA0001520000202A02021004020212C8F00059A
+:105BB00015E0000200809821241300040E00016506
+:105BC000026020218F87004002609021AF80004456
+:105BD00094F4000A026080211260004E3291FFFFAF
+:105BE0003C1670003C1440003C1E20003C17600036
+:105BF0008F9900508F380000031618241074004F3E
+:105C00000283F82B17E0003600000000107E0047EA
+:105C10008F86004414C0003A2403000102031023BD
+:105C2000022320213050FFFF1600FFF13091FFFFCB
+:105C30008F8700403C1100203C108000AE110030E6
+:105C400094EB000A3C178000024B5021A4EA000AA2
+:105C500094E9000A94E800043123FFFF3106000FA5
+:105C600000062D000065F025AEFE008094F3000ACA
+:105C700094F6001812D30036001221408CFF001455
+:105C80008CF4001003E468210000C02101A4782BEB
+:105C90000298702101CF6021ACED0014ACEC001033
+:105CA00002B2382330F5FFFF16A0FFB88F84004002
+:105CB0008FBF00348FBE00308FB7002C8FB6002806
+:105CC0008FB500248FB400208FB3001C8FB2001852
+:105CD0008FB100148FB0001003E0000827BD00381A
+:105CE0001477FFCC8F8600440E000DC102002021E6
+:105CF000004018218F86004410C0FFC90203102302
+:105D0000027070238F87004001C368210A00028857
+:105D100031B2FFFF8F86004414C0FFC93C11002040
+:105D20003C1080000A000252AE1100300E0003FA4F
+:105D3000020020210A00027F0040182102002021D9
+:105D40000E000811022028210A00027F00401821BD
+:105D50000E000192000000000A00026B02B238231C
+:105D600027BDFFC8AFB7002CAFB60028AFB50024E1
+:105D7000AFB40020AFB3001CAFB20018AFB1001435
+:105D8000AFB00010AFBF00300E0000E624130001DA
+:105D90003C047FFF3C0380083C0220003C010800DB
+:105DA000AC2000703497FFFF34750080345200033C
+:105DB0003C1612C0241400013C1080002411FF8006
+:105DC0000E0001E9000000008F8700488F8B00184B
+:105DD0008F8900148CEA00EC8CE800E8014B302B32
+:105DE0000109282300A6102314400006014B1823A4
+:105DF0001440000E3C05800002C3602B1180000B94
+:105E0000000000003C0560008CEE00EC8CED00E82A
+:105E10008CA4180CAF8E001804800045AF8D0014C0
+:105E20008F8F0010ADF400003C0580008CBF000097
+:105E30003BF90001333800011700FFE13C0380000B
+:105E40008C62010024060C001046000900000000CE
+:105E50008C6801002D043080548000103C048000C8
+:105E60008C6901002D2331811060000C3C048000FE
+:105E70008CAA010011460004000020218CA601001C
+:105E800024C5FF8130A400FF8E0B01000E00020D1F
+:105E9000AE0B00240A0002F33C0480008C8E01004B
+:105EA000240C0020AC8E002092AD000031A300FF36
+:105EB000106C00232407005010670026000000002B
+:105EC0003C0480008C8F010015E0000300000000FE
+:105ED000566000143C0440008C8701008C8D01004A
+:105EE0000000982100F17024000E594031AC007F71
+:105EF000016C302500D22825AC8508308C8A010041
+:105F00008C83010025490100013110240002F94071
+:105F10003068007F03E8C8250332C025AC980830FC
+:105F20003C044000AE0401380A0002B20000000048
+:105F300000973824ACA7180C0A0002CB8F8F0010F2
+:105F40008C8501000E0007C3240400800A0002F3C0
+:105F50003C0480008C8401000E001420000000002E
+:105F60000A0002F33C04800000A4102B240300016B
+:105F700010400009000030210005284000A4102B2B
+:105F800004A00003000318405440FFFC0005284013
+:105F90005060000A0004182B0085382B54E00004E0
+:105FA0000003184200C33025008520230003184257
+:105FB0001460FFF9000528420004182B03E00008D4
+:105FC00000C310213084FFFF30C600FF3C07800073
+:105FD0008CE201B80440FFFE00064C00012430258D
+:105FE0003C08200000C820253C031000ACE00180E4
+:105FF000ACE50184ACE4018803E00008ACE301B83F
+:106000003C0660008CC5201C2402FFF03083020097
+:10601000308601001060000E00A2282434A5000183
+:106020003087300010E0000530830C0034A50004F8
+:106030003C04600003E00008AC85201C1060FFFDFC
+:106040003C04600034A5000803E00008AC85201C77
+:1060500054C0FFF334A500020A00034B3087300020
+:1060600027BDFFE8AFB00010AFBF00143C076000D1
+:10607000240600021080001100A080218F830050B0
+:106080000E0003428C6400188F8200500000202113
+:10609000240600018C45000C0E00033300000000B4
+:1060A0001600000224020003000010218FBF00141C
+:1060B0008FB0001003E0000827BD00188CE8201CFA
+:1060C0002409FFF001092824ACE5201C8F8700502B
+:1060D0000A0003688CE5000C3C02600E0080402141
+:1060E00034460100240900180000000000000000F0
+:1060F000000000003C0A00503C03800035470200CD
+:10610000AC68003834640400AC65003CAC67003017
+:106110008C6C0000318B00201160FFFD2407FFFF15
+:106120002403007F8C8D00002463FFFF248400047F
+:10613000ACCD00001467FFFB24C600040000000083
+:10614000000000000000000024A402000085282BAD
+:106150003C0300203C0E80002529FFFF0105402163
+:10616000ADC300301520FFE00080282103E00008C7
+:10617000000000008F82005027BDFFD8AFB3001C85
+:10618000AFBF0020AFB20018AFB10014AFB0001025
+:1061900094460002008098218C5200182CC3008184
+:1061A0008C4800048C4700088C51000C8C4900106E
+:1061B000106000078C4A00142CC4000414800013E3
+:1061C00030EB000730C5000310A0001000000000F5
+:1061D0002410008B02002021022028210E0003330E
+:1061E00024060003166000022402000300001021B0
+:1061F0008FBF00208FB3001C8FB200188FB1001426
+:106200008FB0001003E0000827BD00281560FFF1E3
+:106210002410008B3C0C80003C030020241F000154
+:10622000AD830030AF9F004400000000000000007C
+:10623000000000002419FFF024D8000F031978246F
+:106240003C1000D0AD88003801F0702524CD00034B
+:106250003C08600EAD87003C35850400AD8E0030F3
+:10626000000D38823504003C3C0380008C6B00003C
+:10627000316200201040FFFD0000000010E0000827
+:1062800024E3FFFF2407FFFF8CA800002463FFFF27
+:1062900024A50004AC8800001467FFFB24840004DC
+:1062A0003C04600EAC8600380000000000000000D6
+:1062B000000000003C0700203C0680000120202157
+:1062C00001402821ACC700300E0003780000802177
+:1062D0000E000342024020210A0003B802002021E0
+:1062E00027BDFFE0AFB200183092FFFFAFB100143E
+:1062F000AFBF001CAFB000101640000D0000882199
+:106300000A000427022010212405000350850027DD
+:106310008CE5000C0000000D262C00013191FFFFE0
+:1063200024EB00200232502B11400019AF8B00509B
+:106330008F820044144000168F8700503C06700086
+:106340003C0320008CE5000000A6202414830010EC
+:106350008F840058000544023C09800000A9802475
+:106360001480FFE9310600FF2CCA000B1140FFEB3F
+:10637000262C0001000668803C0E080025CE52A0A5
+:1063800001AE60218D8B000001600008000000005C
+:10639000022010218FBF001C8FB200188FB1001493
+:1063A0008FB0001003E0000827BD00200E0003336B
+:1063B000240400841600FFD88F8700500A000408C8
+:1063C000AF800058020028210E00035A2404000167
+:1063D0008F8700500A000408AF820058020028216D
+:1063E0000E00035A000020210A0004378F87005056
+:1063F0000E00039F020020218F8700500A0004082E
+:10640000AF82005830AFFFFF000F19C03C0480007E
+:106410008C9001B80600FFFE3C1920043C181000C7
+:10642000AC830180AC800184AC990188AC9801B840
+:106430000A000409262C000190E2000290FF0003EC
+:106440000000202100023A0000FF28252406000851
+:106450000E000333000000001600FFDD24020003DD
+:106460008F870050000010210A000408AF820058F6
+:1064700090E50002000020210A00045624060009CD
+:1064800094E5000490E9000390E300020005340065
+:106490000009420000C82025008328252406000AA0
+:1064A0000A0004560000202190E50002000020218F
+:1064B0000A0004562406000B000449C23127003F9D
+:1064C000000443423C028000000820402403168060
+:1064D0002CE60020AC43002C24EAFFE024820001DB
+:1064E00014C0000330A900FF00801021314700FFD5
+:1064F000000260803C0D8000240A0001018D2021F3
+:106500003C0B000E00EA2804008B3021112000050E
+:10651000000538278CCE000001C5382503E00008AF
+:10652000ACC700008CD800000307782403E0000803
+:10653000ACCF000027BDFFE0AFB10014AFB000103A
+:10654000AFBF00183C0760008CE408083402F0007C
+:106550003C1160003083F000240501C03C04800E33
+:106560000000302110620006241000018CEA0808A7
+:106570003149F0003928E0000008382B000780403E
+:106580003C0D0200AE2D0814240C16803C0B80003C
+:106590008E2744000E000E6AAD6C002C1200000421
+:1065A0003C02169124050001120500103C023D6CCE
+:1065B000345800E0AE3844083C1108008E31007CAD
+:1065C0008FBF00183C06600000118540360F168012
+:1065D0008FB100148FB000103C0E020027BD0020C8
+:1065E000ACCF442003E00008ACCE08103C0218DA1F
+:1065F000345800E0AE3844083C1108008E31007C6D
+:106600008FBF00183C06600000118540360F1680D1
+:106610008FB100148FB000103C0E020027BD002087
+:10662000ACCF442003E00008ACCE08100A00047090
+:10663000240500010A00047000002821240204003F
+:10664000A7820024A780001C000020213C0608002F
+:1066500024C655A82405FFFF2489000100044080BA
+:106660003124FFFF010618212C87002014E0FFFAD7
+:10667000AC65000024040400A7840026A780001E47
+:10668000000020213C06080024C656282405FFFFF0
+:10669000248D00010004608031A4FFFF0186582191
+:1066A0002C8A00201540FFFAAD650000A780002865
+:1066B000A7800020A7800022000020213C060800BF
+:1066C00024C656A82405FFFF249900010004C080B9
+:1066D0003324FFFF030678212C8E000415C0FFFA37
+:1066E000ADE500003C0560008CA73D002403E08F71
+:1066F00000E310243446014003E00008ACA63D004E
+:106700002487007F000731C224C5FFFF000518C29F
+:10671000246400013082FFFF000238C0A7840030EB
+:106720003C010800AC270030AF80002C000028217D
+:1067300000002021000030212489000100A7282129
+:106740003124FFFF2CA81701110000032C830080C7
+:106750001460FFF924C6000100C02821AF86002C78
+:1067600010C0001DA786002A24CAFFFF000A11429C
+:106770003C080800250856A81040000A0000202107
+:10678000004030212407FFFF248E000100046880B0
+:1067900031C4FFFF01A860210086582B1560FFFA65
+:1067A000AD87000030A2001F504000080004308078
+:1067B000240300010043C80400041080004878212D
+:1067C0002738FFFF03E00008ADF8000000C82021D3
+:1067D0002405FFFFAC85000003E000080000000076
+:1067E00030A5FFFF30C6FFFF30A8001F00806021EA
+:1067F00030E700FF000529420000502110C0001DB5
+:1068000024090001240B000125180001010B2004BC
+:10681000330800FF01267826390E00202DED0001F7
+:106820002DC2000101A218251060000D0144502561
+:106830000005C880032C40210100182110E0000F42
+:10684000000A20278D040000008A1825AD030000EF
+:1068500024AD0001000040210000502131A5FFFFC0
+:10686000252E000131C9FFFF00C9102B1040FFE7A2
+:106870002518000103E00008000000008D0A000058
+:10688000014440240A000556AC68000027BDFFE81B
+:1068900030A5FFFF30C6FFFFAFB00010AFBF001440
+:1068A00030E7FFFF000050213410FFFF000060219F
+:1068B00024AF001F00C04821241800012419002023
+:1068C00005E0001601E010210002F943019F682A4B
+:1068D0000009702B01AE402411000017000C188035
+:1068E0000064102110E000058C4B000000F840040B
+:1068F0000008382301675824000038211540004162
+:1069000000004021556000163169FFFF258B000112
+:10691000316CFFFF05E1FFEC01E0102124A2003EF5
+:106920000002F943019F682A0009702B01AE402440
+:106930001500FFEB000C1880154600053402FFFF20
+:10694000020028210E00053A000038210200102123
+:106950008FBF00148FB0001003E0000827BD00189F
+:106960001520000301601821000B1C0224080010F0
+:10697000306A00FF15400005306E000F250D00083D
+:1069800000031A0231A800FF306E000F15C0000589
+:10699000307F00032510000400031902320800FFB5
+:1069A000307F000317E0000538690001250200026E
+:1069B00000031882304800FF3869000131230001CC
+:1069C00010600004310300FF250A0001314800FF78
+:1069D000310300FF000C694001A34021240A00019B
+:1069E00010CAFFD53110FFFF246E000131C800FF2F
+:1069F0001119FFC638C900012D1F002053E0001CEB
+:106A0000258B0001240D00010A0005CD240E002075
+:106A100051460017258B000125090001312800FF90
+:106A20002D09002051200012258B00012543000173
+:106A3000010D5004014B1024250900011440FFF4FE
+:106A4000306AFFFF3127FFFF10EE000C2582FFFFA9
+:106A5000304CFFFF000050213410FFFF312800FFB1
+:106A60002D0900205520FFF225430001258B000150
+:106A7000014648260A000587316CFFFF00003821D7
+:106A8000000050210A0005D93410FFFF27BDFFD8B0
+:106A9000AFB0001030F0FFFFAFB10014001039426A
+:106AA0003211FFE000071080AFB3001C00B12823B3
+:106AB00030D3FFFFAFB2001830A5FFFF0080902158
+:106AC0000260302100442021AFBF00200E00056588
+:106AD0003207001F022288213403FFFF02402021D9
+:106AE00002002821026030210000382110430009F3
+:106AF0003231FFFF022010218FBF00208FB3001C16
+:106B00008FB200188FB100148FB0001003E000089E
+:106B100027BD00280E000565000000000040882108
+:106B2000022010218FBF00208FB3001C8FB20018ED
+:106B30008FB100148FB0001003E0000827BD0028BB
+:106B4000000424003C036000AC603D0810A000027B
+:106B5000348210063482101603E00008AC623D0453
+:106B600027BDFFE0AFB00010309000FF2E020006FE
+:106B7000AFBF001810400008AFB100140010308003
+:106B80003C030800246352CC00C328218CA40000DD
+:106B90000080000800000000000020218FBF0018C6
+:106BA0008FB100148FB000100080102103E00008A6
+:106BB00027BD00209791002A1620005100002021B7
+:106BC0003C020800904200330A000640000000002A
+:106BD000978D002615A00031000020210A000640F4
+:106BE000240200089787002414E0001A00001821EE
+:106BF00000602021240200011080FFE98FBF0018EF
+:106C0000000429C20045302100A6582B1160FFE482
+:106C10003C0880003C072000000569C001A76025F2
+:106C2000AD0C00203C0380082402001F2442FFFF1B
+:106C3000AC6000000441FFFD2463000424A50001B2
+:106C400000A6702B15C0FFF5000569C00A00062AD2
+:106C50008FBF00189787001C3C040800248455A8A7
+:106C6000240504000E0005E524060001978B00248E
+:106C700024440001308AFFFF2569FFFF2D480400EE
+:106C80000040282115000040A789002424AC3800CA
+:106C9000000C19C00A00063EA780001C9787001E42
+:106CA0003C04080024845628240504000E0005E551
+:106CB0002406000197990026244400013098FFFF24
+:106CC000272FFFFF2F0E04000040882115C0002C45
+:106CD000A78F0026A780001E3A0200032624010089
+:106CE0003084FFFF0E0006122C4500010011F8C091
+:106CF00027F00100001021C00A000640240200080D
+:106D00009785002E978700223C040800248456A80B
+:106D10000E0005E5240600019787002A8F89002CC4
+:106D20002445000130A8FFFF24E3FFFF0109302BB9
+:106D30000040802114C00018A783002AA7800022E9
+:106D4000978500300E000E5402002021244A0500D1
+:106D50003144FFFF0E000612240500013C05080027
+:106D600094A500320E000E5402002021244521007B
+:106D70003C020800904200330A000640000521C092
+:106D80000A000678A784001E24AC3800000C19C045
+:106D90000A00063EA784001C0A000692A78500226E
+:106DA000308400FF27BDFFE82C820006AFBF00142F
+:106DB000AFB000101040001500A038210004408042
+:106DC0003C030800246352E4010328218CA4000042
+:106DD000008000080000000024CC007F000751C2A2
+:106DE000000C59C23170FFFF2547C40030E5FFFF9A
+:106DF0002784001C020030210E00053A2407000100
+:106E00009786002802062021A78400288FBF00143F
+:106E10008FB0001003E0000827BD00183C050800F3
+:106E20008CA50030000779C20E00031C25E4DF00AA
+:106E30003045FFFF3C040800248456A824060001C6
+:106E40000E00053A24070001978E002A8FBF001418
+:106E50008FB0001025CD000127BD001803E0000809
+:106E6000A78D002A0007C9C22738FF00001878C282
+:106E700031F0FFFF3C04080024845628020028213A
+:106E8000240600010E00053A24070001978D002614
+:106E9000260E0100000E840025AC00013C0B6000B2
+:106EA000A78C0026AD603D083604000600003021A6
+:106EB0003C0760008CE23D04305F000617E0FFFDF8
+:106EC00024C9000100061B00312600FF0064402594
+:106ED0002CC50004ACE83D0414A0FFF68FBF0014DD
+:106EE0008FB0001003E0000827BD0018000751C252
+:106EF0002549C80024060001240700013C040800BD
+:106F0000248455A80E00053A3125FFFF97870024F9
+:106F10008FBF00148FB0001024E6000127BD0018B9
+:106F200003E00008A78600243084FFFF30A5FFFFA0
+:106F30003C0680008CC201B80440FFFE3C08408043
+:106F4000008838253C031000ACC00180ACC501842A
+:106F5000ACC7018803E00008ACC301B83084FFFF70
+:106F60003C0680008CC201B80440FFFE3C0840385B
+:106F70008CA70000008828253C031000ACC70180C6
+:106F8000ACC5018803E00008ACC301B88F83007072
+:106F90008F8600681066000B008040213C070800C7
+:106FA00024E756B8000328C000A710218C44000035
+:106FB00024630001108800053063000F5466FFFA57
+:106FC000000328C003E00008000010213C0708006F
+:106FD00024E756BC00A7302103E000088CC2000063
+:106FE0003C03900034620001008220253C038000B5
+:106FF000AC6400208C65002004A0FFFE00000000AF
+:1070000003E00008000000003C028000344300015F
+:107010000083202503E00008AC44002027BDFFE0EA
+:10702000AFB100143091FFFFAFB00010AFBF001838
+:107030001220001200A080218CA5000014A00011D5
+:10704000240400023C0680008CC201B80440FFFE0C
+:107050003C074000022720258FBF00188FB1001485
+:107060008FB000103C03100027BD0020ACC501808C
+:10707000ACC4018803E00008ACC301B80A000753A0
+:107080008CA500000E0006AA24060200000028219C
+:107090000A000753AE0000003087FFFF3C06800067
+:1070A0008CC201B80440FFFE3C0A40068CA90000D7
+:1070B00000EA4025ACC901808CA400043C03100008
+:1070C000ACC40184ACC8018803E00008ACC301B8BB
+:1070D0008F83FD8C27BDFFE8AFBF0014AFB0001059
+:1070E00090670008008010210080282130E60040D1
+:1070F0000000202110C000088C5000000E00008805
+:1071000002002021020020218FBF00148FB0001048
+:107110000A0004CD27BD00180E000768000000001B
+:107120000E00008802002021020020218FBF0014E1
+:107130008FB000100A0004CD27BD001827BDFFE066
+:10714000AFB000108F90FD8CAFBF001CAFB2001825
+:10715000AFB1001492060001008088210E00073AAA
+:1071600030D2000492040005001129C2A6050000D7
+:1071700034830040A20300050E00074402202021B2
+:107180000E0004CF0220202124020001AE02000CD8
+:1071900002202821A602001024040002A6020012E8
+:1071A00024060200A60200140E0006AAA60200167B
+:1071B0001640000F8FBF001C978C006C3C0B080022
+:1071C0008D6B00782588FFFF3109FFFF256A0001DC
+:1071D000012A382B10E00006A788006C3C0F6006DF
+:1071E000240E001635ED0010ADAE00508FBF001C10
+:1071F0008FB200188FB100148FB0001003E00008A8
+:1072000027BD002027BDFFE0AFB10014AFBF0018BD
+:10721000AFB000101080000400A08821240200807C
+:1072200010820007000000000000000D8FBF001852
+:107230008FB100148FB0001003E0000827BD0020BC
+:107240000E00073A00A020218F86FD8C022020210D
+:1072500090C500050E00074430B000FF2403003E37
+:107260001603FFF1000000003C0580008CA40178AB
+:107270000480FFFE240800073C071000ACB1014069
+:1072800002202021A0A801448FBF00188FB1001454
+:107290008FB00010ACA701780A00079127BD00202D
+:1072A00027BDFFE0AFB00010AFBF0018AFB10014B2
+:1072B0003C1080008E110020000000000E0004CF62
+:1072C000AE040020AE1100208FBF00188FB1001453
+:1072D0008FB0001003E0000827BD00203084FFFFBE
+:1072E0003C0680008CC201B80440FFFE3C084035DB
+:1072F000008838253C031000ACC50180ACC0018477
+:10730000ACC7018803E00008ACC301B83084FFFFBC
+:107310003C0680008CC201B80440FFFE3C084036A9
+:10732000008838253C031000ACC50180ACC0018446
+:10733000ACC7018803E00008ACC301B827BDFFD08B
+:10734000AFB500243095FFFFAFB60028AFB40020E2
+:10735000AFBF002CAFB3001CAFB20018AFB1001428
+:10736000AFB0001030B6FFFF12A000270000A02130
+:107370008F9200508E4300003C06800024020040A3
+:1073800000033E0200032C0230E4007F00669824D4
+:107390001482001D30A500FF8F8300602C68000A56
+:1073A000510000108F860044000358803C0C0800F8
+:1073B000258C5300016C50218D49000001200008EC
+:1073C0000000000002D4702131C5FFFF0E00070C41
+:1073D00024040084166000028F920050AF80006089
+:1073E0008F860044264F00202689000101E090216D
+:1073F0003134FFFF14C00004AF8F00500295282BDA
+:1074000014A0FFDC00000000028010218FBF002CC0
+:107410008FB600288FB500248FB400208FB3001CD6
+:107420008FB200188FB100148FB0001003E0000875
+:1074300027BD00302407003414A7014600000000D7
+:107440009247000E8F98FD908F90FD8C240F1600B0
+:10745000A30700199244000D3C0880003C07800CF3
+:10746000A3040018965F00123C0960003C117FFFE6
+:10747000A61F005C965900103622FFFF2404000569
+:107480003325FFFFAE0500548E46001CAD0F0028CB
+:107490008CEE00008D2D444801C6182601A3302132
+:1074A000AE0600388E0C003824CA00013C0D7F0067
+:1074B000AE0C003C8E0B003CAF0B0004AE0A00206B
+:1074C0008E130020AE13001CA300001BAE02002C84
+:1074D000A30400128E5F001424130050AE1F00346A
+:1074E0008E190034AF1900148E450018AE050048FF
+:1074F000924F000CA20F004E92090008352E00207A
+:10750000A20E00088E030018006D6024358B400029
+:10751000AE0B0018920A0000315200FF125302A66F
+:107520002413FF803C040800248457380E0007769B
+:1075300000000000240C0004240800013C050800A1
+:107540008CA557383C048000A20C0025A208000539
+:107550008C9001780600FFFE8F920050240D0002EF
+:107560003C031000AC850140A08D0144AC83017840
+:107570000A00083AAF8000602CAD003711A0FF99D7
+:107580008F860044000580803C1108002631532876
+:10759000021178218DEE000001C0000800000000FB
+:1075A0002410000414B0008E3C0780003C0B08003F
+:1075B0008D6B57388F86FD8CACEB00208E43000816
+:1075C0008F8FFD90240E0050ACC300308E4A00080F
+:1075D000ACCA00508E42000CACC200348E44001085
+:1075E000ACC400388E5F0010ACDF00548E5900141C
+:1075F000ACD9003C8E580018ADF800048E51001C28
+:10760000ACD1002090C5000030A900FF112E0276F9
+:10761000000000008CC500348CD1003000B1302354
+:1076200004C000F32404008C126000F02402000364
+:107630000A00083AAF820060240F000514AF00680A
+:107640003C0B80003C0308008C6357388F86FD8C10
+:10765000AD6300208E4A00048F99FD90240720001E
+:10766000ACCA001C9242000824120008A322001990
+:107670008F840050909F0009A33F00188F85005011
+:1076800090B8000A330400FF10920010288C000903
+:10769000158000BC24080002240E0020108E000B70
+:1076A00034078000288900211520000824074000A5
+:1076B00024110040109100053C070001240F0080B8
+:1076C000108F00023C070002240740008CDF0018E6
+:1076D0003C04FF0003E4C8240327C025ACD80018ED
+:1076E00090B2000BA0D200278F8300509465000C4D
+:1076F00010A0022A000000009467000C3C198000D2
+:10770000240BFFBFA4C7005C9062000E2407000496
+:10771000A0C200088F840050909F000FA0DF0009D6
+:107720008F8C00508D9200108F38007402582823DF
+:10773000ACC500588D8F0014ACCF002C959100186B
+:107740003229FFFFACC90040958E001A31D0FFFFEF
+:10775000ACD000448D8D001CACCD00489588000253
+:10776000A4C800789183000EA0C3000890CA000846
+:10777000014B1024126001D4A0C200088F92005067
+:107780000A00083AAF8700602406000614A6001419
+:107790003C0D80003C1008008E1057388F8CFD88FF
+:1077A000ADB000208E4800188F86FD8C8F8AFD902A
+:1077B000AD8800008CC3003824040005AD830004AC
+:1077C0008CCB003C12600081AD4B00000A00083AEF
+:1077D000AF840060240E000710AE004B24040006A6
+:1077E0003C05080024A557380E00074924040081F1
+:1077F0008F9200500013102B0A00083AAF820060ED
+:107800002419002314B9FFF63C0B80003C0C08003F
+:107810008D8C57388F8AFD90AD6C00208F91FD8C38
+:107820008E4600042544002026450014AE2600287C
+:10783000240600030E000E60255000308F87005094
+:1078400002002021240600030E000E6024E500083B
+:107850003C040800248457380E000776000000001E
+:1078600092220000241F0050304400FF549FFFE18B
+:107870008F9200500E000E4B000000000A00093FDE
+:107880008F9200502403003314A300323C02800086
+:107890003C1108008E3157388F8EFD90AC5100207E
+:1078A0008E440008240900288F88FD8CADC4003068
+:1078B0008E5F000C24060009ADDF00348E590010E5
+:1078C000ADD900388E580014ADD800208E45001870
+:1078D000ADC500248E4F001CADCF0028A1C90011FA
+:1078E0008E4D000412600031AD0D00288F920050C3
+:1078F0000A00083AAF8600602409002214A9FFB8E4
+:1079000000000000240400073C0F08008DEF5738EA
+:107910003C118000AE2F00205660FEB1AF840060A5
+:107920003C040800248457380E00077624130050C6
+:107930008F98FD8C93120000324500FF10B301694F
+:10794000000000008F920050000020210A00083A39
+:10795000AF8400603C05080024A557380E000719C5
+:10796000240400810A00093F8F92005002D498211C
+:107970003265FFFF0E00070C240400840A00083A59
+:107980008F9200501088FF512407040028870003BD
+:1079900010E001A324100004240D0001548DFF4BBE
+:1079A000240740000A0008F5240701003C050800F0
+:1079B00024A557380E000768240400828F920050D7
+:1079C000000030210A00083AAF8600603C0408003D
+:1079D000248457388CC200380E0007768CC3003CD4
+:1079E0008F9200500A000995000020212404008293
+:1079F0003C05080024A557380E0007680000000069
+:107A00008F920050000010210A00083AAF820060F7
+:107A10008E5000048F91FD8C3C0A8000AD500020F8
+:107A200092220005020028213046000214C0018085
+:107A30002404008A8F92FD90020028212404008DE6
+:107A4000924B001B3163002014600179000000009C
+:107A5000922D0009240C001231A800FF110C0174B2
+:107A6000240400810E00073A020020219245001BE9
+:107A7000240E00040200202134A90042A249001B68
+:107A80000E000744A22E00253C0480008C91017852
+:107A90000620FFFE24180002AC900140A09801448B
+:107AA0008F9200503C0F1000AC8F01780A00094003
+:107AB0000013102B8E5000048F91FD8C3C1F800012
+:107AC000AFF0002092390005020028213327000280
+:107AD00014E000172404008A9224000924120004F0
+:107AE00002002821308600FF10D2001124040081FA
+:107AF0000E00073A020020218F8CFD90240B00120B
+:107B00002403FFFE918D001B0200202135A80020D8
+:107B1000A188001BA22B0009922A00050143102412
+:107B20000E000744A22200050200282100002021A7
+:107B30000E000805000000000A00093F8F92005067
+:107B40008E5100043C0280003C100800261057387B
+:107B5000AC5100203C010800AC315738924600037C
+:107B600030C40004108001658F84FD8C240200065F
+:107B7000A0820009924D001B2408FFC031AC003FD9
+:107B800001885825A08B000892430003306A000149
+:107B90001540015C000000008E420008AE020008A3
+:107BA0003C0208008C4257401040015B8F8EFD90D4
+:107BB000000281C28F85FD8CA5D0000C8E5F000C69
+:107BC000240F000124090014ADDF002C8E59001091
+:107BD000ADD9001C96470016A5C7003C9658001466
+:107BE000A5D8003EACAF000CA4AF0010A4AF0012AB
+:107BF000A4AF0014A4AF00161260015FA1C9001168
+:107C000092440003309200022E5300018F920050E4
+:107C1000266200080A00083AAF8200608E4600041F
+:107C20003C0580003C048008ACA600208E4700087C
+:107C30009089000024110050312200FF105100B83B
+:107C4000240500883C0480008C8F01B805E0FFFE0D
+:107C50000013802B3C18400900B81025AF9000603D
+:107C60003C101000AC860180AC870184AC82018896
+:107C7000AC9001B80A00083B8F8600448E45000492
+:107C80003C0680003C098008ACC50020913F000004
+:107C90002404005033F900FF132400B024060088A8
+:107CA0003C0480008C8A01B80540FFFE3C0E400E6B
+:107CB00000CE68253C081000AC850180AC800184B2
+:107CC000AC8D0188AC8801B8912B0000240CFF809A
+:107CD00024040004016C1825240600300E0006AAB6
+:107CE000A12300000A00093F8F9200508E5000042B
+:107CF0008F91FD903C0F8000ADF000209225001B7D
+:107D000030A900101120007C240300813C04800075
+:107D10008C8701B804E0FFFE3C1F401FAC9001803F
+:107D2000007F10250013C82B3C101000AC8001848C
+:107D3000AF990060AC820188AC9001B80A00083BA2
+:107D40008F8600448E44001C0E00072500000000B2
+:107D5000104000F8004038218F920050240600891E
+:107D60003C0580008CAE01B805C0FFFE000000009D
+:107D7000ACA701808E50001C3C1140010013782BF1
+:107D800000D138253C131000ACB00184AF8F0060E7
+:107D9000ACA70188ACB301B80A00083B8F86004449
+:107DA000965900023C10080026105738333800045A
+:107DB000130000A33C0460008E5F001C3C068000A2
+:107DC000ACDF00203C010800AC3F5738964F000262
+:107DD00031E7000114E000E3000000008E420004DF
+:107DE000AE0200083C1008008E105740120000D967
+:107DF0003C0680008F85FD8C241000018CBF00188C
+:107E00008F91FD908F89FD8803E6C825ACB90018D5
+:107E1000A0A00005ACB0000C3C1808008F1857401B
+:107E20008F870050A4B00010001879C2A4B00012CF
+:107E3000A4B00014A4B00016A62F000C8CEE00080D
+:107E40008F8D00508F8C0050AE2E002C8DA8000C12
+:107E500024070002AE28001C918B0010A22B0011F9
+:107E60008F830050906A0011A12A00088F82005071
+:107E700090440012A0A4004E8F920050924600132E
+:107E8000A22600128F920050965F0014A63F003C7D
+:107E900096590016A639003E8E580018AE380014C8
+:107EA0005660FD4FAF8700603C05080024A5573899
+:107EB0000E000749000020218F9200500000382159
+:107EC0000A00083AAF8700603C05080024A557382F
+:107ED0000E000768240400828F9200500A000922D5
+:107EE000000038210E000E4B000000008F92005061
+:107EF0000A000995000020210E00073A0200202107
+:107F00009232001B02002021365800100E00074458
+:107F1000A238001B8F9200500A000A850000182129
+:107F20009243000C306A0001114000030000000081
+:107F3000964B000EA48B002C9248000C310C0002D2
+:107F40001180FF4000002821964E00128E4D001433
+:107F5000A48E001A0A000A53AC8D001C8F83007097
+:107F60008F8700681067FF4E000030213C08080032
+:107F7000250856BC000320C0008830218CD10000A9
+:107F8000122500C8246200013043000F1467FFFA75
+:107F9000000320C00A000A6A000030213C050800E6
+:107FA00024A557380E0007682404008B8F920050D8
+:107FB0000A0009220013382B3C0B08008D6B573840
+:107FC00024D8FFFE25710100322A007F014790214D
+:107FD00002331024AD020028AE4600D0AE4000D4DB
+:107FE0000A00088BAE58001CACC000543C0E0800C0
+:107FF0008DCE57383C09800C352C0100ACEE0028A2
+:108000008E500014AD9000D08E4D0014AD8D00D474
+:108010008E4800102507FFFE0A0008C7AD87001C28
+:108020005490FDAA240740000A0008F52407100018
+:108030000E0007F9000000000A00093F8F9200506F
+:108040008C83442C3C05DEAD34B2BEEF3C0108000D
+:10805000AC20573810720090000000003C046C62A5
+:10806000348279701462000824040002978A006C3C
+:1080700097830064020028210143482B1120001936
+:1080800024040092240400020E00061A24050200B3
+:108090003C0B8000AD6200203C010800AC22573848
+:1080A0001040000D8F8E0050240C00282404000383
+:1080B00091CD001031A800FF550C000124040001EF
+:1080C0000E00004C00000000104000042404008357
+:1080D0000A000AB58F920050240400833C05080072
+:1080E00024A557380E000749000000008F92005069
+:1080F0000013382B0A00083AAF8700600A000A1EF6
+:10810000240200128E4400080E0007250000000023
+:108110000A000A2AAE0200083C05080024A55738C8
+:108120000E000719240400878F9200500A000A47A6
+:108130000013102B240400040E00061A240500303E
+:1081400014400014004038218F9200500A000A9A0F
+:10815000240600833C05080024A557380A000B7B41
+:10816000240400878E4400040E0007250000000050
+:108170000A000ABBAE0200083C05080024A55738D7
+:108180000E000768240400828F9200500A000A47FC
+:10819000000010218F9200503C0880083C0C8000A9
+:1081A000240B0050240A0001AD820020A10B000026
+:1081B000A10A000192490004A10900189244000597
+:1081C000A1040019924300063C040800248456BC14
+:1081D000A103001A924200073C030800246356B82A
+:1081E000A102001B92450008A105001C924600094F
+:1081F000A106001D925F000AA11F001E9259000BEC
+:10820000A119001F9258000CA11800209251000DD6
+:10821000A11100219250000EA1100022924F000FD8
+:10822000A10F0023924E0010A10E0024924D0011C8
+:10823000A10D0025964C0014A50C0028964B0016A5
+:108240008F8A00688F980070A50B002A9649001845
+:10825000000A10C025450001A509002C8E46001C0F
+:108260000044C8210043F82130A5000FAFE600000C
+:10827000AF27000010B80003AF8500680A000A9A13
+:108280000000302124AD000131A8000F0000302192
+:108290000A000A9AAF8800708C83442C0A000B5A9B
+:1082A0003C046C623C07080024E756B80087902124
+:1082B000ACC00000000030210A000A6AAE40000095
+:1082C0003C0482013C03600034820E02AC603D68D5
+:1082D000AF80009003E00008AC623D6C27BDFFE872
+:1082E000AFB000103090FFFF001018422C62004128
+:1082F000AFBF001414400002240400802403004097
+:108300003C010800AC3000603C010800AC23006474
+:108310000E000E5400602821244802BF2409FF806B
+:108320000109282400103980001030408FBF00144C
+:108330008FB0001000A7202100861821AF8300789D
+:108340003C010800AC2500583C010800AC24005C4E
+:1083500003E0000827BD0018308300FF30C6FFFF90
+:1083600030E400FF3C0880008D0201B80440FFFEAD
+:1083700000035400014438253C09600000E9202531
+:108380003C031000AD050180AD060184AD040188F9
+:1083900003E00008AD0301B88F8600503C0960126D
+:1083A000352700108CCB00043C0C600E3585001086
+:1083B000316A00062D480001ACE800C48CC40004FA
+:1083C000ACA431808CC2000894C30002ACA23184FA
+:1083D00003E00008A78300888F8500508F87FF186F
+:1083E0008F86FF208CAE00043C0F601235E8001031
+:1083F000ACEE00688CAD0008ACED006C8CAC0010ED
+:10840000ACCC004C8CAB000CACCB004894CA0054F4
+:108410003C0208008C42004425490001A4C90054D4
+:1084200094C400543083FFFF106200170000000066
+:108430003C0208008C420040A4C200528CA30018E9
+:10844000ACE300308CA20014ACE2002C8CB9001814
+:10845000ACF900388CB8001424050001ACF80034E5
+:108460008D0600BC50C500198D0200B48D0200B805
+:10847000A4E2004894E40048A4E4004A94E800DA46
+:1084800003E000083102FFFF3C0208008C42002498
+:10849000A4C00054A4C200528CA30018ACE3003066
+:1084A0008CA20014ACE2002C8CB90018ACF9003896
+:1084B0008CB8001424050001ACF800348D0600BC13
+:1084C00054C5FFEB8D0200B88D0200B4A4E2004851
+:1084D00094E40048A4E4004A94E800DA03E00008C9
+:1084E0003102FFFF8F8600503C0480008CC90008D9
+:1084F0008CC80008000929C0000839C0AC870020DA
+:1085000090C30007306200041040003AAF85008C31
+:1085100090CB0007316A0008114000398F87FF1C9B
+:108520008CCD000C8CCE001401AE602B118000327B
+:10853000000000008CC2000CACE200708CCB001874
+:108540008F85FF188F88FF20ACEB00748CCA001059
+:108550002402FFF8ACAA00C88CC9000CAD09006069
+:108560008CC4001CACA400C090E3007C0062C82452
+:10857000A0F9007C90D80007330F000811E0000438
+:108580000000000090ED007C35AC0001A0EC007C08
+:1085900090CF000731EE000111C00009000000007B
+:1085A00090E4007C2418000234820002A0E2007CE7
+:1085B00090A300EC307900FF133800132408003436
+:1085C00090C900073126000210C00004000000001E
+:1085D00090EB007C356A0004A0EA007C90ED007D01
+:1085E00031AC003FA0EC007D94A700DA03E0000866
+:1085F00030E2FFFF8F87FF1C0A000C908CC2001432
+:108600000A000C91ACE000700A000CB2ACA800CCDF
+:108610008F8C005027BDFFD8AFB3001CAFB200183D
+:10862000AFB00010AFBF0020AFB10014918F0015A4
+:108630003C13600E3673001031EB000FA38B0094D7
+:108640008D8F00048D8B0008959F00129599001066
+:108650009584001A9598001E958E001C33EDFFFF3F
+:10866000332AFFFF3089FFFF3308FFFF31C7FFFFC9
+:108670003C010800AC2D00243C010800AC2900445A
+:108680003C010800AC2A0040AE683178AE67317C0E
+:1086900091850015959100163C126012365200101B
+:1086A00030A200FF3230FFFFAE623188AE5000B41E
+:1086B00091830014959F0018240600010066C804E9
+:1086C00033F8FFFFAE5900B8AE5800BC918E0014CD
+:1086D000AF8F007C3C08600631CD00FFAE4D00C07E
+:1086E000918A00159584000E3C07600A314900FF0D
+:1086F000AF8B00803084FFFFAE4900C835110010F9
+:108700000E000BF934F004103C0208008C420060AB
+:108710003C0308008C6300643C0608008CC60058CB
+:108720003C0508008CA5005C8F8400788FBF00207A
+:10873000AE23004CAE65319CAE030054AE4500DC68
+:10874000AE6231A0AE6331A4AE663198AE2200486D
+:108750008FB3001CAE0200508FB10014AE4200E097
+:10876000AE4300E4AE4600D88FB000108FB20018C0
+:108770000A00050227BD00289785008A97830074A8
+:1087800027BDFFE8AFB0001000A3102BAFBF00144F
+:10879000240400058F900050104000552409000269
+:1087A0000E00061A8F850078AF82008C2404000327
+:1087B0001040004F240900023C0680000E00004CCF
+:1087C000ACC2002024070001240820001040004D06
+:1087D00024040005978E008A8F8AFF1C240900500C
+:1087E00025C50001A785008AA14900003C0D0800AD
+:1087F0008DAD0064240380008F84FF18000D660097
+:10880000AD4C0018A5400006954B000A8F85FF204F
+:108810002402FF8001633024A546000A915F000A0C
+:108820000000482103E2C825A159000AA0A00008C1
+:10883000A140004CA08000C59618000297830088D4
+:108840003C020004A49800DA960F00022418FFBF2F
+:1088500025EE2401A48E00AE8E0D0004ACAD0044C4
+:108860008E0C0008ACAC0040A4A00050A4A00054A2
+:108870008E0B000C240C0030AC8B00288E060010F0
+:10888000AC860024A480003EA487004EA48700503C
+:10889000A483003CAD420074AC8800C8ACA8006062
+:1088A000A08700EC909F00C433F9007FA09900C41A
+:1088B000909000C402187824A08F00C4914E007CD0
+:1088C00035CD0001A14D007C938B0094AD48007024
+:1088D000AC8C00CCA08B00C68F8800808F87007C7A
+:1088E000AC8800B4AC8700B8A5400078A540007AF9
+:1088F0008FBF00148FB000100120102103E000088A
+:1089000027BD00188F85008C0E0006AA8F86007880
+:108910000A000D7E2409000227BDFFE0AFB0001061
+:108920008F900050AFB10014AFBF00188E09000443
+:108930000E0004CF000921C08E0800048F84FF18A8
+:108940008F82FF20000839C03C068000ACC70020A1
+:10895000948500DA904300131460001C30B1FFFFCF
+:108960008F8CFF1C918B0008316A00401540000B72
+:10897000000000008E0D0004022030218FBF00187F
+:108980008FB100148FB000102404002200003821A1
+:10899000000D29C00A000C1827BD00200E0000633E
+:1089A000000000008E0D0004022030218FBF00184F
+:1089B0008FB100148FB00010240400220000382171
+:1089C000000D29C00A000C1827BD00200E00005B16
+:1089D000000000008E0D0004022030218FBF00181F
+:1089E0008FB100148FB00010240400220000382141
+:1089F000000D29C00A000C1827BD002027BDFFE08C
+:108A0000AFB200183092FFFFAFB00010AFBF001C34
+:108A1000AFB100141240001E000080218F8600506C
+:108A20008CC500002403000600053F020005140267
+:108A300030E4000714830016304500FF2CA8000620
+:108A400011000040000558803C0C0800258C54049F
+:108A5000016C50218D490000012000080000000039
+:108A60008F8E0090240D000111CD005024020002D1
+:108A7000AF820090260900013130FFFF24C800209A
+:108A80000212202B010030211480FFE5AF88005036
+:108A9000020010218FBF001C8FB200188FB100148C
+:108AA0008FB0001003E0000827BD002093870076F8
+:108AB00054E00034000030210E000CC6000000001D
+:108AC0008F8600500A000DDE240200018F8700907F
+:108AD0002405000210E500312404001300002821C1
+:108AE00000003021240700010E000C1800000000D7
+:108AF0000A000DDF8F8600508F8300902402000251
+:108B00001462FFF6240400120E000C7B000000002B
+:108B10008F85008C00403021240400120E000C18B8
+:108B2000000038210A000DDF8F8600508F830090EF
+:108B30002411000310710029241F0002107FFFCEB2
+:108B40002609000124040010000028210000302123
+:108B50000A000DFC240700018F91009024060002FA
+:108B60001626FFF9240400100E000D20000000005E
+:108B7000144000238F9800508F8600500A000DDEAD
+:108B800024020003240400140E000C180000282105
+:108B90008F8600500A000DDE240200020E000D88B0
+:108BA000000000000A000DDF8F8600500E000C2828
+:108BB00000000000241900022404001400002821F1
+:108BC0000000302100003821AF9900900E000C18F1
+:108BD000000000000A000DDF8F8600500E000C38E8
+:108BE000000000008F85008C241900020040302115
+:108BF00024040010000038210A000E35AF990090BF
+:108C00000040382124040010970F000200002821A2
+:108C10000E000C1831E6FFFF8F8600500A000DDFB2
+:108C2000AF9100908F84FF1C3C077FFF34E6FFFF6D
+:108C30008C8500182402000100A61824AC830018BB
+:108C400003E00008A08200053084FFFF30A5FFFF8D
+:108C5000108000070000182130820001104000023F
+:108C600000042042006518211480FFFB0005284005
+:108C700003E000080060102110C0000700000000A1
+:108C80008CA2000024C6FFFF24A50004AC820000D3
+:108C900014C0FFFB2484000403E00008000000006F
+:108CA00010A0000824A3FFFFAC8600000000000015
+:108CB000000000002402FFFF2463FFFF1462FFFA9C
+:108CC0002484000403E0000800000000000411C038
+:108CD00003E000082442024027BDFFE8AFB00010C7
+:108CE00000808021AFBF00140E000E7500A020216F
+:108CF00000504821240AFF808FBF00148FB000105D
+:108D0000012A30243127007F3C08800A3C042100DE
+:108D100000E8102100C428253C03800027BD00186E
+:108D2000AC650024AF820038AC400000AC65002484
+:108D300003E00008AC4000403C0D08008DAD005839
+:108D400000056180240AFF8001A45821016C48219C
+:108D5000012A30243127007F3C08800C3C0421008C
+:108D600000E8102100C428253C038000AC650028E1
+:108D7000AF82003403E00008AC40002430A5FFFFC0
+:108D80003C0680008CC201B80440FFFE3C08601520
+:108D900000A838253C031000ACC40180ACC001849D
+:108DA000ACC7018803E00008ACC301B83C0D080063
+:108DB0008DAD005800056180240AFF8001A4582170
+:108DC000016C4021010A4824000931403107007F2D
+:108DD00000C728253C04200000A418253C02800080
+:108DE000AC43083003E00008AF80003427BDFFE843
+:108DF000AFB0001000808021AFBF00140E000E75D0
+:108E000000A0202100504821240BFF80012B50247A
+:108E1000000A39403128007F3C0620008FBF001433
+:108E20008FB0001000E8282534C2000100A21825E8
+:108E30003C04800027BD0018AC83083003E0000824
+:108E4000AF8000383C0580088CA700603C06800895
+:108E50000087102B144000112C8340008CA8006068
+:108E60002D0340001060000F240340008CC90060F7
+:108E70000089282B14A00002008018218CC30060F8
+:108E800000035A42000B30803C0A0800254A5480F7
+:108E900000CA202103E000088C8200001460FFF368
+:108EA0002403400000035A42000B30803C0A0800B3
+:108EB000254A548000CA202103E000088C8200006B
+:108EC0003C05800890A60008938400A024C20001FD
+:108ED000304200FF3043007F1064000C000238274E
+:108EE000A0A200083C0480008C85017804A0FFFE4D
+:108EF0008F8A0098240900023C081000AC8A0140C7
+:108F0000A089014403E00008AC8801780A000EFA49
+:108F100030E2008027BDFFD8AFB200188F92009CCE
+:108F2000AFBF0020AFB3001CAFB00010AFB1001452
+:108F30008F9300348E5900283C1000803C0EFFEFC8
+:108F4000AE7900008E580024A260000A35CDFFFFE4
+:108F5000AE7800049251002C3C0BFF9F356AFFFF56
+:108F6000A271000C8E6F000C3C080040A271000B37
+:108F700001F06025018D4824012A382400E83025BD
+:108F8000AE66000C8E450004AE6000183C0400FF85
+:108F9000AE6500148E43002C3482FFFFA6600008EB
+:108FA0000062F824AE7F00108E5900088F90009860
+:108FB000964E0012AE7900208E51000C31D83FFF42
+:108FC00000187980AE7100248E4D001401F06021EC
+:108FD00031CB0001AE6D00288E4A0018000C41C252
+:108FE000000B4B80AE6A002C8E46001C0109382114
+:108FF000A667001CAE660030964500028E44002035
+:10900000A665001EAE640034924300333062000453
+:1090100054400006924700003C028008344301009F
+:109020008C7F00C0AE7F0030924700008F860038F2
+:10903000A0C700309245003330A4000250800007E2
+:10904000925100018F880038240BFF80910A003074
+:10905000014B4825A1090030925100018F90003842
+:10906000240CFFBF2404FFDFA21100318F8D0038D4
+:109070003C1880083711008091AF003C31EE007F32
+:10908000A1AE003C8F890038912B003C016C50242C
+:10909000A12A003C8F9F00388E68001493E6003CA4
+:1090A0002D0700010007114000C4282400A2182544
+:1090B000A3E3003C8F87003896590012A4F90032D0
+:1090C0008E450004922E007C30B0000300107823FF
+:1090D00031ED000300AD102131CC000215800002FB
+:1090E00024460034244600303C028008344300808B
+:1090F000907F007C00BFC8243338000417000002B2
+:1091000024C2000400C010218F98003824190002E6
+:10911000ACE20034A3190000924F003F8F8E00385C
+:109120003C0C8008358B0080A1CF00018F91003866
+:10913000924D003F8E440004A62D0002956A005C0B
+:109140000E000ED33150FFFF00024B800130382556
+:109150003C08420000E82825AE2500048E44003873
+:109160008F850038ACA400188E460034ACA6001CD5
+:10917000ACA0000CACA00010A4A00014A4A0001689
+:10918000A4A00020A4A00022ACA000248E620014A1
+:1091900050400001240200018FBF00208FB3001C4B
+:1091A0008FB200188FB100148FB00010ACA200086D
+:1091B0000A000EF227BD002827BDFFC83C05800825
+:1091C00034A40080AFBF0034AFBE0030AFB7002C76
+:1091D000AFB60028AFB50024AFB40020AFB3001C79
+:1091E000AFB20018AFB10014AFB000109483007894
+:1091F0009482007A104300512405FFFF0080F02183
+:109200000A0010020080B821108B004D8FBF00347F
+:109210008F8600983C1808008F18005C2411FF808E
+:109220003C1680000306782101F18024AED0002C8A
+:1092300096EE007A31EC007F3C0D800E31CB7FFF43
+:10924000018D5021000B4840012AA82196A400005E
+:109250003C0808008D0800582405FF8030953FFF2A
+:1092600001061821001539800067C8210325F8245C
+:109270003C02010003E290253338007F3C11800C52
+:10928000AED20028031190219250000D320F00043D
+:1092900011E0003702E0982196E3007A96E8007A20
+:1092A00096E5007A2404800031077FFF24E3000163
+:1092B00030627FFF00A4F82403E2C825A6F9007AF3
+:1092C00096E6007A3C1408008E94006030D67FFF4A
+:1092D00012D400C1000000008E5800188F8400983E
+:1092E00002A028212713FFFF0E000EADAE53002C65
+:1092F00097D5007897D4007A1295001000002821A5
+:109300003C098008352401003C0A80089148000887
+:10931000908700C53114007F30E400FF0284302BB9
+:1093200014C0FFB9268B0001938E00A0268C00018B
+:10933000008E682115ACFFB78F8600988FBF003470
+:109340008FBE00308FB7002C8FB600288FB5002459
+:109350008FB400208FB3001C8FB200188FB100149F
+:109360008FB0001000A0102103E0000827BD0038D6
+:1093700000C020210E000E78028028218E4B0010A4
+:109380008E4C00308F84003824090002016C502379
+:10939000AE4A0010A089000096E3005C8E440030C5
+:1093A0008F9100380E000ED33070FFFF0002438013
+:1093B000011028253C07420000A71025AE2200041A
+:1093C0008E5F00048F8A00388E590000240B00083D
+:1093D000AD5F001CAD590018AD40000CAD40001051
+:1093E0009246000A240400052408C00030D000FF83
+:1093F000A550001496580008A55800169251000A6E
+:109400003C188008322F00FFA54F0020964E000820
+:1094100037110100A54E0022AD400024924D000BF3
+:1094200031AC00FFA54C0002A14B00018E49003079
+:109430008F830038240BFFBFAC690008A0640030A4
+:109440008F9000382403FFDF9607003200E82824BD
+:1094500000B51025A6020032921F003233F9003FFA
+:1094600037260040A20600328F8C0038AD800034D1
+:109470008E2F00C0AD8F0038918E003C3C0F7FFFD7
+:1094800031CD007FA18D003C8F84003835EEFFFF89
+:10949000908A003C014B4824A089003C8F8500380D
+:1094A00090A8003C01033824A0A7003C8E42003461
+:1094B0008F9100383C038008AE2200408E59002C6A
+:1094C0008E5F0030033F3023AE26004492300048C8
+:1094D0003218007FA23800488F8800388E4D003047
+:1094E0008D0C004801AE582401965024014B4825AC
+:1094F000AD0900489244000AA104004C96470008B8
+:109500008F850038A4A7004E8E5000308E44003066
+:109510000E00031C8C65006092F9007C0002F9408B
+:10952000004028210002110003E2302133360002FE
+:1095300012C00003020680210005B08002168021BF
+:10954000926D007C31B3000412600002000570804F
+:10955000020E80218E4B003024058000316A00030A
+:10956000000A482331240003020418218F90003898
+:10957000AE03003496E4007A96E8007A96F1007A19
+:1095800031077FFF24E20001305F7FFF0225C824FE
+:10959000033F3025A6E6007A96F8007A3C120800D0
+:1095A0008E520060330F7FFF11F2001800000000A0
+:1095B0008F8400980E000EAD02A028218F840098A1
+:1095C0000E000EBD028028210E000EF200000000E9
+:1095D0000A000FFE0000000096F1007A02248024A9
+:1095E000A6F0007A92EF007A92EB007A31EE00FF5B
+:1095F000000E69C2000D6027000C51C03169007F68
+:10960000012A20250A000FF8A2E4007A96E6007AE3
+:1096100000C5C024A6F8007A92EF007A92F3007A8F
+:1096200031F200FF001271C2000E6827000DB1C0B8
+:10963000326C007F01962825A2E5007A0A0010AF5F
+:109640008F8400983C0380003084FFFF30A5FFFF2B
+:10965000AC640018AC65001C03E000088C620014C8
+:1096600027BDFFA83C068008AFBE0050AFBF005426
+:10967000AFB7004CAFB60048AFB50044AFB4004040
+:10968000AFB3003CAFB20038AFB10034AFB0003080
+:1096900034C80100910500C590C70008309EFFFF47
+:1096A00030A500FF30E2007F0045182AA7A0001473
+:1096B000A7A0001E10600053AFA0001090C90008C2
+:1096C0003126007F00A620232493FFFF0013802B68
+:1096D000001E882B0211782451E000848FB3001003
+:1096E0003C1980089736005297370050001EC4007E
+:1096F00002D7A8230015A4000014140303C2902A63
+:109700001640000200182C0300402821001314000A
+:109710000002240300A4F82A57E0000100A0202141
+:1097200028830009146000020080A021241400088E
+:109730003C0A80088D450048001449808D48004C43
+:109740003C0380003124FFFF3C06001000863825D2
+:1097500034710400AC650038AF91009CAC68003CEB
+:10976000AC670030000000000000000000000000B6
+:1097700000000000000000000000000000000000E9
+:10978000000000008C6C0000318B00201160FFFD98
+:109790000014682A01B01024104000390000A821EC
+:1097A0003C16800892D700083C1280008E440100CD
+:1097B00032F6007F0E000E7802C028218E2F001096
+:1097C0008E4401000000902131F73FFF0E000E9003
+:1097D00002E02821922E000031C2003F2C500008E8
+:1097E00052000010000088210002F8803C030800AD
+:1097F0002463542C03E3C8218F38000003000008C1
+:109800000000000090CE0008938B00A031CD007FB7
+:1098100000AD6023016C50210A0010F52553FFFFB5
+:10982000000088213C1080008E0401000E000EAD67
+:1098300002E028218E0401000E000EBD02C0282186
+:109840001220000F0013802B8F8A009C26A9000194
+:109850000009AC00027298230015AC0325450040B6
+:1098600002B4B02A0013802B2417000100A0882125
+:1098700002D01024AF85009C1440FFC9AFB7001080
+:109880003C07800894F100503C0580003C06002015
+:1098900002B1C821A4F90050ACA6003094F40050E5
+:1098A00094E3005203D560231074001D319EFFFF26
+:1098B0008CE5004C8CE900480015618000ACB021BB
+:1098C0000000A02102CCA82B013450210155B82161
+:1098D000ACF6004CACF70048001E882B021178242F
+:1098E00015E0FF803C1980088FB300108FBF005433
+:1098F0008FBE00503A6200018FB7004C8FB600480F
+:109900008FB500448FB400408FB3003C8FB2003855
+:109910008FB100348FB0003003E0000827BD00583D
+:1099200094F200548CEF0044325FFFFE001FC0C071
+:1099300001F87021ACAE003C8CEB00448CAD003CD7
+:10994000016D40231900003B000000008CE2004044
+:10995000244200013C07005034E400103C03800026
+:10996000ACA20038AC640030000000000000000031
+:1099700000000000000000000000000000000000E7
+:1099800000000000000000008C76000032D70020AC
+:1099900012E0FFFD3C118008962800543C0A80002C
+:1099A0003C06800831190001001960C0018AA0211D
+:1099B0008E8304003C0708008CE700443C1500201F
+:1099C000ACC300488E89040424050001ACC9004CD6
+:1099D00010E50259AD550030963F00523C05080095
+:1099E0008CA5004000BFC021A6380052962F00541D
+:1099F00025EE0001A62E00549626005430C4FFFF29
+:109A00005487FF34001E882B30A5FFFF0E0010D3B3
+:109A1000A62000543C0408008C84002496270052A1
+:109A20000044102300E29023A63200520A0010F7EF
+:109A3000001E882B8CE200400A0011983C07005061
+:109A400092280001240700013102007F1447001C06
+:109A500097AC001E8E2A0014240BC00031443FFF37
+:109A6000018B48243C0608008CC600600124282590
+:109A700030A43FFF0086882B12200011A7A5001EEE
+:109A80003C1108008E3100588F82009800044180FC
+:109A90002407FF80022218210068F82103E7C82468
+:109AA00033EF007F3C1880003C12800EAF19002C71
+:109AB00001F2682191AE000D35D00004A1B0000D77
+:109AC0000E000F0724120001241100013C10800039
+:109AD0008E0401000E000EAD02E028218E0401006C
+:109AE0000E000EBD02C028211620FF588F8A009C50
+:109AF0000A0011620013802B8F86009C90C9000120
+:109B00003125002010A0018A241000013C048008A7
+:109B1000348C0080918B007C8F9100340000902168
+:109B2000316A00011140000FAFB000208CD000144A
+:109B30008C8E0060020E682B15A0000302003821F5
+:109B40008C8700603C048008348300808C72007035
+:109B500000F2782B15E0000200E020218C640070F8
+:109B6000008090213C07800834E500808CD90014E7
+:109B70008CBF0070033FC02B170000020320202180
+:109B80008CA400700092182310600003AFA300287B
+:109B900024080002AFA800208FA500200265102B2A
+:109BA000144000B5000018218CC400388E2F000C22
+:109BB0003C180080AE2400008CCE00343C10FF9F87
+:109BC00001F86025AE2E000490CB003F360DFFFF5C
+:109BD000018D48243C0A00203C06FFEFA22B000B1D
+:109BE000012A382534C5FFFF00E540243C02000867
+:109BF0008F87009C01022025AE24000C8CE300140A
+:109C0000AE2000188FAF0028AE2300148CF8001887
+:109C10003C1FFFFB37F9FFFFAE38001C8CEE00083D
+:109C200000996824024F8021AE2E00248CEC000C99
+:109C3000AE2D000CA6200038A620003AAE30002C35
+:109C4000AE2C0020AE2000288CEB00148FAA002838
+:109C500001724823012A302310C00011AE260010E3
+:109C600090F0003D8E2C00048E2A00000010690048
+:109C7000018D28210000102100AD302B0142482128
+:109C800001264021AE250004AE28000090E3003DEF
+:109C9000A223000A8F9F009C97F90006A6390008AE
+:109CA0008F8A0038240200023C068008A14200008E
+:109CB00034C900809525005C024020218F90003837
+:109CC00030A8FFFF0E000ED3AFA800248FA30024FE
+:109CD0000002FB808F85009C3C04420003E3C82502
+:109CE0000324C025AE1800048F8400388CAF0038E0
+:109CF000AC8F00188CAE0034AC8E001CAC80000C15
+:109D0000AC800010A4800014A4800016A480002061
+:109D1000A4800022AC80002490A7003FA48700020A
+:109D20005240018C240700018FAB002851600002D3
+:109D300090A2003D90A2003E244C0001A08C0001A6
+:109D40008F840038AC9200083C18800837100080DF
+:109D5000920F007C31EE000215C00002240700348F
+:109D6000240700308F85009C3C088008350900805E
+:109D700090A300009128007C32590003A08300309A
+:109D80008F9F009C8F9000382404000493F80001FA
+:109D900000997823240DC000A21800318F99003853
+:109DA0008F8E009C31E50003972C003295CB00127A
+:109DB00000F24821018D502431623FFF01423025DD
+:109DC000A7260032932300320125382131080004F0
+:109DD000307F003F37E40040A324003212400002ED
+:109DE0008F85003800E838213C0C8008ACA700348F
+:109DF000358B01008D6200C02E4400012403FFDF7B
+:109E0000ACA2003890AA003C0004C9403146007F53
+:109E1000A0A6003C8F8900382405FFBF9127003C95
+:109E200000E54024A128003C8F8F003891FF003CC2
+:109E300003E3C02403198025A1F0003C8F8B009C14
+:109E40008F8A00388D6E0020AD4E00408D6D00244D
+:109E5000AD4D00448D6C0028AD4C00488D62002C47
+:109E60000E000EF2AD42004C8FA600202407000227
+:109E700010C700118FA300200003202B00048023B3
+:109E80000270982400608021006090210A00114B2C
+:109E90000010882B962700128F84009800009021D4
+:109EA00030E5FFFFA7A700140E000EA1241100014A
+:109EB0000A0011F63C1080003C1980003C0280082A
+:109EC0008F240100905800080E000E783305007FA3
+:109ED0008F8E00388FAF00208FA40028A1CF000004
+:109EE0000E000ED38F9000388FAD002400023B800F
+:109EF0003C0B420000ED40258F87009C010B202584
+:109F0000AE0400048CE500388F900038000050212A
+:109F1000000A1900AE0500188CEC00343C087FFFE5
+:109F20003504FFFFAE0C001C90E9003E8E1F001CA4
+:109F30008E1800180009C9000009370203F96821CA
+:109F40000066102501B9782B0302702101CF58213A
+:109F5000AE0D001CAE0B0018AE00000CAE000010E1
+:109F600090E5003E8FAF0028240E0005A6050014E2
+:109F700094EC00042405C00001E45824A60C00164B
+:109F800090EA003E01E02021A60A002094E60004A9
+:109F9000A6060022AE00002490E3003FA6030002C4
+:109FA00090E9003E90FF003D03E9C82327380001F7
+:109FB000A21800018F8D00383C108008ADAF00085A
+:109FC000A1AE00308F9800388F82009C360F0100C0
+:109FD000970C0032944A00122410FF8000AC382401
+:109FE00031463FFF00E61825A703003293090032EF
+:109FF0002405FFBF2403FFDF313F003F37F9004056
+:10A00000A31900328F8C00382418FFFFAD80003474
+:10A010008DEE00C0AD8E0038918D003C31A2007FE6
+:10A02000A182003C8F87003890EA003C0145302433
+:10A03000A0E6003C8F9900389329003C0123F824C6
+:10A04000A33F003C8F8D00383C1F8008ADB8004016
+:10A05000ADB2004491AF00483C12800001F0702581
+:10A06000A1AE00488F8700388F86009C8CEC00489A
+:10A0700001921024004B5025ACEA004890C5003EE8
+:10A08000A0E5004C8F88009C8F8300389509000460
+:10A09000A469004E8FE500600E00031C0000000064
+:10A0A0008F99FF248FAE002800028140932F007CFF
+:10A0B0000002C1000218682131F20002004028218C
+:10A0C000164000AA01CD30213C0A800835430080AB
+:10A0D0009069007C313F000413E000038FAE00283C
+:10A0E0000005608000CC3021240D00048F900038E2
+:10A0F00031C7000301A758233168000300C820219D
+:10A10000AE0400343C068008A62500383C058000DB
+:10A110008CA4010090D100080E000EBD3225007FF6
+:10A120000E000EF2000000000A0012E08FA30020D3
+:10A130008F8500348CC2003824180003A4A00008C6
+:10A14000ACA200008CDF0034A0A0000A8F92009C1B
+:10A15000ACBF00043C040080924F003FA0B8000C4C
+:10A160008CAE000C3C0DFF9FA0AF000B01C440253E
+:10A1700035ABFFFF3C11FFEF8F98009C010B3024A3
+:10A180003639FFFF00D96024ACAC000C8F030014FB
+:10A19000971F00128F870098ACA300108F0900143E
+:10A1A000ACA00018ACA00020ACA90014ACA0002406
+:10A1B0008F0A001833E93FFF00091180ACAA00287C
+:10A1C0008F1200080047782133EE0001ACB2003056
+:10A1D0008F08000C8F990038000F69C2000E238091
+:10A1E00001A45821241100023C068008A4AB001CE5
+:10A1F000A4A00034ACA8002CA331000034D9008006
+:10A20000972C005C8F8F00383C034200318AFFFF9F
+:10A2100001433825ADE700048F82009C241800011B
+:10A220002411C0008C5F003824070034ADFF0018F3
+:10A230008C520034ADF2001CADE0000CADE000101B
+:10A24000A5E00014A5E00016A5E00020A5E000228E
+:10A25000ADE00024A5F00002A1F800018F8B0038CA
+:10A260008F8E009CAD70000891CD0000A16D003074
+:10A270008F88009C8F84003891050001A0850031F3
+:10A280008F920038964C00320191502401491825D4
+:10A29000A6430032925F003233E2003FA242003216
+:10A2A0009338007C330F000215E000028F840038E1
+:10A2B000240700303C028008AC870034345201008F
+:10A2C0008E5F00C0240EFFBF02009021AC9F0038BB
+:10A2D0009098003C330F007FA08F003C8F8800389F
+:10A2E000910D003C01AE5824A10B003C8F86003834
+:10A2F00090D1003C36390020A0D9003C8F8A009CC8
+:10A300008F8500380010882B8D4C0020ACAC0040AD
+:10A310008D430024ACA300448D490028ACA900481B
+:10A320008D47002CACA7004C0E000EF23C108000B4
+:10A330000A00114C0000000094CD00523C0B0800B4
+:10A340008D6B0024016D8821A4D100520A0010F702
+:10A35000001E882BA08700018F840038240D000187
+:10A36000AC8D00080A0012953C188008000290800D
+:10A370000A00137400D2302127BDFFE03C0D800895
+:10A38000AFB20018AFB00010AFBF001CAFB10014E7
+:10A3900035B200808E4C001835A80100964B00069F
+:10A3A00095A70050910900EC000C56020167282384
+:10A3B0003143007F312600FF24020003A38300A065
+:10A3C000AF84009810C2001B30B0FFFF910600EC74
+:10A3D0002412000530C200FF1052003300000000BC
+:10A3E000160000098FBF001C8FB200188FB1001437
+:10A3F0008FB00010240D0C003C0C800027BD002005
+:10A4000003E00008AD8D00240E0010DA02002021C8
+:10A410008FBF001C8FB200188FB100148FB00010D6
+:10A42000240D0C003C0C800027BD002003E0000838
+:10A43000AD8D0024965800789651007A924E007D9A
+:10A440000238782631E8FFFF31C400C014800009CB
+:10A450002D11000116000037000000005620FFE219
+:10A460008FBF001C0E000FB0000000000A00143C5B
+:10A470008FBF001C1620FFDA000000000E000FB096
+:10A48000000000001440FFD88FBF001C16000022FF
+:10A4900000000000925F007D33E2003FA242007D99
+:10A4A0000A00143C8FBF001C950900DA8F860078E3
+:10A4B00000802821240400050E0006AA3130FFFF89
+:10A4C0009783008A3C0480002465FFFFA785008AEB
+:10A4D0008C8A01B80540FFFE00000000AC800180BE
+:10A4E0008FBF001CAC9001848FB200188FB1001494
+:10A4F0008FB000103C0760133C0B1000240D0C00C3
+:10A500003C0C800027BD0020AC870188AC8B01B8D3
+:10A5100003E00008AD8D00240E0010DA02002021B7
+:10A520005040FFB18FBF001C925F007D0A0014698C
+:10A5300033E2003F0E0010DA020020211440FFAA8F
+:10A540008FBF001C12200007000000009259007D00
+:10A550003330003F36020040A242007D0A00143C26
+:10A560008FBF001C0E000FB0000000005040FF9E87
+:10A570008FBF001C9259007D3330003F0A001498B1
+:04A58000360200405F
+:0CA58400000000000000001B0000000FA1
+:10A590000000000A0000000800000006000000059E
+:10A5A000000000050000000400000004000000039B
+:10A5B000000000030000000300000003000000038F
+:10A5C0000000000200000002000000020000000283
+:10A5D0000000000200000002000000020000000273
+:10A5E0000000000200000002000000020000000263
+:10A5F0000000000200000002000000020000000154
+:08A60000000000010000000150
+:08A608008008010080080080B9
+:10A610008008000000000C000000308008001020BE
+:10A62000080010CC080010E4080010F80800110C15
+:10A6300008001020080010200800114008001178C0
+:10A6400008001188080011B0080018A0080018A020
+:10A65000080018D8080018D8080018EC080018BC22
+:10A6600008001B1408001AE008001B6C08001B6C93
+:10A6700008001BF408001B24800802400800228008
+:10A68000080020CC080022A80800234008002490DD
+:10A69000080024DC08002600080025080800258C96
+:10A6A0000800213C08002AA808002A4C080020E8DD
+:10A6B000080020E8080020E8080026740800267436
+:10A6C000080020E8080020E808002924080020E805
+:10A6D000080020E8080020E8080020E80800298495
+:10A6E000080020E8080020E8080020E8080020E82A
+:10A6F000080020E8080020E8080020E8080020E81A
+:10A70000080020E8080020E8080020E8080020E809
+:10A71000080020E8080020E8080024FC080020E8E1
+:10A72000080020E8080029F4080020E8080020E8D4
+:10A73000080020E8080020E8080020E8080020E8D9
+:10A74000080020E8080020E8080020E8080020E8C9
+:10A75000080020E8080020E8080020E8080020E8B9
+:10A76000080020E8080020E8080020E80800284841
+:10A77000080020E8080020E8080027BC0800271887
+:10A78000080038600800383408003800080037D462
+:10A79000080037B40800376880080100800800808E
+:10A7A0008008000080080080080047C808004800B2
+:10A7B00008004748080047C8080047C8080045285F
+:08A7C000080047C808004B9C8B
+:08A7C8000A000C7600000000FD
+:10A7D000000000000000000D727870352E302E3021
+:10A7E0006A31350005000003000000000000000190
+:10A7F0000000000000000000000000000000000059
+:10A800000000000000000000000000000000000048
+:10A810000000000000000000000000000000000038
+:10A820000000000000000000000000000000000028
+:10A830000000000000000000000000000000000018
+:10A840000000000000000000000000000000000008
+:10A8500000000000000000000000000000000000F8
+:10A8600000000000000000000000000000000000E8
+:10A8700000000000000000000000000000000000D8
+:10A8800000000000000000000000000000000000C8
+:10A8900000000000000000000000000000000000B8
+:10A8A00000000000000000000000000000000000A8
+:10A8B0000000000000000000000000000000000098
+:10A8C0000000000000000000000000000000000088
+:10A8D0000000000000000000000000000000000078
+:10A8E0000000000000000000000000000000000068
+:10A8F0000000000000000000000000000000000058
+:10A900000000000000000000000000000000000047
+:10A910000000000000000000000000000000000037
+:10A920000000000000000000000000000000000027
+:10A930000000000000000000000000000000000017
+:10A940000000000000000000000000000000000007
+:10A9500000000000000000000000000000000000F7
+:10A9600000000000000000000000000000000000E7
+:10A9700000000000000000000000000000000000D7
+:10A9800000000000000000000000000000000000C7
+:10A9900000000000000000000000000000000000B7
+:10A9A00000000000000000000000000000000000A7
+:10A9B0000000000000000000000000000000000097
+:10A9C0000000000000000000000000000000000087
+:10A9D0000000000000000000000000000000000077
+:10A9E0000000000000000000000000000000000067
+:10A9F0000000000000000000000000000000000057
+:10AA00000000000000000000000000000000000046
+:10AA10000000000000000000000000000000000036
+:10AA20000000000000000000000000000000000026
+:10AA30000000000000000000000000000000000016
+:10AA40000000000000000000000000000000000006
+:10AA500000000000000000000000000000000000F6
+:10AA600000000000000000000000000000000000E6
+:10AA700000000000000000000000000000000000D6
+:10AA800000000000000000000000000000000000C6
+:10AA900000000000000000000000000000000000B6
+:10AAA00000000000000000000000000000000000A6
+:10AAB0000000000000000000000000000000000096
+:10AAC0000000000000000000000000000000000086
+:10AAD0000000000000000000000000000000000076
+:10AAE0000000000000000000000000000000000066
+:10AAF0000000000000000000000000000000000056
+:10AB00000000000000000000000000000000000045
+:10AB10000000000000000000000000000000000035
+:10AB20000000000000000000000000000000000025
+:10AB30000000000000000000000000000000000015
+:10AB40000000000000000000000000000000000005
+:10AB500000000000000000000000000000000000F5
+:10AB600000000000000000000000000000000000E5
+:10AB700000000000000000000000000000000000D5
+:10AB800000000000000000000000000000000000C5
+:10AB900000000000000000000000000000000000B5
+:10ABA00000000000000000000000000000000000A5
+:10ABB0000000000000000000000000000000000095
+:10ABC0000000000000000000000000000000000085
+:10ABD0000000000000000000000000000000000075
+:10ABE0000000000000000000000000000000000065
+:10ABF0000000000000000000000000000000000055
+:10AC00000000000000000000000000000000000044
+:10AC10000000000000000000000000000000000034
+:10AC20000000000000000000000000000000000024
+:10AC30000000000000000000000000000000000014
+:10AC40000000000000000000000000000000000004
+:10AC500000000000000000000000000000000000F4
+:10AC600000000000000000000000000000000000E4
+:10AC700000000000000000000000000000000000D4
+:10AC800000000000000000000000000000000000C4
+:10AC900000000000000000000000000000000000B4
+:10ACA00000000000000000000000000000000000A4
+:10ACB0000000000000000000000000000000000094
+:10ACC0000000000000000000000000000000000084
+:10ACD0000000000000000000000000000000000074
+:10ACE0000000000000000000000000000000000064
+:10ACF0000000000000000000000000000000000054
+:10AD00000000000000000000000000000000000043
+:10AD10000000000000000000000000000000000033
+:10AD20000000000000000000000000000000000023
+:10AD30000000000000000000000000000000000013
+:10AD40000000000000000000000000000000000003
+:10AD500000000000000000000000000000000000F3
+:10AD600000000000000000000000000000000000E3
+:10AD700000000000000000000000000000000000D3
+:10AD800000000000000000000000000000000000C3
+:10AD900000000000000000000000000000000000B3
+:10ADA00000000000000000000000000000000000A3
+:10ADB0000000000000000000000000000000000093
+:10ADC0000000000000000000000000000000000083
+:10ADD0000000000000000000000000000000000073
+:10ADE0000000000000000000000000000000000063
+:10ADF0000000000000000000000000000000000053
+:10AE00000000000000000000000000000000000042
+:10AE10000000000000000000000000000000000032
+:10AE20000000000000000000000000000000000022
+:10AE30000000000000000000000000000000000012
+:10AE40000000000000000000000000000000000002
+:10AE500000000000000000000000000000000000F2
+:10AE600000000000000000000000000000000000E2
+:10AE700000000000000000000000000000000000D2
+:10AE800000000000000000000000000000000000C2
+:10AE900000000000000000000000000000000000B2
+:10AEA00000000000000000000000000000000000A2
+:10AEB0000000000000000000000000000000000092
+:10AEC0000000000000000000000000000000000082
+:10AED0000000000000000000000000000000000072
+:10AEE0000000000000000000000000000000000062
+:10AEF0000000000000000000000000000000000052
+:10AF00000000000000000000000000000000000041
+:10AF10000000000000000000000000000000000031
+:10AF20000000000000000000000000000000000021
+:10AF30000000000000000000000000000000000011
+:10AF40000000000000000000000000000000000001
+:10AF500000000000000000000000000000000000F1
+:10AF600000000000000000000000000000000000E1
+:10AF700000000000000000000000000000000000D1
+:10AF800000000000000000000000000000000000C1
+:10AF900000000000000000000000000000000000B1
+:10AFA00000000000000000000000000000000000A1
+:10AFB0000000000000000000000000000000000091
+:10AFC0000000000000000000000000000000000081
+:10AFD0000000000000000000000000000000000071
+:10AFE0000000000000000000000000000000000061
+:10AFF0000000000000000000000000000000000051
+:10B000000000000000000000000000000000000040
+:10B010000000000000000000000000000000000030
+:10B020000000000000000000000000000000000020
+:10B030000000000000000000000000000000000010
+:10B040000000000000000000000000000000000000
+:10B0500000000000000000000000000000000000F0
+:10B0600000000000000000000000000000000000E0
+:10B0700000000000000000000000000000000000D0
+:10B0800000000000000000000000000000000000C0
+:10B0900000000000000000000000000000000000B0
+:10B0A00000000000000000000000000000000000A0
+:10B0B0000000000000000000000000000000000090
+:10B0C0000000000000000000000000000000000080
+:10B0D0000000000000000000000000000000000070
+:10B0E0000000000000000000000000000000000060
+:10B0F0000000000000000000000000000000000050
+:10B10000000000000000000000000000000000003F
+:10B11000000000000000000000000000000000002F
+:10B12000000000000000000000000000000000001F
+:10B13000000000000000000000000000000000000F
+:10B1400000000000000000000000000000000000FF
+:10B1500000000000000000000000000000000000EF
+:10B1600000000000000000000000000000000000DF
+:10B1700000000000000000000000000000000000CF
+:10B1800000000000000000000000000000000000BF
+:10B1900000000000000000000000000000000000AF
+:10B1A000000000000000000000000000000000009F
+:10B1B000000000000000000000000000000000008F
+:10B1C000000000000000000000000000000000007F
+:10B1D000000000000000000000000000000000006F
+:10B1E000000000000000000000000000000000005F
+:10B1F000000000000000000000000000000000004F
+:10B20000000000000000000000000000000000003E
+:10B21000000000000000000000000000000000002E
+:10B22000000000000000000000000000000000001E
+:10B23000000000000000000000000000000000000E
+:10B2400000000000000000000000000000000000FE
+:10B2500000000000000000000000000000000000EE
+:10B2600000000000000000000000000000000000DE
+:10B2700000000000000000000000000000000000CE
+:10B2800000000000000000000000000000000000BE
+:10B2900000000000000000000000000000000000AE
+:10B2A000000000000000000000000000000000009E
+:10B2B000000000000000000000000000000000008E
+:10B2C000000000000000000000000000000000007E
+:10B2D000000000000000000000000000000000006E
+:10B2E000000000000000000000000000000000005E
+:10B2F000000000000000000000000000000000004E
+:10B30000000000000000000000000000000000003D
+:10B31000000000000000000000000000000000002D
+:10B32000000000000000000000000000000000001D
+:10B33000000000000000000000000000000000000D
+:10B3400000000000000000000000000000000000FD
+:10B3500000000000000000000000000000000000ED
+:10B3600000000000000000000000000000000000DD
+:10B3700000000000000000000000000000000000CD
+:10B3800000000000000000000000000000000000BD
+:10B3900000000000000000000000000000000000AD
+:10B3A000000000000000000000000000000000009D
+:10B3B000000000000000000000000000000000008D
+:10B3C000000000000000000000000000000000007D
+:10B3D000000000000000000000000000000000006D
+:10B3E000000000000000000000000000000000005D
+:10B3F000000000000000000000000000000000004D
+:10B40000000000000000000000000000000000003C
+:10B41000000000000000000000000000000000002C
+:10B42000000000000000000000000000000000001C
+:10B43000000000000000000000000000000000000C
+:10B4400000000000000000000000000000000000FC
+:10B4500000000000000000000000000000000000EC
+:10B4600000000000000000000000000000000000DC
+:10B4700000000000000000000000000000000000CC
+:10B4800000000000000000000000000000000000BC
+:10B4900000000000000000000000000000000000AC
+:10B4A000000000000000000000000000000000009C
+:10B4B000000000000000000000000000000000008C
+:10B4C000000000000000000000000000000000007C
+:10B4D000000000000000000000000000000000006C
+:10B4E000000000000000000000000000000000005C
+:10B4F000000000000000000000000000000000004C
+:10B50000000000000000000000000000000000003B
+:10B51000000000000000000000000000000000002B
+:10B52000000000000000000000000000000000001B
+:10B53000000000000000000000000000000000000B
+:10B5400000000000000000000000000000000000FB
+:10B5500000000000000000000000000000000000EB
+:10B5600000000000000000000000000000000000DB
+:10B5700000000000000000000000000000000000CB
+:10B5800000000000000000000000000000000000BB
+:10B5900000000000000000000000000000000000AB
+:10B5A000000000000000000000000000000000009B
+:10B5B000000000000000000000000000000000008B
+:10B5C000000000000000000000000000000000007B
+:10B5D000000000000000000000000000000000006B
+:10B5E000000000000000000000000000000000005B
+:10B5F000000000000000000000000000000000004B
+:10B60000000000000000000000000000000000003A
+:10B61000000000000000000000000000000000002A
+:10B62000000000000000000000000000000000001A
+:10B63000000000000000000000000000000000000A
+:10B6400000000000000000000000000000000000FA
+:10B6500000000000000000000000000000000000EA
+:10B6600000000000000000000000000000000000DA
+:10B6700000000000000000000000000000000000CA
+:10B6800000000000000000000000000000000000BA
+:10B6900000000000000000000000000000000000AA
+:10B6A000000000000000000000000000000000009A
+:10B6B000000000000000000000000000000000008A
+:10B6C000000000000000000000000000000000007A
+:10B6D000000000000000000000000000000000006A
+:10B6E000000000000000000000000000000000005A
+:10B6F000000000000000000000000000000000004A
+:10B700000000000000000000000000000000000039
+:10B710000000000000000000000000000000000029
+:10B720000000000000000000000000000000000019
+:10B730000000000000000000000000000000000009
+:10B7400000000000000000000000000000000000F9
+:10B7500000000000000000000000000000000000E9
+:10B7600000000000000000000000000000000000D9
+:10B7700000000000000000000000000000000000C9
+:10B7800000000000000000000000000000000000B9
+:10B7900000000000000000000000000000000000A9
+:10B7A0000000000000000000000000000000000099
+:10B7B0000000000000000000000000000000000089
+:10B7C0000000000000000000000000000000000079
+:10B7D0000000000000000000000000000000000069
+:10B7E0000000000000000000000000000000000059
+:10B7F0000000000000000000000000000000000049
+:10B800000000000000000000000000000000000038
+:10B810000000000000000000000000000000000028
+:10B820000000000000000000000000000000000018
+:10B830000000000000000000000000000000000008
+:10B8400000000000000000000000000000000000F8
+:10B8500000000000000000000000000000000000E8
+:10B8600000000000000000000000000000000000D8
+:10B8700000000000000000000000000000000000C8
+:10B8800000000000000000000000000000000000B8
+:10B8900000000000000000000000000000000000A8
+:10B8A0000000000000000000000000000000000098
+:10B8B0000000000000000000000000000000000088
+:10B8C0000000000000000000000000000000000078
+:10B8D0000000000000000000000000000000000068
+:10B8E0000000000000000000000000000000000058
+:10B8F0000000000000000000000000000000000048
+:10B900000000000000000000000000000000000037
+:10B910000000000000000000000000000000000027
+:10B920000000000000000000000000000000000017
+:10B930000000000000000000000000000000000007
+:10B9400000000000000000000000000000000000F7
+:10B9500000000000000000000000000000000000E7
+:10B9600000000000000000000000000000000000D7
+:10B9700000000000000000000000000000000000C7
+:10B9800000000000000000000000000000000000B7
+:10B9900000000000000000000000000000000000A7
+:10B9A0000000000000000000000000000000000097
+:10B9B0000000000000000000000000000000000087
+:10B9C0000000000000000000000000000000000077
+:10B9D0000000000000000000000000000000000067
+:10B9E0000000000000000000000000000000000057
+:10B9F0000000000000000000000000000000000047
+:10BA00000000000000000000000000000000000036
+:10BA10000000000000000000000000000000000026
+:10BA20000000000000000000000000000000000016
+:10BA30000000000000000000000000000000000006
+:10BA400000000000000000000000000000000000F6
+:10BA500000000000000000000000000000000000E6
+:10BA600000000000000000000000000000000000D6
+:10BA700000000000000000000000000000000000C6
+:10BA800000000000000000000000000000000000B6
+:10BA900000000000000000000000000000000000A6
+:10BAA0000000000000000000000000000000000096
+:10BAB0000000000000000000000000000000000086
+:10BAC0000000000000000000000000000000000076
+:10BAD0000000000000000000000000000000000066
+:10BAE0000000000000000000000000000000000056
+:10BAF0000000000000000000000000000000000046
+:10BB00000000000000000000000000000000000035
+:10BB10000000000000000000000000000000000025
+:10BB20000000000000000000000000000000000015
+:10BB30000000000000000000000000000000000005
+:10BB400000000000000000000000000000000000F5
+:10BB500000000000000000000000000000000000E5
+:10BB600000000000000000000000000000000000D5
+:10BB700000000000000000000000000000000000C5
+:10BB800000000000000000000000000000000000B5
+:10BB900000000000000000000000000000000000A5
+:10BBA0000000000000000000000000000000000095
+:10BBB0000000000000000000000000000000000085
+:10BBC0000000000000000000000000000000000075
+:10BBD0000000000000000000000000000000000065
+:10BBE0000000000000000000000000000000000055
+:10BBF0000000000000000000000000000000000045
+:10BC00000000000000000000000000000000000034
+:10BC10000000000000000000000000000000000024
+:10BC20000000000000000000000000000000000014
+:10BC30000000000000000000000000000000000004
+:10BC400000000000000000000000000000000000F4
+:10BC500000000000000000000000000000000000E4
+:10BC600000000000000000000000000000000000D4
+:10BC700000000000000000000000000000000000C4
+:10BC800000000000000000000000000000000000B4
+:10BC900000000000000000000000000000000000A4
+:10BCA0000000000000000000000000000000000094
+:10BCB0000000000000000000000000000000000084
+:10BCC0000000000000000000000000000000000074
+:10BCD0000000000000000000000000000000000064
+:10BCE0000000000000000000000000000000000054
+:10BCF0000000000000000000000000000000000044
+:10BD00000000000000000000000000000000000033
+:10BD10000000000000000000000000000000000023
+:10BD20000000000000000000000000000000000013
+:10BD30000000000000000000000000000000000003
+:10BD400000000000000000000000000000000000F3
+:10BD500000000000000000000000000000000000E3
+:10BD600000000000000000000000000000000000D3
+:10BD700000000000000000000000000000000000C3
+:10BD800000000000000000000000000000000000B3
+:10BD900000000000000000000000000000000000A3
+:10BDA0000000000000000000000000000000000093
+:10BDB0000000000000000000000000000000000083
+:10BDC0000000000000000000000000000000000073
+:10BDD0000000000000000000000000000000000063
+:10BDE0000000000000000000000000000000000053
+:10BDF0000000000000000000000000000000000043
+:10BE00000000000000000000000000000000000032
+:10BE10000000000000000000000000000000000022
+:10BE20000000000000000000000000000000000012
+:10BE30000000000000000000000000000000000002
+:10BE400000000000000000000000000000000000F2
+:10BE500000000000000000000000000000000000E2
+:10BE600000000000000000000000000000000000D2
+:10BE700000000000000000000000000000000000C2
+:10BE800000000000000000000000000000000000B2
+:10BE900000000000000000000000000000000000A2
+:10BEA0000000000000000000000000000000000092
+:10BEB0000000000000000000000000000000000082
+:10BEC0000000000000000000000000000000000072
+:10BED0000000000000000000000000000000000062
+:10BEE0000000000000000000000000000000000052
+:10BEF0000000000000000000000000000000000042
+:10BF00000000000000000000000000000000000031
+:10BF10000000000000000000000000000000000021
+:10BF20000000000000000000000000000000000011
+:10BF30000000000000000000000000000000000001
+:10BF400000000000000000000000000000000000F1
+:10BF500000000000000000000000000000000000E1
+:10BF600000000000000000000000000000000000D1
+:10BF700000000000000000000000000000000000C1
+:10BF800000000000000000000000000000000000B1
+:10BF900000000000000000000000000000000000A1
+:10BFA0000000000000000000000000000000000091
+:10BFB0000000000000000000000000000000000081
+:10BFC0000000000000000000000000000000000071
+:10BFD0000000000000000000000000000000000061
+:10BFE0000000000000000000000000000000000051
+:10BFF0000000000000000000000000000000000041
+:10C000000000000000000000000000000000000030
+:10C010000000000000000000000000000000000020
+:10C020000000000000000000000000000000000010
+:10C030000000000000000000000000000000000000
+:10C0400000000000000000000000000000000000F0
+:10C0500000000000000000000000000000000000E0
+:10C0600000000000000000000000000000000000D0
+:10C0700000000000000000000000000000000000C0
+:10C0800000000000000000000000000000000000B0
+:10C0900000000000000000000000000000000000A0
+:10C0A0000000000000000000000000000000000090
+:10C0B0000000000000000000000000000000000080
+:10C0C0000000000000000000000000000000000070
+:10C0D0000000000000000000000000000000000060
+:10C0E0000000000000000000000000000000000050
+:10C0F0000000000000000000000000000000000040
+:10C10000000000000000000000000000000000002F
+:10C11000000000000000000000000000000000001F
+:10C12000000000000000000000000000000000000F
+:10C1300000000000000000000000000000000000FF
+:10C1400000000000000000000000000000000000EF
+:10C1500000000000000000000000000000000000DF
+:10C1600000000000000000000000000000000000CF
+:10C1700000000000000000000000000000000000BF
+:10C1800000000000000000000000000000000000AF
+:10C19000000000000000000000000000000000009F
+:10C1A000000000000000000000000000000000008F
+:10C1B000000000000000000000000000000000007F
+:10C1C000000000000000000000000000000000006F
+:10C1D000000000000000000000000000000000005F
+:10C1E000000000000000000000000000000000004F
+:10C1F000000000000000000000000000000000003F
+:10C20000000000000000000000000000000000002E
+:10C21000000000000000000000000000000000001E
+:10C22000000000000000000000000000000000000E
+:10C2300000000000000000000000000000000000FE
+:10C2400000000000000000000000000000000000EE
+:10C2500000000000000000000000000000000000DE
+:10C2600000000000000000000000000000000000CE
+:10C2700000000000000000000000000000000000BE
+:10C2800000000000000000000000000000000000AE
+:10C29000000000000000000000000000000000009E
+:10C2A000000000000000000000000000000000008E
+:10C2B000000000000000000000000000000000007E
+:10C2C000000000000000000000000000000000006E
+:10C2D000000000000000000000000000000000005E
+:10C2E000000000000000000000000000000000004E
+:10C2F000000000000000000000000000000000003E
+:10C30000000000000000000000000000000000002D
+:10C31000000000000000000000000000000000001D
+:10C32000000000000000000000000000000000000D
+:10C3300000000000000000000000000000000000FD
+:10C3400000000000000000000000000000000000ED
+:10C3500000000000000000000000000000000000DD
+:10C3600000000000000000000000000000000000CD
+:10C3700000000000000000000000000000000000BD
+:10C3800000000000000000000000000000000000AD
+:10C39000000000000000000000000000000000009D
+:10C3A000000000000000000000000000000000008D
+:10C3B000000000000000000000000000000000007D
+:10C3C000000000000000000000000000000000006D
+:10C3D000000000000000000000000000000000005D
+:10C3E000000000000000000000000000000000004D
+:10C3F000000000000000000000000000000000003D
+:10C40000000000000000000000000000000000002C
+:10C41000000000000000000000000000000000001C
+:10C42000000000000000000000000000000000000C
+:10C4300000000000000000000000000000000000FC
+:10C4400000000000000000000000000000000000EC
+:10C4500000000000000000000000000000000000DC
+:10C4600000000000000000000000000000000000CC
+:10C4700000000000000000000000000000000000BC
+:10C4800000000000000000000000000000000000AC
+:10C49000000000000000000000000000000000009C
+:10C4A000000000000000000000000000000000008C
+:10C4B000000000000000000000000000000000007C
+:10C4C000000000000000000000000000000000006C
+:10C4D000000000000000000000000000000000005C
+:10C4E000000000000000000000000000000000004C
+:10C4F000000000000000000000000000000000003C
+:10C50000000000000000000000000000000000002B
+:10C51000000000000000000000000000000000001B
+:10C52000000000000000000000000000000000000B
+:10C5300000000000000000000000000000000000FB
+:10C5400000000000000000000000000000000000EB
+:10C5500000000000000000000000000000000000DB
+:10C5600000000000000000000000000000000000CB
+:10C5700000000000000000000000000000000000BB
+:10C5800000000000000000000000000000000000AB
+:10C59000000000000000000000000000000000009B
+:10C5A000000000000000000000000000000000008B
+:10C5B000000000000000000000000000000000007B
+:10C5C000000000000000000000000000000000006B
+:10C5D000000000000000000000000000000000005B
+:10C5E000000000000000000000000000000000004B
+:10C5F000000000000000000000000000000000003B
+:10C60000000000000000000000000000000000002A
+:10C61000000000000000000000000000000000001A
+:10C62000000000000000000000000000000000000A
+:10C6300000000000000000000000000000000000FA
+:10C6400000000000000000000000000000000000EA
+:10C6500000000000000000000000000000000000DA
+:10C6600000000000000000000000000000000000CA
+:10C6700000000000000000000000000000000000BA
+:10C6800000000000000000000000000000000000AA
+:10C69000000000000000000000000000000000009A
+:10C6A000000000000000000000000000000000008A
+:10C6B000000000000000000000000000000000007A
+:10C6C000000000000000000000000000000000006A
+:10C6D000000000000000000000000000000000005A
+:10C6E000000000000000000000000000000000004A
+:10C6F000000000000000000000000000000000003A
+:10C700000000000000000000000000000000000029
+:10C710000000000000000000000000000000000019
+:10C720000000000000000000000000000000000009
+:10C7300000000000000000000000000000000000F9
+:10C7400000000000000000000000000000000000E9
+:10C7500000000000000000000000000000000000D9
+:10C7600000000000000000000000000000000000C9
+:10C7700000000000000000000000000000000000B9
+:10C7800000000000000000000000000000000000A9
+:10C790000000000000000000000000000000000099
+:10C7A0000000000000000000000000000000000089
+:10C7B0000000000000000000000000000000000079
+:10C7C0000000000000000000000000000000000069
+:10C7D0000000000000000000000000000000000059
+:10C7E0000000000000000000000000000000000049
+:10C7F0000000000000000000000000000000000039
+:10C800000000000000000000000000000000000028
+:10C810000000000000000000000000000000000018
+:10C820000000000000000000000000000000000008
+:10C8300000000000000000000000000000000000F8
+:10C8400000000000000000000000000000000000E8
+:10C8500000000000000000000000000000000000D8
+:10C8600000000000000000000000000000000000C8
+:10C8700000000000000000000000000000000000B8
+:10C8800000000000000000000000000000000000A8
+:10C890000000000000000000000000000000000098
+:10C8A0000000000000000000000000000000000088
+:10C8B0000000000000000000000000000000000078
+:10C8C0000000000000000000000000000000000068
+:10C8D0000000000000000000000000000000000058
+:10C8E0000000000000000000000000000000000048
+:10C8F0000000000000000000000000000000000038
+:10C900000000000000000000000000000000000027
+:10C910000000000000000000000000000000000017
+:10C920000000000000000000000000000000000007
+:10C9300000000000000000000000000000000000F7
+:10C9400000000000000000000000000000000000E7
+:10C9500000000000000000000000000000000000D7
+:10C9600000000000000000000000000000000000C7
+:10C9700000000000000000000000000000000000B7
+:10C9800000000000000000000000000000000000A7
+:10C990000000000000000000000000000000000097
+:10C9A0000000000000000000000000000000000087
+:10C9B0000000000000000000000000000000000077
+:10C9C0000000000000000000000000000000000067
+:10C9D0000000000000000000000000000000000057
+:10C9E0000000000000000000000000000000000047
+:10C9F0000000000000000000000000000000000037
+:10CA00000000000000000000000000000000000026
+:10CA10000000000000000000000000000000000016
+:10CA20000000000000000000000000000000000006
+:10CA300000000000000000000000000000000000F6
+:10CA400000000000000000000000000000000000E6
+:10CA500000000000000000000000000000000000D6
+:10CA600000000000000000000000000000000000C6
+:10CA700000000000000000000000000000000000B6
+:10CA800000000000000000000000000000000000A6
+:10CA90000000000000000000000000000000000096
+:10CAA0000000000000000000000000000000000086
+:10CAB0000000000000000000000000000000000076
+:10CAC0000000000000000000000000000000000066
+:10CAD0000000000000000000000000000000000056
+:10CAE0000000000000000000000000000000000046
+:10CAF0000000000000000000000000000000000036
+:10CB00000000000000000000000000000000000025
+:10CB10000000000000000000000000000000000015
+:10CB20000000000000000000000000000000000005
+:10CB300000000000000000000000000000000000F5
+:10CB400000000000000000000000000000000000E5
+:10CB500000000000000000000000000000000000D5
+:10CB600000000000000000000000000000000000C5
+:10CB700000000000000000000000000000000000B5
+:10CB800000000000000000000000000000000000A5
+:10CB90000000000000000000000000000000000095
+:10CBA0000000000000000000000000000000000085
+:10CBB0000000000000000000000000000000000075
+:10CBC0000000000000000000000000000000000065
+:10CBD0000000000000000000000000000000000055
+:10CBE0000000000000000000000000000000000045
+:10CBF0000000000000000000000000000000000035
+:10CC00000000000000000000000000000000000024
+:10CC10000000000000000000000000000000000014
+:10CC20000000000000000000000000000000000004
+:10CC300000000000000000000000000000000000F4
+:10CC400000000000000000000000000000000000E4
+:10CC500000000000000000000000000000000000D4
+:10CC600000000000000000000000000000000000C4
+:10CC700000000000000000000000000000000000B4
+:10CC800000000000000000000000000000000000A4
+:10CC90000000000000000000000000000000000094
+:10CCA0000000000000000000000000000000000084
+:10CCB0000000000000000000000000000000000074
+:10CCC0000000000000000000000000000000000064
+:10CCD0000000000000000000000000000000000054
+:10CCE0000000000000000000000000000000000044
+:10CCF0000000000000000000000000000000000034
+:10CD00000000000000000000000000000000000023
+:10CD10000000000000000000000000000000000013
+:10CD20000000000000000000000000000000000003
+:10CD300000000000000000000000000000000000F3
+:10CD400000000000000000000000000000000000E3
+:10CD500000000000000000000000000000000000D3
+:10CD600000000000000000000000000000000000C3
+:10CD700000000000000000000000000000000000B3
+:10CD800000000000000000000000000000000000A3
+:10CD90000000000000000000000000000000000093
+:10CDA0000000000000000000000000000000000083
+:10CDB0000000000000000000000000000000000073
+:10CDC0000000000000000000000000000000000063
+:10CDD0000000000000000000000000000000000053
+:10CDE0000000000000000000000000000000000043
+:10CDF0000000000000000000000000000000000033
+:10CE00000000000000000000000000000000000022
+:10CE10000000000000000000000000000000000012
+:10CE20000000000000000000000000000000000002
+:10CE300000000000000000000000000000000000F2
+:10CE400000000000000000000000000000000000E2
+:10CE500000000000000000000000000000000000D2
+:10CE600000000000000000000000000000000000C2
+:10CE700000000000000000000000000000000000B2
+:10CE800000000000000000000000000000000000A2
+:10CE90000000000000000000000000000000000092
+:10CEA0000000000000000000000000000000000082
+:10CEB0000000000000000000000000000000000072
+:10CEC0000000000000000000000000000000000062
+:10CED0000000000000000000000000000000000052
+:10CEE0000000000000000000000000000000000042
+:10CEF0000000000000000000000000000000000032
+:10CF00000000000000000000000000000000000021
+:10CF10000000000000000000000000000000000011
+:10CF20000000000000000000000000000000000001
+:10CF300000000000000000000000000000000000F1
+:10CF400000000000000000000000000000000000E1
+:10CF500000000000000000000000000000000000D1
+:10CF600000000000000000000000000000000000C1
+:10CF700000000000000000000000000000000000B1
+:10CF800000000000000000000000000000000000A1
+:10CF90000000000000000000000000000000000091
+:10CFA0000000000000000000000000000000000081
+:10CFB0000000000000000000000000000000000071
+:10CFC0000000000000000000000000000000000061
+:10CFD0000000000000000000000000000000000051
+:10CFE0000000000000000000000000000000000041
+:10CFF0000000000000000000000000000000000031
+:10D000000000000000000000000000000000000020
+:10D010000000000000000000000000000000000010
+:10D020000000000000000000000000000000000000
+:10D0300000000000000000000000000000000000F0
+:10D0400000000000000000000000000000000000E0
+:10D0500000000000000000000000000000000000D0
+:10D0600000000000000000000000000000000000C0
+:10D0700000000000000000000000000000000000B0
+:10D0800000000000000000000000000000000000A0
+:10D090000000000000000000000000000000000090
+:10D0A0000000000000000000000000000000000080
+:10D0B0000000000000000000000000000000000070
+:10D0C0000000000000000000000000000000000060
+:10D0D0000000000000000000000000000000000050
+:10D0E0000000000000000000000000000000000040
+:10D0F0000000000000000000000000000000000030
+:10D10000000000000000000000000000000000001F
+:10D11000000000000000000000000000000000000F
+:10D1200000000000000000000000000000000000FF
+:10D1300000000000000000000000000000000000EF
+:10D1400000000000000000000000000000000000DF
+:10D1500000000000000000000000000000000000CF
+:10D1600000000000000000000000000000000000BF
+:10D1700000000000000000000000000000000000AF
+:10D18000000000000000000000000000000000009F
+:10D19000000000000000000000000000000000008F
+:10D1A000000000000000000000000000000000007F
+:10D1B000000000000000000000000000000000006F
+:10D1C000000000000000000000000000000000005F
+:10D1D000000000000000000000000000000000004F
+:10D1E000000000000000000000000000000000003F
+:10D1F000000000000000000000000000000000002F
+:10D20000000000000000000000000000000000001E
+:10D21000000000000000000000000000000000000E
+:10D2200000000000000000000000000000000000FE
+:10D2300000000000000000000000000000000000EE
+:10D2400000000000000000000000000000000000DE
+:10D2500000000000000000000000000000000000CE
+:10D2600000000000000000000000000000000000BE
+:10D2700000000000000000000000000000000000AE
+:10D28000000000000000000000000000000000009E
+:10D29000000000000000000000000000000000008E
+:10D2A000000000000000000000000000000000007E
+:10D2B000000000000000000000000000000000006E
+:10D2C000000000000000000000000000000000005E
+:10D2D000000000000000000000000000000000004E
+:10D2E000000000000000000000000000000000003E
+:10D2F000000000000000000000000000000000002E
+:10D30000000000000000000000000000000000001D
+:10D31000000000000000000000000000000000000D
+:10D3200000000000000000000000000000000000FD
+:10D3300000000000000000000000000000000000ED
+:10D3400000000000000000000000000000000000DD
+:10D3500000000000000000000000000000000000CD
+:10D3600000000000000000000000000000000000BD
+:10D3700000000000000000000000000000000000AD
+:10D38000000000000000000000000000000000009D
+:10D39000000000000000000000000000000000008D
+:10D3A000000000000000000000000000000000007D
+:10D3B000000000000000000000000000000000006D
+:10D3C000000000000000000000000000000000005D
+:10D3D000000000000000000000000000000000004D
+:10D3E000000000000000000000000000000000003D
+:10D3F000000000000000000000000000000000002D
+:10D40000000000000000000000000000000000001C
+:10D41000000000000000000000000000000000000C
+:10D4200000000000000000000000000000000000FC
+:10D4300000000000000000000000000000000000EC
+:10D4400000000000000000000000000000000000DC
+:10D4500000000000000000000000000000000000CC
+:10D4600000000000000000000000000000000000BC
+:10D4700000000000000000000000000000000000AC
+:10D48000000000000000000000000000000000009C
+:10D49000000000000000000000000000000000008C
+:10D4A000000000000000000000000000000000007C
+:10D4B000000000000000000000000000000000006C
+:10D4C000000000000000000000000000000000005C
+:10D4D000000000000000000000000000000000004C
+:10D4E000000000000000000000000000000000003C
+:10D4F000000000000000000000000000000000002C
+:10D50000000000000000000000000000000000001B
+:10D51000000000000000000000000000000000000B
+:10D5200000000000000000000000000000000000FB
+:10D5300000000000000000000000000000000000EB
+:10D5400000000000000000000000000000000000DB
+:10D5500000000000000000000000000000000000CB
+:10D5600000000000000000000000000000000000BB
+:10D5700000000000000000000000000000000000AB
+:10D58000000000000000000000000000000000009B
+:10D59000000000000000000000000000000000008B
+:10D5A000000000000000000000000000000000007B
+:10D5B000000000000000000000000000000000006B
+:10D5C000000000000000000000000000000000005B
+:10D5D000000000000000000000000000000000004B
+:10D5E000000000000000000000000000000000003B
+:10D5F000000000000000000000000000000000002B
+:10D60000000000000000000000000000000000001A
+:10D61000000000000000000000000000000000000A
+:10D6200000000000000000000000000000000000FA
+:10D6300000000000000000000000000000000000EA
+:10D6400000000000000000000000000000000000DA
+:10D6500000000000000000000000000000000000CA
+:10D6600000000000000000000000000000000000BA
+:10D6700000000000000000000000000000000000AA
+:10D68000000000000000000000000000000000009A
+:10D69000000000000000000000000000000000008A
+:10D6A000000000000000000000000000000000007A
+:10D6B000000000000000000000000000000000006A
+:10D6C000000000000000000000000000000000005A
+:10D6D000000000000000000000000000000000004A
+:10D6E000000000000000000000000000000000003A
+:10D6F000000000000000000000000000000000002A
+:10D700000000000000000000000000000000000019
+:10D710000000000000000000000000000000000009
+:10D7200000000000000000000000000000000000F9
+:10D7300000000000000000000000000000000000E9
+:10D7400000000000000000000000000000000000D9
+:10D7500000000000000000000000000000000000C9
+:10D7600000000000000000000000000000000000B9
+:10D7700000000000000000000000000000000000A9
+:10D780000000000000000000000000000000000099
+:10D790000000000000000000000000000000000089
+:10D7A0000000000000000000000000000000000079
+:10D7B0000000000000000000000000000000000069
+:10D7C0000000000000000000000000000000000059
+:10D7D0000000000000000000000000000000000049
+:10D7E0000000000000000000000000000000000039
+:10D7F0000000000000000000000000000000000029
+:10D800000000000000000000000000000000000018
+:10D810000000000000000000000000000000000008
+:10D8200000000000000000000000000000000000F8
+:10D8300000000000000000000000000000000000E8
+:10D8400000000000000000000000000000000000D8
+:10D8500000000000000000000000000000000000C8
+:10D8600000000000000000000000000000000000B8
+:10D8700000000000000000000000000000000000A8
+:10D880000000000000000000000000000000000098
+:10D890000000000000000000000000000000000088
+:10D8A0000000000000000000000000000000000078
+:10D8B0000000000000000000000000000000000068
+:10D8C0000000000000000000000000000000000058
+:10D8D0000000000000000000000000000000000048
+:10D8E0000000000000000000000000000000000038
+:10D8F0000000000000000000000000000000000028
+:10D900000000000000000000000000000000000017
+:10D910000000000000000000000000000000000007
+:10D9200000000000000000000000000000000000F7
+:10D9300000000000000000000000000000000000E7
+:10D9400000000000000000000000000000000000D7
+:10D9500000000000000000000000000000000000C7
+:10D9600000000000000000000000000000000000B7
+:10D9700000000000000000000000000000000000A7
+:10D980000000000000000000000000000000000097
+:10D990000000000000000000000000000000000087
+:10D9A0000000000010000003000000000000000D57
+:10D9B0000000000D3C020801244282603C03080183
+:10D9C00024638320AC4000000043202B1480FFFD23
+:10D9D000244200043C1D080037BD9FFC03A0F02139
+:10D9E0003C100800261031D83C1C0801279C82609E
+:10D9F0000E0011EA000000000000000D3C02800053
+:10DA000030A5FFFF30C600FF344301803C08800092
+:10DA10008D0901B80520FFFE00000000AC64000085
+:10DA200024040002A4650008A066000AA064000B9C
+:10DA3000AC6700183C03100003E00008AD0301B818
+:10DA40003C0560008CA24FF80440FFFE000000007F
+:10DA5000ACA44FC03C0310003C040200ACA44FC473
+:10DA600003E00008ACA34FF89486000C00A05021FE
+:10DA70002488001400062B02000510800044482171
+:10DA80000109182B10600011000000009103000034
+:10DA90002C64000950800009911900010003608086
+:10DAA0003C0D080125AD8108018D58218D670000CE
+:10DAB00000E0000800000000911900010119402158
+:10DAC0000109302B54C0FFF29103000003E000086D
+:10DAD000000010210A000CBE25080001910F000172
+:10DAE000240E000A15EE00400128C8232F38000A32
+:10DAF0001700003D250D00028D580000250F00067F
+:10DB0000370E0100AD4E0000910C000291AB0001F8
+:10DB100091A4000291A60003000C2E00000B3C0013
+:10DB200000A7102500041A000043C8250326C025BD
+:10DB3000AD580004910E000691ED000191E700023E
+:10DB400091E50003000E5E00000D6400016C3025BD
+:10DB50000007220000C41025004518252508000AEA
+:10DB60000A000CBEAD430008910F0001250400021D
+:10DB70002408000255E80001012020210A000CBE03
+:10DB800000804021910C0001240B0003158B00162E
+:10DB9000000000008D580000910E000225080003CF
+:10DBA000370D0008A14E00100A000CBEAD4D00005C
+:10DBB00091190001240F0004172F000B0000000032
+:10DBC00091070002910400038D43000000072A0022
+:10DBD00000A410253466000425080004AD42000CA2
+:10DBE0000A000CBEAD46000003E00008240200015C
+:10DBF00027BDFFE8AFBF0014AFB000100E0014E661
+:10DC0000008080213C0480083485008090A60005B7
+:10DC10002403FFFE0200202100C310248FBF001444
+:10DC20008FB00010A0A200050A0014F027BD001854
+:10DC300027BDFFE8AFB00010AFBF00140E000F4EBD
+:10DC4000008080213C06800834C5008090A400003C
+:10DC500024020050308300FF106200073C0980005E
+:10DC6000020020218FBF00148FB00010AD20018072
+:10DC70000A00101027BD0018240801003C0780008E
+:10DC8000020020218FBF00148FB00010ACE801808B
+:10DC90000A00101027BD001827BDFF703C0880083F
+:10DCA000AFB60080AFB5007CAFB1006CAFBF008CE9
+:10DCB000AFBE0088AFB70084AFB40078AFB30074D4
+:10DCC000AFB20070AFB00068350500803C0780003F
+:10DCD0008CF2012890A40009ACE0008490A6000515
+:10DCE000309100FF0000A8210006182730620001D3
+:10DCF0000000B02114400067AFA0005090A90000C0
+:10DD000024050020312400FF10850016240A00504D
+:10DD1000108A008C000000003C0C08008D8C00DC98
+:10DD2000258B00013C010800AC2B00DC0E0015DC4B
+:10DD3000000000008FBF008C8FBE00888FB700846A
+:10DD40008FB600808FB5007C8FB400788FB30074DD
+:10DD50008FB200708FB1006C8FB0006803E00008D4
+:10DD600027BD00900000000D3C108000AFA00030E7
+:10DD7000961F01168E1901043C1E002036130C005C
+:10DD8000033EC0240018B82B00173140AFA6003066
+:10DD90008E0E010433F4FFFF3C0F004002938021FC
+:10DDA00001CF68249213000D11A0004834C4004034
+:10DDB000326200201440000234860080008030214E
+:10DDC00014C00093AFA600303C05800834A8008042
+:10DDD0009107000830E6004050C000063C0680086D
+:10DDE00024090004122900A2240A0012122A002980
+:10DDF0003C06800834D401003C17800096EF011ADD
+:10DE0000960D000E928E0008326B000431F7FFFF72
+:10DE100001CD6004AFAC00548E14000411600031D9
+:10DE20008E1E000834C3008090790008333800400B
+:10DE300017000028000000008C730050029390230C
+:10DE4000064000063C0C80008C7E0034029E80233D
+:10DE5000060200838EA200083C0C8000AD800044C6
+:10DE6000240200018FBF008C8FBE00888FB7008412
+:10DE70008FB600808FB5007C8FB400788FB30074AC
+:10DE80008FB200708FB1006C8FB0006803E00008A3
+:10DE900027BD00900E000D1A000020218FBF008CBE
+:10DEA0008FBE00888FB700848FB600808FB5007C4E
+:10DEB0008FB400788FB300748FB200708FB1006C94
+:10DEC0008FB0006803E0000827BD00900A000D7ABB
+:10DED00000C020210E00163D028020211440FFDFEB
+:10DEE0003C0C80003C038008346300808C6200346A
+:10DEF0000282F82307E00017000000003C1508002C
+:10DF00008EB5310026B100013C010800AC31310072
+:10DF10000E0014E6024020213C0B80083570008082
+:10DF2000920A002502402021354200040E0014F020
+:10DF3000A20200250E000C9E024020210A000DA71F
+:10DF4000240200013C15080126B583100A000D6962
+:10DF50003C1080008C660030028620231880000868
+:10DF60002409000C3C0808008D083100327300FCC5
+:10DF70000000B821250700013C010800AC27310052
+:10DF8000AFA900308C65003000B4382318E000DB06
+:10DF900002E7502A1540FFDE0000000012E7002AC9
+:10DFA00002E768230287A02131B7FFFF326E00022B
+:10DFB00011C00034327F00103C148008369000807D
+:10DFC000920F000831F6004052C000CE8EA2000829
+:10DFD000024020210E0014E624130018A2130009A9
+:10DFE000921800052419FFFE024020210319B824CD
+:10DFF0000E0014F0A21700052404003900002821A7
+:10E000000E001618240600180A000DA724020001AD
+:10E0100092B6000C3C048008348300808C67003882
+:10E020000016AB0036B10081024020213225F0817C
+:10E030000E000C8D30C600FF3C0C8000AD8000440B
+:10E040000A000DA7240200013A6C0001318B000187
+:10E050001560FFAF0287A0210A000DF80000000044
+:10E060000040F809240400160A000DA7240200014C
+:10E07000024020210E00171D020028210A000D5C1D
+:10E080008FBF008C13E0FF743C038008346800806D
+:10E090008D0400388C66000403C610231C40FF6FFB
+:10E0A0003C0C800003C4282304A200010080F0215E
+:10E0B000AFB40010AFB70014AFA700183C1F80002A
+:10E0C00097E301208D0900309506005C8FB900545C
+:10E0D0008FAC00303062FFFF30D8FFFF0047702167
+:10E0E00037EF40000338682B01CF5821018D5025B0
+:10E0F000AFAB0020AFA90028AFAA0030AFA9002421
+:10E10000AFA0002CAFBE00349107000830E4000837
+:10E110001480008F020020218EA200040040F80924
+:10E1200027A400108FA900303128000255000001FB
+:10E13000327300FE3C048008348C0080918B000810
+:10E14000316A0040514000128FA400248C8D0004DD
+:10E1500011BE00BE240E00143265000110A0000C98
+:10E160008FA400242404000C122400D42A27000DBC
+:10E1700010E000CE2409000E2408000A52280001F5
+:10E18000241600088FA2002424440001AFA4002418
+:10E190008FA600143C038008346500800086F821B7
+:10E1A0008CB10030ACBF003090B9004E8CAE003066
+:10E1B0003418FFFF0338780401CF6821ACAD003478
+:10E1C0008FA600308FAC005430CA000803CC582111
+:10E1D0001140000CAFAB00588CA400208FB0005849
+:10E1E0001090009430C600FF92A2000C8FA700345C
+:10E1F0000240202100024B00352800800E000C8DCB
+:10E200003105F0803C0C8008359000808E0B00308A
+:10E210000171502319400070265900803C180800F5
+:10E220008F183198241FFF80033F7824332D007FFF
+:10E230003C0680003C0E800433110010ACCF0090EF
+:10E240001220003401AE282190A3006B54600032EC
+:10E250003C10800824070001A0A7006B94C4007A3A
+:10E260002486000AA60600123C0D800835A5008011
+:10E2700090B10008322C0040158000043C03800857
+:10E28000326E000115C0006200000000346400809E
+:10E290008C8F00208FB3005811F3000A3463010003
+:10E2A0008C7900000299C0231B0000778FA80058CA
+:10E2B000AC880020AC74000024140001AC7E000483
+:10E2C000AFB4005016C00037000000008FA400500B
+:10E2D000148000300000000012E00005000018214A
+:10E2E0008FA900303137000452E0FE920060102107
+:10E2F000240300010A000D5B006010210A000DF9E3
+:10E30000000038210040F809240400170A000DA776
+:10E31000240200013C10800836100080240900010E
+:10E32000024020210E0014E6A609001292080025E2
+:10E3300024050001AFA50050350200010240202154
+:10E340000E0014F0A20200250A000EA93C0D800860
+:10E3500027A50038AFA800600E000CA8AFA00038B9
+:10E360001440FF6D8FA800608FA5003830B0010009
+:10E370005200FF6A8EA200048FA3003C8D07005854
+:10E38000006720230483FF64AD0300580A000E5584
+:10E390008EA200040E000C9E024020210A000EC432
+:10E3A000000000000E0014E6024020213C05800819
+:10E3B00034A30080024020210E0014F0A076000952
+:10E3C00002C03021240400370E0016180000282156
+:10E3D0000A000EC28FA400508FA200185840FFA35D
+:10E3E0003C0D80080E0014E602402021920A002510
+:10E3F000240B0001AFAB0050354200040240202145
+:10E400000E0014F0A20200250A000EA93C0D80089F
+:10E410008CB600308EBE00082404001826D50001FA
+:10E4200003C0F809ACB500308FB200300A000D5BB4
+:10E43000324200043C07800094E5011A50A0FF6AB4
+:10E4400034C600100A000E8992A2000C122E002A77
+:10E450002A2F001511E0001E241900162418000CA4
+:10E460005638FF3E326500013C1F800893E3001BD5
+:10E470002410FFBD2416000E00703024A3E6001BFC
+:10E480000A000E65326500018C7F000017F4FF8DD5
+:10E49000000000008C67000403C7302304C1FF8420
+:10E4A0008FA800580A000EBF000000001629FF3692
+:10E4B0008FA200240A000E70241600102411000EF2
+:10E4C00052D1FF30241600100A000E6F24160016D9
+:10E4D0005639FF22326500013C1F800893E3001B80
+:10E4E0002410FFBD2416001000703024A3E6001B8A
+:10E4F0000A000E65326500010A000E64241600123F
+:10E500003C0380008C6201B80440FFFE2404080034
+:10E51000AC6401B803E000080000000030A5FFFF74
+:10E5200030C6FFFF3C0780008CE201B80440FFFECC
+:10E5300034E80180AD040000ACE400203C04800815
+:10E54000948300483063FFFF1060001D3C0B800087
+:10E5500024AA0012006A482B5120001A240A000342
+:10E5600094F901208F890000240C001A3338FFFF32
+:10E570002707FFFE0067782B39EE000100096B8248
+:10E5800001AE5824A10C000B116000478F830004DA
+:10E59000A50700148F88000435070001AF87000429
+:10E5A00030CC00405580000F3C0880003C0C8000BF
+:10E5B00035840180A485000E0A000F988F8F000C0F
+:10E5C000240A00033564018030CC00408F890000AC
+:10E5D0008F870004A08A000B5180FFF53C0C80005F
+:10E5E0003C088000950301203C08800895180040F5
+:10E5F0003079FFFF272EFFFE330FFFFF01CF682B7F
+:10E6000011A0000301C02021950200403044FFFF0B
+:10E610003C0B800000A4502335650180A4A4000EAB
+:10E62000A4AA00248F8F000C3C05800034AE01802A
+:10E630002418000230ED8000A5D8000CA5C90010F8
+:10E64000ADCF0028A5C6000811A0000E3C04800034
+:10E6500094AA01163142FFFC244800040105182148
+:10E660008C7940003326FFFF14C00007240EBFFF43
+:10E670003C0BFFFF35657FFF00E53824AF870004C2
+:10E680003C048000240EBFFF348C018000EE68241F
+:10E69000A58D0026AD89002C3C071000AC8701B881
+:10E6A00003E00008000000002402FFFE006238249E
+:10E6B0000A000F76AF8700043C05800034A4007088
+:10E6C0008C8A000090A601128F84000027BDFFF005
+:10E6D00030C300FF0003188230820100000038219F
+:10E6E00010400039246600033087400050E00039B4
+:10E6F00030882000000610800045C8218F2F400080
+:10E700002478000400187080AFAF000001C56821B4
+:10E710008DAC4000AFAC000494AB01163169FFFC36
+:10E72000012540218D054000AFA500088FA90008F4
+:10E7300000003021000028213C07080024E70100E8
+:10E740000A000FE9240800089042000024A50001F7
+:10E750002CAD000C0062C8210019C080030778218D
+:10E760008DEE000011A0000600CE302603A510217A
+:10E7700014A8FFF500051A005520FFF49042000090
+:10E780003C048000348700703C0508008CA53104EF
+:10E790008CE300002CA8002011000009006A382337
+:10E7A000000558803C0C0800258C3108016C48217C
+:10E7B00024AA0001AD2700003C010800AC2A310466
+:10E7C000AF86000C2407000100E0102103E00008E0
+:10E7D00027BD00101100FFFC0000382100066080FA
+:10E7E000018558218D6440002469000400093880A7
+:10E7F000AFA4000000E518218C664000AFA000081F
+:10E800000A000FD9AFA6000427BDFFD8AFB2001889
+:10E81000AFB00010AFBF0024AFB40020AFB3001CF6
+:10E82000AFB100148F8700003C0480009483010E78
+:10E8300030E2400000008021104000103072FFFFE5
+:10E840003C06002000E6282410A0000D30EA8000DD
+:10E850008F8800042409BFFF00E938243503100025
+:10E86000AF87000030F120001620000B3C1400049C
+:10E870002418FFBF0A0010380078102430EA800006
+:10E88000154000863C0C002030F120001220FFF8DB
+:10E890008F8300043C14000400F498241260FFF5F8
+:10E8A0002418FFBF3462004030F901001320000F2C
+:10E8B000AF8200043C02002000E2F82413E00005CF
+:10E8C0003C0B80003C04000400E41824106000CFDE
+:10E8D00000000000956A011E9569011C3146FFFF8A
+:10E8E0000009440000C82825AF85000C3C0E8000BC
+:10E8F00095CD010C8DC44000340CFFFF108C00B08E
+:10E9000031A5FFFF308F010055E0000124100010F9
+:10E9100030F11000522000083611000130F30020C1
+:10E920001660009F3C18100000F8A0241680009686
+:10E930003C040C003611000130E801001500000B0A
+:10E940003C0A00018F8800043109400015200008AE
+:10E9500000EA30243C0C1F0100EC58243C0A100053
+:10E96000516A00AE30AD02003C0A000100EA3024DA
+:10E9700014C000953C05100000E520240000402153
+:10E98000108000070000902100079E023272000FE5
+:10E99000001278803C0E080125CE82C001EE402195
+:10E9A0008F9400181280004702208021108000916F
+:10E9B000000000003C0980009539010E9103000021
+:10E9C000022030213338FFFF2705000410600008C3
+:10E9D0000000A021241F0003107F013A240400023C
+:10E9E000910C00011184011830EA00400012A1C00E
+:10E9F0008F92001C52400001362600403C138000DC
+:10EA00008E6F400031F10100122000CB30D1FFFBAE
+:10EA10003C1808008F18002430D20004330600048C
+:10EA200014C000CC30B0FFFF564000013631000466
+:10EA300002802021020028210E000F5502203021E3
+:10EA40001640000D00002021366501803C04800046
+:10EA50008C9301B80660FFFE2419200024140002E4
+:10EA6000A4B90008A0B4000BA4A000103C0510003D
+:10EA7000AC8501B8000020218FBF00248FB4002096
+:10EA80008FB3001C8FB200188FB100148FB000102C
+:10EA90000080102103E0000827BD002800EC582466
+:10EAA0001160FF7A30F120008F8D00043C0FFFFFD2
+:10EAB00035EE7FFF00EE382435A380000A001027D2
+:10EAC000AF8700003C0208008C4200383C0408007C
+:10EAD000248400381040004B2449FFFF3C03800091
+:10EAE000946C010E318BFFFF110000A02573000410
+:10EAF0003C1008008E1000301200000A30E60100C1
+:10EB00008F8A000431434000106000063C0F0F0064
+:10EB100000EF70243C0D010001AE402B110000DF1E
+:10EB20003265FFFF10C000693C140F0000F4282478
+:10EB30003C18020010B800658F99000C3270FFFF7E
+:10EB40000329982402649021924900042527000497
+:10EB5000000721C002002821362600020E000F55B2
+:10EB6000000000008FBF00248FB400208FB3001C72
+:10EB70008FB200188FB100148FB000100000102168
+:10EB800003E0000827BD00283C020BFF00E4182426
+:10EB9000345FFFFF03E3C82B5320FF6736110001EA
+:10EBA0003C0608008CC6002C3611000524D000015C
+:10EBB0003C010800AC30002C0A00105D30E8010078
+:10EBC0000A00105224100020024028213C120800A4
+:10EBD0008E5200D824040080264D00013C0108001C
+:10EBE000AC2D00D80E000F55240600030A0010E8D3
+:10EBF0008FBF00243C080801250882C00A00107C51
+:10EC00003C0980000A0010C5000048210E000FBC1E
+:10EC1000000000000A0010498F87000015A0FF5374
+:10EC20003C0A00012645000430AAFFFF36260002F8
+:10EC30003C0380008C7201B80640FFFE8F850008FF
+:10EC400034690180AD20000010A000AF3C048000BA
+:10EC5000254F001200AF702B51C000AC24030003FD
+:10EC6000947801202414001A30F140003313FFFF80
+:10EC7000A134000B122000B62663FFFE00A3C82BB0
+:10EC8000572000B4241FFFFE35080001A5230014FF
+:10EC9000AF8800043C108000240CBFFF010C482406
+:10ECA000240B000236080180A50B000CA50A000EFB
+:10ECB000A5060008A5090026A50700103C071000BE
+:10ECC000AE0701B80A0010E88FBF00243C0308001B
+:10ECD0008C6300D02E45000C001221C0386B00015F
+:10ECE0002D6200010045F82417E0FF9A3270FFFF03
+:10ECF000264CFFFC2D84000454800050000020218D
+:10ED0000386A00022D430001006580241600004A85
+:10ED10003270FFFF00076A420012702B01AE4024E0
+:10ED20005500006300002021001221C002002821AC
+:10ED30000A0010E53626000234DF0002028020219E
+:10ED400033E6FFFF0E000F5530A5FFFF0A0010ACA1
+:10ED50000000202124040100020028210E000F558C
+:10ED6000022030210A001098000000008C6640004C
+:10ED700030CF010011E0003D30F801003C120800E6
+:10ED80008E52002413000011323400043C1F0F0087
+:10ED900000FFC8243C0502001325000C8F8C000CDA
+:10EDA000022030213265FFFF0189582401641021BF
+:10EDB000904900043230FFFB2411FFFE2527000498
+:10EDC0000E000F55000721C00251902424040001B9
+:10EDD00012440052324300011460005802003021F6
+:10EDE000324A0004114000048F8D000031A8080051
+:10EDF0001500005A3265FFFF1680FF5B8FBF0024AD
+:10EE00003C138000366501803C0480008C9001B882
+:10EE10000600FFFE24062000240F0002A4A600081E
+:10EE2000A0AF000BA4A000103C0E1000AC8E01B8E7
+:10EE30000A0010E88FBF00240000202102002821D2
+:10EE40000A0010E5362600021140FEE90000A0216C
+:10EE5000952E0110950D000231C8FFFF51A8FEE468
+:10EE60000012A1C00A00108B8F92001C3C05080004
+:10EE70008CA5002430B800015300FF3B8FBF002455
+:10EE80003265FFFF36260002000020210E000F55DC
+:10EE9000000000000A0010E88FBF002436260002A0
+:10EEA0000E000F55240400800A0010E88FBF0024D4
+:10EEB000020028210E000F553226FFFB0A001159CF
+:10EEC000001221C091030001240200011062FEEA39
+:10EED00024040001241000021470FEC50000A021CB
+:10EEE00030E300401060FEC38F92001C952B011090
+:10EEF000950900023167FFFF1127FEE08FBF002454
+:10EF00000A00108B000000002403000334820180FB
+:10EF1000A043000B0A0011343C108000321400049E
+:10EF2000168000033265FFFF361200023250FFFFE9
+:10EF3000020030210A0011B1000020210000202130
+:10EF40000E000F553265FFFF0A0011863210FFFBDD
+:10EF5000241FFFFE0A001132011F4024020030214D
+:10EF60000E000F55240401000A00118C000000005F
+:10EF700027BDFFC8AFB00010AFBF00343C10600C1D
+:10EF8000AFBE0030AFB7002CAFB60028AFB500243D
+:10EF9000AFB40020AFB3001CAFB20018AFB1001483
+:10EFA0008E0E5000240FFF7F3C06800001CF6824A6
+:10EFB00035AC380C240B0003AE0C5000ACCB000871
+:10EFC0003C010800AC2000200E00174900000000A2
+:10EFD0003C0A0010354980513C066016AE09537C4E
+:10EFE0008CC700003C0860148D0500A03C03FFFFA7
+:10EFF00000E320243C02535300051FC2108202622A
+:10F0000034C57C008CBE007C8CBF00783C02600064
+:10F01000344420203C05080124A581382406000A38
+:10F020003C170098AF9E0014AF9F00100E0015F221
+:10F030003C11800036F600C03C1900103C18600CF2
+:10F040003C158000AF1953FC363E0180AEB6013C42
+:10F050008E300000320400031080FFFD32050001F5
+:10F0600014A000593206000210C0FFF93C048000D1
+:10F070008C92014024100040AC9200208C8F0148FB
+:10F08000000F760231C300701070013E2C780041F1
+:10F090005300000824040060241900201079000E99
+:10F0A0003C1F40003C088000AD1F01780A0012227E
+:10F0B000000000001464FFFB3C1F40000E001F66B0
+:10F0C000000000003C1F40003C088000AD1F01789C
+:10F0D0000A001222000000008C940148241700044A
+:10F0E0003488018000144C02312500FF8C830140DC
+:10F0F00010B7017024ABFFFA2D6A000651400013CF
+:10F100003C0580008C86014430A400FF30C300FF22
+:10F1100030D500FF2C76000816C0000226A7000498
+:10F1200024070003240C0009108C01A8288D000A74
+:10F1300011A001942413000A24050008108500146E
+:10F140008F980018000719C03C0580008CA701B8F3
+:10F1500004E0FFFE24140002AD030000A50900082E
+:10F16000A114000B8CB701483C0910003C1F400063
+:10F17000A51700108CA40144AD0400243C088000B5
+:10F18000ACA901B8AD1F01780A00122200000000EE
+:10F19000000692020007C8803C040801248482C053
+:10F1A00003247821270E0001324500FF24100001BE
+:10F1B000A1F2000014B0FFE3AF8E0018000719C0E1
+:10F1C0000A001260AF85001C8E3401283C068008BE
+:10F1D000AE3400208E2A01048E29010094C8004814
+:10F1E000AF8A0000AF8900043103FFFF0E000F4E0D
+:10F1F000AF8300083C0708008CE700C010E0002443
+:10F200008F8700003C0C08008D8C00C4258B00010A
+:10F210003C010800AC2B00C43C1980008F24012461
+:10F220003C186020AF040014000000003C06800081
+:10F230003C174000ACD70138000000005280FF8A24
+:10F240003206000226870140268500802409FF80BF
+:10F2500000E9682400A998240013194030AC007F0D
+:10F26000000DB14030F5007F3C0B200035620002FC
+:10F27000006C402502D550250142A0250102F82549
+:10F28000ACDF0830ACD408300A0012283206000285
+:10F290003C0E001000EE682415A000A68F83000429
+:10F2A0003C1508008EB500203C16800096D2010E59
+:10F2B00026B3000130EF40003255FFFF3C0108004B
+:10F2C000AC33002011E000B6000090213C18002073
+:10F2D00000F8B82412E000B330E280008F990004F7
+:10F2E000241FBFFF00FF382437231000AF87000022
+:10F2F00030EA2000114000B5240CFFBF3C0B000495
+:10F3000000EB302410C00002006C10243462004076
+:10F3100030ED010011A0000EAF8200043C0F002070
+:10F3200000EF702411C000043C16000400F698247D
+:10F3300012600135000000009622011E963F011C5C
+:10F340003058FFFF001FCC000319B825AF97000C01
+:10F350009628010C8E2440003403FFFF108300C860
+:10F360003105FFFF308901005520000124120010F3
+:10F3700030E41000108000133653000130EA002002
+:10F380001540000A3C0B100000EB302410C0000DAB
+:10F390003C0F0BFF3C130C0000F3702435EDFFFF16
+:10F3A00001AE602B11800007365300013C160800A7
+:10F3B0008ED6002C3653000526D200013C010800F1
+:10F3C000AC32002C30F7010016E0000B3C060001C7
+:10F3D0008F880004311840005700000800E62824F8
+:10F3E0003C021F0100E2F8243C19100013F9010A45
+:10F3F00030A302003C06000100E6282414A000A26D
+:10F400003C09100000E92024000040211080000782
+:10F410000000A821000766023195000F00155880F2
+:10F420003C0A0801254A82C0016A40218F8D0018DC
+:10F4300011A0006802609021148000033C09800044
+:10F440003C080801250882C0952E010E910300009A
+:10F450000260302131C4FFFF2485000410600008E1
+:10F460000000B821240F0003106F011E24190002B0
+:10F47000911F000113F9002630E200400015B9C0C9
+:10F480008F89001C51200001366600403C16800028
+:10F490008ECB400031730100126000C530D50004EE
+:10F4A0003C0C08008D8C002430D3FFFB3186000417
+:10F4B00014C0010630B2FFFF56A0000136730004ED
+:10F4C00002E02021024028210E000F550260302169
+:10F4D00016A0000D0000202136C501803C048000EC
+:10F4E0008C8D01B805A0FFFE240F2000240E000221
+:10F4F000A4AF0008A0AE000BA4A000103C051000B3
+:10F50000AC8501B8000020210A001367008010219B
+:10F510001040FFDB0000B821952A0110950300027E
+:10F520003148FFFF5068FFD60015B9C00A00132FFD
+:10F530008F89001C2413BFFF0073282410A000072C
+:10F54000240E87FF006E48241520000A3C1200603C
+:10F5500000F2782411E00007000000000E000D34D6
+:10F56000000000001040FF323C0680000A001295A7
+:10F570003C1980000E0014CF000000000A00136741
+:10F58000000000000E0014F5000000003C1F4000C9
+:10F590003C088000AD1F01780A0012220000000024
+:10F5A00030E280001040FF528F8300043C050020B1
+:10F5B00000E520241080FF4E3C09FFFF35287FFF27
+:10F5C00000E838240A0012C9346380000A0012D20D
+:10F5D000006C10243C0408008C8400381480000265
+:10F5E0002489FFFF000048213C0380009476010E2F
+:10F5F00032D7FFFF110000EA26F600043C12080093
+:10F600008E5200301240000A30EA01008F99000447
+:10F6100033384000130000063C030F0000E3402491
+:10F620003C0201000048F82B13E000D232C5FFFF76
+:10F630001140002F3C0C0F0000EC30243C0B02006A
+:10F6400010CB002B8F8F000C3C0E080025CE00380D
+:10F6500032D2FFFF01E9282400AE682191A90004FD
+:10F6600025270004000721C0024028213666000239
+:10F670000E000F55000000000A0013670000102163
+:10F680000A0012EA241200203C0308008C6300D810
+:10F6900002A0282124040080246200013C0108000B
+:10F6A000AC2200D80E000F55240600030A00136791
+:10F6B000000010218C840140010028213C038000BF
+:10F6C0008C7F01B807E0FFFE2402001CACA4000000
+:10F6D000A0A2000B3C081000AC6801B83C1F400021
+:10F6E0003C088000AD1F01780A00122200000000D3
+:10F6F0003C0308008C6300D02EA5000C001521C02F
+:10F70000387800012F1200010245B82416E0FFD618
+:10F7100032D2FFFF26B9FFFC2F240004148000081A
+:10F7200000002021386800022D0200010045F82465
+:10F7300013E0000600075A4232D2FFFF00002021EA
+:10F74000024028210A0013AA366600020015182B71
+:10F75000016350241540000532D2FFFF001521C07F
+:10F76000024028210A0013AA366600020000202168
+:10F77000024028210E000F553266FFFB0A0013E6F7
+:10F78000001521C010930068000768802406000B54
+:10F790001486FE6D000719C00007C0803C190801DF
+:10F7A000273982C0031930210A001260A0C000016D
+:10F7B00034D5000202E0202130A5FFFF0E000F55D6
+:10F7C00032A6FFFF0A001350000020210007A0808E
+:10F7D0003C1F080127FF82C0029F102190570000A4
+:10F7E00012E0FE59000719C0A04000008F8A0018DF
+:10F7F0002542FFFF1440FE54AF820018000719C0D5
+:10F800000A001260AF80001C0E000FBC0000000058
+:10F810000A0012E28F8700001460FEF73C06000128
+:10F8200026A900043125FFFF366600023C03800054
+:10F830008C7501B806A0FFFE8F8900083C0A800085
+:10F8400035440180AC8000001120009B2418000387
+:10F8500024AC0012012C582B11600097000000000E
+:10F86000947201203C138000240F001A324EFFFFD7
+:10F87000366A018030ED4000A14F000B11A00091CD
+:10F8800025C3FFFE0123B02B16C0008F2417FFFEF7
+:10F8900035080001A5430014AF880004241FBFFFF2
+:10F8A000011FC82424080002A7C8000CA7C5000E29
+:10F8B000A7C60008A7D90026A7C700103C0710005C
+:10F8C000AE2701B80A0013670000102124040100CC
+:10F8D000024028210E000F55026030210A00133C1F
+:10F8E0000000000091030001241500011075FF06BF
+:10F8F00024040001241200021472FEE10000B82169
+:10F9000030F6004052C0FEDF8F89001C95270110A1
+:10F910009518000230F7FFFF1317FEFB0000B82117
+:10F920000A00132F8F89001C3C120801265282C046
+:10F9300001B2702100067A02A1CF00013C0B6000E9
+:10F940008D6318202410000100F098043C05080184
+:10F9500024A582C20073B02501A5A8210006640277
+:10F96000000719C0A6AC0000AD7618200A0012618D
+:10F970003C058000366600020E000F55240400800E
+:10F980000A001367000010210003A080028698215E
+:10F990008E7200043C1160000A00120F02512821EF
+:10F9A0008C66400030D5010012A0003730EC010019
+:10F9B0003C1508008EB50024118000133277000436
+:10F9C0003C050F0000E568243C07020011A7000E6B
+:10F9D0008F84000C3C180800271800380260302182
+:10F9E000008990240258782191EE000432C5FFFF6F
+:10F9F0003272FFFB25C90004000921C00E000F551B
+:10FA00002413FFFE02B3A8242419000112B9003008
+:10FA100032A200011040000732A800040240302149
+:10FA2000000020210E000F5532C5FFFF3252FFFBB0
+:10FA300032A80004110000048F8B0000316A080016
+:10FA40005540002B32C5FFFF16E0FEC60000102116
+:10FA50003C16800036C401803C0580008CA301B8B0
+:10FA60000460FFFE240C200024060002A48C000881
+:10FA7000A086000BA48000103C151000ACB501B8A6
+:10FA80000A001367000010213C0D08008DAD002412
+:10FA900031A7000150E0FEB30000102132C5FFFF86
+:10FAA00036660002000020210E000F550000000005
+:10FAB0000A00136700001021A3D8000B0A001436B7
+:10FAC000241FBFFF2417FFFE0A001434011740242F
+:10FAD0003257000416E0000332C5FFFF365F000214
+:10FAE00033F2FFFF024030210A0014B80000202149
+:10FAF000024030210E000F55240401000A0014A01A
+:10FB0000000000003C0380008C6401003082003E55
+:10FB10001440000800000000AC6000488C66010042
+:10FB200030C507C010A0000500000000AC60004C0C
+:10FB3000AC60005003E0000824020001AC600054F7
+:10FB4000AC6000408C6801003107380010E0FFF91C
+:10FB5000000000002402000103E00008AC60004443
+:10FB60003C03900034620001008220253C038000A9
+:10FB7000AC6400208C65002004A0FFFE00000000A3
+:10FB800003E00008000000003C0280003443000154
+:10FB90000083202503E00008AC44002027BDFFD8E7
+:10FBA000AFB100143C048000AFBF0020AFB3001C15
+:10FBB000AFB20018AFB000108C9201408C90014899
+:10FBC0002402000E00108C02322300FF1062005944
+:10FBD000020428242866000F10C00013286A00378A
+:10FBE000240700061067008E286800075100002DCA
+:10FBF00024040009106000783C06800024090001FC
+:10FC0000106900B0000000000000000D8FBF002050
+:10FC10008FB3001C8FB200188FB100148FB000108A
+:10FC200003E0000827BD002811400059240D0038CA
+:10FC3000286B0035116000053C058000240C001F76
+:10FC4000146CFFF1000000003C0580008CB801B886
+:10FC50000700FFFE34B90180AF320000241F00010D
+:10FC6000241200023C021000AF200004A73100085B
+:10FC7000A33F000AA332000BA7300010AF200024DE
+:10FC8000AF200028ACA201B88FBF00208FB3001CAA
+:10FC90008FB200188FB100148FB0001003E000087D
+:10FCA00027BD0028106400232405000B1465FFD62F
+:10FCB0003218FFFF170000203C0580008F93FED014
+:10FCC000927F000533F900041720FFCF00000000E9
+:10FCD0000E0014E602402021926900050240202116
+:10FCE000352800040E0014F0A26800059267000594
+:10FCF00030E2000414400002000000000000000D8B
+:10FD0000926B000024060020316A00FF1546000AAD
+:10FD10003C0580008CA401B80480FFFE34AD018056
+:10FD2000240E00053C0C1000ADB20000A1AE000B8B
+:10FD3000ACAC01B83C0580008CA301B80460FFFEA8
+:10FD400034AF018024130002ADF20000ADF20004D4
+:10FD5000A5F10008A1F3000AA1F3000BA5F0001023
+:10FD6000ADE000248CB101443C101000ADF100283E
+:10FD7000ACB001B88FBF00208FB3001C8FB2001849
+:10FD80008FB100148FB0001003E0000827BD0028D9
+:10FD9000106DFFAD240E0080146EFF9B000000006C
+:10FDA0003C0580008CA301B80460FFFE34AF0180E5
+:10FDB00024120002A1F2000BA5F10008A5F000102A
+:10FDC0008CB301443C021000A5F30012ACA201B8B0
+:10FDD0000A0015318FBF00208CC301B80460FFFEFC
+:10FDE00034D30180AE720000AE6000042412000122
+:10FDF000A671000824110002A272000AA271000B71
+:10FE0000A67000108CD001443C0F1000AE7000248E
+:10FE1000AE600028ACCF01B80A00156C8FBF00207F
+:10FE20003C0380008C6601B804C0FFFE3462018090
+:10FE30003C06080190C68300AC52000010C00003CD
+:10FE4000000038213C0708018CE783083C0580004E
+:10FE500034AA01802404000234CC0001AC47000421
+:10FE6000A5510008A14C000AA144000BA5500010A8
+:10FE70008CAB01440000202101402821AD4B00241F
+:10FE800010C000038FBF00203C0408018C84830451
+:10FE90008FB3001C8FB200188FB100148FB0001008
+:10FEA0003C0E10003C0D800027BD0028ACA40028AB
+:10FEB000ADAE01B83C010801A020830003E00008BA
+:10FEC0000000000010A0000B3C0680008C9801444C
+:10FED000241900023C010801A03983003C010801FB
+:10FEE000AC3283083C010801AC3883040A00156C6D
+:10FEF0008FBF00208CDF01B807E0FFFE34C7018010
+:10FF000024090002ACF20000ACF20004A4F10008E5
+:10FF1000A0E9000AA0E9000BA4F00010ACE0002466
+:10FF20008CC801443C021000ACE80028ACC201B807
+:10FF30000A00156C8FBF002027BDFFE8AFBF00107F
+:10FF40000E000F4E000000003C0280008FBF00102A
+:10FF500000002021AC4001800A00101027BD0018CD
+:10FF60003084FFFF30A5FFFF10800007000018213C
+:10FF70003082000110400002000420420065182178
+:10FF80001480FFFB0005284003E0000800601021FA
+:10FF900010C00007000000008CA2000024C6FFFF74
+:10FFA00024A50004AC82000014C0FFFB24840004DC
+:10FFB00003E000080000000010A0000824A3FFFFD9
+:10FFC000AC86000000000000000000002402FFFFDB
+:10FFD0002463FFFF1462FFFA2484000403E0000896
+:10FFE0000000000027BDFFE8AFBF0014AFB0001055
+:10FFF0000E0014E6008080213C04800834830080D9
+:020000040001F9
+:10000000906500250200202134A200200E0014F08B
+:10001000A0620025020020218FBF00148FB00010C5
+:100020000A000C9E27BD00183C03800027BDFFF886
+:1000300034620180AFA20000308C00FF30AD00FFC1
+:1000400030CE00FF3C0B80008D6401B80480FFFEC1
+:10005000000000008FA900008D6801288FAA000011
+:100060008FA700008FA400002405000124020002D5
+:10007000A085000A8FA30000359940003C051000C0
+:10008000A062000B8FB800008FAC00008FA60000AC
+:100090008FAF000027BD0008AD280000AD40000470
+:1000A000AD800024ACC00028A4F90008A70D001002
+:1000B000A5EE001203E00008AD6501B83C0680081B
+:1000C00027BDFFE834C50080AFBF001090A700092E
+:1000D0002402001230E300FF1062000B0080302188
+:1000E0008CA8005000882023048000088FBF0010D7
+:1000F0008CAA0034240400390000282100CA4823B7
+:1001000005200005240600128FBF00102402000104
+:1001100003E0000827BD00180E00161800000000BC
+:100120008FBF00102402000103E0000827BD001863
+:1001300027BDFFC8AFB1002C00A08821AFB20030AE
+:1001400027A500100080902102202021AFBF00349D
+:10015000AFB000280E000CA8AFA000101440009B08
+:100160003C07800834E400809086000830C5000811
+:1001700014A000698FA700103C1880083710008079
+:10018000920F000831EE000815C000022408000399
+:10019000000040213C0B800891650011916A00121B
+:1001A000356600808CDF0054314900FF0128202192
+:1001B00030A300FF000410800062282100BFC82B7C
+:1001C000132000080000000094D0005C8CCF005485
+:1001D000320DFFFF01E5702301AE602B118000940A
+:1001E0000000000094D9005C3323FFFF30FF0004BF
+:1001F00013E00074000830808FA8001C0068102BEA
+:100200005040004F30E30004006610232C4600806D
+:1002100010C0000200408021241000800E0014E66F
+:10022000024020213C03800834660080240700013E
+:10023000ACC7000C90C8000800106840346701008B
+:10024000311F007FA0DF00088E390004273800012D
+:10025000ACD80030A4D0005C8CCF003C9630000EAF
+:1002600001F07021ACCE00208CCC003C018D5821D7
+:10027000ACCB001C8E2A0004ACEA00008E290008DA
+:10028000ACE900048FA5001030A4000854800032AF
+:1002900093A60020A0C0004E90C9004E2402FFDFAC
+:1002A0003C188008A0E9000890C50008370D0080C0
+:1002B000240A005000A22024A0C400088E3900089F
+:1002C000ADB900388F0F00148DB0003001F07021EF
+:1002D000ADAE003491AC0000318B00FF116A002CF0
+:1002E000264501000E0014F00240202124040038AD
+:1002F000000028210E0016182406000A8FBF0034C3
+:100300008FB200308FB1002C8FB000282402000182
+:1003100003E0000827BD003830E801001100003D6F
+:100320008FA300148C8A0058006A48230520FF938D
+:100330003C188008AC8300580A00166C8FA7001088
+:10034000240702181060FFB100E610238FA2001CE2
+:100350000A001691004610233C188008370D0080D3
+:10036000A0E600088E390008240A0050ADB9003814
+:100370008F0F00148DB0003001F07021ADAE00344D
+:1003800091AC0000318B00FF156AFFD626450100B5
+:100390002406FF8000A610243C098000AD2200281E
+:1003A0008E27000830A3007F3C04800C0064F821F5
+:1003B000AFE700D08E280008AF9F00280A0016C7BC
+:1003C000AFE800D40A00168E2C6202188E230008B3
+:1003D0003C04800834820080AC4300540240202159
+:1003E0000E001607AC400030240400382405008DB0
+:1003F0000E001618240600128FBF00348FB2003092
+:100400008FB1002C8FB000282402000103E0000807
+:1004100027BD0038AC800058908C0008240DFFF7F1
+:10042000018D5824A08B00080A00166C8FA70010BD
+:100430008CD800540A0016890305182327BDFFE84D
+:10044000AFBF001090A6000D30C7001010E0000CE8
+:10045000008040213C0280088C4400048CA30008EA
+:100460001064000830C9000530C5000510A0001C4C
+:100470008FBF00102402000103E0000827BD001810
+:1004800030C900051120001030CB001210E0FFF938
+:100490008FBF00103C0880088CA700088D06000460
+:1004A00014E6FFF524020001240400382405008D21
+:1004B0000E001618240600128FBF0010240200013F
+:1004C00003E0000827BD0018240A0012156AFFE99E
+:1004D0008FBF0010010020210A00165A27BD001806
+:1004E000000020210A000D1A27BD00183C05080055
+:1004F00024A55D683C04080024847B343C02080089
+:1005000024425D70240300063C010801AC258310E1
+:100510003C010801AC2483143C010801AC2283187F
+:100520003C010801A023831C03E000080000000038
+:1005300003E00008240200013C028000308800FF34
+:10054000344701803C0680008CC301B80460FFFE84
+:10055000000000008CC501282418FF803C0D800A93
+:1005600024AF010001F8702431EC007FACCE0024F0
+:10057000018D2021ACE50000948B00DA3509600084
+:1005800024080002316AFFFFACEA000424020001E3
+:10059000A4E90008A0E8000BACE000243C07100030
+:1005A000ACC701B8AF84002803E00008AF85005C49
+:1005B0008C9800048F8C00282409FFBF0305782342
+:1005C000AC8F0004918E00C42403FFEF31CD007F77
+:1005D000A18D00C48C8B00208F860028A780004C42
+:1005E000356A0002A4C000ACAC8A002090C800C4E8
+:1005F00001093824A0C700C48F840028AC8000DC27
+:10060000908500C400A3102403E00008A08200C469
+:100610003C028000344501803C0480008C8301B89A
+:100620000460FFFE8F89005C2407608324060002BB
+:10063000ACA900008C880124ACA80004A4A7000881
+:10064000A0A6000B3C05100003E00008AC8501B833
+:10065000938800388F8900508F82002830C600FFB1
+:100660000109382330E900FF0122182130A500FFDD
+:100670002468007810C0000201243821008038214D
+:1006800030E400031480000330AA00031140000D81
+:10069000312B000310A000090000102190ED000094
+:1006A000244E000131C200FF0045602BA10D000067
+:1006B00024E700011580FFF92508000103E0000888
+:1006C000000000001560FFF30000000010A0FFFB19
+:1006D000000010218CF8000024590004332200FF90
+:1006E0000045782BAD18000024E7000415E0FFF961
+:1006F0002508000403E0000800000000938500388E
+:10070000938800488F870050000432003103007F37
+:1007100000E5102B30C47F001040000F0064282536
+:100720008F8400283C0980008C8A00DCAD2A00A45C
+:100730003C03800000A35825AC6B00A08C6C00A08B
+:100740000580FFFE000000008C6D00ACAC8D00DC6D
+:1007500003E000088C6200A80A0017DA8F840028E2
+:10076000938800493C02800000805021310300FE44
+:10077000A383004930ABFFFF30CC00FF30E7FFFF21
+:10078000344801803C0980008D2401B80480FFFEBC
+:100790008F8D005C24180016AD0D00008D22012401
+:1007A0008F8D0028AD0200048D590020A507000898
+:1007B000240201B4A119000AA118000B952F0120F1
+:1007C0008D4E00088D4700049783004C8D590024FE
+:1007D00001CF302100C7282100A320232418FFFFC8
+:1007E000A504000CA50B000EA5020010A50C00121C
+:1007F000AD190018AD18002495AF00D83C0B1000BF
+:100800002407FFF731EEFFFFAD0E00288DAC00741A
+:10081000AD0C002CAD2B01B88D46002000C728245C
+:1008200003E00008AD4500208F8800280080582193
+:1008300030E7FFFF910900C63C02800030A5FFFFB2
+:10084000312400FF00041A000067502530C600FF65
+:10085000344701803C0980008D2C01B80580FFFEE3
+:100860008F82005C240F0017ACE200008D39012458
+:10087000ACF900048D780020A4EA0008241901B422
+:10088000A0F8000AA0EF000B952301208D6E000850
+:100890008D6D00049784004C01C35021014D6021EF
+:1008A00001841023A4E2000CA4E5000EA4F90010BA
+:1008B000A4E60012ACE000148D780024240DFFFFA4
+:1008C000ACF800188D0F006CACEF001C8D0E0068AA
+:1008D0003C0F1000ACEE0020ACED0024950A00AEF9
+:1008E000240DFFF73146FFFFACE60028950C0070A1
+:1008F0009504007231837FFF0003CA003082FFFF3E
+:100900000322C021ACF8002CAD2F01B8950E007267
+:100910008D6A002000AE3021014D2824A50600720A
+:1009200003E00008AD6500203C02800034460180F1
+:100930003C0580008CA301B80460FFFE2409001868
+:10094000ACC40000A0C9000B8F8800283C04100034
+:10095000950700AEA4C70010ACC0003003E000084B
+:10096000ACA401B83C028000344501803C04800006
+:100970008C8301B80460FFFE8F8A003424060019BE
+:100980009549001C3128FFFF000839C0ACA70000C2
+:10099000A0A6000B3C05100003E00008AC8501B8E0
+:1009A0008F87003C0080402130C400FF3C0680005F
+:1009B0008CC201B80440FFFE8F89005C938300580D
+:1009C00034996000ACA90000A0A300058CE20010DF
+:1009D000240F00022403FFF7A4A20006A4B9000814
+:1009E0008D180020A0B8000AA0AF000B8CEE00000C
+:1009F000ACAE00108CED0004ACAD00148CEC001C0F
+:100A0000ACAC00248CEB0020ACAB00288CEA002CB2
+:100A10003C071000ACAA002C8D090024ACA90018DA
+:100A2000ACC701B88D05002000A3202403E0000816
+:100A3000AD040020938500582403000127BDFFE882
+:100A400000A330042CA20020AFB00010AFBF0014F0
+:100A500000C01821104000132410FFFE3C070800BE
+:100A60008CE7319000E610243C08800035050180B9
+:100A700014400005240600848F890028240A0004FD
+:100A80002410FFFFA12A00EC0E00187600000000E1
+:100A9000020010218FBF00148FB0001003E0000887
+:100AA00027BD00183C0608008CC631940A0018A81F
+:100AB00000C310248F87003427BDFFE0AFB20018B9
+:100AC000AFB10014AFB00010AFBF001C30D000FFBA
+:100AD00090E6000D00A088210080902130C5007FA5
+:100AE000A0E5000D8F8500288E2300188CA200C081
+:100AF0001062002E240A000E0E00189BA38A0058D4
+:100B00002409FFFF104900222404FFFF52000020A7
+:100B1000000020218E2600003C0C001000CC582440
+:100B2000156000393C0E000800CE682455A0003F37
+:100B3000024020213C18000200D880241200001F2F
+:100B40003C0A00048F8700348CE200148CE3001010
+:100B50008CE500140043F82303E5C82B132000059F
+:100B6000024020218E24002C8CF1001010910031C5
+:100B70000240202124020012A38200580E00189B7C
+:100B80002412FFFF105200022404FFFF0000202166
+:100B90008FBF001C8FB200188FB100148FB00010EF
+:100BA0000080102103E0000827BD002090A800C4A9
+:100BB000350400200A0018D1A0A400C400CA4824AB
+:100BC0001520000B8F8B00348F8D00348DAC0010FE
+:100BD0001580000B024020218E2E002C51C0FFEC0E
+:100BE00000002021024020210A0018EC24020017F6
+:100BF0008D66001050C0FFE6000020210240202139
+:100C00000A0018EC240200110240202124020015E1
+:100C10000E00189BA3820058240FFFFF104FFFDC2B
+:100C20002404FFFF0A0018DB8E2600000A001912B8
+:100C3000240200143C08000400C8382450E0FFD40B
+:100C400000002021024020210A0018EC2402001399
+:100C50008F86002827BDFFE0AFB10014AFBF00189A
+:100C6000AFB0001090C300C430A500FF3062002078
+:100C700010400008008088218CCB00C02409FFDFD1
+:100C8000256A0001ACCA00C090C800C4010938241C
+:100C9000A0C700C414A000403C0C80008F84002832
+:100CA000908700C42418FFBF2406FFEF30E3007FC5
+:100CB000A08300C4979F004C8F8200508F8D002826
+:100CC00003E2C823A799004CA5A000AC91AF00C4D3
+:100CD00001F87024A1AE00C48F8C0028A18000C749
+:100CE0008F8A0028A5400072AD4000DC914500C409
+:100CF00000A65824A14B00C48F9000248F8400507C
+:100D00009786004C0204282110C0000FAF850024F4
+:100D1000A38000483C0780008E2C000894ED012041
+:100D20008E2B0004018D5021014B802102062023CF
+:100D30003086FFFF30C8000F390900013131000152
+:100D400016200009A3880048938600388FBF00183A
+:100D50008FB100148FB0001027BD0020AF85005464
+:100D600003E00008AF86005000C870238FBF001852
+:100D7000938600388FB100148FB0001034EF0C0050
+:100D8000010F282127BD0020ACEE0084AF85005460
+:100D900003E00008AF860050359001800200282152
+:100DA0000E001876240600828F840028908600C4E6
+:100DB00030C5004050A0FFBAA38000588F85003C8A
+:100DC0003C0680008CCD01B805A0FFFE8F89005C39
+:100DD0002408608224070002AE090000A60800086B
+:100DE000A207000B8CA300083C0E1000AE030010FD
+:100DF0008CA2000CAE0200148CBF0014AE1F0018B1
+:100E00008CB90018AE1900248CB80024AE18002844
+:100E10008CAF0028AE0F002CACCE01B80A001936FA
+:100E2000A38000588F8A002827BDFFE0AFB10014CF
+:100E3000AFB000108F880050AFBF00189389002C0E
+:100E4000954200AC30D100FF0109182B00808021B1
+:100E500030AC00FF3047FFFF000058211460000352
+:100E6000310600FF01203021010958239783004CEF
+:100E70000068202B1480001B000000001068004355
+:100E8000240A0001118A004834E708803165FFFF19
+:100E90000E001818020020210E0018588F84005CE4
+:100EA0008F840028948D007025AC0001A48C007004
+:100EB000948B00703C0608008CC6318831677FFF38
+:100EC00010E6004F0000000002002021022028212F
+:100ED0008FBF00188FB100148FB000100A001922C4
+:100EE00027BD0020914400C42406FF800086882589
+:100EF000A15100C49784004C3088FFFF1100001CF2
+:100F00009389002C8F8E00282419EFFF008BF82383
+:100F100095D800AC0168682B33E900FF03197824E9
+:100F2000A5CF00AC51A0002A010058218E05002059
+:100F30002408FFFB2403000100A81024AE020020B7
+:100F40001183002534E78000020020213165FFFF76
+:100F50000E00181801203021978B004C8F8700500D
+:100F6000A780004C00EB8023AF9000509389002CA9
+:100F70008F8C00288FBF00188FB100148FB0001025
+:100F800027BD002003E00008A18900C78E080020CB
+:100F90002409FFFB34E7800001092824AE05002066
+:100FA000158AFFBA34E70880020020210E0017E6F8
+:100FB0003165FFFF02002021022028218FBF001889
+:100FC0008FB100148FB000100A00192227BD002035
+:100FD0000A0019D900004821020020213165FFFFD5
+:100FE0000E0017E601203021978B004C8F870050B0
+:100FF000A780004C00EB80230A0019E9AF90005055
+:1010000094890070240A8000012A4024A48800707A
+:10101000908500709099007030A200FF000219C204
+:101020000003F827001FC1C0332F007F01F870258F
+:10103000A08E00700A0019C1020020218F880028AC
+:1010400024030001910A0078910500C72509007862
+:101050003147003F24E6FFE000C318042CC2002003
+:1010600030670019A385002C1040001AAF89003C9E
+:101070003C0A8000354B00022405000124060001D3
+:1010800014E00016006B1024000028211440000F0B
+:10109000306300201060000F240500018D060074ED
+:1010A0008D1900742403FF8000C3102400027940CE
+:1010B0003338007F01F868253C0E100001AE602532
+:1010C000AD4C083091280001310600010A00199743
+:1010D0000000000003E00008000000008D0F007415
+:1010E0008D0D00742418FF8001F87024000E41401B
+:1010F00031AC007F010C50253C0B1000014B382512
+:101100003C0980000A001997AD27083027BDFFD899
+:10111000AFB000108F90003CAFB40020AFB100140E
+:10112000AFBF0024AFB3001CAFB200188E05001093
+:101130003C0208008C4231B08F86004030A73FFF50
+:1011400000E2182B8CD20014008088218CD3002060
+:10115000106000070000A02190CB000D240AFF8042
+:10116000014B4824312800FF1500000C0005638264
+:10117000022020212411000DA39100588FBF0024CC
+:101180008FB400208FB3001C8FB200188FB10014F1
+:101190008FB000100A00189B27BD0028318500037E
+:1011A00054A0FFF40220202194CF001C8F8E002831
+:1011B0008E070028A5CF00D88CCD0010024D30231B
+:1011C00010E6005C2402001F0E00189BA38200584A
+:1011D000241FFFFF105F004E2404FFFF8F83004495
+:1011E0008F880034026398218D0900100123102399
+:1011F0008F830020AD020010AD1300208C670074B7
+:1012000000F3202B14800062022020218F860040F2
+:101210008E0C00248CC5002411850007022020219B
+:10122000240E001C0E00189BA38E0058240DFFFFF7
+:10123000104D00372404FFFF8F8400348C98002465
+:10124000270F0001AC8F0024127200448F990020F8
+:101250008F320074125300413C0A00808E09000056
+:10126000012A10241440003A000000008E040014EB
+:101270002412FFFF10920006240B001B02202021E5
+:101280000E00189BA38B0058105200212404FFFF6E
+:101290008E0300003C0C0001006C282410A00013F9
+:1012A0003C0600800066A024168000090200282168
+:1012B00002202021240E001A0E00189BA38E005835
+:1012C000240DFFFF104D00122404FFFF020028210F
+:1012D000022020210E0018BB240600012410FFFF6D
+:1012E0002404FFFF1050000A241400018F8F0034E3
+:1012F000022020210280302195F2003424050001D3
+:10130000265800010E001997A5F80034000020218E
+:101310008FBF00248FB400208FB3001C8FB2001841
+:101320008FB100148FB000100080102103E000087E
+:1013300027BD00288F83004400E3C8210259C02B39
+:101340001300FFA88F8800340A001A8024020018B6
+:10135000AC8000200A001AAA8E0400148E1F000020
+:101360003C07008003E798241660FFF92408001A60
+:10137000022020210E00189BA38800582403FFFFA1
+:101380001443FFBA2404FFFF0A001AD38FBF0024BE
+:10139000240B001D0E00189BA38B0058240AFFFF8E
+:1013A000144AFF9A2404FFFF0A001AD38FBF0024B7
+:1013B0008F85002827BDFFD8AFB3001CAFB200183F
+:1013C000AFB10014AFB00010AFBF002090A700C4B1
+:1013D0008F90003C2412FFFF34E200409206000090
+:1013E000A0A200C48E030010008098211072000695
+:1013F00030D1003F2408000D0E00189BA388005830
+:10140000105200252404FFFF8F8A00288E0900183F
+:101410008D4400C01124000702602021240C000E1E
+:101420000E00189BA38C0058240BFFFF104B001AD2
+:101430002404FFFF24040020122400048F8D0028C0
+:1014400091AF00C435EE0020A1AE00C48F850044EA
+:1014500010A00019000000001224004A8F980028F4
+:101460008F92FED0971000709651000A52300048BB
+:101470008F9300303C1F08008FFF318C03E5C82B91
+:101480001720001E02602021000028210E0019975D
+:1014900024060001000020218FBF00208FB3001C14
+:1014A0008FB200188FB100148FB00010008010218F
+:1014B00003E0000827BD00285224002A8E050014EE
+:1014C0008F840028948A007025490001A489007047
+:1014D000948800703C0208008C42318831077FFFFD
+:1014E00010E2000E00000000026020210E00192210
+:1014F000240500010A001B34000020212402002DD5
+:101500000E00189BA38200582403FFFF1443FFE141
+:101510002404FFFF0A001B358FBF00209499007040
+:10152000241F800024050001033FC024A4980070FC
+:1015300090920070908E0070325100FF001181C2B5
+:1015400000107827000F69C031CC007F018D58252D
+:10155000A08B00700E001922026020210A001B34AB
+:10156000000020212406FFFF54A6FFD68F84002808
+:10157000026020210E001922240500010A001B34FC
+:1015800000002021026020210A001B4E2402000AD4
+:101590002404FFFD0A001B34AF9300508F880028FD
+:1015A00027BDFFE8AFB00010AFBF0014910A00C420
+:1015B0008F87003C00808021354900408CE6001078
+:1015C000A10900C43C0208008C4231B030C53FFF85
+:1015D00000A2182B106000078F850040240DFF80AB
+:1015E00090AE000D01AE6024318B00FF1560000845
+:1015F0000006C382020020212403000D8FBF0014C7
+:101600008FB0001027BD00180A00189BA383005854
+:1016100033060003240F000254CFFFF702002021FD
+:1016200094A2001C8F85002824190023A4A200D8AE
+:101630008CE8000000081E02307F003F13F90035DF
+:101640003C0A00838CE800188CA600C01106000834
+:10165000000000002405000E0E00189BA385005812
+:101660002407FFFF104700182404FFFF8F85002880
+:1016700090A900C435240020A0A400C48F8C00349D
+:10168000918E000D31CD007FA18D000D8F83004420
+:101690001060001C020020218F8400408C980010F4
+:1016A0000303782B11E0000D2419001802002021FB
+:1016B000A39900580E00189B2410FFFF1050000241
+:1016C0002404FFFF000020218FBF00148FB0001002
+:1016D0000080102103E0000827BD00188C86001050
+:1016E0008F9F00340200202100C31023AFE20010BE
+:1016F000240500010E001997240600010A001BC0F2
+:10170000000020210E001922240500010A001BC040
+:1017100000002021010A5824156AFFD98F8C00345B
+:10172000A0A600EC0A001BADA386004A27BDFFD887
+:10173000AFB000108F90003CAFB20018AFBF0020D8
+:10174000AFB3001CAFB100148E1100103C030800B1
+:101750008C6331B032253FFF00A3102B10400008EE
+:10176000008090218F8600402409FF8090CA000DE0
+:10177000012A4024310700FF14E0000B00116B82A6
+:10178000024020212412000DA39200588FBF002098
+:101790008FB3001C8FB200188FB100148FB00010EF
+:1017A0000A00189B27BD002831AC0003240B000160
+:1017B000558BFFF40240202190CF000D31EE000840
+:1017C00011C000608F9300441660000924020027B6
+:1017D0008E19000C8CD80020173800052402002038
+:1017E0008E0200088CDF0024105F004024020020DD
+:1017F0000E00189BA38200582406FFFF10460033FA
+:101800002404FFFF8F990034240AFFF73C13800E55
+:101810009329000D2404FF803C0D8000012AF82448
+:10182000A33F000D8F9900203C0808008D0831ACC3
+:101830008F83005C972700788F9F0034010310216D
+:1018400030E57FFF000530400046782131F8007F09
+:101850000313602101E47024ADAE002CA5910000BB
+:101860008FEB0028256A0001AFEA00288FE3002CE7
+:101870008E09002C00694021AFE8002C8E07002C57
+:10188000AFE700308E050014AFE5003497E6003A6C
+:1018900024C20001A7E2003A973300783C10080008
+:1018A0008E1031B02663000130717FFF12300027A7
+:1018B000006030218F8F002002402021240500018C
+:1018C0000E001922A5E60078000020218FBF00201D
+:1018D0008FB3001C8FB200188FB100148FB00010AE
+:1018E0000080102103E0000827BD00288E050014A9
+:1018F0002413FFFF10B3001D8F8300288E080018EB
+:101900008C6700C0150700092402000E8E0A00240F
+:101910008CC9002815490005240200218E070028E3
+:101920008CCB002C10EB00132402001F0E00189B20
+:10193000A38200581453FFB32404FFFF0A001C4283
+:101940008FBF00200A001C0A24020024240E8000FD
+:10195000006E682431ACFFFF000C5BC2317100FFE8
+:10196000001180270A001C3B001033C00A001C59DC
+:10197000240200258E05002C10A0FFEC2402002379
+:101980008F8E00208DCD007401A5602B1580FFE7A0
+:10199000240200268CCF001400A7C02101F8202BC0
+:1019A0001080FF998F990034024020210A001C59B1
+:1019B0002402002227BDFFE0AFB000108F90003C52
+:1019C000AFB10014AFBF00188E0500103C03080033
+:1019D0008C6331B00080882130A43FFF0083102B3E
+:1019E000104000078F8600402409FF8090CA000D38
+:1019F000012A4024310700FF14E000098F8B0044C6
+:101A00002410000D02202021A39000588FBF001841
+:101A10008FB100148FB000100A00189B27BD002062
+:101A2000116000070005CB828F8F00288F8EFED0BB
+:101A300095EC007095CD000A11AC00578F850030F1
+:101A4000333800031700001000000000921F00024E
+:101A500013E00041000000008E06002450C0000F7B
+:101A600092040003022020212402000F0E00189B84
+:101A7000A38200582408FFFF144800072404FFFF36
+:101A80000A001CD58FBF001890C7000D30E3000876
+:101A90001060003702202021920400032409000274
+:101AA000308A00FF15490005308500FF8F8B004408
+:101AB0005160003102202021308500FF38B800102D
+:101AC0002CAF00012F0E000102002821022020214E
+:101AD0000E0018BB01EE30252410FFFF1050000E41
+:101AE0002404FFFF8F830044106000170220202190
+:101AF0003C1F08008FFF318C03E3C82B5720000CDC
+:101B00002411002D02202021000028210E00199709
+:101B100024060001000020218FBF00188FB100149F
+:101B20008FB000100080102103E0000827BD0020C6
+:101B30000E00189BA39100581450FFF62404FFFFD9
+:101B40000A001CD58FBF00180E00192224050001C1
+:101B50000A001CD4000020218CC400248E02002422
+:101B60005444FFC1022020210A001CB59204000346
+:101B70000A001CA924020010240D002C0E00189B42
+:101B8000A38D0058240CFFFF104CFFE32404FFFF3B
+:101B90000A001CBC920400032404FFFD0A001CD4AC
+:101BA000AF85005030A500FF2406000124A90001E4
+:101BB00000C9102B1040000C00004021240A000135
+:101BC00000A61823308B000124C60001006A3804E7
+:101BD000000420421160000200C9182B01074025B3
+:101BE0001460FFF800A6182303E00008010010218C
+:101BF00027BDFFD8AFB000188F90003CAFB1001CDC
+:101C0000AFBF00202403FFFF2411002FAFA300105B
+:101C10009206000024050008261000010066202618
+:101C20000E001CF7308400FF00021E003C021EDC88
+:101C300034466F410A001D1F0000102110A000094A
+:101C4000008018212445000130A2FFFF2C45000828
+:101C50000461FFFA000320400086202614A0FFF94B
+:101C6000008018210E001CF7240500208FA300100F
+:101C70002629FFFF313100FF00034202240700FF45
+:101C80001627FFE20102182600035027AFAA00140E
+:101C9000AFAA00100000302127A8001027A70014C9
+:101CA00000E6782391ED000324CE000100C86021F6
+:101CB00031C600FF2CCB00041560FFF9A18D000098
+:101CC0008FA200108FBF00208FB1001C8FB00018B2
+:101CD00003E0000827BD00289383003827BDFFE0FC
+:101CE00024020034AFB10014AFB00010AFBF001C2D
+:101CF000AFB20018008080211062006500A088212A
+:101D000092240004148000488F880028A380002CAF
+:101D10008E2500048D0700C83C0600FF34C3FFFF7A
+:101D200000A3302400E6102B14400050AF8600447E
+:101D30008F870050978A004CAF87003001474023BF
+:101D400010C00034A788004C8F99002030DF0003BA
+:101D5000001F20239332007C309000030206702184
+:101D60000012C082331200010012788001CF682176
+:101D7000310CFFFF018D582B5160005F8F880028C8
+:101D80008F8900248F8200541049007B3C033F015F
+:101D90008E2600003C11250000C3282414B10078D1
+:101DA0008F84003C8F8A003C8F8800288D4B000078
+:101DB000AD0B00788D470010AD0700888F8700506D
+:101DC0008F860044938C002C01276821020628216D
+:101DD000020C1821A383002C950900ACAF8D0024C0
+:101DE00035301000A51000AC1640005024720004DD
+:101DF000AF850050000020218FBF001C8FB200185B
+:101E00008FB100148FB000100080102103E0000893
+:101E100027BD00208F840024AF8000500087402120
+:101E20000A001D8BAF880024241F000CA39F0058BC
+:101E30000E00189B020020212419FFFF1059FFEE0D
+:101E40002404FFFF8F880028A380002C8E25000427
+:101E50008D0700C83C0600FF34C3FFFF00A33024F9
+:101E600000E6102B1040FFB2AF8600440200202194
+:101E700024090019A38900580E00189B2410FFFFA5
+:101E80001050FFDD2404FFFF0A001D5A8F86004416
+:101E90008F8400288F87003C8CF20030908600C42D
+:101EA00030C5001014A000108F8300502C6800056E
+:101EB0001500002600000000908A00C4246BFFFC7F
+:101EC0003149001015200008316400FF8F8D005447
+:101ED0008F8C002411AC0004388F000131EE00011A
+:101EE00015C0002F000000000E001D0A00000000B9
+:101EF0000A001DE2000000008F890024938C002C52
+:101F00000127682102062821020C1821A383002C36
+:101F1000950900ACAF8D002435301000A51000AC41
+:101F20005240FFB4AF85005024720004A392002CED
+:101F3000950F00AC24B80004AF98005035EE200097
+:101F4000A50E00AC0A001D8C000020218C8200DC54
+:101F50001242FF6B0200202124180005A3980058AC
+:101F60000E00189B2412FFFF1452FF652404FFFF8C
+:101F70000A001D8D8FBF001C0A001DCD8F88002810
+:101F800030E500FF0E0017A2000030218F880028E6
+:101F90008F8700508F8900240A001D7F8F860044A0
+:101FA0000E0017CD000000000A001DE20000000036
+:101FB0009383004A27BDFFE024020002AFB200185D
+:101FC000AFB10014AFBF001CAFB00010008088217B
+:101FD000106200B6000090219783004C8F8500505E
+:101FE0003066FFFF00C5202B1480005B938700380C
+:101FF0003C0880009504012010E500528F8A0024DF
+:102000008F84005430A500FF0E0017A224060001A3
+:102010008F82005C3C0B80003C1F4080244E017886
+:1020200031D00078240FFF80021F60253578090029
+:1020300031D9000701CF6824AD6D08000338802135
+:10204000AD6C081002202021020028210E001D4442
+:10205000AF90003C2403FFFF104300332404FFFF34
+:102060008E0C00103C0708008CE731B0920600008F
+:1020700031843FFF0087282B10A0002330CD003F84
+:102080008F99005C000479803C0408008C8431A89E
+:102090002409FF809390004900994021010F2021DD
+:1020A00000897824000F51403C098000309F007F58
+:1020B0003C0B00808F880028308E00783578000136
+:1020C000015F282530860007352709403C031000B2
+:1020D0003C02800C01D8582500C7C82100A3502518
+:1020E00003E2C021360E0001AD2F0804AF99004075
+:1020F000AD2B0814AF980034AD2F0028AD04007448
+:10210000AD2A0830A38E00499383004A24100003AF
+:102110005070002725A3FFE0240C0001106C001C68
+:1021200024060023024020218FBF001C8FB200181C
+:102130008FB100148FB000100080102103E0000860
+:1021400027BD0020314900035520FFAE8F84005485
+:102150000A001E1F8F9000548F840054306500FFCA
+:102160000E0017A224060001938E003824070034C5
+:1021700011C700188F8500509783004C3078FFFFFF
+:1021800000B87023AF8E00500A001E57A780004C85
+:1021900011A6003200000000022020212411000BB3
+:1021A0000E00189BA39100580A001E570040902172
+:1021B0002C7200201240FFF8000310803C0508013B
+:1021C00024A581600045F8218FED000001A00008E2
+:1021D000000000002CB800051700FFE89783004CB2
+:1021E000978A004C3148FFFF00A848232D2B00059B
+:1021F00011600003314400FF24AFFFFC31E400FF15
+:102200008F9000548F99002412190004389F000108
+:1022100033ED000115A00029000000008F85002883
+:1022200090A700C434E30010A0A300C49783004C1F
+:102230008F8500508F8400283078FFFF00B870230E
+:10224000AC8000DCA780004C0A001E57AF8E005007
+:102250002403FFFF11830005000000000E001B7522
+:10226000022020210A001E57004090210E001AFA79
+:10227000022020210A001E57004090210E001C7BE6
+:10228000022020210A001E57004090210E001BD979
+:10229000022020210A001E57004090210E001A51F2
+:1022A000022020210A001E5700409021938500380B
+:1022B0002404FFFD0A001E58AF8500500E0017CD04
+:1022C000000000009783004C8F85005000402021C3
+:1022D0003066FFFF00A660232D8200051040FFA896
+:1022E0003078FFFF8F91002800B87023AE2400DC07
+:1022F000A780004C0A001E57AF8E005027BDFFD0AC
+:10230000AFB20018AFB00010AFBF0028AFB50024C7
+:10231000AFB40020AFB3001CAFB100143C0C800080
+:102320008D880128240FFF803C07800A25100100BA
+:10233000250B0080020F68243205007F016F702496
+:10234000AD8E009000A72821AD8D002490A700EC51
+:102350003169007F3C0A8004012A1821A387004AC2
+:102360009066007C00809021AF83002030C2000284
+:10237000AF88005CAF85002800A01821144000023F
+:102380002404003424040030A38400388C6600CC7C
+:1023900030F100FF24040004AF8600501224000432
+:1023A000A38000588E5300041660001D3C08800076
+:1023B0009387004930F200011240000F8FBF0028C0
+:1023C0008CB800748CA400742419FF80031988242D
+:1023D00000117140308F007F01CF60253C0D20003F
+:1023E000018D582530F500FE3C0A8000AD4B0830C9
+:1023F000A39500498FBF00288FB500248FB400201B
+:102400008FB3001C8FB200188FB100148FB0001072
+:102410002402000127BD003003E00008ACA600CC78
+:102420008E590008951F01208E460010033FC021E1
+:102430003307FFFF30F5000F32B40001AF860024F0
+:102440001680003BA395004835060C0002A610211B
+:1024500000F51823AD030084AF8200548E490004B8
+:102460003128FFFF1100002BA789004C2410FF80AA
+:102470003C1580003C1420000A001F442413FFFE7A
+:1024800090AE00C4020E682431AC00FF1580002A13
+:1024900002402021938400499786004C308F000130
+:1024A00011E0000B026428248F8900288D2300741A
+:1024B0008D280074A3850049007010240002C940D3
+:1024C000311F007F033FC02503148825AEB10830BB
+:1024D00010C000108F85002890A700C40207582460
+:1024E000316A00FF1540FFE6024020210E001DFA70
+:1024F0009791004C1040FFE8938400492405FFFDAC
+:10250000544500058E430020022028210E00177A32
+:10251000024020218E430020307000041600000A83
+:102520002414FFFB8F8500280A001EFA8F860050B6
+:102530000A001F25AF8600540E001A1D000000007F
+:102540000A001F3493840049007498240E001792E7
+:10255000AE5300208F8500280A001EFA8F86005097
+:1025600027BDFFD8AFB3001CAFB10014AFBF002030
+:10257000AFB20018AFB000103C0280008C52014096
+:102580008C4B01483C048000000B8C02322300FF7E
+:10259000317300FF8C8501B804A0FFFE34900180E8
+:1025A000AE1200008C8701442464FFF02406000270
+:1025B0002C830013AE070004A6110008A206000B2E
+:1025C000AE1300241060004F8FBF0020000448802D
+:1025D0003C0A0801254A81E0012A40218D040000BF
+:1025E00000800008000000003C1008008E1031A898
+:1025F00031733FFF001389800212C8212405FF8038
+:1026000003312021264C0100264700803C1F80001A
+:1026100000E51824318F007F30E9007F308A007F89
+:102620003C18800A3C0E80043C0D800C0085102470
+:1026300001853024014D8021AFE6002401F84021BE
+:10264000AFE30090012E9821AFE20028AF90003454
+:10265000AF880028AF9300200E001867016080212A
+:102660003C0380008C6B01B80560FFFE8F8700344F
+:10267000346501808F86002890E3000DACB2000025
+:10268000A4B00006000316000002FE03001F9027FE
+:10269000001227C21080007A24C2007824196082B8
+:1026A000A4B90008A0A00005241F0002A0BF000BD1
+:1026B00000041C008F8B00203C0227000062902544
+:1026C000ACB20010ACA00014ACA00024ACA0002858
+:1026D000ACA0002C8D7300382410FF80ACB3001820
+:1026E00090E4000D02048824322500FF10A00005AC
+:1026F0008FBF002090EC000D3188007FA0E8000D16
+:102700008FBF00208FB3001C8FB200188FB1001450
+:102710008FB000103C0D10003C0A800027BD00283F
+:1027200003E00008AD4D01B8265F01002405FF80DD
+:1027300033F8007F3C06800003E578243C19800ACA
+:1027400003192021ACCF0024908E00C400AE682471
+:1027500031AC00FF1180FFEAAF840028248E00789E
+:1027600095CD00123C0C08008D8C31A831AB3FFF99
+:1027700001924821000B5180012A402101052024AB
+:10278000ACC400283107007F3C06800C00E6202105
+:102790009083000D00A31024304500FF10A0FFD847
+:1027A000AF8400349098000D330F001015E0FFD572
+:1027B0008FBF00200E001867000000003C0380005F
+:1027C0008C7901B80720FFFE00000000AE12000067
+:1027D0008C720144AE120004A611000824110002FC
+:1027E000A211000BAE1300240A001FCF8FBF0020E0
+:1027F0003C1260008E452C083C03F0033462FFFF5E
+:1028000000A2F824AE5F2C088E582C083C1901B0A9
+:1028100003199825AE532C080A001FCF8FBF002044
+:10282000264D010031AF007F3C10800A240EFF804E
+:1028300001F0282101AE60243C0B8000AD6C002427
+:102840001660FFAFAF85002824110003A0B100EC93
+:102850000A001FCF8FBF002026480100310A007FE9
+:102860003C0B800A2409FF80014B30210109202400
+:102870003C078000ACE400240A001FCEAF8600288D
+:10288000944A001232083FFF314C3FFF1588FF8405
+:102890002419608290CF00C4240EFF8001CF482409
+:1028A000312D00FF11A0FF7E00000000240700046E
+:1028B000A0C700EC8F870034241860842406000D24
+:1028C000A4B80008A0A600050A001FB9241F000232
+:1028D0000800330C0800330C080033E8080033BC50
+:1028E000080033A0080032F0080032F0080032F08F
+:1028F0000800331480080100800800808008000070
+:102900005F865437E4AC62CC50103A453662198584
+:10291000BF14C0E81BC27A1E84F4B556094EA6FE49
+:102920007DDA01E7C04D748108007A8808007AB426
+:1029300008007A94080079D008007A9408007AD4C4
+:1029400008007A94080079D0080079D0080079D07E
+:10295000080079D0080079D0080079D0080079D033
+:10296000080079D0080079D0080079D008007AC42E
+:1029700008007AA4080079D0080079D0080079D03E
+:10298000080079D0080079D0080079D0080079D003
+:10299000080079D0080079D0080079D0080079D0F3
+:1029A000080079D008007AA40800809008007F38D9
+:1029B0000800805808007F380800802808007E2022
+:1029C00008007F3808007F3808007F3808007F380B
+:1029D00008007F3808007F3808007F3808007F38FB
+:1029E00008007F3808007F3808007F3808007F38EB
+:0429F00008007F60FC
+:0C29F4000A0001220000000000000000AA
+:102A00000000000D747061352E302E306A313500B3
+:102A100005000001000000000000000000000000B0
+:102A200000000000000000000000000000000000A6
+:102A30000000000000000000000000000000000096
+:102A40000000000000000000000000000000000086
+:102A50000000000000000000000000000000000076
+:102A60000000000000000000000000000000000066
+:102A70000000000000000000000000000000000056
+:102A800010000003000000000000000D0000000D19
+:102A90003C02080024421C203C03080024631FA0C1
+:102AA000AC4000000043202B1480FFFD24420004B2
+:102AB0003C1D080037BD2FFC03A0F0213C1008008E
+:102AC000261004883C1C0800279C1C200E0002E2F3
+:102AD000000000000000000D2402FF8027BDFFE081
+:102AE00000821024AFB00010AF420020AFBF00182A
+:102AF000AFB10014936500043084007F03441821B3
+:102B00003C0200080062182130A5002003608021EB
+:102B10003C080111277B000814A000022466005C19
+:102B200024660058920200049743010492040004B2
+:102B30003047000F3063FFFF3084004000672823D8
+:102B40001080000900004821920200053042000474
+:102B5000104000050000000010A00003000000006D
+:102B600024A5FFFC24090004920200053042000461
+:102B7000104000120000000010A000100000000033
+:102B80009602000200A72021010440252442FFFEF6
+:102B9000A7421016920300042402FF800043102471
+:102BA000304200FF104000033C0204000A000172A2
+:102BB000010240258CC20000AF4210188F420178FC
+:102BC0000440FFFE2402000AA742014096020002D0
+:102BD000240400093042000700021023304200079D
+:102BE000A7420142960200022442FFFEA74201448E
+:102BF000A740014697420104A74201488F420108BD
+:102C000030420020504000012404000192020004E0
+:102C1000304200101440000234830010008018215C
+:102C2000A743014A0000000000000000000000006F
+:102C300000000000AF48100000000000000000008D
+:102C400000000000000000008F4210000441FFFE61
+:102C50003102FFFF10400007000000009202000454
+:102C60003042004014400003000000008F42101862
+:102C7000ACC20000960200063042FFFF2442000270
+:102C800000021043000210400362882196220000D7
+:102C90001120000D3044FFFF00A710218F83003862
+:102CA0008F45101C0002108200021080004310218A
+:102CB000AC45000030A6FFFF0E0002D100052C023B
+:102CC00000402021A6220000920300042402FF807D
+:102CD00000431024304200FF1040001F000000009D
+:102CE00092020005304200021040001B000000006C
+:102CF0009742100C2442FFFEA7421016000000006D
+:102D00003C02040034420030AF42100000000000DA
+:102D10000000000000000000000000008F421000D2
+:102D20000441FFFE000000009742100C8F45101C6C
+:102D30003042FFFF24420030000210820002108067
+:102D4000005B1021AC45000030A6FFFF0E0002D151
+:102D500000052C02A622000096040002248400082C
+:102D60000E0001E73084FFFF974401040E0001F5D7
+:102D70003084FFFF8FBF00188FB100148FB0001098
+:102D80003C02100027BD002003E00008AF4201789C
+:102D90003084FFFF308200078F850024104000023E
+:102DA000248300073064FFF800A4102130421FFF85
+:102DB00003421821247B4000AF850028AF82002405
+:102DC00003E00008AF4200843084FFFF3082000F30
+:102DD0008F85002C8F860034104000022483000F62
+:102DE0003064FFF000A410210046182BAF8500309E
+:102DF0000046202314600002AF82002CAF84002C18
+:102E00008F82002C340480000342182100641821B2
+:102E1000AF83003803E00008AF4200808F820014C7
+:102E2000104000088F8200048F82FFCC1440000500
+:102E30008F8200043C02FFBF3442FFFF0082202447
+:102E40008F82000430430006240200021062000F4B
+:102E50003C0201012C6200035040000524020004E2
+:102E60001060000F3C0200010A00022E000000006A
+:102E700010620005240200061462000C3C020111DD
+:102E80000A000227008210253C0200110082102552
+:102E9000AF421000240200010A00022EAF82000C93
+:102EA00000821025AF421000AF80000C000000002F
+:102EB000000000000000000003E000080000000027
+:102EC0008F82000C10400004000000008F421000B0
+:102ED0000441FFFE0000000003E0000800000000C5
+:102EE0008F8200102443F800000229C224A2FFF0C0
+:102EF0002C63030110600003000210420A00025517
+:102F0000AC8200008F83001800A3102B1440000B2C
+:102F10000000382100A31023244600018F82001CEA
+:102F2000006210212442FFFF0045102B5440000492
+:102F30002402FFFF0A000255AC8600002402FFFFB6
+:102F40000A00025AAC8200008C8200003C03080098
+:102F500024631C5C000211400043382103E0000898
+:102F600000E010213C0908008D291D80000451401B
+:102F70003C19080027391C5C00C0782100806021C2
+:102F8000240EFFFF00003821015940211120003696
+:102F9000000030213C18080027181D983C0D08003F
+:102FA00025AD1D9C000F582B0006118000461021F6
+:102FB000000218C0007810218C4200001582002009
+:102FC000006D20218CA20000544000098D020018E1
+:102FD0003C0208008C421D8424420001AC820000A7
+:102FE0003C010800AC221D840A0002CF0000202111
+:102FF0008F47002000003021000211C01160004AFC
+:10300000AF4200208D08001C3C0900088CA3000082
+:103010000066182100031880007A10210049102151
+:103020008C44000024C600010068182100CF102B3A
+:103030001440FFF6AC6400000A0002CD000000005E
+:103040008C840000008E102B5040000424C6000128
+:103050000080702100C0382124C6000100C9102B57
+:103060001440FFD20006118024020001ACA200002F
+:103070003C0208008C421D7C3C0308008C631D80D0
+:103080000043102B1440002A2404FFFE0159102194
+:103090008C420018104000262404FFFF0007218006
+:1030A0003C0508008CA51D84008720218D06001892
+:1030B000000420C03C02080024421D980082102118
+:1030C0003C03080024631D9CAC4C000024A50001B7
+:1030D000008318213C02080024421DA0AC650000BA
+:1030E000000631C03C010800AC251D84008220216F
+:1030F0008F470020AD04001CAF46002011E0000AFD
+:10310000000030213C020008034228218CA200006C
+:1031100024C6000100CF182BAC82000024A50004B7
+:103120001460FFFA24840004AF470020000020212F
+:1031300003E00008008010213084FFFF30C6FFFF4D
+:1031400000052C0000A628253882FFFF004510212D
+:103150000045282B0045102100021C023042FFFFD1
+:103160000043102100021C023042FFFF00431021E7
+:103170003842FFFF03E000083042FFFF27BDFFC8D1
+:10318000AFBF0030AFB3002CAFB20028AFB1002406
+:10319000AFB000203C0460088C8250002403FF7F05
+:1031A0003C066000004310243442380CAC825000CE
+:1031B0008CC24C1C3C1A8000000216023042000FE8
+:1031C00010400007AF82001C8CC34C1C3C02001F47
+:1031D0003442FC0000621824000319C2AF830018B7
+:1031E0008F420008275B400034420001AF420008D4
+:1031F000AF8000243C02601CAF400080AF400084E0
+:103200008C4500088CC3080834028000034220214A
+:103210002402FFF0006218243C0200803C010800F8
+:10322000AC2204203C025709AF8400381462000429
+:10323000AF850034240200010A000314AF82001499
+:10324000AF8000142403003D240200043C01080068
+:10325000AC221D943C010800AC231D903C010800E9
+:10326000AC231D8C3C010800AC231D883C130800D6
+:1032700026731C5C240400043C02080024421C74D5
+:10328000240300082463FFFFAC400004AC400000AE
+:103290000461FFFC24420020000410C000441021FF
+:1032A0002442003D3C010800AC221D902402000194
+:1032B0003C010800AC221D7C2402FFFF3C010800F9
+:1032C000AC221D983C010800AC201D848F420000F8
+:1032D00038420001304200011440FFFC8F8200148C
+:1032E0001040001600000000974201041040000545
+:1032F0008F830000146000072462FFFF0A00034B65
+:103300002C62000A2C620010504000048F830000E1
+:1033100024620001AF8200008F8300002C62000A4B
+:10332000144000032C6200070A000352AF80FFCC58
+:103330001040000224020001AF82FFCC8F4301083D
+:103340008F44010030622000AF8300041040000869
+:10335000AF8400103C0208008C42042C244200017F
+:103360003C010800AC22042C0A0006D73C024000B5
+:103370003065020014A0000324020F001482030928
+:1033800024020D0097420104104003713C024000EA
+:1033900030624000144000AD8F8200388C44000839
+:1033A0008F4201780440FFFE24020800AF420178FA
+:1033B00024020008A7420140A740014297420104AD
+:1033C0008F8400043051FFFF30820001104000075D
+:1033D000022080212623FFFE240200023070FFFF1E
+:1033E000A74201460A00037FA7430148A7400146C0
+:1033F0003C0208008C42043C1440000D8F830010F6
+:10340000308200201440000224030009240300013C
+:10341000006020218F830010240209005062000107
+:1034200034840004A744014A0A00039A0000000003
+:1034300024020F00146200053082002014400006B0
+:103440002403000D0A000399240300051440000220
+:103450002403000924030001A743014A3C02080099
+:103460008C4204203C0400480E00020A004420253F
+:103470000E000233000000008F82000C1040003E5E
+:10348000000000008F4210003C0300200043102485
+:10349000104000398F820004304200021040003694
+:1034A0000000000097421014144000330000000098
+:1034B000974210088F8800383042FFFF24420006F0
+:1034C000000218820003388000E8302130430001F8
+:1034D0008CC4000010600004304200030000000DA6
+:1034E0000A0003DB00E81021544000103084FFFF85
+:1034F0003C05FFFF00852024008518260003182BBB
+:103500000004102B004310241040000500000000B0
+:10351000000000000000000D000000002400021C5C
+:103520008CC200000A0003DA004520253883FFFF23
+:103530000003182B0004102B00431024104000053A
+:1035400000000000000000000000000D000000006E
+:10355000240002258CC200003444FFFF00E8102143
+:10356000AC4400003C0208008C42043024420001BC
+:103570003C010800AC2204308F6200008F840038C8
+:10358000AF8200088C8300003402FFFF1462000F3A
+:10359000000010213C0508008CA504543C040800E0
+:1035A0008C84045000B0282100B0302B00822021F0
+:1035B000008620213C010800AC2504543C01080091
+:1035C000AC2404500A0006CD240400088C820000BC
+:1035D000304201001040000F000010213C0508009F
+:1035E0008CA5044C3C0408008C84044800B02821BD
+:1035F00000B0302B00822021008620213C010800F1
+:10360000AC25044C3C010800AC2404480A0006CD5B
+:10361000240400083C0508008CA504443C04080070
+:103620008C84044000B0282100B0302B008220217F
+:10363000008620213C010800AC2504443C01080020
+:10364000AC2404400A0006CD240400088F62000860
+:103650008F62000000021602304300F024020030A6
+:1036600010620005240200401062016B8F8200206E
+:103670000A0006D52442000114A000050000000045
+:10368000000000000000000D0000000024000250B7
+:103690008F4201780440FFFE000000000E00023B54
+:1036A00027A4001014400005004080210000000005
+:1036B0000000000D00000000240002578E020000F0
+:1036C0001040000500000000000000000000000D98
+:1036D000000000002400025A8F62000C0443000323
+:1036E000240200010A00055DAE000000AE020000E9
+:1036F0008F8200388C450008A20000078F65000CFF
+:103700008F64000430A3FFFF0004240200852023FF
+:10371000308200FF0043102124420005000288830C
+:103720002E220081A605000A14400005A204000410
+:10373000000000000000000D0000000024000272E4
+:103740003C0708008CE71D808FA800102409FFFFAC
+:103750000000502110E00013000030213C0C080054
+:10376000258C1D9C01802821000018218CA2FFFCC3
+:103770005102002F006C18218CA400002463020861
+:103780000089102B1040000324A502080080482166
+:1037900000C0502124C6000100C7102B5440FFF484
+:1037A0008CA2FFFC3C0508008CA51D803C02080093
+:1037B0008C421D7C3C09080025291C603C03080044
+:1037C00024631D9800A2102B3C0C0800258C1D9C26
+:1037D0003C0408008C841D843C0B0800256B1DA054
+:1037E0001040001A000831400005118000451021EA
+:1037F000000210C000C9382124840001004B302190
+:103800000043182124A50001004C1021AC680000E1
+:10381000ACE600183C010800AC241D84AC44000058
+:103820003C010800AC251D800A0004A88E04001C81
+:103830003C0208008C421D84244200013C01080027
+:10384000AC221D840A0004A7AC620000000A1180AB
+:10385000004A1021000210C0004328218CA3000060
+:10386000004C3821248400010003194000C9302194
+:1038700000691821004B1021ACA80000AC600018B2
+:103880003C010800AC241D84ACC20018ACE400006C
+:103890008E04001C8F8500380E0006E702203021C0
+:1038A0008F6200048F430108A60200083C0210004A
+:1038B0000062182410600008000000009742010414
+:1038C000920300072442FFEC346300023045FFFFFF
+:1038D0000A0004BCA2030007974201042442FFF03F
+:1038E0003045FFFF960600082CC200135440000527
+:1038F000920300079202000734420001A20200076F
+:103900009203000724020001106200052402000354
+:103910001062000B30C7FFFF0A0004DB24E2000244
+:103920008F8200383C04FFFF8C43000C0064182495
+:1039300000651825AC43000C0A0004DA30C7FFFF0D
+:103940008F8200383C04FFFF8C4300100064182471
+:1039500000651825AC43001030C7FFFF24E20002C9
+:1039600000021083A20200058F830038304200FF5E
+:1039700000021080004330218CC500008CC2000082
+:103980002403000400021702144300130000000087
+:10399000974201043C03FFFF00A318243042FFFFBD
+:1039A000004710232442FFFE00622825ACC500001A
+:1039B000920400058E03001C308200FF000210807C
+:1039C00000431021904200003042000F00441021BB
+:1039D0000A000510A20200068CC4000497420104EC
+:1039E0009603000A3085FFFF3042FFFF0047102397
+:1039F0002442FFD60002140000A22825ACC5000412
+:103A00009202000792040005246300280003188333
+:103A10000064182134420004A2030006A202000739
+:103A20008F8200042403FFFB344200020043102471
+:103A3000AF820004920300068E07001C8F860038B8
+:103A400000031880006710218C44000C3C02FFF634
+:103A50003442FFFF0082282400661821AE04000CC7
+:103A6000AC65000C920300068E04000C3C02FF7F44
+:103A70003442FFFF0003188000A228240082202483
+:103A800000671821AE04000CAC65000C9202000621
+:103A9000000210800047102194450012AC45001030
+:103AA000920200060002108000461021AC45001072
+:103AB0008FA200109203000500021140000318803D
+:103AC00000671821005320218C6200048C830018A9
+:103AD0001460000EAE0200143C0308008C631D8CC1
+:103AE000AC8300183C0208008C421D900062102B31
+:103AF00010400019000000003C0208008C421D9498
+:103B0000006210213C010800AC221D8C8E020018BE
+:103B10008F48002000003021000211C01220000B4D
+:103B2000AF4200203C0200080342282100E020218F
+:103B30008C82000024C6000100D1182BACA200002A
+:103B4000248400041460FFFA24A50004AF48002078
+:103B50000A00055E24020010000000000000000DB5
+:103B600000000000240002D424020010A7420140FB
+:103B700024020002A7400142A7400144A742014697
+:103B8000974201043C0400082442FFFEA74201487A
+:103B9000240200010E00020AA742014A9603000A0D
+:103BA0009202000400431021244200023042000728
+:103BB00000021023304200070E000233AE02001054
+:103BC0008F6200003C0308008C630444240400104E
+:103BD000AF820008974201043042FFFF2442FFFEFB
+:103BE00000403821000237C33C0208008C420440E8
+:103BF000006718210067282B00461021004510217E
+:103C00003C010800AC2304443C010800AC22044001
+:103C10000A0006620000000014A000050000000079
+:103C2000000000000000000D00000000240003045C
+:103C30008F4201780440FFFE000000000E00023BAE
+:103C400027A400141440000500408021000000005B
+:103C50000000000D000000002400030B9206000489
+:103C60008FA4001427A50018000630820E00025C05
+:103C7000AFA00018504000068E02000000000000B7
+:103C80000000000D00000000240003118E0200005F
+:103C90005440000692020007000000000000000DE2
+:103CA00000000000240003169202000730420004C6
+:103CB000104000058F8200042403FFFB3442000201
+:103CC00000431024AF8200048F6200040443000903
+:103CD00092020007920200068E03001C8E04000C64
+:103CE0000002108000431021AC44000CAE00000024
+:103CF00092020007304200045440000B920300047B
+:103D0000920300058E0400148E05001C0003188029
+:103D10003C0200010082202100651821AE0400143D
+:103D2000AC640004920300049602000A00621021B1
+:103D300024420005000290838FA200181040000D5D
+:103D4000277100088FA40014000310820242302360
+:103D500027A500180E00025CAFA200185040000614
+:103D60008E05001C000000000000000D0000000097
+:103D70002400033F8E05001C022020210E0006E7D0
+:103D800002403021920400068F6500043C027FFF50
+:103D900000042080009120218C8300043442FFFF26
+:103DA00000A2282400651821AC83000492020007B9
+:103DB00092030004920500053042000410400014F4
+:103DC0009607000830A500FF0005288000B12821D3
+:103DD0008CA40004974201049606000A306300FF99
+:103DE0003042FFFF004310210046102130E3FFFF67
+:103DF000004310232442FFD83084FFFF0002140048
+:103E000000822025ACA400040A00061692030007D5
+:103E100030A500FF0005288000B128218CA40000F7
+:103E200097420104306300FF3042FFFF004310213E
+:103E3000004710233C03FFFF008320243042FFFF94
+:103E400000822025ACA40000920300072402000198
+:103E5000106200060000000024020003106200113E
+:103E6000000000000A0006398E030010974201048A
+:103E7000920300049605000A8E24000C00431021D2
+:103E8000004510212442FFF23C03FFFF0083202461
+:103E90003042FFFF00822025AE24000C0A000639C4
+:103EA0008E03001097420104920300049605000A55
+:103EB0008E24001000431021004510212442FFEE03
+:103EC0003C03FFFF008320243042FFFF00822025B7
+:103ED000AE2400108E0300102402000AA742014005
+:103EE000A74301429603000A920200043C040040EA
+:103EF00000431021A7420144A74001469742010414
+:103F0000A7420148240200010E00020AA742014A0A
+:103F10000E000233000000008F62000092030004D4
+:103F200000002021AF820008974201049606000A93
+:103F30003042FFFF00621821006028213C03080086
+:103F40008C6304443C0208008C4204400065182144
+:103F5000004410210065382B004710213C01080067
+:103F6000AC2304443C010800AC2204409204000449
+:103F7000008620212484000A3084FFFF0E0001E720
+:103F800000000000974401043084FFFF0E0001F59B
+:103F9000000000003C021000AF4201780A0006D485
+:103FA0008F820020148200273062000697420104AD
+:103FB000104000673C0240003062400010400005A5
+:103FC00000000000000000000000000D00000000E4
+:103FD0002400041A8F4201780440FFFE24020800E6
+:103FE000AF42017824020008A7420140A7400142E5
+:103FF0008F82000497430104304200011040000703
+:104000003070FFFF2603FFFE24020002A742014694
+:10401000A74301480A00068C2402000DA740014670
+:104020002402000DA742014A8F6200002404000808
+:10403000AF8200080E0001E7000000000A000666DB
+:1040400002002021104000423C0240009362000028
+:10405000304300F0240200101062000524020070BA
+:10406000106200358F8200200A0006D5244200012C
+:104070008F620000974301043050FFFF3071FFFF53
+:104080008F4201780440FFFE320200070002102335
+:10409000304200072403000A2604FFFEA743014024
+:1040A000A7420142A7440144A7400146A751014845
+:1040B0008F4201083042002014400002240300090E
+:1040C00024030001A743014A0E00020A3C040040F9
+:1040D0000E000233000000003C0708008CE7044497
+:1040E000021110212442FFFE3C0608008CC6044049
+:1040F0000040182100E33821000010218F650000E6
+:1041000000E3402B00C230212604000800C8302103
+:104110003084FFFFAF8500083C010800AC27044451
+:104120003C010800AC2604400E0001E7000000003E
+:104130000A000666022020210E000139000000005E
+:104140008F82002024420001AF8200203C02400008
+:10415000AF4201380A000336000000003084FFFF40
+:1041600030A5FFFF000018211080000700000000AC
+:104170003082000110400002000420420065182136
+:104180000A0006DD0005284003E000080060102159
+:1041900010C0000624C6FFFF8CA2000024A5000466
+:1041A000AC8200000A0006E72484000403E0000853
+:1041B0000000000010A0000824A3FFFFAC86000050
+:1041C00000000000000000002402FFFF2463FFFF46
+:1041D0001462FFFA2484000403E0000800000000D9
+:0441E00000000001DA
+:0C41E4000A00002A00000000000000009B
+:1041F0000000000D747870352E302E306A31350095
+:10420000050000000000000A000001360000EA601E
+:10421000000000000000000000000000000000009E
+:10422000000000000000000000000000000000008E
+:10423000000000000000000000000000000000007E
+:104240000000000000000016000000000000000058
+:10425000000000000000000000000000000000005E
+:10426000000000000000000000000000000000004E
+:1042700000000000000000000000000000001388A3
+:1042800000000000000005DC00000000000000004D
+:1042900010000003000000000000000D0000000DF1
+:1042A0003C020800244239203C03080024633BD42C
+:1042B000AC4000000043202B1480FFFD244200048A
+:1042C0003C1D080037BD7FFC03A0F0213C10080016
+:1042D000261000A83C1C0800279C39200E0004076B
+:1042E000000000000000000D8F86003C3C039000A1
+:1042F0003C0280000086282500A32025AC44002035
+:104300003C0380008C67002004E0FFFE00000000FA
+:1043100003E00008000000000A000041240400013E
+:104320008F85003C3C0480003483000100A31025ED
+:1043300003E00008AC82002003E000080000102128
+:104340003084FFFF30A5FFFF108000070000182118
+:104350003082000110400002000420420065182154
+:104360001480FFFB0005284003E0000800601021D6
+:1043700010C00007000000008CA2000024C6FFFF50
+:1043800024A50004AC82000014C0FFFB24840004B8
+:1043900003E000080000000010A0000824A3FFFFB5
+:1043A000AC86000000000000000000002402FFFFB7
+:1043B0002463FFFF1462FFFA2484000403E0000872
+:1043C0000000000090AA00318FAB00108CAC0040C0
+:1043D0003C0300FF8D680004AD6C00208CAD0044F0
+:1043E00000E060213462FFFFAD6D00248CA700481F
+:1043F0003C09FF000109C024AD6700288CAE004CC9
+:104400000182C82403197825AD6F0004AD6E002C1D
+:104410008CAD0038314A00FFAD6D001C94A900320C
+:104420003128FFFFAD68001090A70030A5600002A2
+:10443000A1600004A167000090A30032306200FF79
+:104440000002198210600005240500011065000EAD
+:104450000000000003E00008A16A00018CD80028D9
+:10446000354A0080AD7800188CCF0014AD6F001471
+:104470008CCE0030AD6E00088CC4002CA16A000107
+:1044800003E00008AD64000C8CCD001CAD6D00187D
+:104490008CC90014AD6900148CC80024AD680008F4
+:1044A0008CC70020AD67000C8CC200148C83007098
+:1044B0000043C82B13200007000000008CC200142A
+:1044C000144CFFE400000000354A008003E00008BF
+:1044D000A16A00018C8200700A0000B70000000091
+:1044E0009089003027BDFFF88FA8001CA3A9000009
+:1044F0008FA300003C0DFF8035A2FFFF8CAC002C89
+:1045000000625824AFAB0000A100000400C0582195
+:10451000A7A000028D06000400A048210167C82161
+:104520008FA50000008050213C18FF7F032C20261F
+:104530003C0E00FF2C8C0001370FFFFF35CDFFFF35
+:104540003C02FF0000AFC82400EDC02400C2782464
+:10455000000C1DC00323682501F87025AD0D000077
+:10456000AD0E00048D240024AFAD0000AD040008A2
+:104570008D2C00202404FFFFAD0C000C9547003269
+:1045800030E6FFFFAD0600109145004830A200FF65
+:10459000000219C2506000018D240034AD040014E3
+:1045A0008D4700388FAA001827BD0008AD0B0028E2
+:1045B000AD0A0024AD07001CAD00002CAD000018B2
+:1045C00003E00008AD00002027BDFFE0AFB20018F7
+:1045D000AFB10014AFB00010AFBF001C9098003016
+:1045E00000C088213C0D00FF330F007FA0CF0000EA
+:1045F000908E003135ACFFFF3C0AFF00A0CE0001D9
+:1046000094A6001EA22000048CAB00148E29000486
+:1046100000A08021016C2824012A402400809021E0
+:1046200001052025A6260002AE2400042605002050
+:10463000262400080E000063240600029247003082
+:10464000260500282624001400071E000003160378
+:1046500024060004044000032403FFFF965900329F
+:104660003323FFFF0E000063AE2300102624002436
+:104670008FBF001C8FB200188FB100148FB00010D4
+:1046800024050003000030210A00006D27BD002032
+:1046900027BDFFD8AFB1001CAFB00018AFBF0020DE
+:1046A00090A900302402000100E050213123003F96
+:1046B00000A040218FB000400080882100C0482128
+:1046C000106200148FA70038240B000500A02021E1
+:1046D00000C02821106B0013020030210E0000F9E9
+:1046E000000000009225007C30A40002108000032E
+:1046F00026030030AE000030260300348FBF0020B8
+:104700008FB1001C8FB000180060102103E000087A
+:1047100027BD00280E000078AFB000100A0001404D
+:10472000000000008FA3003C01002021012028216F
+:1047300001403021AFA300100E0000BFAFB0001445
+:104740000A000140000000003C0580008CA30E1010
+:104750008F840044AC8300208CA20E1803E0000874
+:10476000AC8200243C0580008CA30E148F8400448E
+:10477000AC8300208CA20E1C03E00008AC82002455
+:104780009382000C1040001B2483000F2404FFF0D0
+:104790000064382410E00019978B00109784000EF5
+:1047A0009389000D3C0A601C0A00017B01644023D0
+:1047B00001037021006428231126000231C2FFFF8B
+:1047C00030A2FFFF0047302B50C0000E00E448210C
+:1047D0008D4D000C31A3FFFF00036400000C2C037F
+:1047E00004A1FFF30000302130637FFF0A00017352
+:1047F0002406000103E00008000000009784000E7A
+:1048000000E448213123FFFF3168FFFF0068382BA7
+:1048100054E0FFF8A783000E938A000D11400005B5
+:10482000240F0001006BC023A380000D03E00008EB
+:10483000A798000E006BC023A38F000D03E00008B3
+:10484000A798000E03E000080000000027BDFFE865
+:10485000AFB000103084FFFF3C10800093A8002B05
+:10486000AFBF0014A6040144960A0E1630C600FF1E
+:104870008FA90030A60A0146AE050148A2060152E2
+:10488000A608015AAE0701608FA3002CA6090158A3
+:10489000012020210E000167AE0301543C021000EC
+:1048A000AE0201788FBF00148FB0001003E0000843
+:1048B00027BD00188F8500002484000727BDFFF85E
+:1048C0003084FFF83C06800094CB008A316AFFFFF9
+:1048D000AFAA00008FA90000012540232507FFFF94
+:1048E00030E31FFF0064102B1440FFF700056882BF
+:1048F000000D288034CC400000AC102103E00008FB
+:1049000027BD00088F8200002486000730C5FFF80D
+:1049100000A2182130641FFF03E00008AF840000EC
+:104920008F8500448F8A003C27BDFFB03C04800087
+:10493000AFB70044AFB40038AFB1002CAFBF0048F0
+:10494000AFB60040AFB5003CAFB30034AFB20030FB
+:10495000AFB000288C8701048CA90024AC8A0080A9
+:104960008CA8002000E988230000B821AC880E1034
+:104970008CA600240000A021AC860E188C820E109C
+:10498000AC820E148C830E18AC830E1C122000FB1C
+:104990003C168000936B0008116000F100000000DD
+:1049A000976E001031CDFFFF022D602B158000ECBB
+:1049B0000000000097700010320FFFFFAECF0E0016
+:1049C0003C0580008CB30000327200081240FFFDED
+:1049D0000000000094B50E088CA70E0432A5FFFF5E
+:1049E00030B40001128000E1000000000000000D62
+:1049F00030B9A040241800401338011730B4A0008B
+:104A0000128000DC000000009373000812600008B0
+:104A100000000000976900103122FFFF00E2202B08
+:104A20001080000330A6004010C000D2000000003B
+:104A3000A7850040AF870038936A0008022038211C
+:104A4000AFB10020154000F127B40020AF60000C8A
+:104A50009785004030B14000162000022403001664
+:104A60002403000E24154007A363000AAF75001449
+:104A7000939000428F6F0014321900010019C24058
+:104A800001F84025AF680014978700408F63001439
+:104A900030EE0010006E6825AF6D0014978C00405A
+:104AA000318B000811600165000000008F65001463
+:104AB0003C0B10003C0A800000AB8825AF7100144D
+:104AC00095460E0A3C0981002413000E30C2FFFFF8
+:104AD00000492025AF640004A3730002937F000AFD
+:104AE0003406FFFC27F20004A372000A978D0040F1
+:104AF00031AC200011800157000000003C0780000D
+:104B0000978D004094EC0E0C97910040000D584298
+:104B10003185C000316A00030005130332291000FB
+:104B200001429825000922030264F825001F90C065
+:104B3000A7720012979500409379000A00158182B0
+:104B40003218003C0319782125E8003CA3680009CD
+:104B500094EE0E0C31C33FFFA76300109763001261
+:104B60009367000900E3702125CD000231AC0007F6
+:104B7000000C582331650007A365000B93710009F1
+:104B800097640012976A0010322200FF8F9100385C
+:104B9000979F004000444821012A982102669021F5
+:104BA00033F5004012A000053246FFFF00D1402B34
+:104BB0003C12800011000016000098210226782B7C
+:104BC00015E001368FA700203C1880008F100E14CE
+:104BD0003C058000AF100E108F190E1CAF190E1877
+:104BE000AF060E008CB200003255000812A0FFFD87
+:104BF0000000000094BF0E0800C088210000902132
+:104C0000A79F00408CA60E0424130001AF86003835
+:104C1000976900103135FFFF8E8C00000191202331
+:104C200010800118AE8400009367000814E000D8DB
+:104C3000000000000E0001B4240400108F8E004814
+:104C40003C0332000040282131C600FF00063C0032
+:104C500000E3602525CD0001AF8D0048AC4C00007D
+:104C60009362000997640012937F000A304A00FFA4
+:104C7000308BFFFF014B48210009CC0033F000FFCF
+:104C80000330C025ACB800048F8F004897880040DF
+:104C90003103200010600103ACAF0008976F0012D1
+:104CA00031E8FFFF06400101ACA8000C97900040DE
+:104CB0003205000814A0000226280006262800025B
+:104CC0003C048000948B0E148C850E1C8F670004AE
+:104CD000936A00023164FFFF314900FFAFA9001061
+:104CE0008F7F0014AFA80018AFBF00140E00019A08
+:104CF00000000000240400100E0001C800000000A5
+:104D00008E92000016400005000000008F7900140C
+:104D10002405FFBF0325A024AF7400148F69000C85
+:104D20000135F821AF7F000C9375000816A000082C
+:104D30000000000012600006000000008F6B0014ED
+:104D40003C0CEFFF3584FFFE01645024AF6A001471
+:104D5000A37300088FA700200A0003160220202159
+:104D6000AED10E000A0001F83C05800014E0FF21DE
+:104D700030B9A0400E0001600000A0212E9100017A
+:104D80000237B02512C000178FBF00488F85003C46
+:104D900024170F0010B700CD3C0480008C990178D7
+:104DA0000720FFFE24150F0050B500EB3C048000E7
+:104DB0008C890E14240502403C141000AC89014477
+:104DC0008C9F0E1CAC9F0148A0800152A480015A08
+:104DD000AC800160A4800158AC850154AC9401788A
+:104DE0008FBF00488FB700448FB600408FB5003C9E
+:104DF0008FB400388FB300348FB200308FB1002CE5
+:104E00008FB0002803E0000827BD00508F910038C4
+:104E1000979300403C1280000220A821326A004093
+:104E20001540FF7D00009821976B00108F8500389A
+:104E30003162FFFF104500A2000020210080A02168
+:104E4000108000E500E088211620FED2000000005E
+:104E50000A0002E72E9100013C0380008C7F01785C
+:104E600007E0FFFE240408008F860000AC64017890
+:104E70003C038000946C008A318BFFFF0166502355
+:104E80002549FFFF31281FFF2D0200081440FFF9BC
+:104E9000000000008F8E0048346F40008F83003C7C
+:104EA00000E0A021240D0F0025C70001AF870048B6
+:104EB00000CF3021023488233C08800031D500FF28
+:104EC000106D000524070001939300423272000127
+:104ED0000012824036070001001514003C09010051
+:104EE00000492025ACC400008F9F004830B900362F
+:104EF00030B80008ACDF00041300009000F99825DA
+:104F000095070E0A8F8E00003C03810030EDFFFFF5
+:104F100025CB000801A328253C0C1000316A1FFF97
+:104F2000269200062406000EAD050160026C98254D
+:104F3000A506015AAF8A0000A512015816200008E4
+:104F40003C1080008F99003C24180F005338000259
+:104F500024170001367300400E0001593C108000F8
+:104F60008E1F0E1402402021AE1F01448E120E1C13
+:104F7000AE120148A2150152AE1301540E00016792
+:104F80003C151000AE1501780A000319000000005E
+:104F900093780009976300129368000B330F00FFAA
+:104FA00001E33821310200FF00E2702125D0000A20
+:104FB0003210FFFF0E0001B4020020218F8600484E
+:104FC0003C1941003C07800024CD0001AF8D004812
+:104FD000936C00099764001230C600FF318A00FF0D
+:104FE000308BFFFF014B482100062C00253F0002BB
+:104FF00000BFC02503197825AC4F00008F68000C56
+:1050000094EE0E1401121825AC4300048CE50E1C1E
+:105010008F670004936D000231C4FFFF31AC00FFC5
+:10502000AFAC00108F620014AFB100180E00019AEF
+:10503000AFA200140A0002C502002021AF600004E4
+:10504000A3600002978D004031AC20001580FEABBC
+:1050500000003021A7600012979000409378000A6A
+:105060003C03800032191F000019798301F84021A8
+:1050700025070028A3670009946E0E0C0A00025E43
+:10508000A76E00108F6E001435CD00400E00015940
+:10509000AF6D00140A000291000000000A00031620
+:1050A000000020210641FF01ACA0000C8CB8000CD0
+:1050B0003C198000031990250A0002B2ACB2000C22
+:1050C000000090210A00028D2413000112800005C7
+:1050D0003C0D800095A60E0830D3004012600042BF
+:1050E000000000008C9001780600FFFE0000000028
+:1050F00094920E103C030500240720003258FFFF55
+:1051000003037825AC8F014C8C880E143C0E1000E4
+:10511000AC8801448C820E1CAC820148A0800152F4
+:10512000A480015AAC800160A4800158AC8701546E
+:10513000AC8E01780A0002EE3C0480008F900000E3
+:1051400026920002A5120158260F000831E81FFF21
+:105150000A000356AF880000AC80014C1280001991
+:10516000000000008C8A0E10AC8A01448C830E185B
+:105170003C0C800024160040AC8301488FBF0048DF
+:10518000A18001528FB70044A580015A8FB5003C21
+:10519000AD8001608FB40038A58001588FB3003412
+:1051A000AD9601548FB200308FB600408FB1002C05
+:1051B0008FB000283C04100027BD005003E0000819
+:1051C000AD8401788C8B0E14AC8B01448C830E1C47
+:1051D0000A0003E43C0C80000E0001602E910001E7
+:1051E0000A0002E80237B025000000000000000DB0
+:1051F000000000002400033A0A0003C03C048000C1
+:1052000027BDFFE0AFBF001C3C1F20FF3C07600034
+:105210003C0980002402001037F9FFFDACE23008A1
+:10522000AFB20018AFB10014AFB00010AD390E002E
+:10523000000000000000000000000000000000006E
+:10524000000000003C1800FF3712FFFDAD320E00D9
+:105250003C0B60048D7050002411FF7F3C0E000257
+:105260000211782435EC380C35CD0109ACED4C1821
+:10527000240A0009AD6C50008CE80438AD2A0008FF
+:10528000AD2000148CE54C1C3106FFFF38C42F7193
+:1052900000051E023062000F2486C0B310400007D4
+:1052A000AF8200088CE54C1C3C09001F3528FC002F
+:1052B00000A81824000321C2AF8400048CF1080860
+:1052C0003C0F57092412F0000232702435F0001010
+:1052D00001D0602601CF68262DAA00012D8B000188
+:1052E000014B382550E00009A380000C3C02601CF3
+:1052F0008C590008241F0001A39F000C33387C0048
+:10530000A7980010A780000EA380000DAF80004872
+:1053100014C00003AF8000003C066000ACC0442C09
+:105320000E0004B63C1080000E000E0E00000000BF
+:105330003C110800263139883C12080026523A08F0
+:105340008E05000038A30001306400011480FFFCCA
+:10535000000000008E0601003C0C800A240AFF8039
+:1053600024C7024030EB007F016C482100EA402452
+:10537000AE060020AF890044AE0800243C03800044
+:10538000AF86003C8C6D017805A0FFFE2419080053
+:10539000AC79017890780108A3980042938F00427D
+:1053A00031EE000111C0000F240D0D0024C2F800E1
+:1053B0002C5F030113E0001C000629C224A3FFF0A8
+:1053C00000032042000431400E0001CF00D1D8215B
+:1053D0003C0440003C068000ACC401380A0004577D
+:1053E0000000000010CD0026240E0F0010CE002A71
+:1053F0003C028008345F008093F90000240F0050C5
+:10540000333800FF170FFFF33C0440000E00092F54
+:10541000000000003C0440003C068000ACC40138A1
+:105420000A000457000000008F83000400A3402BF3
+:105430001500000B8F8B0008006B50212547FFFFE4
+:1054400000E5482B1520000600A36023000C29402E
+:105450000E0001CF00B2D8210A00047C3C044000B9
+:10546000000000000000000D00000000240003AD5B
+:105470000E0001CF000000000A00047C3C04400044
+:105480003C1B0800277B3B080E0001CF00000000FA
+:105490000A00047C3C0440003C1B0800277B3B289E
+:1054A0000E0001CF000000000A00047C3C04400014
+:1054B000000411C003E00008244202403C0408003C
+:1054C00024843B6C2405001A0A00006D0000302182
+:1054D00027BDFFE0AFBF001CAFB20018AFB1001492
+:1054E000AFB000103C108000920B01092412FF8025
+:1054F0000E0004B33164007F8F91003C00515021B5
+:1055000001524024AE080024920301090E0004B3A6
+:105510003064007F24060080240700C0240400407B
+:10552000AE000810AE040814AE060818AE07081C3A
+:10553000920C01090051F82133F8007F3C19800AD0
+:10554000031910213184007F0E0004B3AF820044A0
+:105550008E1101003C0C008035850001022278216B
+:1055600001F24824AE0908048E0E010035980002AD
+:105570003609090001C2682131AB00780165502568
+:10558000AE0A08208E0501008E080100360509804C
+:10559000010218212464004000923024AE0608085D
+:1055A0008E07010000E2F82127F90040333200782D
+:1055B00002588825AE1108248E040100952F000C96
+:1055C0008FBF001C8FB2001831EEFFFF000E69C0C4
+:1055D000AE0D0800AE0C0828952B000C8FB10014FE
+:1055E000316AFFFF000A41C0AE08002C8CA30050B6
+:1055F0008FB000108CA2003C8D2400048CA6001CEF
+:105600008CA7003827BD0020AF830060AF82005018
+:10561000AF84004CAF86005803E00008AF87005C01
+:105620003C098000352309009128010B906A001184
+:105630002402002800804821314700FF00A070218B
+:1056400000C068213108004010E20002340C86DD01
+:10565000240C08003C0A800035420A9A9447000056
+:10566000354B0A9C35460AA030F9FFFFAD390000E2
+:105670008D780000354B0A8024040001AD38000409
+:105680008CCF0000AD2F00089165001930A30003F6
+:105690001064008E28640002148000AD240500020E
+:1056A0001065009C240F0003106F00B235450AA45A
+:1056B000240A0800118A0047000000005100003C45
+:1056C0003C0B80003C04800034830900906700128A
+:1056D00030E200FF004D7821000FC8802724000130
+:1056E0003C0A8000354F090091E50019354C0980CE
+:1056F0008D87002830A300FF0003150000475825C0
+:105700000004C4003C19600001793025370806FF09
+:10571000AD260000AD2800048DEA002C25280028C5
+:10572000AD2A00088DEC0030AD2C000C8DE5003466
+:10573000AD2500108DE40038AD2400148DE3001C6D
+:10574000AD2300188DE700203C038000AD27001C2E
+:105750008DE20024AD2200208DF900283462093C3E
+:10576000AD3900248C450000AD0E000434790900E9
+:10577000AD0500008C67010C25020014AD07000880
+:10578000932B00123C04080090843B90AD00001065
+:10579000317800FF030D302100064F0000047C002B
+:1057A000012F702535CDFFFF03E00008AD0D000C83
+:1057B00035780900930600123C05080094A53B804B
+:1057C00030C800FF010D5021000A60800A00053F2B
+:1057D000018520211500005A000000003C08080047
+:1057E00095083B863C06080094C63B8001061021C4
+:1057F0003C0B80003579090093380011932A001979
+:1058000035660A80330800FF94CF002A00086082C2
+:10581000314500FF978A0054000C1E00000524004B
+:105820003047FFFF006410250047C02501EA302102
+:105830003C0B4000030B402500066400AD2800002F
+:10584000AD2C0004932500183C0300062528001405
+:1058500000053E0000E31025AD2200088F24002C37
+:105860003C0380003462093CAD24000C8F38001CDE
+:10587000254F000131EB7FFFAD3800108C45000053
+:10588000AD0E000434790900AD0500008C67010CF1
+:10589000A78B005425020014AD070008932B0012BB
+:1058A0003C04080090843B90AD000010317800FF6C
+:1058B000030D302100064F0000047C00012F7025ED
+:1058C00035CDFFFF03E00008AD0D000C3C020800E1
+:1058D00094423B8A3C05080094A53B8035440AA4C9
+:1058E0003C07080094E73B7C948B00000045C821EE
+:1058F0000327C023000B1C002706FFF2006650257B
+:10590000AD2A000CAD200010AD2C00140A000533A8
+:1059100025290018354F0AA495E500009564002854
+:105920000005140000043C003459810000EC5825A7
+:10593000AD39000CAD2B00100A00053325290014E9
+:105940003C0C0800958C3B860A00058325820001EB
+:105950005460FF58240A080035580AA4970600002E
+:1059600000061C00006C5025AD2A000C0A0005330F
+:10597000252900103C03080094633B8A3C0708007B
+:1059800094E73B803C0F080095EF3B7C94A400001B
+:105990009579002800671021004F582300041C004F
+:1059A000001934002578FFEE00D87825346A81008C
+:1059B000AD2A000CAD2F0010AD200014AD2C001846
+:1059C0000A0005332529001C03E00008240207D043
+:1059D00027BDFFE0AFB20018AFB10014AFB00010A8
+:1059E000AFBF001C0E00004D008088218F88005042
+:1059F0008F87004C3C05800834B2008001112821BB
+:105A00003C10800024020080240300C000A7202353
+:105A1000AE0208183C068008AE03081C188000047B
+:105A2000AF850050ACC500048CC90004AF89004CA0
+:105A300012200009360409800E0005F9000000005C
+:105A4000924C00278E0B007401825004014B3021D0
+:105A5000AE46000C360409808C8E001C8F8F0058D7
+:105A600001CF682319A000048FBF001C8C90001C7C
+:105A7000AF9000588FBF001C8FB200188FB1001478
+:105A80008FB000100A00004F27BD00208F860060F5
+:105A90008F8300508F82004C3C05800834A4008026
+:105AA000AC860050AC83003C03E00008ACA20004CC
+:105AB0003C0308008C63005427BDFFF8308400FFCE
+:105AC0002462000130A500FF3C010800AC22005414
+:105AD00030C600FF3C0780008CE801780500FFFE1F
+:105AE0003C0A7FFFA3A400038FA400003549FFFFF9
+:105AF00000891824000647C000681025AFA20000E6
+:105B000090F9010AA3A000023C1880FFA3B900018C
+:105B10008FAE000030AD007F370FFFFF01CF58245C
+:105B2000000D66003C090020016C50253526200040
+:105B30002405FF803C04100027BD0008ACEA014C9E
+:105B4000ACE60154A4E00158A0E5015203E00008CE
+:105B5000ACE40178308800FF3C03800030A400FFF3
+:105B60008C6201780440FFFE000000003C038000CE
+:105B700034660A008CCA0020346709800004482B70
+:105B8000AC6A01448CC5002400091540AC6501488D
+:105B9000A068015090E4004CA064016D03E000088F
+:105BA000A460015827BDFFE8308400FFAFBF00109C
+:105BB0000E00065C30A500FF8F8300508FBF0010E1
+:105BC0003C058000344600402404FF903C02100055
+:105BD00027BD0018ACA3014CA0A40152ACA60154EF
+:105BE00003E00008ACA2017827BDFFE03C08800874
+:105BF000AFBF001CAFB20018AFB10014AFB00010BF
+:105C0000351000808E0600183C078000309200FF9F
+:105C100000C72025AE0400180E00004D30B100FF73
+:105C200092030005346200080E00004FA202000536
+:105C3000024020210E00067002202821024020216F
+:105C40008FBF001C8FB200188FB100148FB00010EE
+:105C500024050005240600010A00063327BD0020A4
+:105C60003C05800034A309809066000830C200081B
+:105C70001040000F3C0A01013549080AAC890000B8
+:105C80008CA80074AC8800043C07080090E73B90A7
+:105C900030E5001050A00008AC8000083C0D8008E2
+:105CA00035AC00808D8B0058AC8B00082484000C30
+:105CB00003E00008008010210A0006B32484000CD1
+:105CC00027BDFFE83C088000AFB00010AFBF001454
+:105CD0003506098090C7000924020006350909002D
+:105CE00030E300FF0080802100A06021240B00042D
+:105CF000106200792407000294CF005C3C0E02047D
+:105D000031EDFFFF01AE5025AE0A000090C500083E
+:105D100030A40020108000080000000090C2004E57
+:105D20003C1F010337F90300305800FF03193025E9
+:105D3000240B0008AE0600049139001191260012D0
+:105D400091240011333800FF0018708230CF00FF1B
+:105D500001CF5021014C6821308800FF31AAFFFF9C
+:105D600039030028000A28801460002B0205402314
+:105D7000912400123C0E800035D90980308500FF47
+:105D800000AC182100031080004BF821001F840094
+:105D9000360906FFAD09000435C909009126001136
+:105DA000912F0012000BC0828F2B003431ED00FFC9
+:105DB0008DC4010C01AC282100B810210164F82326
+:105DC0000007840000021F000070C82533E9FFFFB0
+:105DD00030CF00FC032970250158202101E86821FB
+:105DE00000045080ADAE000C0E00004D010A802171
+:105DF0003C078008240C000434EB00800E00004FA8
+:105E0000A16C0009020010218FBF00148FB0001098
+:105E100003E0000827BD0018912500119123001907
+:105E20003C18080097183B8630A200FF0002F88259
+:105E3000307000FF001FCE0000104C0003293025F9
+:105E400000D870253C0F400001CF68253C0E800033
+:105E5000AD0D000035C9090091260011912F0012E7
+:105E600035D90980000BC08231ED00FF8F2B003443
+:105E70008DC4010C01AC282100B810210164F82365
+:105E80000007840000021F000070C82533E9FFFFEF
+:105E900030CF00FC032970250158202101E868213A
+:105EA00000045080ADAE000C0E00004D010A8021B0
+:105EB0003C078008240C000434EB00800E00004FE7
+:105EC000A16C0009020010218FBF00148FB00010D8
+:105ED00003E0000827BD00180A0006C524070012C9
+:105EE00027BDFFD0AFB60028AFB50024AFB4002067
+:105EF000AFB10014AFBF002CAFB3001CAFB200189D
+:105F0000AFB000103C06800090C3010B309400FF3E
+:105F100030B500FF306200300000B0211040009D1D
+:105F20000000882134C409809088000800083E00E1
+:105F300000072E0304A000C4240400048F8700502F
+:105F40003C010800A0243B903C0C8000AD80004840
+:105F50003C038000906D010B31A5002010A00007CC
+:105F60003C0B8000347209809250000800107E00C3
+:105F7000000F760305C000C93C1980089169010B28
+:105F8000356A098091480008312400400004102B34
+:105F900031030008241200031460000200E2982379
+:105FA000000090213C108000360E0A80360809005F
+:105FB00095C7002C910300119102001291C50018A1
+:105FC000307800FF305F00FF025FC8210019788041
+:105FD00091CC001801F8682101B1302130B100FFE7
+:105FE00000D11821A78700543C010800A4263B8655
+:105FF0003C010800A4233B8815800002000000003B
+:106000000000000D9204010B3065FFFF3C01080009
+:10601000A4233B8A308900403C010800A4203B8037
+:106020003C010800A4203B7C1120000224A4000AAB
+:1060300024A4000B3091FFFF0E0001B402202021A8
+:106040009219010B3C0E080095CE3B8A3C0D0800CE
+:1060500091AD3B910019C182330F000101CF28217E
+:10606000000D340024A7000200C758253C0C110085
+:10607000016C5025AC4A000024440008026028212D
+:10608000024030210E00050FAC4000040E00069FB8
+:106090000040202116C00068004020219212010B10
+:1060A0003256004012C000053C0200FF8C930000F5
+:1060B000345FFFFF027F8024AC9000000E0001C817
+:1060C000022020213C03080090633B9030710003C4
+:1060D000122000163C1080088F8C00503C0B80086A
+:1060E00035640080258A0001AC8A003C3C058008AC
+:1060F0008CA9000401402021012A4023190000023C
+:10610000AF8A00508CA400040E0005F9ACA4000472
+:106110003C0E80008DCD00743C05800834A60080C4
+:10612000004D3821ACC7000C3C10800836120080AE
+:106130000280202102A02821A240006B0E00065CF4
+:106140003C1480008F9600503C151000AE96014C18
+:106150008F980048344F00068FBF002C271900018C
+:10616000AF9900488FB60028A29801528FB3001C47
+:10617000AE8F01548FB20018AE9501788FB1001424
+:106180008FB500248FB400208FB0001003E000080A
+:1061900027BD003034C30980906F0008000F7600DF
+:1061A000000E6E0305A0003334DF090093F8001BD6
+:1061B000241900103C010800A0393B903313000261
+:1061C0001260FF638F8700508F82005C1447FF616D
+:1061D0003C0380000E00004D000000003C048008DD
+:1061E0003485008090A8000924070016310300FFC1
+:1061F0001067000D0000000090AB00093C0608008D
+:1062000090C63B9024090008316400FF34CA0001A5
+:106210003C010800A02A3B901089002F240C000AA2
+:10622000108C00282402000C0E00004F000000001B
+:106230000A00075B8F8700500E0006B70240282136
+:106240000A0007AE004020213C0B8008356A008020
+:106250008D4700548CC9010C1120FF39AF870050C5
+:10626000240600143C010800A0263B900A00075AAF
+:106270003C0C800090710008241200023C010800D0
+:10628000A0323B90323000201200000B2416000197
+:106290008F8700500A00075B241100083733008005
+:1062A0008E7F0038AF3F00048F380004AE78003C8A
+:1062B0000A0007663C0B80008F8700500A00075BCE
+:1062C00024110004A0A200090E00004F00000000ED
+:1062D0000A00075B8F870050240200140A00083967
+:1062E000A0A2000927BDFFE8AFBF0014AFB00010A7
+:1062F0003C10800092020109240500010E00065C9A
+:10630000304400FF3C1F800893F8000E37E3008004
+:1063100093F9000F906E002693E9000A332F00FFD7
+:1063200000186600000F6C0031CB00FF018D502576
+:10633000000B320001463825312800FF344560004B
+:1063400000E820252402FF813C031000AE04014C2C
+:106350008FBF0014AE050154A2020152AE030178B2
+:106360008FB0001003E0000827BD001827BDFFE82C
+:10637000308400FFAFBF00100E00065C30A500FFA8
+:10638000344600403C0480002405FF92AC86015452
+:10639000A08501528F8300508FBF00103C02100077
+:1063A00027BD0018AC83014C03E00008AC820178E3
+:1063B00027BDFFD8AFB20018AFB10014AFB00010C6
+:1063C000AFBF0020AFB3001C3C07800090E2010982
+:1063D000308600FF30B000FF000618C23204000211
+:1063E0003071000114800007305200FF3C09800822
+:1063F00035330080926800053105000810A0000CBC
+:1064000030CA0010024020210E00068102202821FF
+:10641000240200018FBF00208FB3001C8FB2001830
+:106420008FB100148FB0001003E0000827BD0028D2
+:106430001540003034E50A008CB900248CB80008FF
+:1064400013380047000040213C0E800835D30080FF
+:10645000926D0068240B000231AC00FF118B0080AC
+:106460003C068000927F004C90C40109509F0004BC
+:106470003213007C11000067000000003213007C22
+:106480001660005A0240202116200008320C00013C
+:106490003C07800034EB0A008D6500248CE8010481
+:1064A00014A8FFDC00001021320C00011180000D47
+:1064B000024020213C1080008E0E010C8F8D006068
+:1064C00011CD0008000000000E00073F0220282127
+:1064D0008E0F010C3C18800837100080AE0F005062
+:1064E000024020210E000670022028210A00088C9C
+:1064F000240200013C0708008CE7006424E6000148
+:106500003C010800AC2600641600000D00000000ED
+:10651000022028210E00067002402021926F0068A0
+:10652000240D000231EE00FF11CD00220240202197
+:106530000E000840000000000A00088C2402000140
+:106540000E00004124040001926C0025020C582525
+:106550000E00004FA26B00250A0008CC0220282163
+:106560008E6300188CE401048CBF00240003160223
+:10657000149FFFB53045007F9269004C264400010E
+:106580003093007F12650040312300FF1464FFAF99
+:106590003C0E8008264800013111007F310200FFC7
+:1065A0001225000B24080001004090210A000899E0
+:1065B00024110001240500040E0006332406000106
+:1065C0000E000840000000000A00088C24020001B0
+:1065D0002407FF800247282400A79026324200FFAC
+:1065E000004090210A000899241100010E00073F85
+:1065F000022028213206003010C0FFA33210008292
+:10660000024020210E000681022028210A00088C69
+:10661000240200018E63001802402021022028215C
+:10662000006610250E000862AE6200189264004CED
+:1066300024050003240600010E000633308400FF09
+:106640000E00004124040001926A0025020A482538
+:106650000E00004FA26900250A00088C24020001E8
+:106660008E7800183C1980000240202103197825FB
+:10667000022028210E000670AE6F00189264004CB4
+:106680000A000914240500043246008038CA00803C
+:10669000146AFF6E3C0E80080A0008ED26480001CF
+:1066A00027BDFFC0AFB000183C108000AFBF00385E
+:1066B000AFB70034AFB60030AFB5002CAFB4002890
+:1066C000AFB30024AFB200200E0004BBAFB1001C7A
+:1066D000920401089205010B308400FF0E0008733C
+:1066E00030A500FF144000E58FBF00383C0980084A
+:1066F00035280080A100006B3607098090E6000075
+:10670000240200503C17080026F73B4830C300FF26
+:106710003C13080026733B58106200033C108000B5
+:106720000000B82100009821241F001036110A0033
+:10673000361409808E1601048F8D00508E38002487
+:1067400036190A808E9200203C010800A03F3B9041
+:10675000972C002C8EF50000932B0018024D70230F
+:1067600002D878233C010800AC2F3B6C3C010800A8
+:10677000AC2E3B703C010800AC2D3B94A78C005420
+:1067800002A0F809317200FF304A0002154000E80B
+:106790003045000110A000C300000000928A0008EC
+:1067A0003150000816000002241400030000A0214C
+:1067B0003C06800034C4090034C30A008C6E0024F7
+:1067C00090850011908200129099001130B800FF5E
+:1067D000305100FF0291F821001FB080332F00FFDD
+:1067E00002D85821024FA82126AC0010017268215E
+:1067F0003C1580003C010800AC2E3B983C01080091
+:10680000A42D3B883C010800A42C3B843C010800DB
+:10681000A42B3B8636B609808F8700508F8900589D
+:106820008ED20020240800060127302302472823A7
+:106830003C010800AC283B8C04C000B5000090214E
+:1068400004A000B300C5802B120000B500000000BA
+:106850003C010800AC263B708E7100000220F80954
+:1068600000000000304A0002154000740040802102
+:10687000304B0001556000118E7100043C0D080082
+:106880008DAD3B743C0EC0003C04800001AE602521
+:10689000AEAC0E008C980000330F000811E0FFFD35
+:1068A00000000000949F0E0824120001A79F0040E2
+:1068B0008C990E04AF9900388E7100040220F809FB
+:1068C000000000000202802532020002144000B4E1
+:1068D000000000003C08080095083B7C3C110800C3
+:1068E00096313B883C09080095293B7E3C03080013
+:1068F0008C633B74011168213C1F08008FFF3B989B
+:106900003C07080094E73B923C11800001A920213C
+:106910008E38010C006828212499000200A77021FC
+:1069200003E37821AF9800603C010800AC2F3B984E
+:106930003C010800A42E3B803C010800A42D3B8AAA
+:106940000E0001B43324FFFF8F8C0048004020214B
+:106950003C010800A02C3B918E620008258B0001B1
+:10696000AF8B00480040F809000000008F85005000
+:10697000028030210E00050F004020210E00069FEE
+:10698000004020218E6A000C0140F80900402021BF
+:106990003C08080095083B8A3C09080095293B7E85
+:1069A0000109382124E600020E0001C830C4FFFFAF
+:1069B0003C0408008C843B6C3C0308008C633B74F3
+:1069C000008328233C010800AC253B6C14A0000682
+:1069D000000000003C0A08008D4A3B8C3546004010
+:1069E0003C010800AC263B8C124000438F8C0044D5
+:1069F0008E2B0E108F920044AE4B00208E220E186C
+:106A0000AE4200243C04080094843B800E0005FB49
+:106A1000000000008F9900508E7800103C010800A3
+:106A2000AC393B940300F809000000003C0F08005B
+:106A30008DEF3B6C15E0FF798F87005097940054E1
+:106A40003C13800E321501000E00062AA674002C9D
+:106A500016A00046320300105460004D8EE500047D
+:106A60003207004054E0001D8EF000088EE4000C58
+:106A70000080F809000000008FBF00388FB7003495
+:106A80008FB600308FB5002C8FB400288FB3002450
+:106A90008FB200208FB1001C8FB0001803E00008F7
+:106AA00027BD0040920901098F88003C00093E0083
+:106AB00000E83025AE0600808E2300208E240024BE
+:106AC000AFA30010AE030E148FA20010AE020E1082
+:106AD000AE040E1C0A00096EAE040E180200F8097E
+:106AE000000000008EE4000C0080F80900000000A7
+:106AF0000A000A268FBF0038240E0001240D000171
+:106B0000A5800020A58E00220A000A08AD8D002471
+:106B10003C010800AC203B700A00099E8E71000009
+:106B20003C010800AC253B700A00099E8E710000F4
+:106B300092110109000028210E000670322400FF86
+:106B40008FBF00388FB700348FB600308FB5002C60
+:106B50008FB400288FB300248FB200208FB1001CA7
+:106B60008FB0001803E0000827BD00403C1F8000E4
+:106B700093F60109000028210E00073F32C400FFF0
+:106B8000320300105060FFB7320700408EE500046A
+:106B900000A0F809000000000A000A2032070040A7
+:106BA0005240FFA7979400548EB60E148F93004462
+:106BB000AE7600208EB40E1CAE7400240A000A17B4
+:106BC000979400548F8200140004218003E0000891
+:106BD000008210213C07800834E200809043006965
+:106BE00000804021106000093C0401003C070800BF
+:106BF0008CE73B948F83003000E32023048000085F
+:106C00009389001C14E300030100202103E0000825
+:106C1000008010213C04010003E0000800801021E6
+:106C20001120000B006738233C0D800035AC098033
+:106C3000918B007C316A000211400020240900344D
+:106C400000E9702B15C0FFF10100202100E9382375
+:106C50002403FFFC00A3C82400E3C02400F9782B20
+:106C600015E0FFEA0308202130C4000300041023CC
+:106C700014C00014304900030000302100A978211D
+:106C800001E6702100EE682B11A0FFE03C0401003A
+:106C90002D3800010006C82B0105482103193824AE
+:106CA00014E0FFDA2524FFFC2402FFFC00A21824D4
+:106CB0000068202103E00008008010210A000A97E4
+:106CC000240900303C0C80003586098090CB007C84
+:106CD000316A00041540FFE9240600040A000AA6F0
+:106CE000000030213C0308008C63005C8F82001898
+:106CF00027BDFFE8AFBF001410620005AFB0001061
+:106D0000000329C024A40280AF840014AF830018BC
+:106D10003C10800036030A00946500320E000A78A9
+:106D200030A43FFF8E0401003C180080370F0003A1
+:106D30000082C8212402FF80032260243329007FBF
+:106D4000000CF94003E94025332E00783C0D10007B
+:106D5000010D502501CF5825AE0C002836080980BA
+:106D6000AE0C080CAE0B082CAE0A0830910300697B
+:106D70003C06800C0126382110600006AF870034E5
+:106D80008D09003C8D06006C0126382318E0007F39
+:106D9000000000003C0C8008358B00803C0A80001D
+:106DA000A1600069355009808E0200383C068000E1
+:106DB00034C50A0090AD003C31A800201100001934
+:106DC000AF820030240E00013C19800037300A00E9
+:106DD000A38E001CAF8000248E0400248F85002425
+:106DE00024180008AF800020AF8000283C01080074
+:106DF000A4383B7E3C010800A4203B920E000A7C94
+:106E000000003021920F003C8FBF00148FB00010A3
+:106E1000000F7142AF82002C27BD001803E000086C
+:106E200031C2000190B90032240F0001333800FF55
+:106E300000182182108F003F241F0002109F006263
+:106E400034C20AC03C03800034640A008C990024D8
+:106E50001720001D3466090090830030241F0005B0
+:106E60003062003F105F004C240500018F86002037
+:106E7000A385001CAF860028AF8600243C19800043
+:106E800037300A008E0400248F850024241800085F
+:106E90003C010800A4383B7E3C010800A4203B9242
+:106EA0000E000A7C00000000920F003C8FBF00140F
+:106EB0008FB00010000F7142AF82002C27BD001868
+:106EC00003E0000831C200018C8800088C8D00248A
+:106ED0008CCB00643C19800037300A00AF8B002453
+:106EE000A380001C8E0400248F8600208F85002440
+:106EF000010D602324180008AF8C00283C01080015
+:106F0000A4383B7E3C010800A4203B920E000A7C82
+:106F100000000000920F003C8FBF00148FB00010E3
+:106F2000000F7142AF82002C27BD001803E000085B
+:106F300031C2000190A7003030E3003F50640028C8
+:106F400034C50AC08CAA00241540002234C80900A8
+:106F50008CAB00483C0C7FFF3585FFFF016510249A
+:106F60003C188000AF820020370509008F8E00207A
+:106F70008CAF006001CF682B15A0000201C020215A
+:106F80008CA400600A000B18AF8400208D02006CF6
+:106F90000A000AF33C0680008C8900488F86002096
+:106FA0003C0A7FFF3550FFFF013038243C04800845
+:106FB00024050001AF870028AC80006CA385001C6D
+:106FC0000A000B26AF8600248C4400140A000B181C
+:106FD000AF8400208D0200680A000B603C1880001E
+:106FE00034C409808C8600708CB0001400D0482B0B
+:106FF00011200004000000008C8200700A000B6069
+:107000003C1880008CA200140A000B603C18800021
+:107010008F85002427BDFFE0AFBF0018AFB100147B
+:1070200014A00008AFB000103C04800034870A00B0
+:1070300090E600302402000530C3003F106200BE1D
+:10704000348409008F91002000A080213C0480003E
+:10705000348E0A008DCD00043C0608008CC63B70BF
+:1070600031A73FFF00E6602B5580000100E0302192
+:10707000938F001C11E0007600D0102B349909800A
+:107080009338007C3304000210800077240300341E
+:1070900000C3F82B17E000DD00C3302300D0102B15
+:1070A0003C010800A4233B7C1440006D0200182121
+:1070B0003C0408008C843B6C0064282B54A0000125
+:1070C000006020213C05800034A90A009128003C82
+:1070D0003C010800AC243B74310300201460000222
+:1070E000000048218CA90E188F88002C0128502BF5
+:1070F0001140005F000000003C0508008CA53B74B7
+:1071000000A96021010C582B1160005C00B0682BB5
+:107110000109382300E028213C010800AC273B741A
+:10712000120000032403FFFC10B00093322B000375
+:1071300000A310243C010800A4203B923C0108005D
+:10714000AC223B74004028218F84002412040006E6
+:107150003C0A80088D4B006C02002021AF9100207A
+:1071600025700001AD50006C8F8C002800858823AD
+:10717000AF91002401852023AF8400281220000253
+:1071800024070018240700103C0F800835E6008013
+:1071900090CE00683C010800A0273B902407000126
+:1071A00031CD00FF11A7004A000000001480001834
+:1071B000000028213C0C800091850109359109804F
+:1071C0008E2B001830A500FF24A30001000B8602BF
+:1071D0003206007F306A007F114600852407FF8059
+:1071E0003C04800834890080A123004C3C0808003E
+:1071F0008D083B8C240F00023C010800A02F3BD1DE
+:10720000350E00083C010800AC2E3B8C2405001014
+:107210003C028000345F0A0093F9003C33380020C0
+:107220001300000500A02021240300013C010800F8
+:10723000AC233B7434A400018FBF00188FB100143D
+:107240008FB000100080102103E0000827BD00204F
+:107250003C010800A4203B7C1040FF95020018214F
+:107260000A000BB300C018210A000BAB2403003046
+:107270003C0508008CA53B7400B0682B11A0FFA84A
+:10728000000000003C04080094843B7C00857821C9
+:1072900001E7702B11C000242CA300043C1F6000E8
+:1072A0008FF954043338003F1300001F0000000022
+:1072B0003C0208008C4200A41040FFDF240400427E
+:1072C00014A000198FBF00180A000C16000000005F
+:1072D0001528FFB6000000008CC300183C19800080
+:1072E000241F000200791025ACC2001837380A00AC
+:1072F000A0DF00689309003C2404000400A01021D2
+:10730000312800203C010800A0243BD111000002DC
+:1073100024050010240200013C010800AC223B6C53
+:107320000A000C0C3C0280001060FF7D2404004227
+:107330000A000C168FBF00188F8800288C89006007
+:107340000109282B14A00002010088218C91006003
+:107350003C0B80008D640E18240A000102202821B5
+:1073600002203021A38A001C0E000A7C022080210A
+:107370000A000B9AAF82002C000B5023122000074A
+:10738000314400033C0E800035CD098091A7007C7C
+:1073900030EC000415800019248F00043C01080023
+:1073A000A4243B923C19080097393B920325C02145
+:1073B00000D8202B1080FF658F8400242CA60005A8
+:1073C00014C0FF9D2404004230BF000317E00002F8
+:1073D00000BF182324A3FFFC3C010800AC233B742E
+:1073E0003C010800A4203B920A000BD90060282130
+:1073F00000A768240A000BFF01A718263C0108001B
+:10740000A42F3B920A000C70000000003C01080011
+:10741000AC203B740A000C15240400428F83002822
+:107420003C0B8000356A0A00146000060000102141
+:10743000914600302405000530C400FF108500038C
+:107440000000000003E0000800000000914900482F
+:10745000312800FF000839C214E0FFFA3C0480081C
+:107460003C06080094C63B7C3C0308008C633B94BC
+:107470003C0508008CA53B743C18080097183B920B
+:107480000066C8218C8E00040325782101F868214C
+:1074900001AE60231980001D000000009158004CCF
+:1074A0008F8D0034956E0E10330F00FF8DA90004F0
+:1074B00001CF30238DAA000030CFFFFF000F610005
+:1074C000012C2821000038210147202100AC182B75
+:1074D0000083C821ADA50004ADB9000091B8000A31
+:1074E00001F87021A1AE000A956C0E128F8A00344B
+:1074F000A54C00089549003825280001A54800380A
+:107500009147000D34EB0008A14B000D03E000088B
+:107510000000000027BDFFD8AFB00018938F001CFB
+:107520008FB000143C087FFF8F8700243C0C800044
+:107530003518FFFFAFBF0020AFB1001C35990A001E
+:1075400002181824932A003C000F5FC03C02BFFFC2
+:107550002CF000013449FFFF006BF8253C080800BF
+:107560008D083B948F9900303C18080097183B8A8F
+:1075700003E9582400107F803C07EFFF3C05F0FF33
+:10758000016F18253C1180003149002034E2FFFFD3
+:1075900034ADFFFF362E098027A500102406000217
+:1075A00001194023270A000200621824008080216C
+:1075B00015200002000058218D8B0E1CA7AA001276
+:1075C0000500003A2407000030EF00FF000F3F00E5
+:1075D000006740253C028008AFA80014344B0080AF
+:1075E000916A00683C0F080091EF3B913C09DFFF76
+:1075F000353FFFFF000A602B3C02080094423B84A9
+:10760000A3AF0011011FC024000CCF40031918259F
+:107610008FA70010AFA300143C1F080093FF3B93FB
+:10762000A7A200168FA8001400ED48243C0B01000F
+:107630003C0A0FFF012BC82533F80003354CFFFF30
+:10764000010D78243C027000032C382400181E0021
+:1076500000E2482501E35825AFAB0014AFA90010A4
+:1076600091DF007CA3BF00150E0000630000000046
+:10767000362D0A0091A6003C30C400201080000680
+:10768000260200083C11080096313B80262EFFFFA1
+:107690003C010800A42E3B808FBF00208FB1001C4E
+:1076A0008FB0001803E0000827BD00288F8A002C47
+:1076B000016A602B5580FFC4240700010A000CFA00
+:1076C00030EF00FF9383001C3C02800027BDFFD8F1
+:1076D00034480A0000805021AFBF002034460AC061
+:1076E000010028211060000E344409809107003009
+:1076F000240B00058F89002030EC003F118B000B1C
+:1077000000003821AFA900103C0B80088D69006C87
+:10771000AFAA00180E00012BAFA90014A380001C13
+:107720008FBF002003E0000827BD00288D1F004800
+:107730003C1808008F183B748F9900283C027FFF8B
+:107740008D0800443443FFFFAFA900103C0B8008B4
+:107750008D69006C03E370240319782101CF68233D
+:1077600001A83821AFAA00180E00012BAFA9001400
+:107770000A000D4FA380001C3C05800034A60A00BF
+:1077800090C7003C3C06080094C63B923C020800AF
+:107790008C423B8C30E30020000624001060001E69
+:1077A000004438253C0880083505008090A3006817
+:1077B00000003021240800010000202124030001E2
+:1077C0003C0580008CAC01780580FFFE00000000C5
+:1077D000ACA80148A4A40144A4A301463C030800AA
+:1077E0008C633B943C188008370F0080ACA3014C9D
+:1077F0003C19080093393B913C0D1000A0B901528F
+:10780000ACA70154A4A6015891EE004CA0AE016DA6
+:1078100003E00008ACAD01788CA80E1C3C0B0800FE
+:107820008D6B3B7494AA0E1694A90E140166302138
+:107830003143FFFF0A000D773124FFFF3C04800035
+:1078400034830A009065003C30A200201040001CE8
+:10785000000000000000302100002021000018215D
+:107860003C0580008CA901780520FFFE0000000087
+:10787000ACA601483C0E08008DCE3B94240DFF9130
+:10788000240C00403C0B8008A4A30144356A00800E
+:10789000A4A40146ACAE014CA0AD0152ACAC015465
+:1078A000A4A0015890A301099144004C90A601099D
+:1078B0003C041000A0A6016D03E00008ACA4017810
+:1078C0008C860E1894880E1294870E103104FFFFD8
+:1078D0000A000D9F30E3FFFF3C04800034830A0060
+:1078E0009065003C30A200201040002627BDFFF824
+:1078F0002409000100003821240800013C06800012
+:107900008CC401780480FFFE0000000090CA0109C9
+:107910003C04080090843BD13C1880FFA3AA0003DC
+:107920008FA300003085007F370FFFFF0066102512
+:10793000AFA2000090D9010AA3A0000200056E00CA
+:10794000A3B900018FAE0000240A300027BD000853
+:1079500001CF6024018D5825ACCB014CACCA015439
+:10796000A4C00158ACC90148A4C701442409FF8040
+:10797000A4C801463C081000A0C9015203E0000859
+:10798000ACC801788C890E1894870E1294860E105C
+:1079900030E8FFFF0A000DC630C7FFFF27BDFFE834
+:1079A000AFB000103C108000AFBF001436180A00C2
+:1079B000970F00320E000A7831E43FFF8E0E01006F
+:1079C000240DFF803C04200001C25821016D602479
+:1079D000000C4940316A007F012A40250104382506
+:1079E0003C048008AE0708303486008090C50068EB
+:1079F0002403000230A200FF104300048F9F0020E8
+:107A00008F990024AC9F0068AC9900648FBF00146C
+:107A10008FB0001003E0000827BD00183C0A0800E2
+:107A2000254A36583C090800252936F43C08080048
+:107A300025082B003C07080024E737B83C0608005F
+:107A400024C634E03C05080024A532383C04080074
+:107A500024842E2C3C030800246335943C02080047
+:107A6000244233303C010800AC2A3B503C01080062
+:107A7000AC293B4C3C010800AC283B483C010800C9
+:107A8000AC273B543C010800AC263B643C01080099
+:107A9000AC253B5C3C010800AC243B583C01080091
+:107AA000AC233B683C010800AC223B6003E00008CB
+:047AB00000000000D2
+:0C7AB400800009408000090080080100EB
+:107AC0008008008080080000800E00008008008090
+:107AD0008008000080000A8080000A008000098081
+:047AE0008000090019
+:00000001FF
+/*
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ */
diff --git a/firmware/bnx2/bnx2-mips-09-5.0.0.j9.fw.ihex b/firmware/bnx2/bnx2-mips-09-5.0.0.j9.fw.ihex
deleted file mode 100644 (file)
index 36e922e..0000000
+++ /dev/null
@@ -1,6058 +0,0 @@
-:100000000800011008000000000051C4000000C8F2
-:10001000000000000000000000000000080051C4C3
-:10002000000000380000528C080000880800000022
-:10003000000051B4000052C4080053A00000008426
-:100040000000A478080051B4000001C00000A4FC26
-:10005000080031D808000000000081540000A6BC50
-:1000600000000000000000000000000008008154B3
-:100070000000012400012810080004880800040082
-:10008000000017EC0001293400000000000000000F
-:100090000000000008001BEC0000000400014120EB
-:1000A000080000A8080000000000381400014124E6
-:1000B00000000000000000000000000008003814EC
-:0800C000000000300001793856
-:0800C8000A00004400000000E2
-:1000D000000000000000000D636F6D352E302E30E3
-:1000E0006A39000005000002000000000000000363
-:1000F00000000014000000320000000300000000B7
-:1001000000000000000000000000000000000000EF
-:1001100000000010000001360000EA600000000549
-:1001200000000000000000000000000000000008C7
-:1001300000000000000000000000000000000000BF
-:1001400000000000000000000000000000000000AF
-:10015000000000000000000000000000000000009F
-:10016000000000020000000000000000000000008D
-:10017000000000000000000000000000000000007F
-:10018000000000000000000000000010000000005F
-:10019000000000000000000000000000000000005F
-:1001A000000000000000000000000000000000004F
-:1001B000000000000000000000000000000000003F
-:1001C000000000000000000000000000000000002F
-:1001D000000000000000000000000000100000030C
-:1001E000000000000000000D0000000D3C020800AF
-:1001F000244252203C03080024635354AC400000C6
-:100200000043202B1480FFFD244200043C1D080005
-:1002100037BD9FFC03A0F0213C1008002610011000
-:100220003C1C0800279C52200E00025F00000000CA
-:100230000000000D27BDFFE0AFBF0018AFB10014F4
-:10024000AFB000103C04800094820108304370007D
-:10025000240220001062000B2862200114400036A6
-:1002600000001021240240001062002C0000000059
-:10027000240260001062002D000010210A00009D81
-:100280008FBF001834910100922400098E300018AD
-:1002900010800020240300012402000914820006BB
-:1002A0008F82001C3C0280089442001A0002140055
-:1002B000020280258F82001C8C42000C1040001529
-:1002C000000018210E000D45000000008F83001C67
-:1002D000962400088F8200189463001E9625000C57
-:1002E0000004240000832025AC500000AC4500042D
-:1002F000AC400008AC40000CAC400010AC40001416
-:10030000AC400018AC44001C0E000D792404000120
-:10031000000018210A00009C006010210E00042E2D
-:10032000000000000A00009C000010210E000C6577
-:1003300000000000000010218FBF00188FB10014D2
-:100340008FB0001003E0000827BD00208F82001C42
-:1003500027BDFFE0AFB00010AFBF0018AFB1001471
-:100360008C42000C3C1080008E11010010400034C3
-:100370008FBF00180E000D45000000008F8500188B
-:1003800024047FFF0091202BACB100008E030104F8
-:100390009602010800031C003042FFFF006218258E
-:1003A000ACA300049202010A96030114304200FF3C
-:1003B0003063FFFF0002140000431025ACA20008C8
-:1003C0009603010C9602010E00031C003042FFFF51
-:1003D00000621825ACA3000C9603011096020112CE
-:1003E00000031C003042FFFF00621825ACA3001080
-:1003F0008E020118ACA200148E02011CACA20018DF
-:10040000148000088F82001C978200003C042005A5
-:100410000044182524420001ACA3001C0A0000DBA4
-:10042000A78200003C0340189442001E00431025A0
-:10043000ACA2001C0E000D79240400018FBF00182F
-:100440008FB100148FB000100000102103E00008ED
-:1004500027BD00203C0680008CC202B824030001A6
-:1004600004410008008028213C0208008C42006002
-:10047000244200013C010800AC22006003E00008B7
-:10048000006010218C83002094820016ACC302808F
-:100490002442FFFCA4C202843C0208008C42005C9F
-:1004A0008C84000494A3000E244200013C01080047
-:1004B000AC22005C3C021000A4C30286ACC40288DB
-:1004C00000001821ACC202B803E00008006010214F
-:1004D00027BDFFE0AFB000103C108000AFB20018A5
-:1004E000AFBF001CAFB10014361201009243000BE5
-:1004F0002402001A965100081462005A00002821B4
-:1005000032220001104000188F82001C8E42000031
-:10051000000223403C02003F3442FFFF0044102B06
-:10052000104000043C030040964200140A000124DD
-:10053000008320218E030100240201005462000682
-:10054000964200143C028008904200043042000FA2
-:10055000000225009642001400821025AE020080A1
-:100560000A000157000000008C42000C10400028D7
-:10057000000000000E000D4500000000960201087A
-:100580009603010C8F8500183042003E3063FFFF58
-:100590000002140000431025ACA200008E020100EE
-:1005A000ACA20004960301169604010E8F82001C73
-:1005B00000031C003084FFFF00641825ACA3000872
-:1005C00096030110960401129446001E00031C00BD
-:1005D0003084FFFF00641825ACA3000C3C0220000F
-:1005E00000C2302596020114240400013042FFFFAE
-:1005F000ACA200108E020118ACA200149202010BF2
-:10060000304200FFACA200180E000D79ACA6001C11
-:100610003C0208008C420040244200013C010800DA
-:10062000AC2200403C0308008C63004432220002EC
-:1006300032240004246300013C010800AC23004480
-:10064000108000080002282B024020218FBF001CD0
-:100650008FB200188FB100148FB000100A0000E3B1
-:1006600027BD00208FBF001C8FB200188FB100146F
-:100670008FB0001000A0102103E0000827BD00206B
-:1006800027BDFFE0AFB000103C108000AFB20018F3
-:10069000AFBF001CAFB10014361201009243000B33
-:1006A000240200031462006A9651000832220001FD
-:1006B000104000178F82001C8E4300003C02003F58
-:1006C0003442FFFF000323400044102B504000053C
-:1006D00024020100964200143C0300400A00018EEF
-:1006E0000083202154620006964200143C028008D8
-:1006F000904200043042000F000225009642001490
-:1007000000821025AE0200800A0001BE0000000039
-:100710008C42000C10400025000000000E000D452A
-:1007200000000000960201089603010C8F85001856
-:100730003042003E3063FFFF0002140000431025EA
-:10074000ACA200008E020100ACA2000496030116C8
-:100750009604010E8F82001C00031C003084FFFFF2
-:1007600000641825ACA3000896030110960401123A
-:100770009446001E00031C003084FFFF006418250F
-:10078000ACA3000C3C02200000C2302596020114EC
-:10079000240400013042FFFFACA20010ACA0001402
-:1007A000ACA000180E000D79ACA6001C3C0208009D
-:1007B0008C420040244200013C010800AC22004071
-:1007C0003C0208008C420044322300042442000111
-:1007D0003C010800AC2200441060000832220002F4
-:1007E000024020218FBF001C8FB200188FB100146F
-:1007F0008FB000100A0000E327BD00201040001554
-:100800008FBF001C3C0480008C8301043C026020EC
-:10081000AC4300148C420004240301FE304203FF69
-:100820001443000C8FBF001C8C820100000219C20F
-:100830002462FFFC2C420008104000032404000244
-:100840002462FFFD004420043C026000AC446914B3
-:100850008FBF001C8FB200188FB100148FB0001032
-:100860000000102103E0000827BD00203C048000A8
-:100870008C83010024020100506200033C028008C6
-:100880000000000D3C02800890430004000010218D
-:100890003063000F00031D0003E00008AC830080FC
-:1008A0002C8407811080000A000028213C0280006F
-:1008B00094420108240320003042700014430005D4
-:1008C0002783FFB03C02800890420005304500FFBE
-:1008D0002783FFB00005208000832021000510C081
-:1008E000004510238C8400003C030800246352E47C
-:1008F000000210C0004310213C038000AC64009053
-:1009000003E00008AF82001C03E000080000102193
-:1009100003E00008000010212402010014820008F6
-:10092000000000003C0208008C4200FC2442000150
-:100930003C010800AC2200FC0A00022430A2002086
-:100940003C0208008C420084244200013C01080063
-:10095000AC22008430A200201040000830A3001018
-:100960003C0208008C420108244200013C010800BE
-:10097000AC22010803E0000800000000106000083D
-:10098000000000003C0208008C42010424420001E7
-:100990003C010800AC22010403E000080000000054
-:1009A0003C0208008C420100244200013C01080086
-:1009B000AC22010003E000080000000027BDFFE8B2
-:1009C000AFB000103C108000AFBF0014360401002F
-:1009D0009483000830620004104000053066000275
-:1009E0008FBF00148FB000100A0000E327BD00186D
-:1009F00010C00006006028218E0401000E000214C1
-:100A0000000000000A00025B240200018F8200083F
-:100A10008E03010410430007000010218E04010022
-:100A20000E000214000000008E020104AF820008D4
-:100A3000000010218FBF00148FB0001003E00008E9
-:100A400027BD001827BDFFD83C036010AFB3001CC2
-:100A5000AFBF0020AFB20018AFB10014AFB00010AC
-:100A60008C6450002402FF7F3C1308002673524818
-:100A7000008220243484380CAC6450003C02800096
-:100A800024030037AC4300083C06080024C6084095
-:100A9000026010212404001C2484FFFFAC460000E7
-:100AA0000481FFFD244200043C0208002442016C42
-:100AB0003C010800AC2252503C020800244205B818
-:100AC0003C010800AC2252543C020800244202843B
-:100AD0003C010800AC2252903C0208002442040869
-:100AE0003C030800246308483C040800248408F4FC
-:100AF0003C05080024A52C4C3C010800AC2252B057
-:100B00003C020800244207A43C010800AC2652988D
-:100B10003C010800AC2552A43C010800AC2352ACB7
-:100B20003C010800AC2452B43C010800AC2252B88D
-:100B30003C010800AC23524C3C010800AC20525848
-:100B40003C010800AC20525C3C010800AC20526023
-:100B50003C010800AC2052643C010800AC20526803
-:100B60003C010800AC20526C3C010800AC205270E3
-:100B70003C010800AC2452743C010800AC205278BF
-:100B80003C010800AC20527C3C010800AC205280A3
-:100B90003C010800AC2052843C010800AC20528883
-:100BA0003C010800AC26528C3C010800AC26529453
-:100BB0003C010800AC20529C3C010800AC2552A02E
-:100BC0003C010800AC2352A80E00055A00000000AA
-:100BD0008F8300043C0208008C4200201062001F3A
-:100BE000000088212792FFB03C100800261052E434
-:100BF0003C0208008C420020240500010225180454
-:100C0000004320248F820004004310245044000C31
-:100C10002631000110800008AF90001C8E430000B8
-:100C20003C028000AC4300900E000D0CAE05000CA1
-:100C30000A0002DE26310001AE00000C2631000160
-:100C40002E220002261000381440FFE9265200042C
-:100C50003C0208008C420020AF8200043C1080005F
-:100C60008E110000322200071040FFDA8F8300044B
-:100C70003222000110400021322200028E020100C7
-:100C8000AE0200208E020104AE0200A80E0001F6A2
-:100C90008E0401009202010B304300FF2C62001D04
-:100CA00054400004000310800E0002100A0002FFEE
-:100CB00000000000005310218C4200000040F809A1
-:100CC00000000000104000043C0280008C4301043E
-:100CD0003C026020AC4300143C0208008C4200340B
-:100CE0003C0440003C03800024420001AC64013815
-:100CF0003C010800AC2200343222000210400010F7
-:100D0000322200043C1080008E020140AE0200201E
-:100D10000E0001F68E0401400E0003970000000053
-:100D20003C024000AE0201783C0208008C420038D0
-:100D3000244200013C010800AC22003832220004A9
-:100D40001040FFA48F8300043C1080008E020180BD
-:100D5000AE0200200E0001F68E0401808E03018099
-:100D600024020F00146200073C0280088E020188F2
-:100D70003C0300E03042FFFF004310250A00033B24
-:100D8000AE020080344200809042000024030050F4
-:100D9000304200FF14430007000000000E000374FF
-:100DA0000000000014400003000000000E00095D78
-:100DB000000000003C0208008C42003C3C04400063
-:100DC0003C03800024420001AC6401B83C010800EF
-:100DD000AC22003C0A0002C38F8300043C02900056
-:100DE00034420001008220253C028000AC440020F7
-:100DF0003C0380008C6200200440FFFE00000000E5
-:100E000003E00008000000003C02800034430001C1
-:100E10000083202503E00008AC44002027BDFFE04C
-:100E2000AFB10014AFB0001000808821AFBF001830
-:100E30000E00034530B000FF8F83FFA80220202161
-:100E40009062002502028025A07000258C70001899
-:100E50003C0280000E000350020280241600000AAB
-:100E60008FBF00183C0380008C6201F80440FFFE35
-:100E700024020002AC7101C0A06201C43C02100057
-:100E8000AC6201F88FBF00188FB100148FB0001052
-:100E900003E0000827BD002027BDFFE8AFBF00101A
-:100EA0003C0380009462018430420200104000053F
-:100EB000000020210E000FCD000000000A00038A70
-:100EC000240400018C6201880440000A8FBF0010D6
-:100ED0008C6201883C03FF00004310243C030400A3
-:100EE00014430004240400018F82FFA890420008EC
-:100EF0008FBF00100080102103E0000827BD0018FC
-:100F00008F82FFAC2403000124050001A040001AD9
-:100F10008F82FFA8A44300163C0280000A000355FC
-:100F20008C4401408F85FFA827BDFFE0AFBF001CA8
-:100F3000AFB20018AFB10014AFB0001090A2000023
-:100F4000304400FF38830020388200300003182B23
-:100F50000002102B00621824106000053C02800083
-:100F600024020050148200818FBF001C3C028000CC
-:100F700090420148304200FF2443FFFF2C620005ED
-:100F80001040007A8FBF001C000310803C03080053
-:100F9000246351DC004310218C4200000040000813
-:100FA000000000003C1180008E2401400E0003452B
-:100FB0008F92FFA88E50000C8E2201441602000270
-:100FC00024020001AE42000C0E0003508E240140AA
-:100FD0008E220144145000068FBF001C8FB20018EF
-:100FE0008FB100148FB000100A000F3927BD002008
-:100FF0008E42000C0A0004220000000094A200109F
-:101000003C0480008C8301443042FFFF14620009DD
-:101010000000000024020001A4A200108C82014004
-:10102000AC8202003C021000AC8202380A000429A3
-:101030008FBF001C94A200100A00042200000000D0
-:10104000240200201482000E3C11800094A20012A1
-:101050003C0380008C6301443042FFFF14620005B2
-:101060000000000024020001A4A200120A0003FCF8
-:101070008FBF001C94A200120A000422000000008E
-:101080008E2401400E0003458F92FFA89642001265
-:101090008E2301443050FFFF16030002240200019A
-:1010A000A64200120E0003508E2401408E220144FD
-:1010B000160200068FBF001C8FB200188FB10014FB
-:1010C0008FB000100A00038E27BD00209642001248
-:1010D0000A0004220000000094A200143C038000D7
-:1010E0008C6301443042FFFF146200088FBF001C74
-:1010F000240200018FB200188FB100148FB00010CD
-:10110000A4A200140A00142427BD002094A20014F5
-:101110000A0004220000000094A200163C03800094
-:101120008C6301443042FFFF146200082402000176
-:101130008FBF001C8FB200188FB100148FB0001049
-:10114000A4A200160A000B0027BD002094A20016DE
-:10115000144000068FBF001C3C0208008C42007047
-:10116000244200013C010800AC2200708FB200183C
-:101170008FB100148FB0001003E0000827BD0020DD
-:1011800027BDFFD8AFB200188F92FFA8AFB10014EF
-:10119000AFBF0020AFB3001CAFB000103C02800016
-:1011A000345101008C50010092420000922300094A
-:1011B000304400FF2402001F106200AB28620020B0
-:1011C00010400019240200382862000A1040000D67
-:1011D0002402000B286200081040002E8F82001CA1
-:1011E00004600103286200021440002A8F82001C60
-:1011F00024020006106200268FBF00200A00054C62
-:101200008FB3001C106200602862000B144000F9CC
-:101210008FBF00202402000E106200788F82001C15
-:101220000A00054C8FB3001C106200D128620039FF
-:101230001040000A2402008024020036106200E4FC
-:1012400028620037104000C224020035106200D826
-:101250008FBF00200A00054C8FB3001C1062002DC8
-:101260002862008110400006240200C824020039D0
-:10127000106200C88FBF00200A00054C8FB3001C0D
-:10128000106200A28FBF00200A00054C8FB3001C23
-:101290008F82001C8C42000C104000D68FBF0020B3
-:1012A0000E000D45000000003C0380003463010087
-:1012B0008C6200008F850018946700089466000C0B
-:1012C000ACA200008C6400048F82001C0006340075
-:1012D000ACA400049448001E8C62001800073C0077
-:1012E00000E83825ACA200088C62001C2404000130
-:1012F000ACA2000C9062000A00C23025ACA600101F
-:10130000ACA00014ACA00018ACA7001C0A00050B90
-:101310008FBF00208F82001C8C42000C104000B553
-:101320008FBF00200E000D45000000008F82001CC2
-:10133000962400089625000C9443001E0004220207
-:101340009626000E8F8200180004260000832025B8
-:1013500000052C003C03008000A6282500832025E2
-:10136000AC400000AC400004AC400008AC40000CB5
-:10137000AC450010AC400014AC400018AC44001C5C
-:101380000A00050A240400019622000C14400018EB
-:10139000000000009242000530420010144000148A
-:1013A000000000000E0003450200202192420005CB
-:1013B00002002021344200100E000350A24200051A
-:1013C0009242000024030020304200FF10430088B6
-:1013D000020020218FBF00208FB3001C8FB20018A5
-:1013E0008FB100148FB000100A00103627BD0028FE
-:1013F0000000000D0A00054B8FBF00208C42000C3E
-:101400001040007C8FBF00200E000D450000000042
-:101410008E2200048F8400189623000CAC820000FA
-:101420003C0280089445002C8F82001C00031C00A5
-:1014300030A5FFFF9446001E3C02400E00651825B3
-:1014400000C23025AC830004AC800008AC80000CE6
-:10145000AC800010AC800014AC800018AC86001C7E
-:101460000A00050A240400010E00034502002021A1
-:101470008F93FFAC020020210E000350A660000CE9
-:10148000020020210E000355240500018F82001C5C
-:101490008C42000C104000578FBF00200E000D45FD
-:1014A000000000009622000C8F8300180002140038
-:1014B000AC700000AC620004AC6000088E440038E0
-:1014C0008F82001CAC64000C8E46003C9445001ECC
-:1014D0003C02401FAC66001000A228258E6200046A
-:1014E00024040001AC620014AC600018AC65001C60
-:1014F0008FBF00208FB3001C8FB200188FB1001473
-:101500008FB000100A000D7927BD002824020020AA
-:10151000108200398FB3001C0E000F1F0000000066
-:10152000104000348FBF00203C0380008C6201F823
-:101530000440FFFE24020002AC7001C0A06201C49E
-:101540003C021000AC6201F80A00054B8FBF00207E
-:10155000020020218FBF00208FB3001C8FB2001823
-:101560008FB100148FB000100A000E6827BD00284C
-:101570009625000C020020218FBF00208FB3001C95
-:101580008FB200188FB100148FB000100A000E8DBA
-:1015900027BD0028020020218FB3001C8FB2001845
-:1015A0008FB100148FB000100A000EB827BD0028BC
-:1015B0009225000D020020218FB3001C8FB200186D
-:1015C0008FB100148FB000100A000F0927BD00284A
-:1015D000020020218FBF00208FB3001C8FB20018A3
-:1015E0008FB100148FB000100A000EE027BD002854
-:1015F0008FBF00208FB3001C8FB200188FB1001472
-:101600008FB0001003E0000827BD00283C038000D5
-:101610008C6202780440FFFE24020002AC640240A7
-:10162000A06202443C02100003E00008AC620278B1
-:10163000A380001003E00008A38000113C03800099
-:101640008C6202780440FFFE8F820014AC6202407C
-:1016500024020002A06202443C02100003E00008E1
-:10166000AC6202783C02600003E000088C42540443
-:101670009083003024020005008040213063003F49
-:101680000000482114620005000050219082004CA7
-:101690009483004E304900FF306AFFFFAD00000C1C
-:1016A000AD000010AD000024950200148D05001C53
-:1016B0008D0400183042FFFF004910230002110082
-:1016C000000237C3004038210086202300A2102BDF
-:1016D0000082202300A72823AD05001CAD040018BC
-:1016E000A5090014A5090020A50A001603E00008BA
-:1016F000A50A002203E000080000000027BDFFD873
-:10170000AFB200183C128008AFB40020AFB3001C89
-:10171000AFB10014AFBF0024AFB0001036510100CC
-:101720003C0260008C4254049222000C3C140800DD
-:10173000929400F7304300FF24020001106200324F
-:101740000080982124020002146200353650008087
-:101750000E0013FE000000009202004C2403FF80E4
-:101760003C0480003042007F000211C0244202404D
-:101770000262102100431824AC83009492450008B3
-:101780009204004C3042007F3C0380061485000721
-:10179000004380212402FFFFA22200112402FFFF48
-:1017A000A62200120A0005BE2402FFFF96020020B6
-:1017B000A222001196020022A62200128E0200240C
-:1017C0003C048008AE2200143485008090A2004CB6
-:1017D00034830100A06200108CA2003CAC620018AF
-:1017E0008C820068AC6200E48C820064AC6200E031
-:1017F0008C82006CAC6200E824020001A0A20068A8
-:101800000A0005DA3C0480080E00141700000000EE
-:1018100036420080A04000680A0005DA3C048008D7
-:10182000A2000068A20000690A0006153C028008B8
-:10183000348300808C62003834850100AC62006C17
-:1018400024020001A062006990A200C590830008F4
-:10185000305100FF3072007F12320019001111C0A8
-:1018600024420240026210212403FF800043182416
-:101870003C048000AC8300943042007F3C0380062F
-:10188000004380218E02000C1040000D0200202138
-:101890000E00056A0000000026220001305100FF02
-:1018A0009203003C023410260002102B0002102389
-:1018B0003063007F022288240A0005E4A203003C72
-:1018C0003C088008350401008C8200D03507008078
-:1018D000ACE2003C8C8200D0AD02000090E5004CF0
-:1018E000908600C590E3004C908400C52402FF80E0
-:1018F00000A228243063007F308400FF00A6282542
-:101900000064182A1060000230A500FF38A500808E
-:10191000A0E5004CA10500093C0280089043000EA0
-:10192000344400803C058000A043000A8C830018EA
-:101930003C027FFF3442FFFF00621824AC83001892
-:101940008CA201F80440FFFE00000000ACB301C00F
-:101950008FBF00248FB400208FB3001C8FB20018FB
-:101960008FB100148FB0001024020002A0A201C4A5
-:1019700027BD00283C02100003E00008ACA201F8DB
-:1019800090A2000024420001A0A200003C03080035
-:101990008C6300F4304200FF1443000200803021C9
-:1019A000A0A0000090A200008F840014000211C0CB
-:1019B0002442024024830040008220212402FF8030
-:1019C000008220243063007F3C02800A00621821DC
-:1019D0003C028000AC44002403E00008ACC30000DB
-:1019E00094820006908300058C85000C8C86001084
-:1019F0008C8700188C88001C8C8400203C01080017
-:101A0000A42252C63C010800A02352C53C01080094
-:101A1000AC2552CC3C010800AC2652D03C01080059
-:101A2000AC2752D83C010800AC2852DC3C0108002D
-:101A3000AC2452E003E00008000000003C028008F3
-:101A4000344201008C4400343C03800034650400BF
-:101A5000AC6400388C420038AF850020AC62003C9A
-:101A60003C020005AC6200300000000000000000F5
-:101A700003E00008000000003C020006308400FF84
-:101A8000008220253C028000AC44003000000000B1
-:101A900000000000000000003C0380008C62000099
-:101AA000304200101040FFFD3462040003E00008E3
-:101AB000AF82002094C200003C080800950800CACC
-:101AC00030E7FFFF0080482101021021A4C200007E
-:101AD00094C200003042FFFF00E2102B544000018E
-:101AE000A4C7000094A200003C0308008C6300CC53
-:101AF00024420001A4A2000094A200003042FFFF93
-:101B0000144300073C0280080107102BA4A000002A
-:101B10005440000101003821A4C700003C028008A5
-:101B2000344601008CC3002894A200003C048000CD
-:101B30003042FFFE000210C000621021AC82003C67
-:101B40008C82003C00621823186000040000000032
-:101B50008CC200240A0006A6244200018CC2002484
-:101B6000AC8200383C020050344200103C0380003C
-:101B7000AC62003000000000000000000000000027
-:101B80008C620000304200201040FFFD0000000089
-:101B900094A200003C04800030420001000210C00A
-:101BA000004410218C430400AD2300008C42040447
-:101BB000AD2200043C02002003E00008AC820030AB
-:101BC00027BDFFE0AFB20018AFB10014AFB00010F6
-:101BD000AFBF001C94C2000000C080213C1208006E
-:101BE000965200C624420001A6020000960300009F
-:101BF00094E2000000E03021144300058FB1003072
-:101C00000E00067B024038210A0006DD00000000BD
-:101C10008C8300048C82000424420040046100078D
-:101C2000AC8200048C820004044000040000000028
-:101C30008C82000024420001AC8200009602000069
-:101C40003042FFFF50520001A60000009622000023
-:101C500024420001A62200003C0280083442010018
-:101C6000962300009442003C144300048FBF001CE4
-:101C700024020001A62200008FBF001C8FB20018B2
-:101C80008FB100148FB0001003E0000827BD0020C2
-:101C900027BDFFE03C028008AFBF001834420100BE
-:101CA0008C4800343C03800034690400AC68003880
-:101CB0008C42003830E700FFAF890020AC62003C66
-:101CC0003C020005AC620030000000000000000093
-:101CD0000000000000000000000000000000000004
-:101CE0008C82000C8C82000C9783000EAD220000C9
-:101CF0008C82001000604021AD2200048C8200180C
-:101D0000AD2200088C82001CAD22000C8CA20014B5
-:101D1000AD2200108C820020AD22001490820005BC
-:101D2000304200FF00021200AD2200188CA2001801
-:101D3000AD22001C8CA2000CAD2200208CA2001051
-:101D4000AD2200248CA2001CAD2200288CA2002011
-:101D5000AD22002C3402FFFFAD260030AD20003450
-:101D6000506200013408FFFFAD28003850E0001138
-:101D70003C0280083C0480083484010094820050B6
-:101D80003042FFFFAD22003C948300449485004420
-:101D9000240200013063FFFF000318C20064182111
-:101DA0009064005430A5000700A210040A00074800
-:101DB0000044102534420100AD20003C944300440F
-:101DC000944400443063FFFF000318C200621821EE
-:101DD0003084000790650054240200010082100442
-:101DE0000002102700451024A062005400000000EB
-:101DF00000000000000000003C02000634420040E9
-:101E00003C038000AC6200300000000000000000D5
-:101E1000000000008C620000304200101040FFFD06
-:101E20003C06800834C201503463040034C7014AC0
-:101E300034C4013434C5014034C60144AFA200109B
-:101E40000E0006BEAF8300208FBF001803E000081D
-:101E500027BD00208F83000C3C0608008CC600E8DC
-:101E60008F82001430633FFF000319800046102169
-:101E7000004310212403FF80004318243C06800007
-:101E8000ACC300283042007F3C03800C004330216B
-:101E900090C2000D30A500FF000038213442001030
-:101EA000A0C2000D8F89000C3C0280083442010062
-:101EB00094430044000913823048000324020001C7
-:101EC000A4C3000E1102000B2902000210400005FD
-:101ED000240200021100000C240300010A000790F4
-:101EE0000000182111020006000000000A000790FF
-:101EF000000018218CC2002C0A0007902443000126
-:101F00008CC20014244300018CC200180043102B23
-:101F10005040000A240700012402002714A20003F5
-:101F20003C0380080A00079D240700013463010078
-:101F30009462004C24420001A462004C0009138208
-:101F4000304300032C620002104000090080282169
-:101F5000146000040000000094C200340A0007ADC1
-:101F60003046FFFF8CC600380A0007AD00802821EC
-:101F7000000030213C040800248452C00A0006F20C
-:101F80000000000027BDFF90AFB60068AFB5006449
-:101F9000AFB40060AFB3005CAFB20058AFB1005453
-:101FA000AFBF006CAFB000508C9000000080B0213B
-:101FB0003C0208008C4200E8960400328F83001433
-:101FC0002414FF8030843FFF006218210004218028
-:101FD00000641821007410243C13800000A090219C
-:101FE00090A50000AE620028920400323C02800CF2
-:101FF0003063007F00628821308400C024020040EA
-:10200000148200320000A8218E3500388E2200187C
-:102010001440000224020001AE2200189202003C8B
-:10202000304200201440000E8F830014000511C0C0
-:102030002442024000621821306400783C02008093
-:102040000082202500741824AE630800AE640810D6
-:102050008E2200188E03000800431021AE220018C3
-:102060008E22002C8E230018244200010062182BBF
-:102070001060004300000000924200002442000172
-:10208000A24200003C0308008C6300F4304200FFD1
-:1020900050430001A2400000924200008F840014CF
-:1020A000000211C024420240248300403063007FBC
-:1020B000008220213C02800A009420240062182122
-:1020C000AE6400240A0008BEAEC3000092030032D2
-:1020D0002402FFC000431024304200FF14400005DA
-:1020E00024020001AE220018962200340A00082EB5
-:1020F0003055FFFF8E22001424420001AE2200184A
-:102100009202003000021600000216030441001C77
-:10211000000000009602003227A400100080282151
-:10212000A7A2001696020032000030212407000109
-:102130003042FFFFAF82000C0E0006F2AFA0001C81
-:10214000960200328F8300143C0408008C8400E85F
-:1021500030423FFF00021180006418210062182104
-:1021600000741024AE62002C3063007F3C02800EAD
-:10217000006218219062000D3042007FA062000DC5
-:102180009222000D30420010504000789242000030
-:102190003C028008344401009482004C8EC300004D
-:1021A0003C130800967300C62442FFFFA482004C33
-:1021B000946200329623000E3054FFFF3070FFFF10
-:1021C0003C0308008C6300D000701807A7A30038F8
-:1021D0009482003E3063FFFF3042FFFF146200072D
-:1021E000000000008C8200303C038000244200305C
-:1021F000AC62003C0A0008568C82002C948200409D
-:102200003042FFFF5462000927A400408C8200384E
-:102210003C03800024420030AC62003C8C820034DD
-:10222000AC6200380A0008653C03800027A500382E
-:1022300027A60048026038210E00067BA7A00048B0
-:102240008FA300403C02800024630030AC43003880
-:102250008FA30044AC43003C3C0380003C020005DB
-:10226000AC6200303C028008344401009482004299
-:10227000346304003042FFFF0202102B14400007B9
-:10228000AF8300209482004E94830042020210210A
-:10229000004310230A00087B3043FFFF9483004E65
-:1022A0009482004202631821005010230062182318
-:1022B0003063FFFF3C028008344401009482003CFC
-:1022C0003042FFFF14430003000000000A00088BA7
-:1022D000240300019482003C3042FFFF0062102B77
-:1022E000144000058F8200209482003C006210237D
-:1022F0003043FFFF8F820020AC550000AC4000044B
-:10230000AC540008AC43000C3C0200063442001000
-:102310003C038000AC6200300000000000000000C0
-:10232000000000008C620000304200101040FFFDF1
-:102330003C04800834840100001018C20064182195
-:102340009065005432020007240600010046100484
-:1023500000451025A0620054948300429622000E8E
-:1023600050430001A3860010924200002442000165
-:10237000A24200003C0308008C6300F4304200FFDE
-:1023800050430001A2400000924200008F840014DC
-:10239000000211C024420240248300400082202118
-:1023A0002402FF80008220243063007F3C02800AE8
-:1023B000006218213C028000AC440024AEC300003F
-:1023C0008FBF006C8FB600688FB500648FB400605B
-:1023D0008FB3005C8FB200588FB100548FB00050A3
-:1023E00003E0000827BD007027BDFFD8AFB3001C75
-:1023F000AFB20018AFB10014AFB00010AFBF0020F3
-:102400000080982100E0802130B1FFFF0E000D45D3
-:1024100030D200FF000000000000000000000000BB
-:102420008F8200188F83001CAC510000AC52000456
-:10243000AC530008AC40000CAC400010AC400014A1
-:10244000AC4000189463001E02038025AC50001CB1
-:102450000000000000000000000000002404000153
-:102460008FBF00208FB3001C8FB200188FB10014F3
-:102470008FB000100A000D7927BD002830A5FFFF9E
-:102480000A0008C830C600FF3C028008344301003F
-:102490009462000E3C080800950800C63046FFFF15
-:1024A00014C000043402FFFF946500DA0A00091525
-:1024B0008F84001410C20027000000009462004EB8
-:1024C0009464003C3045FFFF00A6102300A6182BA3
-:1024D0003087FFFF106000043044FFFF00C5102369
-:1024E00000E210233044FFFF0088102B1040000E44
-:1024F00000E810233C02800834440100240300015A
-:1025000034420080A44300162402FFFFA482000E80
-:10251000948500DA8F8400140000302130A5FFFF7D
-:102520000A0008ED3C0760200044102A1040000912
-:102530003C0280083443008094620016304200015F
-:10254000104000043C0280009442007E24420014AB
-:10255000A462001603E000080000000027BDFFE0B1
-:102560003C028008AFBF001CAFB00018344201002D
-:10257000944300429442004C104000193068FFFF21
-:102580009383001024020001146200298FBF001CF5
-:102590003C06800834D00100000810C20050102111
-:1025A000904200543103000734C70148304200FF15
-:1025B000006210073042000134C9014E34C4012CBE
-:1025C00034C5013E1040001634C601420E0006BE5E
-:1025D000AFA90010960200420A0009323048FFFFFE
-:1025E0003C028008344401009483004494820042F9
-:1025F0001043000F8FBF001C94820044A48200424D
-:1026000094820050A482004E8C820038AC8200304C
-:1026100094820040A482003E9482004AA482004832
-:102620008FBF001C8FB000180A0008F027BD0020E3
-:102630008FB0001803E0000827BD002027BDFFA0D1
-:10264000AFB1004C3C118000AFBF0058AFB3005495
-:10265000AFB20050AFB000483626018890C20003E8
-:102660003044007FA3A400108E32018090C200008D
-:102670003043007F240200031062003BAF9200143D
-:102680002862000410400006240200042402000214
-:10269000106200098FBF00580A000AFB8FB3005474
-:1026A0001062004D240200051062014E8FBF0058D9
-:1026B0000A000AFB8FB30054000411C0024210212B
-:1026C0002404FF802442024000441024264300409A
-:1026D000AE2200243063007F3C02800A0062182191
-:1026E0009062003CAFA3003C00441025A062003C77
-:1026F0008FA3003C9062003C304200401040016CCF
-:102700008FBF00583C108008A380001036100100D5
-:102710008E0200D08C63003427A4003C27A5001053
-:10272000004310210E0007AFAE0200D093A20010AC
-:102730003C038000A20200C58C6202780440FFFEC8
-:102740008F820014AC62024024020002A0620244A4
-:102750003C021000AC6202780E0009250000000067
-:102760000A000AFA8FBF00583C05800890C3000198
-:1027700090A2000B1443014E8FBF005834A4008078
-:102780008C8200189082004C90A200083C026000ED
-:102790008C4254048C8300183C027FFF3442FFFFBC
-:1027A000006218243C0208008C4200B4AC8300187C
-:1027B0003C038000244200013C010800AC2200B42C
-:1027C0008C6201F80440FFFE8F820014AC6201C0ED
-:1027D0000A000AC2240200023C10800890C30001D3
-:1027E0009202000B144301328FBF005827A4001837
-:1027F00036050110240600033C0260008C4254049C
-:102800000E000E080000000027A40028360501E095
-:102810000E000E08240600038FA2002836030100D4
-:10282000AE0200648FA2002CAE0200688FA20030BE
-:10283000AE02006C93A40018906300C52402FF80D0
-:102840000082102400431025304900FF3084007FAF
-:102850003122007F0082102A544000013929008073
-:10286000000411C0244202402403FF8002421021D0
-:1028700000431024AE220094264200403042007FE4
-:102880003C038006004340218FA3001C2402FFFF6D
-:10289000AFA800403C130800927300F710620033A9
-:1028A00093A2001995030014304400FF3063FFFF2A
-:1028B0000064182B10600010000000009504001444
-:1028C0008D07001C8D0600183084FFFF0044202374
-:1028D0000004210000E438210000102100E4202B36
-:1028E00000C2302100C43021AD07001CAD06001825
-:1028F0000A000A1B93A20019950400148D07001CFE
-:102900008D0600183084FFFF008220230004210080
-:10291000000010210080182100C2302300E4202B89
-:1029200000C4302300E33823AD07001CAD060018B7
-:1029300093A200198FA30040A462001497A2001A6A
-:10294000A46200168FA2001CAC6200108FA2001CB3
-:10295000AC62000C93A20019A462002097A2001A96
-:10296000A46200228FA2001CAC6200243C048008F8
-:10297000348300808C6200388FA2002001208821DF
-:10298000AC62003C8FA20020AC82000093A2001831
-:10299000A062004C93A20018A0820009A060006809
-:1029A00093A20018105100512407FF803229007FA4
-:1029B000000911C024420240024210213046007F2B
-:1029C0003C03800000471024AC6200943C02800667
-:1029D00000C2302190C2003CAFA600400000202180
-:1029E00000471025A0C2003C8FA8004095020002BD
-:1029F000950300148D07001C3042FFFF3063FFFF7A
-:102A00008D060018004310230002110000E2382157
-:102A100000E2102B00C4302100C23021AD07001CA1
-:102A2000AD06001895020002A5020014A5000016CC
-:102A30008D020008AD0200108D020008AD02000CEE
-:102A400095020002A5020020A50000228D020008C8
-:102A5000AD0200249102003C304200401040001AB8
-:102A6000262200013C108008A3A90038A380001092
-:102A7000361001008E0200D08D03003427A40040E0
-:102A800027A50038004310210E0007AFAE0200D08A
-:102A900093A200383C038000A20200C58C62027839
-:102AA0000440FFFE8F820014AC6202402402000248
-:102AB000A06202443C021000AC6202780E000925BC
-:102AC00000000000262200013043007F1473000440
-:102AD000004020212403FF800223102400432026ED
-:102AE00093A200180A000A37309100FF93A400183F
-:102AF0008FA3001C2402FFFF1062000A308900FF30
-:102B000024820001248300013042007F1453000519
-:102B1000306900FF2403FF80008310240043102647
-:102B2000304900FF3C0280089042000801208821C3
-:102B3000305000FF123000193222007F000211C015
-:102B400002421021244202402403FF800043182443
-:102B50003C048000AC8300943042007F3C0380063C
-:102B6000004310218C43000C004020211060000B1A
-:102B7000AFA200400E00056A0000000026230001FD
-:102B80002405FF803062007F1453000202252024B8
-:102B9000008518260A000A9B307100FF3C0480085B
-:102BA000348400808C8300183C027FFF3442FFFF96
-:102BB00000621824AC8300183C0380008C6201F88A
-:102BC0000440FFFE00000000AC7201C024020002BD
-:102BD000A06201C43C021000AC6201F80A000AFACB
-:102BE0008FBF00583C04800890C300019082000B06
-:102BF0001443002F8FBF00583490008092020008C9
-:102C00003042004010400020000000009202000806
-:102C100000021600000216030441000502402021B4
-:102C20000E000E8D240500930A000AFA8FBF00588B
-:102C30009202000924030018304200FF1443000DE3
-:102C400002402021240500390E000E25000030210D
-:102C50000E0003458F8400148F82FFA82403001206
-:102C6000A04300090E0003508F8400140A000AFAE2
-:102C70008FBF0058240500360E000E2500003021BD
-:102C80000A000AFA8FBF00580E00034502402021B7
-:102C9000920200058F840014344200200E0003507D
-:102CA000A20200050E0010368F8400148FBF00585A
-:102CB0008FB300548FB200508FB1004C8FB00048DA
-:102CC00003E0000827BD00603C0280083445010095
-:102CD0003C0280008C42014094A3000E0000302191
-:102CE00000402021AF8200143063FFFF3402FFFF59
-:102CF000106200063C0760202402FFFFA4A2000E21
-:102D000094A500DA0A0008ED30A5FFFF03E00008F3
-:102D10000000000027BDFFC83C0280003C06800880
-:102D2000AFB5002CAFB1001CAFBF0030AFB400286E
-:102D3000AFB30024AFB20020AFB00018345101008F
-:102D400034C501008C4301008E2200148CA400D4F1
-:102D50000000A821AF830014004410231840005243
-:102D6000A38000108E22001400005021ACA200D4D9
-:102D700090C3000890A200C53073007FA3A200108A
-:102D80008CB200D08CB400D4304200FF1053003B12
-:102D900093A200108F8300142407FF80000211C04B
-:102DA00000621021244202402463004000471024A6
-:102DB0003063007F3C0980003C08800A00681821CD
-:102DC000AD2200248C62003427A4001427A5001033
-:102DD000024280210290102304400028AFA3001477
-:102DE0009062003C00E21024304200FF14400019C1
-:102DF000020090219062003C34420040A062003CFE
-:102E00008F86001493A3001024C200403042007F3C
-:102E1000004828213C0208008C4200F42463000191
-:102E2000306400FF14820002A3A30010A3A00010CE
-:102E300093A20010AFA50014000211C0244202406A
-:102E400000C2102100471024AD2200240A000B31DB
-:102E500093A200100E0007AF000000003C028008A3
-:102E600034420100AC5000D093A30010240A0001AA
-:102E7000A04300C50A000B3193A2001024020001F8
-:102E8000154200093C0380008C6202780440FFFE7A
-:102E90008F820014AC62024024020002A06202444D
-:102EA0003C021000AC6202789222000B2403000264
-:102EB000304200FF14430072000000009622000818
-:102EC000304300FF24020082146200402402008488
-:102ED0003C028000344901008D22000C952300063D
-:102EE000000216023063FFFF3045003F2402002736
-:102EF00010A2000FAF83000C28A200281040000889
-:102F0000240200312402002110A20009240200251D
-:102F100010A20007938200110A000BA90000000014
-:102F200010A20007938200110A000BA90000000004
-:102F30000E000763012020210A000C290000000078
-:102F40003C0380008C6202780440FFFE8F820014F4
-:102F5000AC62024024020002A06202443C02100063
-:102F6000AC6202780A000C290000000095230006DC
-:102F7000912400058D25000C8D2600108D2700184A
-:102F80008D28001C8D290020244200013C010800EE
-:102F9000A42352C63C010800A02452C53C010800ED
-:102FA000AC2552CC3C010800AC2652D03C010800B4
-:102FB000AC2752D83C010800AC2852DC3C01080088
-:102FC000AC2952E00A000C29A38200111462000A05
-:102FD000240200813C02800834420100944500DA5A
-:102FE000922600058F84001430A5FFFF30C600FF35
-:102FF0000A000BEA3C0760211462005C000000003C
-:103000009222000A304300FF306200201040000787
-:10301000306200403C02800834420100944500DAEE
-:103020008F8400140A000BE82406004010400007BB
-:10303000000316003C02800834420100944500DA87
-:103040008F8400140A000BE82406004100021603D6
-:10305000044100463C02800834420100944500DAF5
-:103060008F8400142406004230A5FFFF3C0760193E
-:103070000E0008ED000000000A000C29000000000E
-:103080009222000B24040016304200FF1044000678
-:103090003C0680009222000B24030017304200FF00
-:1030A000144300320000000034C5010090A2000B60
-:1030B000304200FF1444000B000080218CA200204D
-:1030C0008CA400202403FF80004310240002114040
-:1030D0003084007F004410253C032000004310256D
-:1030E000ACC2083094A200080002140000021403CD
-:1030F000044200012410000194A200083042008024
-:103100005040001A0200A82194A20008304220007A
-:10311000504000160200A8218CA300183C021C2D70
-:10312000344219ED106200110200A8213C0208008F
-:103130008C4200D4104000053C02800824030004A7
-:1031400034420100A04300EC3C02800834420100FC
-:10315000944500DA8F8400142406000630A5FFFF92
-:103160000E0008ED3C0760210200A8210E00092591
-:10317000000000009222000A3042000810400004C3
-:1031800002A010210E00133A0000000002A010213E
-:103190008FBF00308FB5002C8FB400288FB3002470
-:1031A0008FB200208FB1001C8FB0001803E0000820
-:1031B00027BD00382402FF80008220243C029000BA
-:1031C00034420007008220253C028000AC440020ED
-:1031D0003C0380008C6200200440FFFE00000000E1
-:1031E00003E00008000000003C0380002402FF8090
-:1031F000008220243462000700822025AC64002075
-:103200008C6200200440FFFE0000000003E0000884
-:10321000000000003C028008240300053442010045
-:10322000A04300EC3C0280008C4201003C03800083
-:10323000AF8200148C6202780440FFFE8F8200147B
-:10324000AC62024024020002A06202443C02100070
-:10325000AC62027803E000080000000027BDFFE830
-:103260003C068000AFBF001034C7010094E20008A4
-:10327000304400FF38830082388200842C630001D0
-:103280002C420001006218251060002D24020083EA
-:1032900093820011504000368FBF00103C0208009E
-:1032A000904252CC8CC401003C06080094C652C621
-:1032B0003045003F38A3003238A2003F2C630001A4
-:1032C0002C42000100621825AF840014AF86000C68
-:1032D000A38000111460000700E0202124020020D8
-:1032E00014A20012000000003402FFFF14C2000FFD
-:1032F000000000002402002014A2000500E02821A4
-:103300008CE300142402FFFF5062000B8FBF0010FB
-:103310003C040800248452C0000030210E0006F254
-:10332000240700010A000C9C8FBF00100E000763E9
-:10333000000000008FBF00100A00092527BD0018FB
-:10334000148200062482FF808CC301043C026020AA
-:10335000AC4300140A000CD28FBF0010304200FFB3
-:103360002C42000210400004240200228FBF0010F3
-:103370000A000B1327BD0018148200048F82001C62
-:103380008FBF00100A000C5327BD00188C42000CA0
-:103390001040001E00E0282190E3000924020018DC
-:1033A00014620003240200160A000CBD2403000866
-:1033B0001462000724020017240300123C02800854
-:1033C00034420080A04300090A000CCA94A70008F8
-:1033D0005462000794A700088F82FFA82404FFFE10
-:1033E0009043000500641824A043000594A700083A
-:1033F00090A6001B8CA4000094A500068FBF0010AF
-:1034000000073C000A0008C827BD00188FBF001045
-:1034100003E0000827BD00188F85001C3C048000D5
-:1034200094A2002A8CA30034000230C02402FFF0D2
-:1034300000C2102400621821AC83003C8CA2003032
-:103440003C038000AC8200383C0200503442001043
-:10345000AC6200300000000000000000000000002E
-:103460008C620000304200201040FFFD30C2000896
-:10347000104000063C0280008C620408ACA20020D0
-:103480008C62040C0A000CF5ACA200248C430400EE
-:10349000ACA300208C420404ACA200243C03002016
-:1034A0003C028000AC4300303C0480008C82003041
-:1034B000004310241440FFFD8F86001C3C02004096
-:1034C000AC82003094C3002A94C2002894C4002C1B
-:1034D00094C5002E24630001004410213064FFFFD6
-:1034E000A4C2002814850002A4C3002AA4C0002A94
-:1034F00003E00008000000008F84001C27BDFFE8E7
-:103500003C05800424840010AFBF00100E000E089C
-:103510002406000A8F84001C948200129483002EDB
-:103520003042000F244200030043180424027FFFAE
-:103530000043102B10400002AC8300000000000D7F
-:103540000E000CD4000000008F83001C8FBF001001
-:1035500027BD0018946200149463001A3042000FD3
-:1035600000021500006218253C02800003E00008FC
-:10357000AC4300A08F83001C3C02800494440006EE
-:103580009462001A8C650000A464001600441023A5
-:103590003042FFFF0045102B03E0000838420001D5
-:1035A0008F84001C3C0780049486001A8C850000E0
-:1035B00094E20006A482001694E3000600C31023E0
-:1035C0003042FFFF0045102B384200011440FFF845
-:1035D000A483001603E00008000000008F84001C94
-:1035E0003C028004944200069483001A8C850000FB
-:1035F000A4820016006210233042FFFF0045102B0A
-:10360000384200015040000D8F85001C00603021C1
-:103610003C07800494E20006A482001694E30006AE
-:1036200000C310233042FFFF0045102B3842000139
-:103630001440FFF8A48300168F85001C3C03800013
-:10364000346204008CA40020AF820018AC640038FF
-:103650008CA20024AC62003C3C020005AC6200304D
-:1036600003E00008ACA000048F84001C3C030006AB
-:103670008C82000400021140004310253C038000AE
-:10368000AC620030000000000000000000000000FC
-:103690008C620000304200101040FFFD34620400D4
-:1036A000AC80000403E00008AF8200188F86001C85
-:1036B00027BDFFE0AFB10014AFB00010AFBF0018DE
-:1036C0008CC300048CC500248F820018309000FF4A
-:1036D00094C4001A246300012442002024840001C1
-:1036E00024A70020ACC30004AF820018A4C4001AB1
-:1036F000ACC7002404A100060000882104E20005F4
-:1037000094C2001A8CC2002024420001ACC20020E6
-:1037100094C2001A94C300282E040001004310260E
-:103720002C420001004410245040000594C2001AAD
-:1037300024020001ACC2000894C2001A94C30028FD
-:103740000010202B004310262C42000100441025BD
-:1037500014400007000000008CC200081440000460
-:10376000240200108CC300041462000F8F85001C1B
-:103770000E000D68241100018F82001C9443002864
-:103780009442001A14430003000000000E000CD401
-:1037900000000000160000048F85001C0E000D457F
-:1037A000000000008F85001C94A2001E94A4001C41
-:1037B000244200013043FFFF14640002A4A2001E53
-:1037C000A4A0001E1200000A3C02800494A200146F
-:1037D00094A3001A3042000F000215000062182561
-:1037E0003C028000AC4300A00A000DDFACA0000842
-:1037F0009442000694A3001A8CA40000A4A2001610
-:10380000006210233042FFFF0044102B38420001B9
-:103810001040000D02201021006030213C07800480
-:1038200094E20006A4A2001694E3000600C310234D
-:103830003042FFFF0044102B384200011440FFF8D3
-:10384000A4A30016022010218FBF00188FB100140E
-:103850008FB0001003E0000827BD002003E000083F
-:10386000000000008F8200243C030006000211408B
-:10387000004310253C038000AC62003000000000D3
-:1038800000000000000000008C62000030420010C8
-:103890001040FFFD34620400AF82002003E0000806
-:1038A000AF80002403E000080000102103E00008BE
-:1038B000000000003084FFFF30A5FFFF000018214A
-:1038C000108000070000000030820001104000025C
-:1038D00000042042006518210A000DFE0005284062
-:1038E00003E000080060102110C0000624C6FFFF9E
-:1038F0008CA2000024A50004AC8200000A000E087F
-:103900002484000403E000080000000010A0000868
-:1039100024A3FFFFAC8600000000000000000000B0
-:103920002402FFFF2463FFFF1462FFFA24840004D3
-:1039300003E00008000000003C02800834420080E0
-:1039400024030001AC43000CA4430010A443001264
-:10395000A443001403E00008A44300168F82001C57
-:1039600027BDFFD8AFB3001CAFB20018AFB1001431
-:10397000AFB00010AFBF00208C47000C2482008045
-:103980002409FF803C08800E3043007F00808021A6
-:103990003C0A8000004920240068182130B100FF53
-:1039A00030D200FF10E0002900009821260201001B
-:1039B000AD44002C004928243042007F00482021DB
-:1039C0009062000024030050304200FF14430004C2
-:1039D00000000000AD45002C948200DA3053FFFF58
-:1039E0000E000D45000000008F82001C8F83001820
-:1039F00000112C009442001E0012240034840001A7
-:103A000000A228253C02400000A22825AC7000003E
-:103A10008FBF0020AC6000048FB20018AC730008A8
-:103A20008FB10014AC60000C8FB3001CAC640010AC
-:103A30008FB00010AC60001424040001AC600018CA
-:103A400027BD00280A000D79AC65001C8FBF00203F
-:103A50008FB3001C8FB200188FB100148FB000100C
-:103A600003E0000827BD00283C06800034C20100A6
-:103A70009043000F240200101062000E2865001110
-:103A800010A0000724020012240200082405003AB6
-:103A9000106200060000302103E000080000000072
-:103AA000240500351462FFFC000030210A000E25B9
-:103AB000000000008CC200748F83FFA824420FA076
-:103AC00003E00008AC62000C27BDFFE8AFBF0010A8
-:103AD0000E000355240500013C0480088FBF001030
-:103AE0002402000134830080A462001227BD001864
-:103AF0002402000103E00008A080001A27BDFFE0B7
-:103B0000AFB20018AFB10014AFB00010AFBF001CCF
-:103B100030B2FFFF0E000345008088213C02800880
-:103B2000345000809202000924030004304200FF58
-:103B30001443000C3C028008124000082402000AD2
-:103B40000E000E1C00000000920200052403FFFE80
-:103B500000431024A202000524020012A202000960
-:103B60003C02800834420080022020210E000350D5
-:103B7000A040002716400003022020210E000E80E6
-:103B80000000000002202021324600FF8FBF001CF1
-:103B90008FB200188FB100148FB0001024050038C8
-:103BA0000A000E2527BD002027BDFFE0AFBF001C87
-:103BB000AFB20018AFB10014AFB000100E00034553
-:103BC000008080210E000E1C000000003C028008D6
-:103BD0003445008090A2000924120018305100FFE3
-:103BE000123200030200202124020012A0A20009C8
-:103BF00090A200052403FFFE004310240E00035092
-:103C0000A0A2000502002021240500201632000792
-:103C1000000030218FBF001C8FB200188FB100143C
-:103C20008FB000100A00035527BD00208FBF001C75
-:103C30008FB200188FB100148FB000102405003926
-:103C40000A000E2527BD002027BDFFE83C028000AA
-:103C5000AFB00010AFBF0014344201009442000C1A
-:103C6000240500360080802114400012304600FFF9
-:103C70000E000345000000003C0280083442008032
-:103C800024030012A0430009904300053463001090
-:103C90000E000E1CA04300050E0003500200202160
-:103CA000020020210E000355240500200A000EFD0D
-:103CB000000000000E000E25000000000E0003456D
-:103CC000020020213C0280089043001B2405FF9F36
-:103CD00002002021006518248FBF00148FB000104F
-:103CE000A043001B0A00035027BD001827BDFFE0BA
-:103CF000AFBF0018AFB10014AFB0001030B100FF7B
-:103D00000E000345008080213C028008240300123D
-:103D1000344200800E000E1CA04300090E00035028
-:103D20000200202102002021022030218FBF001834
-:103D30008FB100148FB00010240500350A000E2545
-:103D400027BD00203C0480089083000E9082000A6A
-:103D50001443000B000028218F82FFA82403005089
-:103D60002405000190420000304200FF144300048B
-:103D7000000000009082000E24420001A082000E8C
-:103D800003E0000800A010213C0380008C6201F8D1
-:103D90000440FFFE24020002AC6401C0A06201C422
-:103DA0003C02100003E00008AC6201F827BDFFE010
-:103DB000AFB200183C128008AFB10014AFBF001CB6
-:103DC000AFB0001036510080922200092403000A8F
-:103DD000304200FF1443003E000000008E43000408
-:103DE0008E220038506200808FBF001C922200009B
-:103DF00024030050304200FF144300253C028000A1
-:103E00008C4201408E4300043642010002202821EA
-:103E1000AC43001C9622005C8E2300383042FFFF2A
-:103E20000002104000621821AE23001C8E430004E3
-:103E30008E2400389622005C006418233042FFFF75
-:103E400000031843000210400043102A10400006EF
-:103E5000000000008E4200048E230038004310232F
-:103E60000A000F6B000220439622005C3042FFFFE5
-:103E7000000220403C0280083443010034420080AC
-:103E8000ACA4002CA040002424020001A062000C7D
-:103E90000E000F1F00000000104000538FBF001CD9
-:103EA0003C0280008C4401403C0380008C6201F89D
-:103EB0000440FFFE24020002AC6401C0A06201C401
-:103EC0003C021000AC6201F80A000FC88FBF001C52
-:103ED0009222000924030010304200FF1443000422
-:103EE0003C0280008C4401400A000FAF00002821F2
-:103EF0009222000924030016304200FF14430006FA
-:103F000024020014A22200093C0280008C440140DB
-:103F10000A000FC28FBF001C8E2200388E23003C87
-:103F200000431023044100308FBF001C9222002761
-:103F300024420001A2220027922200272C420004E2
-:103F4000144000163C108000922200092403000453
-:103F5000304200FF144300093C0280008C440140C1
-:103F60008FBF001C8FB200188FB100148FB00010EB
-:103F7000240500930A000E8D27BD00208C440140CB
-:103F8000240500938FBF001C8FB200188FB100145E
-:103F90008FB000100A000F0927BD00208E040140D9
-:103FA0000E000345000000008E4200042442FFFF83
-:103FB000AE4200048E22003C2442FFFFAE22003CB1
-:103FC0000E0003508E0401408E0401408FBF001C80
-:103FD0008FB200188FB100148FB0001024050004B8
-:103FE0000A00035527BD00208FB200188FB10014BE
-:103FF0008FB0001003E0000827BD00203C068000C1
-:104000008CC201883C038008346500809063000EF8
-:1040100000021402304400FF306300FF1464000EFD
-:104020003C02800890A20026304200FF10440009A4
-:104030008F82FFA8A0A40026240300509042000015
-:10404000304200FF14430006000000000A00058D06
-:104050008CC401803C02800834420080A0440026C9
-:1040600003E000080000000027BDFFE030E700FF8C
-:10407000AFB20018AFBF001CAFB10014AFB000105A
-:104080000080902114E0000630C600FF0000000010
-:104090000000000D000000000A0010212400010EA5
-:1040A0003C0380089062000E304200FF144600235B
-:1040B0003462008090420026304200FF1446001F08
-:1040C000000000009062000F304200FF1446001B09
-:1040D000000000009062000A304200FF1446000316
-:1040E0008F90FFA80000000D8F90FFA88F82FFAC7B
-:1040F0003C118000AE05003CAC450000A066000A03
-:104100000E0003458E240100A20000240E0003507F
-:104110008E2401003C0380008C6201F80440FFFE05
-:1041200024020002AC7201C0A06201C43C02100073
-:10413000AC6201F80A0010228FBF001C00000000D2
-:104140000000000D00000000240001378FBF001C9C
-:104150008FB200188FB100148FB0001003E0000878
-:1041600027BD00208F83FFA83C0280008C44010003
-:10417000344201008C65003C9046001B0A000FE8A9
-:10418000240700013C0280089043000E9042000A80
-:1041900000431026304200FF03E000080002102B0D
-:1041A00027BDFFE03C028008AFB10014AFB00010A3
-:1041B000AFBF001834500080920200052403003085
-:1041C0003042003014430085008088218F82001C1B
-:1041D0008C42000C104000828FBF00180E000D456D
-:1041E000000000008F860018ACD100009202000889
-:1041F00092030009304200FF00021200306300FF0A
-:1042000000431025ACC200049202004D00021600CB
-:104210000002160304410005000000003C030800F2
-:104220008C6300480A0010603C108008920200086D
-:104230003042004014400003000018219202002781
-:10424000304300FF3C108008361100809222004D60
-:1042500000031E00304200FF000214000062182517
-:10426000ACC300088E2400308F82001CACC4000C4C
-:104270008E2500349443001E3C02C00BACC50010D8
-:10428000006218258E22003800002021ACC20014E4
-:104290008E22003CACC200180E000D79ACC3001C8D
-:1042A0008E0200048F8400183C058000AC82000060
-:1042B0008E220020AC8200048E22001CAC820008FA
-:1042C0008E2200588CA3007400431021AC82000C95
-:1042D0008E22002CAC8200108E2200408E230044DF
-:1042E0000002140000431025AC8200149222004DFD
-:1042F00024030080304200FF14430004000000004B
-:10430000AC8000180A0010A48F82001C8E23000CC1
-:10431000240200011062000E2402FFFF9222000816
-:10432000304200401440000A2402FFFF8E23000C9C
-:104330008CA20074006218233C0208000062102462
-:1043400014400002000028210060282100051043CD
-:10435000AC8200188F82001C000020219443001EB4
-:104360003C02C00C006218258F8200180E000D79E7
-:10437000AC43001C3C038008346201008C42000006
-:104380008F850018346300808FBF0018ACA2000036
-:10439000ACA000048C6400488F82001C8FB1001414
-:1043A000ACA40008ACA0000CACA000109063000509
-:1043B0009446001E3C02400D00031E0000C2302542
-:1043C000ACA300148FB00010ACA0001824040001AE
-:1043D000ACA6001C0A000D7927BD00208FBF001875
-:1043E0008FB100148FB0001003E0000827BD00203B
-:1043F0003C0280009443007C3C028008344601006B
-:10440000308400FF3065FFFF2402000524A34650DE
-:10441000A0C4000C5482000C3065FFFF90C2000D58
-:104420002C4200071040000724A30A0090C3000D8F
-:10443000240200140062100400A210210A0010E0FF
-:104440003045FFFF3065FFFF3C02800834420080AA
-:1044500003E00008A44500143C0380083468008091
-:10446000AD050038346701008CE2001C308400FF89
-:1044700000A210231840000330C600FF24A2FFFC56
-:10448000ACE2001C30820001504000083C03800870
-:104490008D02003C00A210230441001224040005F8
-:1044A0008C62000410A2000F3C0380088C620004A0
-:1044B00014A2001E000000003C0208008C4200D83C
-:1044C00030420020104000093C0280083462008025
-:1044D000906300089042004C144300043C028008A2
-:1044E000240400040A0010CA0000000034430080C5
-:1044F00034420100A040000C24020001A462001418
-:1045000010C0000A3C0280008C4401003C03800083
-:104510008C6201F80440FFFE24020002AC6401C07A
-:10452000A06201C43C021000AC6201F803E0000884
-:104530000000000027BDFFE800A61823AFBF001051
-:1045400018600080308800FF3C02800834470080FB
-:10455000A0E0002434440100A0E000278C82001C6D
-:1045600000A2102304400056000000008CE2003C32
-:1045700094E3005C8CE4002C004530233063FFFFA3
-:1045800000C318210083202B1080000400E01821B4
-:104590008CE2002C0A00113900A2102194E2005C88
-:1045A0003042FFFF00C2102100A21021AC62001CAB
-:1045B0003C028008344400809482005C8C83001CA0
-:1045C0003042FFFF0002104000A210210043102BD8
-:1045D00010400004000000008C82001C0A00114CF6
-:1045E0003C0680089482005C3042FFFF00021040CD
-:1045F00000A210213C06800834C3010034C70080AB
-:10460000AC82001CA060000CACE500388C62001C81
-:1046100000A210231840000224A2FFFCAC62001C80
-:1046200031020001104000083C0380088CE2003C8D
-:1046300000A2102304410012240400058CC20004CF
-:1046400010A200108FBF00108C62000414A2004F53
-:104650008FBF00103C0208008C4200D8304200207E
-:104660001040000A3C028008346200809063000819
-:104670009042004C144300053C02800824040004CE
-:104680008FBF00100A0010CA27BD001834430080F5
-:1046900034420100A040000C24020001A462001476
-:1046A0003C0280008C4401003C0380008C6201F8D5
-:1046B0000440FFFE240200020A00119900000000DD
-:1046C0008CE2001C004610230043102B54400001D4
-:1046D000ACE5001C94E2005C3042FFFF0062102B4E
-:1046E000144000072402000294E2005C8CE3001CEA
-:1046F0003042FFFF00621821ACE3001C24020002DC
-:10470000ACE500380E000F1FA082000C1040001F07
-:104710008FBF00103C0280008C4401003C038000ED
-:104720008C6201F80440FFFE24020002AC6401C068
-:10473000A06201C43C021000AC6201F80A0011B191
-:104740008FBF001031020010104000108FBF00100A
-:104750003C028008344500808CA3001C94A2005CBD
-:10476000006618233042FFFF006218213C023FFF21
-:104770003444FFFF0083102B5440000100801821B7
-:1047800000C31021ACA2001C8FBF001003E0000882
-:1047900027BD001827BDFFE800C0402100A6302338
-:1047A000AFBF001018C00026308A00FF3C0280080E
-:1047B000344900808D24001C8D23002C0088202388
-:1047C0000064182B1060000F344701008CE20020B9
-:1047D00000461021ACE200208CE200200044102BA7
-:1047E0001440000B3C023FFF8CE2002000441023E9
-:1047F000ACE200209522005C3042FFFF0A0011D19C
-:1048000000822021ACE00020008620213C023FFFF6
-:104810003443FFFF0064102B54400001006020214E
-:104820003C0280083442008000851821AC43001C03
-:10483000A0400024A04000270A0012233C03800867
-:1048400031420010104000433C0380083C068008C1
-:1048500034C400808C82003C004810235840003E45
-:10486000346600809082002424420001A08200244B
-:10487000908200243C0308008C630024304200FF37
-:104880000043102B144000688FBF001034C2010099
-:104890008C42001C00A2102318400063000000009E
-:1048A0008CC300049482005C006818233042FFFF30
-:1048B00000031843000210400043102A1040000576
-:1048C000000000008CC20004004810230A001206F9
-:1048D000000210439482005C3042FFFF000210404F
-:1048E0003C068008AC82002C34C5008094A2005C99
-:1048F0008CA4002C94A3005C3042FFFF0002104007
-:10490000008220213063FFFF008320210104102159
-:10491000ACA2001C8CC2000434C60100ACC2001C56
-:10492000240200020E000F1FA0C2000C1040003E27
-:104930008FBF00103C0280008C4401003C038000CB
-:104940008C6201F80440FFFE240200020A001253A8
-:104950000000000034660080ACC5003834640100FB
-:104960008C82001C00A210231840000224A2FFFC2D
-:10497000AC82001C314200015040000A3C03800818
-:104980008CC2003C00A21023044300142404000540
-:104990008C62000414A200033C0380080A00124544
-:1049A000240400058C62000414A2001F8FBF0010B5
-:1049B0003C0208008C4200D8304200201040000A1F
-:1049C0003C02800834620080906300089042004CF2
-:1049D000144300053C028008240400048FBF00102B
-:1049E0000A0010CA27BD0018344300803442010079
-:1049F000A040000C24020001A46200143C028000CC
-:104A00008C4401003C0380008C6201F80440FFFEEE
-:104A100024020002AC6401C0A06201C43C02100088
-:104A2000AC6201F88FBF001003E0000827BD00183A
-:104A300027BDFFE83C0A8008AFBF00103549008061
-:104A40008D22003C00C04021308400FF004610232E
-:104A50001840009D30E700FF3547010024020001A7
-:104A600000A63023A0E0000CA0E0000DA522001459
-:104A700018C00024308200108D23001C8D22002CD1
-:104A8000006818230043102B1040000F00000000A6
-:104A90008CE2002000461021ACE200208CE20020D5
-:104AA0000043102B1440000B3C023FFF8CE200201F
-:104AB00000431023ACE200209522005C3042FFFF4F
-:104AC0000A00128200621821ACE000200066182162
-:104AD0003C023FFF3446FFFF00C3102B544000014F
-:104AE00000C018213C028008344200800065182173
-:104AF000AC43001CA0400024A04000270A0012D0B4
-:104B00003C038008104000403C0380088D22003C9C
-:104B1000004810235840003D346700809122002453
-:104B200024420001A1220024912200243C03080019
-:104B30008C630024304200FF0043102B1440009A85
-:104B40008FBF00108CE2001C00A2102318400096BA
-:104B5000000000008D4300049522005C00681823CB
-:104B60003042FFFF00031843000210400043102AA8
-:104B700010400005012020218D4200040048102330
-:104B80000A0012B3000210439522005C3042FFFF7E
-:104B9000000210403C068008AC82002C34C5008026
-:104BA00094A2005C8CA4002C94A3005C3042FFFF14
-:104BB00000021040008220213063FFFF0083182193
-:104BC00001031021ACA2001C8CC2000434C60100F9
-:104BD000ACC2001C240200020E000F1FA0C2000C79
-:104BE000104000718FBF00103C0280008C44010017
-:104BF0003C0380008C6201F80440FFFE24020002A6
-:104C00000A0012FA0000000034670080ACE50038AA
-:104C1000346601008CC2001C00A210231840000260
-:104C200024A2FFFCACC2001C3082000150400008EE
-:104C30003C0380088CE2003C00A210230443005196
-:104C4000240400058C62000410A2003E3C0380088E
-:104C50008C62000454A200548FBF00103C02080074
-:104C60008C4200D830420020104000063C028008F0
-:104C700034620080906300089042004C1043004072
-:104C80003C0280083443008034420100A040000C04
-:104C900024020001A46200143C0280008C44010044
-:104CA0003C0380008C6201F80440FFFE24020002F5
-:104CB000AC6401C0A06201C43C021000AC6201F807
-:104CC0000A0013388FBF001024020005A12000271E
-:104CD00014E2000A3C038008354301009062000D95
-:104CE0002C420006504000053C0380089062000DF5
-:104CF00024420001A062000D3C038008346700805C
-:104D0000ACE50038346601008CC2001C00A2102300
-:104D10001840000224A2FFFCACC2001C308200013B
-:104D20005040000A3C0380088CE2003C00A21023A3
-:104D300004410014240400058C62000414A2000342
-:104D40003C0380080A00132F240400058C62000431
-:104D500014A200158FBF00103C0208008C4200D83E
-:104D6000304200201040000A3C028008346200807B
-:104D7000906300089042004C144300053C028008F8
-:104D8000240400048FBF00100A0010CA27BD0018B9
-:104D90003443008034420100A040000C2402000192
-:104DA000A46200148FBF001003E0000827BD0018A4
-:104DB0003C0B800827BDFFE83C028000AFBF00101D
-:104DC00034420100356A00809044000A35690100D0
-:104DD0008C4500148D4800389123000C308400FF6E
-:104DE000010510231C4000B3306700FF2CE20006D1
-:104DF000504000B18FBF00102402000100E23004D7
-:104E000030C200035440000800A8302330C2000C18
-:104E1000144000A130C20030144000A38FBF001026
-:104E20000A0013FC0000000018C0002430820010AB
-:104E30008D43001C8D42002C006818230043102B6A
-:104E40001040000F000000008D22002000461021BD
-:104E5000AD2200208D2200200043102B1440000BB7
-:104E60003C023FFF8D22002000431023AD22002092
-:104E70009542005C3042FFFF0A0013700062182167
-:104E8000AD200020006618213C023FFF3446FFFFA2
-:104E900000C3102B5440000100C018213C028008C0
-:104EA0003442008000651821AC43001CA04000245F
-:104EB000A04000270A0013BE3C03800810400040B9
-:104EC0003C0380088D42003C004810231840003D00
-:104ED000346700809142002424420001A142002452
-:104EE000914200243C0308008C630024304200FF00
-:104EF0000043102B144000708FBF00108D22001C47
-:104F000000A210231840006C000000008D63000414
-:104F10009542005C006818233042FFFF00031843ED
-:104F2000000210400043102A1040000501402021DB
-:104F30008D620004004810230A0013A100021043F0
-:104F40009542005C3042FFFF000210403C068008A2
-:104F5000AC82002C34C5008094A2005C8CA4002C90
-:104F600094A3005C3042FFFF000210400082202129
-:104F70003063FFFF0083182101031021ACA2001C45
-:104F80008CC2000434C60100ACC2001C2402000222
-:104F90000E000F1FA0C2000C104000478FBF001072
-:104FA0003C0280008C4401003C0380008C6201F8CC
-:104FB0000440FFFE240200020A0013EE000000007D
-:104FC00034670080ACE50038346601008CC2001CF8
-:104FD00000A210231840000224A2FFFCACC2001C57
-:104FE000308200015040000A3C0380088CE2003C03
-:104FF00000A2102304430014240400058C62000462
-:1050000014A200033C0380080A0013E024040005F6
-:105010008C62000414A200288FBF00103C0208001C
-:105020008C4200D8304200201040000A3C02800828
-:1050300034620080906300089042004C14430005E5
-:105040003C028008240400048FBF00100A0010CA2C
-:1050500027BD00183443008034420100A040000CFA
-:1050600024020001A46200143C0280008C44010070
-:105070003C0380008C6201F80440FFFE2402000221
-:10508000AC6401C0A06201C43C021000AC6201F833
-:105090000A0013FC8FBF00108FBF001001003021E9
-:1050A0000A00111B27BD0018010030210A00125A06
-:1050B00027BD00188FBF001003E0000827BD0018AF
-:1050C0003C0380083464010024020003A082000C29
-:1050D0008C62000403E00008AC82001C3C058008E0
-:1050E00034A300809062002734A501002406004309
-:1050F00024420001A0620027906300273C020800C0
-:105100008C420048306300FF146200043C076021B9
-:1051100094A500DA0A0008ED30A5FFFF03E00008BF
-:105120000000000027BDFFE8AFBF00103C02800078
-:105130000E0014058C4401803C02800834430100B9
-:10514000A060000C8C4200048FBF001027BD001827
-:1051500003E00008AC62001C27BDFFE03C028008B1
-:10516000AFBF0018AFB10014AFB0001034450080DD
-:10517000344601003C0880008D09014090C3000CBA
-:105180008CA4003C8CA200381482003B306700FFE6
-:105190009502007C90A30027146000093045FFFFB2
-:1051A0002402000554E200083C04800890C2000D6F
-:1051B00024420001A0C2000D0A0014403C048008F3
-:1051C000A0C0000D3C048008348201009042000C15
-:1051D00024030005304200FF1443000A24A205DC2A
-:1051E00034830080906200272C4200075040000565
-:1051F00024A20A0090630027240200140062100415
-:1052000000A210213C108008361000803045FFFFBE
-:10521000012020210E001405A60500149602005C52
-:105220008E0300383C1180003042FFFF0002104026
-:1052300000621821AE03001C0E0003458E240140BD
-:105240009202002534420040A20200250E000350C5
-:105250008E2401408E2401403C0380008C6201F8C2
-:105260000440FFFE24020002AC6401C0A06201C43D
-:105270003C021000AC6201F88FBF00188FB100141F
-:0C5280008FB0001003E0000827BD0020E4
-:04528C008008010095
-:10529000800800808008000000000C8000003200C0
-:1052A0008008024008000EDC08000F3408000F7868
-:1052B00008001010080010508008010080080080CD
-:0452C0008008000062
-:0C52C4000A0000220000000000000000B2
-:1052D0000000000D6370352E302E306A390000005A
-:1052E00005000004000000000000000000000000B5
-:1052F000000000000000000038003C00000000003A
-:10530000000000000000000000000000000000207D
-:10531000000000000000000000000000000000008D
-:10532000000000000000000000000000000000007D
-:105330000000000000000000210038000000000113
-:105340000000002B00000000000000000000000032
-:1053500010000003000000000000000D0000000D20
-:105360003C020800244254243C0308002463564CA9
-:10537000AC4000000043202B1480FFFD24420004B9
-:105380003C1D080037BD9FFC03A0F0213C10080025
-:10539000261000883C1C0800279C54240E0002881C
-:1053A000000000000000000D00A018210080102166
-:1053B000008028213C0460003C07600024060008AF
-:1053C00010600006348420788C420000ACE2200893
-:1053D0008C63000003E00008ACE3200C0A000E2AF6
-:1053E00000000000240300403C02600003E00008CD
-:1053F000AC4320003C0760008F8600008CE52074E1
-:105400000086102100A2182B14600007000028213C
-:105410008F8AFD9824050001A14400138F890000A4
-:1054200001244021AF88000003E0000800A0102103
-:105430008F84FD988F8500009086001330C300FF95
-:1054400000A31023AF82000003E00008A080001337
-:105450008F84FD9827BDFFE8AFB00010AFBF0014E8
-:10546000908900119087001124020028312800FF44
-:105470003906002830E300FF2485002C2CD00001E1
-:10548000106200162484001C0E0000390000000089
-:105490008F8FFD983C0560002402020495EE003ECB
-:1054A00095ED003C000E5C0031ACFFFF016C502517
-:1054B000ACAA20105200000124020004ACA220007B
-:1054C0000000000000000000000000008FBF00147A
-:1054D0008FB0001003E0000827BD00180A0000711B
-:1054E000000028218F85FD9827BDFFD8AFBF002081
-:1054F000AFB3001CAFB20018AFB10014AFB00010D2
-:105500000080982190A4001124B0001C24B1002C2C
-:10551000308300FF386200280E00005B2C5200012F
-:105520000E00006300000000020020211240000273
-:1055300002202821000028210E0000390000000070
-:105540008F8DFD983C0880003C05600095AC003EC6
-:1055500095AB003C02683025000C4C00316AFFFF1F
-:10556000012A3825ACA7201024020202ACA6201480
-:1055700052400001240200028FBF00208FB3001CA4
-:105580008FB200188FB100148FB0001027BD002813
-:1055900003E00008ACA2200027BDFFE0AFB2001876
-:1055A000AFB10014AFB00010AFBF001C3C116000E1
-:1055B0008E2320748F82000030D0FFFF30F2FFFF77
-:1055C0001062000C2406008F0E000039000000005D
-:1055D0003C06801F0010440034C5FF00011238252E
-:1055E00024040002AE27201000003021AE25201434
-:1055F000AE2420008FBF001C8FB200188FB10014A2
-:105600008FB0001000C0102103E0000827BD00206B
-:1056100027BDFFE0AFB0001030D0FFFFAFBF0018D4
-:10562000AFB100140E00003930F1FFFF001024006C
-:10563000009180253C036000AC7020108FBF0018E3
-:105640008FB100148FB0001024020004AC6220005F
-:1056500027BD002003E000080000102127BDFFE85F
-:105660003C0B6018AFBF00108D6F50002418FF7FF7
-:10567000340C807101F8702435CD380C240A0031C7
-:105680003C098000AD6D50003C08800AAD6C53BCF5
-:10569000AD2A00080E00049BAF88002C0E000459B0
-:1056A000000000000E000048000000003C07600001
-:1056B0008CE508082406FFF03C03570900A62024C7
-:1056C0003462F0001082005024190001AF800034D1
-:1056D0000E000BBC000000003C0660168CC40000ED
-:1056E0003C0760148CE500A03C03FFFF00831024FE
-:1056F0003C1F535300051FC2105F003D34C57C00A2
-:1057000094A201F2A780004C10400003A780005C27
-:10571000384B1E1EA78B004C94A201F810400004C9
-:105720008F8D0034384C1E1EA78C005C8F8D00348A
-:1057300011A000049784005C240E0020A78E004C6A
-:105740009784005C2C8F008151E0000124040080CC
-:105750009785004C2CB80401530000012405040077
-:105760003C0260008C4304382419103C307FFFFF5A
-:1057700013F900033087FFFF50E0000F24060050AC
-:10578000A380005E9388005E51000010A784005C37
-:10579000A780005C9785005C8FBF0010A780004C3D
-:1057A000A7800054A78000723C010800AC2500804F
-:1057B00003E0000827BD0018A386005E9388005E02
-:1057C0005500FFF4A780005CA784005CA785004C0F
-:1057D0008FBF00109785005CA7800054A7800072DF
-:1057E0003C010800AC25008003E0000827BD00183C
-:1057F00000035080014648218D2800043C066000CB
-:105800000A00010F010628210A000103AF990034A4
-:105810003083FFFF8F88002C8F87002800032140F2
-:105820003C0580003C020050008248253C06600098
-:105830003C0A010034AC04008CCD08E001AA5824D5
-:1058400011600005000000008CCF08E024E7000193
-:1058500001EA7025ACCE08E08D19001001805821B6
-:10586000ACB900388D180014ACB8003CACA90030BD
-:105870000000000000000000000000000000000028
-:105880000000000000000000000000000000000018
-:105890003C0380008C640000308200201040FFFD3B
-:1058A0003C0F60008DED08E03C0E010001AE1824B5
-:1058B0001460FFE100000000AF87002803E000084B
-:1058C000AF8B00388F85002C240BFFF03C06800046
-:1058D00094A7001A8CA9002430ECFFFF000C38C0FC
-:1058E00000EB5024012A4021ACC8003C8CA40024C9
-:1058F0008CC3003C008310231840003300000000DC
-:105900008CAD002025A200013C0F0050ACC2003835
-:1059100035EE00103C068000ACCE003000000000E8
-:105920000000000000000000000000000000000077
-:105930000000000000000000000000003C048000A7
-:105940008C990000333800201300FFFD30E200087E
-:10595000104000173C0980008C880408ACA8001097
-:105960008C83040CACA300143C1900203C1880006C
-:10597000AF19003094AE001894AF001C01CF302155
-:10598000A4A6001894AD001A25A70001A4A7001A28
-:1059900094AB001A94AC001E118B000300000000B1
-:1059A00003E000080000000003E00008A4A0001AC3
-:1059B0008D2A0400ACAA00108D240404ACA40014A9
-:1059C0000A0001AA3C1900208CA200200A000192C2
-:1059D0003C0F00500A0001800000000027BDFFE8D6
-:1059E000AFBF00100E0001C4000000008F89002C22
-:1059F0008FBF00103C038000A520000A9528000AF4
-:105A00009527000427BD00183105FFFF30E6000F81
-:105A10000006150000A2202503E00008AC64008009
-:105A20003C0508008CA500208F83000427BDFFE8FB
-:105A3000AFB00010AFBF001410A300100000802111
-:105A4000240400010204300400A6202400C3102412
-:105A50005044000626100001001018802787FD9C86
-:105A60001480000A00671821261000012E09000288
-:105A70005520FFF38F830004AF8500048FBF00140F
-:105A80008FB0001003E0000827BD00188C680000EC
-:105A90003C058000ACA800240E0001C626100001C1
-:105AA0003C0508008CA500200A0001EB2E0900022D
-:105AB00024050001008518043C0408008C840020A3
-:105AC00027BDFFC8AFBF003400831024AFBE003035
-:105AD000AFB7002CAFB60028AFB50024AFB400209C
-:105AE000AFB3001CAFB20018AFB1001410400051AA
-:105AF000AFB000108F84002C948700069488000AB1
-:105B000000E8302330D5FFFF12A0004B8FBF0034D8
-:105B1000948B0018948C000A016C50233142FFFFD3
-:105B200002A2482B1520000202A0202100402021C3
-:105B30002C8F000515E0000200809821241300043A
-:105B40000E000153026020218F87002C02609021FB
-:105B5000AF80003094F4000A026080211260004E91
-:105B60003291FFFF3C1670003C1440003C1E2000A8
-:105B70003C1760008F9900388F38000003161824F6
-:105B80001074004F0283F82B17E00036000000006D
-:105B9000107E00478F86003014C0003A24030001B5
-:105BA00002031023022320213050FFFF1600FFF1D3
-:105BB0003091FFFF8F87002C3C1100203C108000AB
-:105BC000AE11003094EB000A3C178000024B5021CC
-:105BD000A4EA000A94E9000A94E800043123FFFFD4
-:105BE0003106000F00062D000065F025AEFE008096
-:105BF00094F3000A94F6001812D3003600122140E4
-:105C00008CFF00148CF4001003E468210000C02114
-:105C100001A4782B0298702101CF6021ACED001413
-:105C2000ACEC001002B2382330F5FFFF16A0FFB82D
-:105C30008F84002C8FBF00348FBE00308FB7002CB4
-:105C40008FB600288FB500248FB400208FB3001CBE
-:105C50008FB200188FB100148FB0001003E000085D
-:105C600027BD00381477FFCC8F8600300E000D8BD7
-:105C700002002021004018218F86003010C0FFC98B
-:105C800002031023027070238F87002C01C3682148
-:105C90000A00027631B2FFFF8F86003014C0FFC9C0
-:105CA0003C1100203C1080000A000240AE11003080
-:105CB0000E0003C4020020210A00026D00401821DA
-:105CC000020020210E0007DB022028210A00026DBD
-:105CD000004018210E000180000000000A00025957
-:105CE00002B2382327BDFFD8AFB40020AFB3001CE9
-:105CF000AFB20018AFB10014AFB00010AFBF0024B6
-:105D00000E0000E6241300013C0280083C03200042
-:105D10003C010800AC200070345400803472000351
-:105D20003C1080002411FF800E0001D7000000000D
-:105D30008E06000038C5000130A400011480FFFA6F
-:105D4000000000008E07010024030C0010E300098E
-:105D50003C0580008E0901002D2830805500001080
-:105D60003C0480008E0B01002D6A31811140000C33
-:105D70003C0480008CAC0100118300040000202151
-:105D80008CAE010025CDFF8131A400FF8E0F0100F4
-:105D90000E0001FBAE0F00240A0002C13C0480008B
-:105DA0008C9F010024180020AC9F002092990000D5
-:105DB000332300FF1078001F2402005010620022DD
-:105DC000000000003C0480008C830100146000038C
-:105DD00000000000566000143C0440008C8201006A
-:105DE0008C990100000098210051F824001F79408F
-:105DF0003338007F01F8702501D26825AC8D08305A
-:105E00008C8C01008C890100258B010001715024CC
-:105E1000000A39403128007F00E8302500D22825CB
-:105E2000AC8508303C044000AE0401380A000299F9
-:105E3000000000008C8501000E00078D2404008006
-:105E40000A0002C13C0480008C8401000E0013EAA9
-:105E5000000000000A0002C13C04800000A4102BD6
-:105E600024030001104000090000302100052840F3
-:105E700000A4102B04A00003000318405440FFFCB2
-:105E8000000528405060000A0004182B0085382BBC
-:105E900054E000040003184200C33025008520238D
-:105EA000000318421460FFF9000528420004182B73
-:105EB00003E0000800C310213084FFFF30C600FF5C
-:105EC0003C0780008CE201B80440FFFE00064C0055
-:105ED000012430253C08200000C820253C03100088
-:105EE000ACE00180ACE50184ACE4018803E000088B
-:105EF000ACE301B83C0660008CC5201C2402FFF016
-:105F000030830200308601001060000E00A22824B9
-:105F100034A500013087300010E0000530830C000C
-:105F200034A500043C04600003E00008AC85201C9C
-:105F30001060FFFD3C04600034A5000803E0000889
-:105F4000AC85201C54C0FFF334A500020A000315E1
-:105F50003087300027BDFFE8AFB00010AFBF00149E
-:105F60003C076000240600021080001100A0802180
-:105F70008F8300380E00030C8C6400188F82003869
-:105F800000002021240600018C45000C0E0002FDBB
-:105F9000000000001600000224020003000010218F
-:105FA0008FBF00148FB0001003E0000827BD001859
-:105FB0008CE8201C2409FFF001092824ACE5201CF2
-:105FC0008F8700380A0003328CE5000C3C02600E1B
-:105FD0000080402134460100240900180000000020
-:105FE00000000000000000003C0A00503C0380005C
-:105FF00035470200AC68003834640400AC65003CEE
-:10600000AC6700308C6C0000318B00201160FFFD0C
-:106010002407FFFF2403007F8C8D00002463FFFF13
-:1060200024840004ACCD00001467FFFB24C60004E8
-:1060300000000000000000000000000024A4020096
-:106040000085282B3C0300203C0E80002529FFFF03
-:1060500001054021ADC300301520FFE0008028215C
-:1060600003E00008000000008F82003827BDFFD841
-:10607000AFB3001CAFBF0020AFB20018AFB1001427
-:10608000AFB0001094460002008098218C52001896
-:106090002CC300818C4800048C4700088C51000CF4
-:1060A0008C490010106000078C4A00142CC40004B6
-:1060B0001480001330EB000730C5000310A000105F
-:1060C000000000002410008B020020210220282163
-:1060D0000E0002FD240600031660000224020003E5
-:1060E000000010218FBF00208FB3001C8FB200185A
-:1060F0008FB100148FB0001003E0000827BD002806
-:106100001560FFF12410008B3C0C80003C03002044
-:10611000241F0001AD830030AF9F0030000000005D
-:1061200000000000000000002419FFF024D8000F38
-:10613000031978243C1000D0AD88003801F0702598
-:1061400024CD00033C08600EAD87003C358504007B
-:10615000AD8E0030000D38823504003C3C038000D9
-:106160008C6B0000316200201040FFFD0000000039
-:1061700010E0000824E3FFFF2407FFFF8CA80000C5
-:106180002463FFFF24A50004AC8800001467FFFB14
-:10619000248400043C04600EAC860038000000003B
-:1061A00000000000000000003C0700203C068000CA
-:1061B0000120202101402821ACC700300E000342FD
-:1061C000000080210E00030C024020210A000382FF
-:1061D0000200202127BDFFE0AFB200183092FFFF80
-:1061E000AFB10014AFBF001CAFB000101640000DDF
-:1061F000000088210A0003F1022010212405000379
-:10620000508500278CE5000C0000000D262C0001B5
-:106210003191FFFF24EB00200232502B1140001976
-:10622000AF8B00388F820030144000168F87003803
-:106230003C0670003C0320008CE5000000A62024F2
-:10624000148300108F840040000544023C09800044
-:1062500000A980241480FFE9310600FF2CCA000B3E
-:106260001140FFEB262C0001000668803C0E080060
-:1062700025CE51C801AE60218D8B00000160000861
-:1062800000000000022010218FBF001C8FB20018F8
-:106290008FB100148FB0001003E0000827BD00206C
-:1062A0000E0002FD240400841600FFD88F870038FA
-:1062B0000A0003D2AF800040020028210E00032410
-:1062C000240400018F8700380A0003D2AF82004007
-:1062D000020028210E000324000020210A000401EE
-:1062E0008F8700380E000369020020218F87003855
-:1062F0000A0003D2AF82004030AFFFFF000F19C089
-:106300003C0480008C9001B80600FFFE3C1920047C
-:106310003C181000AC830180AC800184AC990188EA
-:10632000AC9801B80A0003D3262C000190E20002C9
-:1063300090FF00030000202100023A0000FF282502
-:10634000240600080E0002FD000000001600FFDD1C
-:10635000240200038F870038000010210A0003D2B6
-:10636000AF82004090E50002000020210A000420D6
-:106370002406000994E5000490E9000390E300027C
-:10638000000534000009420000C8202500832825AC
-:106390002406000A0A0004200000202190E50002E3
-:1063A000000020210A0004202406000B000449C23A
-:1063B0003127003F000443423C0280000008204097
-:1063C000240316802CE60020AC43002C24EAFFE0D6
-:1063D0002482000114C0000330A900FF00801021B6
-:1063E000314700FF000260803C0D8000240A00015C
-:1063F000018D20213C0B000E00EA2804008B302187
-:1064000011200005000538278CCE000001C5382575
-:1064100003E00008ACC700008CD800000307782414
-:1064200003E00008ACCF000027BDFFE0AFB10014CF
-:10643000AFB00010AFBF00183C0760008CE4080844
-:106440003402F0003C1160003083F000240501C0EC
-:106450003C04800E00003021106200062410000170
-:106460008CEA08083149F0003928E0000008382B90
-:10647000000780403C0D0200AE2D0814240C16804D
-:106480003C0B80008E2744000E000E34AD6C002CB7
-:10649000120000043C0216912405000112050010B0
-:1064A0003C023D6C345800E0AE3844083C11080012
-:1064B0008E31007C8FBF00183C06600000118540C3
-:1064C000360F16808FB100148FB000103C0E020002
-:1064D00027BD0020ACCF442003E00008ACCE08105C
-:1064E0003C0218DA345800E0AE3844083C11080089
-:1064F0008E31007C8FBF00183C0660000011854083
-:10650000360F16808FB100148FB000103C0E0200C1
-:1065100027BD0020ACCF442003E00008ACCE08101B
-:106520000A00043A240500010A00043A0000282168
-:1065300024020400A7820010A78000080000202188
-:106540003C06080024C654B02405FFFF248900013E
-:10655000000440803124FFFF010618212C87002011
-:1065600014E0FFFAAC65000024040400A7840012C4
-:10657000A780000A000020213C06080024C65530F0
-:106580002405FFFF248D00010004608031A4FFFF7B
-:10659000018658212C8A00201540FFFAAD650000C5
-:1065A000A7800014A780000CA780000E0000202107
-:1065B0003C06080024C655B02405FFFF24990001BD
-:1065C0000004C0803324FFFF030678212C8E0004D2
-:1065D00015C0FFFAADE500003C0560008CA73D004A
-:1065E0002403E08F00E310243446014003E0000858
-:1065F000ACA63D002487007F000731C224C5FFFF01
-:10660000000518C2246400013082FFFF000238C078
-:10661000A784001C3C010800AC270030AF800018A4
-:1066200000002821000020210000302124890001E1
-:1066300000A728213124FFFF2CA817011100000317
-:106640002C8300801460FFF924C6000100C02821BB
-:10665000AF86001810C0001DA786001624CAFFFFD1
-:10666000000A11423C080800250855B01040000AF5
-:1066700000002021004030212407FFFF248E00016C
-:106680000004688031C4FFFF01A860210086582BF8
-:106690001560FFFAAD87000030A2001F50400008CF
-:1066A00000043080240300010043C804000410806B
-:1066B000004878212738FFFF03E00008ADF800000C
-:1066C00000C820212405FFFFAC85000003E000087E
-:1066D0000000000030A5FFFF30C6FFFF30A8001FFC
-:1066E0000080602130E700FF0005294200005021B2
-:1066F00010C0001D24090001240B00012518000111
-:10670000010B2004330800FF01267826390E0020F3
-:106710002DED00012DC2000101A218251060000D11
-:10672000014450250005C880032C40210100182198
-:1067300010E0000F000A20278D040000008A1825B1
-:10674000AD03000024AD00010000402100005021F5
-:1067500031A5FFFF252E000131C9FFFF00C9102B15
-:106760001040FFE72518000103E0000800000000CA
-:106770008D0A0000014440240A000520AC68000096
-:1067800027BDFFE830A5FFFF30C6FFFFAFB0001008
-:10679000AFBF001430E7FFFF000050213410FFFFAF
-:1067A0000000602124AF001F00C048212418000110
-:1067B0002419002005E0001601E010210002F94331
-:1067C000019F682A0009702B01AE402411000017B8
-:1067D000000C18800064102110E000058C4B0000B4
-:1067E00000F84004000838230167582400003821CD
-:1067F0001540004100004021556000163169FFFF3F
-:10680000258B0001316CFFFF05E1FFEC01E0102159
-:1068100024A2003E0002F943019F682A0009702B60
-:1068200001AE40241500FFEB000C18801546000552
-:106830003402FFFF020028210E0005040000382169
-:10684000020010218FBF00148FB0001003E0000879
-:1068500027BD00181520000301601821000B1C0241
-:1068600024080010306A00FF15400005306E000F4C
-:10687000250D000800031A0231A800FF306E000F3A
-:1068800015C00005307F0003251000040003190225
-:10689000320800FF307F000317E00005386900016F
-:1068A0002502000200031882304800FF3869000109
-:1068B0003123000110600004310300FF250A0001AC
-:1068C000314800FF310300FF000C694001A3402163
-:1068D000240A000110CAFFD53110FFFF246E000109
-:1068E00031C800FF1119FFC638C900012D1F002053
-:1068F00053E0001C258B0001240D00010A000597C0
-:10690000240E002051460017258B000125090001A7
-:10691000312800FF2D09002051200012258B000195
-:1069200025430001010D5004014B102425090001ED
-:106930001440FFF4306AFFFF3127FFFF10EE000C18
-:106940002582FFFF304CFFFF000050213410FFFF75
-:10695000312800FF2D0900205520FFF225430001BA
-:10696000258B0001014648260A000551316CFFFFC6
-:1069700000003821000050210A0005A33410FFFF59
-:1069800027BDFFD8AFB0001030F0FFFFAFB100144B
-:10699000001039423211FFE000071080AFB3001C35
-:1069A00000B1282330D3FFFFAFB2001830A5FFFF9E
-:1069B000008090210260302100442021AFBF0020E0
-:1069C0000E00052F3207001F022288213403FFFF2B
-:1069D00002402021020028210260302100003821DD
-:1069E000104300093231FFFF022010218FBF002029
-:1069F0008FB3001C8FB200188FB100148FB000103D
-:106A000003E0000827BD00280E00052F000000004D
-:106A100000408821022010218FBF00208FB3001C6E
-:106A20008FB200188FB100148FB0001003E000087F
-:106A300027BD0028000424003C036000AC603D0832
-:106A400010A00002348210063482101603E0000801
-:106A5000AC623D0427BDFFE0AFB00010309000FFF6
-:106A60002E020006AFBF001810400008AFB100149E
-:106A7000001030803C030800246351F400C3282137
-:106A80008CA400000080000800000000000020210D
-:106A90008FBF00188FB100148FB00010008010213C
-:106AA00003E0000827BD0020979100161620005132
-:106AB000000020213C020800904200330A00060A30
-:106AC00000000000978D001215A000310000202169
-:106AD0000A00060A240200089787001014E0001A32
-:106AE0000000182100602021240200011080FFE92D
-:106AF0008FBF0018000429C20045302100A6582B82
-:106B00001160FFE43C0880003C072000000569C0DC
-:106B100001A76025AD0C00203C0380082402001F63
-:106B20002442FFFFAC6000000441FFFD2463000429
-:106B300024A5000100A6702B15C0FFF5000569C053
-:106B40000A0005F48FBF0018978700083C0408006E
-:106B5000248454B0240504000E0005AF240600016F
-:106B6000978B001024440001308AFFFF2569FFFF46
-:106B70002D4804000040282115000040A78900107E
-:106B800024AC3800000C19C00A000608A7800008D1
-:106B90009787000A3C04080024845530240504002B
-:106BA0000E0005AF2406000197990012244400014D
-:106BB0003098FFFF272FFFFF2F0E04000040882191
-:106BC00015C0002CA78F0012A780000A3A0200030C
-:106BD000262401003084FFFF0E0005DC2C45000157
-:106BE0000011F8C027F00100001021C00A00060AB9
-:106BF000240200089785001A9787000E3C040800BD
-:106C0000248455B00E0005AF2406000197870016B6
-:106C10008F8900182445000130A8FFFF24E3FFFFFF
-:106C20000109302B0040802114C00018A7830016F2
-:106C3000A780000E9785001C0E000E1E020020216A
-:106C4000244A05003144FFFF0E0005DC2405000145
-:106C50003C05080094A500320E000E1E0200202103
-:106C6000244521003C020800904200330A00060A35
-:106C7000000521C00A000642A784000A24AC38009F
-:106C8000000C19C00A000608A78400080A00065C68
-:106C9000A785000E308400FF27BDFFE82C82000688
-:106CA000AFBF0014AFB000101040001500A0382195
-:106CB000000440803C0308002463520C0103282197
-:106CC0008CA40000008000080000000024CC007F9D
-:106CD000000751C2000C59C23170FFFF2547C400A4
-:106CE00030E5FFFF27840008020030210E00050474
-:106CF000240700019786001402062021A7840014AF
-:106D00008FBF00148FB0001003E0000827BD0018EB
-:106D10003C0508008CA50030000779C20E0002E691
-:106D200025E4DF003045FFFF3C040800248455B013
-:106D3000240600010E00050424070001978E0016AA
-:106D40008FBF00148FB0001025CD000127BD0018A3
-:106D500003E00008A78D00160007C9C22738FF000E
-:106D6000001878C231F0FFFF3C040800248455303D
-:106D700002002821240600010E000504240700015A
-:106D8000978D0012260E0100000E840025AC000134
-:106D90003C0B6000A78C0012AD603D083604000675
-:106DA000000030213C0760008CE23D04305F0006AB
-:106DB00017E0FFFD24C9000100061B00312600FF7B
-:106DC000006440252CC50004ACE83D0414A0FFF687
-:106DD0008FBF00148FB0001003E0000827BD00181B
-:106DE000000751C22549C8002406000124070001FC
-:106DF0003C040800248454B00E0005043125FFFF34
-:106E0000978700108FBF00148FB0001024E6000198
-:106E100027BD001803E00008A78600103084FFFF9C
-:106E200030A5FFFF3C0680008CC201B80440FFFE85
-:106E30003C084080008838253C031000ACC001802D
-:106E4000ACC50184ACC7018803E00008ACC301B83D
-:106E50003084FFFF3C0680008CC201B80440FFFE76
-:106E60003C0840388CA70000008828253C0310000F
-:106E7000ACC70180ACC5018803E00008ACC301B811
-:106E80008F8300588F8600501066000B00804021D1
-:106E90003C07080024E755C0000328C000A71021C4
-:106EA0008C44000024630001108800053063000F4B
-:106EB0005466FFFA000328C003E000080000102118
-:106EC0003C07080024E755C400A7302103E0000870
-:106ED0008CC200003C039000346200010082202537
-:106EE0003C038000AC6400208C65002004A0FFFE01
-:106EF0000000000003E00008000000003C028000E9
-:106F0000344300010083202503E00008AC44002046
-:106F100027BDFFE0AFB100143091FFFFAFB000100C
-:106F2000AFBF00181220001200A080218CA5000025
-:106F300014A00011240400023C0680008CC201B899
-:106F40000440FFFE3C074000022720258FBF0018A9
-:106F50008FB100148FB000103C03100027BD00203B
-:106F6000ACC50180ACC4018803E00008ACC301B823
-:106F70000A00071D8CA500000E00067424060200FE
-:106F8000000028210A00071DAE0000003087FFFF27
-:106F90003C0680008CC201B80440FFFE3C0A40065B
-:106FA0008CA9000000EA4025ACC901808CA4000433
-:106FB0003C031000ACC40184ACC8018803E00008A5
-:106FC000ACC301B88F83FD9427BDFFE8AFBF0014A9
-:106FD000AFB00010906700080080102100802821C9
-:106FE00030E600400000202110C000088C50000056
-:106FF0000E00008802002021020020218FBF001413
-:107000008FB000100A00049727BD00180E00073249
-:10701000000000000E000088020020210200202154
-:107020008FBF00148FB000100A00049727BD00180E
-:1070300027BDFFE0AFB000108F90FD94AFBF001CE4
-:10704000AFB20018AFB10014920600010080882191
-:107050000E00070430D2000492040005001129C27A
-:10706000A605000034830040A20300050E00070EB1
-:10707000022020210E000499022020212402000178
-:10708000AE02000C02202821A602001024040002F7
-:10709000A602001224060200A60200140E000674C6
-:1070A000A60200161640000F8FBF001C978C0054DC
-:1070B0003C0B08008D6B00782588FFFF3109FFFF2E
-:1070C000256A0001012A382B10E00006A788005429
-:1070D0003C0F6006240E001635ED0010ADAE0050DA
-:1070E0008FBF001C8FB200188FB100148FB000103A
-:1070F00003E0000827BD002027BDFFE0AFB100146A
-:10710000AFBF0018AFB000101080000400A08821AD
-:107110002402008010820007000000000000000D23
-:107120008FBF00188FB100148FB0001003E000086B
-:1071300027BD00200E00070400A020218F86FD94AB
-:107140000220202190C500050E00070E30B000FF80
-:107150002403003E1603FFF1000000003C05800000
-:107160008CA401780480FFFE240800073C0710006F
-:10717000ACB1014002202021A0A801448FBF00181B
-:107180008FB100148FB00010ACA701780A00075B24
-:1071900027BD002027BDFFE0AFB00010AFBF001833
-:1071A000AFB100143C1080008E11002000000000E0
-:1071B0000E000499AE040020AE1100208FBF00180D
-:1071C0008FB100148FB0001003E0000827BD00202D
-:1071D0003084FFFF3C0680008CC201B80440FFFEF3
-:1071E0003C084035008838253C031000ACC50180C0
-:1071F000ACC00184ACC7018803E00008ACC301B88F
-:107200003084FFFF3C0680008CC201B80440FFFEC2
-:107210003C084036008838253C031000ACC501808E
-:10722000ACC00184ACC7018803E00008ACC301B85E
-:1072300027BDFFD0AFB500243095FFFFAFB60028C3
-:10724000AFB40020AFBF002CAFB3001CAFB200182A
-:10725000AFB10014AFB0001030B6FFFF12A000278E
-:107260000000A0218F9200388E4300003C06800071
-:107270002402004000033E0200032C0230E4007FA1
-:10728000006698241482001D30A500FF8F830048FB
-:107290002C68000A510000108F86003000035880CF
-:1072A0003C0C0800258C5228016C50218D490000AF
-:1072B000012000080000000002D4702131C5FFFF4A
-:1072C0000E0006D624040084166000028F92003857
-:1072D000AF8000488F860030264F002026890001AD
-:1072E00001E090213134FFFF14C00004AF8F00385B
-:1072F0000295282B14A0FFDC000000000280102162
-:107300008FBF002C8FB600288FB500248FB40020CB
-:107310008FB3001C8FB200188FB100148FB0001013
-:1073200003E0000827BD00302407003414A70146FD
-:10733000000000009247000E8F98FD988F90FD94FA
-:10734000240F1600A30700199244000D3C0880008A
-:107350003C07800CA3040018965F00123C096000F3
-:107360003C117FFFA61F005C965900103622FFFFDC
-:10737000240400053325FFFFAE0500548E46001C93
-:10738000AD0F00288CEE00008D2D444801C6182654
-:1073900001A33021AE0600388E0C003824CA00014B
-:1073A0003C0D7F00AE0C003C8E0B003CAF0B00048C
-:1073B000AE0A00208E130020AE13001CA300001B99
-:1073C000AE02002CA30400128E5F001424130050A0
-:1073D000AE1F00348E190034AF1900148E4500180A
-:1073E000AE050048924F000CA20F004E9209000813
-:1073F000352E0020A20E00088E030018006D6024B8
-:10740000358B4000AE0B0018920A0000315200FF8D
-:10741000125302A62413FF803C0408002484564023
-:107420000E00074000000000240C000424080001A6
-:107430003C0508008CA556403C048000A20C0025A9
-:10744000A20800058C9001780600FFFE8F9200389C
-:10745000240D00023C031000AC850140A08D0144C6
-:10746000AC8301780A000804AF8000482CAD0037D7
-:1074700011A0FF998F860030000580803C11080024
-:1074800026315250021178218DEE000001C0000813
-:10749000000000002410000414B0008E3C0780009F
-:1074A0003C0B08008D6B56408F86FD94ACEB0020A2
-:1074B0008E4300088F8FFD98240E0050ACC300301F
-:1074C0008E4A0008ACCA00508E42000CACC2003498
-:1074D0008E440010ACC400388E5F0010ACDF005446
-:1074E0008E590014ACD9003C8E580018ADF8000439
-:1074F0008E51001CACD1002090C5000030A900FFC7
-:10750000112E0276000000008CC500348CD10030B2
-:1075100000B1302304C000F32404008C126000F09A
-:10752000240200030A000804AF820048240F00056B
-:1075300014AF00683C0B80003C0308008C6356408D
-:107540008F86FD94AD6300208E4A00048F99FD98CC
-:1075500024072000ACCA001C924200082412000834
-:10756000A32200198F840038909F0009A33F0018C0
-:107570008F85003890B8000A330400FF1092001085
-:10758000288C0009158000BC24080002240E00206D
-:10759000108E000B34078000288900211520000878
-:1075A0002407400024110040109100053C07000111
-:1075B000240F0080108F00023C07000224074000C7
-:1075C0008CDF00183C04FF0003E4C8240327C02517
-:1075D000ACD8001890B2000BA0D200278F830038DF
-:1075E0009465000C10A0022A000000009467000CB3
-:1075F0003C198000240BFFBFA4C7005C9062000E02
-:1076000024070004A0C200088F840038909F000F58
-:10761000A0DF00098F8C00388D9200108F38007425
-:1076200002582823ACC500588D8F0014ACCF002C15
-:10763000959100183229FFFFACC90040958E001AC1
-:1076400031D0FFFFACD000448D8D001CACCD004884
-:1076500095880002A4C800789183000EA0C300089A
-:1076600090CA0008014B1024126001D4A0C2000887
-:107670008F9200380A000804AF87004824060006ED
-:1076800014A600143C0D80003C1008008E105640DB
-:107690008F8CFD90ADB000208E4800188F86FD9431
-:1076A0008F8AFD98AD8800008CC300382404000543
-:1076B000AD8300048CCB003C12600081AD4B000018
-:1076C0000A000804AF840048240E000710AE004BE7
-:1076D000240400063C05080024A556400E000713AC
-:1076E000240400818F9200380013102B0A00080434
-:1076F000AF8200482419002314B9FFF63C0B800028
-:107700003C0C08008D8C56408F8AFD98AD6C002093
-:107710008F91FD948E4600042544002026450014D8
-:10772000AE260028240600030E000E2A2550003045
-:107730008F87003802002021240600030E000E2A45
-:1077400024E500083C040800248456400E0007404D
-:107750000000000092220000241F0050304400FF6F
-:10776000549FFFE18F9200380E000E1500000000BC
-:107770000A0009098F9200382403003314A3003251
-:107780003C0280003C1108008E3156408F8EFD98DF
-:10779000AC5100208E440008240900288F88FD94F5
-:1077A000ADC400308E5F000C24060009ADDF00344C
-:1077B0008E590010ADD900388E580014ADD8002075
-:1077C0008E450018ADC500248E4F001CADCF00289B
-:1077D000A1C900118E4D000412600031AD0D0028CA
-:1077E0008F9200380A000804AF860048240900225E
-:1077F00014A9FFB800000000240400073C0F080093
-:107800008DEF56403C118000AE2F00205660FEB137
-:10781000AF8400483C040800248456400E00074012
-:10782000241300508F98FD9493120000324500FFFE
-:1078300010B30169000000008F9200380000202181
-:107840000A000804AF8400483C05080024A55640FF
-:107850000E0006E3240400810A0009098F92003813
-:1078600002D498213265FFFF0E0006D6240400845E
-:107870000A0008048F9200381088FF512407040082
-:107880002887000310E001A324100004240D000148
-:10789000548DFF4B240740000A0008BF2407010055
-:1078A0003C05080024A556400E000732240400823F
-:1078B0008F920038000030210A000804AF8600488B
-:1078C0003C040800248456408CC200380E00074057
-:1078D0008CC3003C8F9200380A00095F0000202111
-:1078E000240400823C05080024A556400E000732FF
-:1078F000000000008F920038000010210A000804E8
-:10790000AF8200488E5000048F91FD943C0A8000A5
-:10791000AD500020922200050200282130460002CE
-:1079200014C001802404008A8F92FD98020028214F
-:107930002404008D924B001B3163002014600179F8
-:1079400000000000922D0009240C001231A800FF55
-:10795000110C0174240400810E0007040200202190
-:107960009245001B240E00040200202134A900428D
-:10797000A249001B0E00070EA22E00253C04800029
-:107980008C9101780620FFFE24180002AC90014083
-:10799000A09801448F9200383C0F1000AC8F017802
-:1079A0000A00090A0013102B8E5000048F91FD94D9
-:1079B0003C1F8000AFF00020923900050200282112
-:1079C0003327000214E000172404008A92240009DF
-:1079D0002412000402002821308600FF10D200117A
-:1079E000240400810E000704020020218F8CFD98E2
-:1079F000240B00122403FFFE918D001B02002021A6
-:107A000035A80020A188001BA22B0009922A00059E
-:107A1000014310240E00070EA222000502002821B7
-:107A2000000020210E0007CF000000000A00090915
-:107A30008F9200388E5100043C0280003C100800F8
-:107A400026105640AC5100203C010800AC31564095
-:107A50009246000330C40004108001658F84FD94B9
-:107A600024020006A0820009924D001B2408FFC0DA
-:107A700031AC003F01885825A08B000892430003D9
-:107A8000306A00011540015C000000008E420008D1
-:107A9000AE0200083C0208008C4256481040015BD0
-:107AA0008F8EFD98000281C28F85FD94A5D0000CB9
-:107AB0008E5F000C240F000124090014ADDF002CA0
-:107AC0008E590010ADD9001C96470016A5C7003C82
-:107AD00096580014A5D8003EACAF000CA4AF00101F
-:107AE000A4AF0012A4AF0014A4AF00161260015F8F
-:107AF000A1C9001192440003309200022E530001EC
-:107B00008F920038266200080A000804AF820048FD
-:107B10008E4600043C0580003C048008ACA6002092
-:107B20008E4700089089000024110050312200FF88
-:107B3000105100B8240500883C0480008C8F01B8E7
-:107B400005E0FFFE0013802B3C18400900B810250B
-:107B5000AF9000483C101000AC860180AC870184D7
-:107B6000AC820188AC9001B80A0008058F8600300D
-:107B70008E4500043C0680003C098008ACC500200E
-:107B8000913F00002404005033F900FF132400B09B
-:107B9000240600883C0480008C8A01B80540FFFE62
-:107BA0003C0E400E00CE68253C081000AC850180DC
-:107BB000AC800184AC8D0188AC8801B8912B0000A9
-:107BC000240CFF8024040004016C182524060030D6
-:107BD0000E000674A12300000A0009098F920038E4
-:107BE0008E5000048F91FD983C0F8000ADF0002076
-:107BF0009225001B30A900101120007C2403008175
-:107C00003C0480008C8701B804E0FFFE3C1F401F4D
-:107C1000AC900180007F10250013C82B3C10100091
-:107C2000AC800184AF990048AC820188AC9001B867
-:107C30000A0008058F8600308E44001C0E0006EFF7
-:107C400000000000104000F8004038218F920038FA
-:107C5000240600893C0580008CAE01B805C0FFFEFB
-:107C600000000000ACA701808E50001C3C114001B8
-:107C70000013782B00D138253C131000ACB00184E0
-:107C8000AF8F0048ACA70188ACB301B80A00080563
-:107C90008F860030965900023C100800261056408E
-:107CA00033380004130000A33C0460008E5F001C06
-:107CB0003C068000ACDF00203C010800AC3F564091
-:107CC000964F000231E7000114E000E300000000DD
-:107CD0008E420004AE0200083C1008008E10564888
-:107CE000120000D93C0680008F85FD94241000010D
-:107CF0008CBF00188F91FD988F89FD9003E6C825F1
-:107D0000ACB90018A0A00005ACB0000C3C180800ED
-:107D10008F1856488F870038A4B00010001879C219
-:107D2000A4B00012A4B00014A4B00016A62F000C3A
-:107D30008CEE00088F8D00388F8C0038AE2E002C12
-:107D40008DA8000C24070002AE28001C918B0010A7
-:107D5000A22B00118F830038906A0011A12A00081D
-:107D60008F82003890440012A0A4004E8F920038F9
-:107D700092460013A22600128F920038965F0014DC
-:107D8000A63F003C96590016A639003E8E580018B2
-:107D9000AE3800145660FD4FAF8700483C05080020
-:107DA00024A556400E000713000020218F920038B2
-:107DB000000038210A000804AF8700483C0508008D
-:107DC00024A556400E000732240400828F9200380A
-:107DD0000A0008EC000038210E000E15000000001B
-:107DE0008F9200380A00095F000020210E0007046E
-:107DF000020020219232001B020020213658001080
-:107E00000E00070EA238001B8F9200380A000A4F9E
-:107E1000000018219243000C306A00011140000359
-:107E200000000000964B000EA48B002C9248000C22
-:107E3000310C00021180FF4000002821964E0012F4
-:107E40008E4D0014A48E001A0A000A1DAC8D001C71
-:107E50008F8300588F8700501067FF4E000030213D
-:107E60003C080800250855C4000320C000883021C4
-:107E70008CD10000122500C8246200013043000F9D
-:107E80001467FFFA000320C00A000A340000302102
-:107E90003C05080024A556400E0007322404008B40
-:107EA0008F9200380A0008EC0013382B3C0B0800B6
-:107EB0008D6B564024D8FFFE25710100322A007FC9
-:107EC0000147902102331024AD020028AE4600D0B5
-:107ED000AE4000D40A000855AE58001CACC0005497
-:107EE0003C0E08008DCE56403C09800C352C01001C
-:107EF000ACEE00288E500014AD9000D08E4D0014D2
-:107F0000AD8D00D48E4800102507FFFE0A000891B1
-:107F1000AD87001C5490FDAA240740000A0008BF4A
-:107F2000240710000E0007C3000000000A00090922
-:107F30008F9200388C83442C3C05DEAD34B2BEEF0A
-:107F40003C010800AC205640107200900000000078
-:107F50003C046C62348279701462000824040002CC
-:107F6000978A00549783004C020028210143482B34
-:107F70001120001924040092240400020E0005E4DC
-:107F8000240502003C0B8000AD6200203C0108008B
-:107F9000AC2256401040000D8F8E0038240C002873
-:107FA0002404000391CD001031A800FF550C0001FE
-:107FB000240400010E00004C0000000010400004EA
-:107FC000240400830A000A7F8F920038240400836F
-:107FD0003C05080024A556400E00071300000000D1
-:107FE0008F9200380013382B0A000804AF8700482E
-:107FF0000A0009E8240200128E4400080E0006EF71
-:10800000000000000A0009F4AE0200083C05080068
-:1080100024A556400E0006E3240400878F92003802
-:108020000A000A110013102B240400040E0005E4BA
-:108030002405003014400014004038218F9200388D
-:108040000A000A64240600833C05080024A5564063
-:108050000A000B45240400878E4400040E0006EF3E
-:10806000000000000A000A85AE0200083C05080076
-:1080700024A556400E000732240400828F92003857
-:108080000A000A11000010218F9200383C08800875
-:108090003C0C8000240B0050240A0001AD8200201B
-:1080A000A10B0000A10A000192490004A1090018D7
-:1080B00092440005A1040019924300063C04080004
-:1080C000248455C4A103001A924200073C0308000F
-:1080D000246355C0A102001B92450008A105001CA5
-:1080E00092460009A106001D925F000AA11F001E12
-:1080F0009259000BA119001F9258000CA1180020E2
-:108100009251000DA11100219250000EA1100022E9
-:10811000924F000FA10F0023924E0010A10E0024D9
-:10812000924D0011A10D0025964C0014A50C0028BD
-:10813000964B00168F8A00508F980058A50B002A86
-:1081400096490018000A10C025450001A509002C19
-:108150008E46001C0044C8210043F82130A5000FC2
-:10816000AFE60000AF27000010B80003AF85005055
-:108170000A000A640000302124AD000131A8000F7C
-:10818000000030210A000A64AF8800588C83442C18
-:108190000A000B243C046C623C07080024E755C02D
-:1081A00000879021ACC00000000030210A000A3492
-:1081B000AE4000003C0482013C03600034820E02A9
-:1081C000AC603D68AF80007803E00008AC623D6CB5
-:1081D00027BDFFE8AFB000103090FFFF001018423D
-:1081E0002C620041AFBF0014144000022404008040
-:1081F000240300403C010800AC3000603C01080052
-:10820000AC2300640E000E1E00602821244802BF2B
-:108210002409FF8001092824001039800010304013
-:108220008FBF00148FB0001000A7202100861821F6
-:10823000AF8300603C010800AC2500583C010800F9
-:10824000AC24005C03E0000827BD0018308300FF69
-:1082500030C6FFFF30E400FF3C0880008D0201B80B
-:108260000440FFFE00035400014438253C0960002F
-:1082700000E920253C031000AD050180AD06018416
-:10828000AD04018803E00008AD0301B88F86003813
-:108290003C096012352700108CCB00043C0C600EAA
-:1082A00035850010316A00062D480001ACE800C495
-:1082B0008CC40004ACA431808CC2000894C30002BA
-:1082C000ACA2318403E00008A78300708F850038DA
-:1082D0008F87FF208F86FF288CAE00043C0F601232
-:1082E00035E80010ACEE00688CAD0008ACED006C19
-:1082F0008CAC0010ACCC004C8CAB000CACCB004870
-:1083000094CA00543C0208008C42004425490001F4
-:10831000A4C9005494C400543083FFFF10620017B6
-:10832000000000003C0208008C420040A4C2005241
-:108330008CA30018ACE300308CA20014ACE2002C3B
-:108340008CB90018ACF900388CB800142405000171
-:10835000ACF800348D0600BC50C500198D0200B485
-:108360008D0200B8A4E2004894E40048A4E4004A66
-:1083700094E800DA03E000083102FFFF3C02080045
-:108380008C420024A4C00054A4C200528CA3001844
-:10839000ACE300308CA20014ACE2002C8CB90018C5
-:1083A000ACF900388CB8001424050001ACF8003496
-:1083B0008D0600BC54C5FFEB8D0200B88D0200B4E1
-:1083C000A4E2004894E40048A4E4004A94E800DAF7
-:1083D00003E000083102FFFF8F8600383C04800074
-:1083E0008CC900088CC80008000929C0000839C0E1
-:1083F000AC87002090C30007306200041040003AB0
-:10840000AF85007490CB0007316A00081140003935
-:108410008F87FF248CCD000C8CCE001401AE602B16
-:1084200011800032000000008CC2000CACE2007031
-:108430008CCB00188F85FF208F88FF28ACEB007451
-:108440008CCA00102402FFF8ACAA00C88CC9000C2A
-:10845000AD0900608CC4001CACA400C090E3007C9B
-:108460000062C824A0F9007C90D80007330F0008F0
-:1084700011E000040000000090ED007C35AC00012C
-:10848000A0EC007C90CF000731EE000111C0000984
-:108490000000000090E4007C2418000234820002F6
-:1084A000A0E2007C90A300EC307900FF13380013A9
-:1084B0002408003490C900073126000210C00004CF
-:1084C0000000000090EB007C356A0004A0EA007C0C
-:1084D00090ED007D31AC003FA0EC007D94A700DA68
-:1084E00003E0000830E2FFFF8F87FF240A000C5AE8
-:1084F0008CC200140A000C5BACE000700A000C7C1B
-:10850000ACA800CC8F8C003827BDFFD8AFB3001CBF
-:10851000AFB20018AFB00010AFBF0020AFB1001471
-:10852000918F00153C13600E3673001031EB000F75
-:10853000A38B007C8D8F00048D8B0008959F00120B
-:10854000959900109584001A9598001E958E001C30
-:1085500033EDFFFF332AFFFF3089FFFF3308FFFFB2
-:1085600031C7FFFF3C010800AC2D00243C0108008E
-:10857000AC2900443C010800AC2A0040AE683178C8
-:10858000AE67317C91850015959100163C12601202
-:108590003652001030A200FF3230FFFFAE62318849
-:1085A000AE5000B491830014959F0018240600017A
-:1085B0000066C80433F8FFFFAE5900B8AE5800BCDF
-:1085C000918E0014AF8F00643C08600631CD00FF2F
-:1085D000AE4D00C0918A00159584000E3C07600ADC
-:1085E000314900FFAF8B00683084FFFFAE4900C8FF
-:1085F000351100100E000BC334F004103C020800CB
-:108600008C4200603C0308008C6300643C06080058
-:108610008CC600583C0508008CA5005C8F84006067
-:108620008FBF0020AE23004CAE65319CAE030054DA
-:10863000AE4500DCAE6231A0AE6331A4AE663198C7
-:10864000AE2200488FB3001CAE0200508FB1001460
-:10865000AE4200E0AE4300E4AE4600D88FB000105A
-:108660008FB200180A0004CC27BD0028978500723D
-:108670009783005C27BDFFE8AFB0001000A3102B6C
-:10868000AFBF0014240400058F900038104000553F
-:10869000240900020E0005E48F850060AF8200749B
-:1086A000240400031040004F240900023C0680000F
-:1086B0000E00004CACC2002024070001240820005A
-:1086C0001040004D24040005978E00728F8AFF240D
-:1086D0002409005025C50001A7850072A1490000AA
-:1086E0003C0D08008DAD0064240380008F84FF20C2
-:1086F000000D6600AD4C0018A5400006954B000A21
-:108700008F85FF282402FF8001633024A546000ADC
-:10871000915F000A0000482103E2C825A159000A20
-:10872000A0A00008A140004CA08000C5961800023F
-:10873000978300703C020004A49800DA960F0002B0
-:108740002418FFBF25EE2401A48E00AE8E0D000478
-:10875000ACAD00448E0C0008ACAC0040A4A00050AE
-:10876000A4A000548E0B000C240C0030AC8B00280D
-:108770008E060010AC860024A480003EA487004E24
-:10878000A4870050A483003CAD420074AC8800C8AC
-:10879000ACA80060A08700EC909F00C433F9007F74
-:1087A000A09900C4909000C402187824A08F00C43F
-:1087B000914E007C35CD0001A14D007C938B007C57
-:1087C000AD480070AC8C00CCA08B00C68F880068D0
-:1087D0008F870064AC8800B4AC8700B8A5400078EF
-:1087E000A540007A8FBF00148FB000100120102127
-:1087F00003E0000827BD00188F8500740E00067482
-:108800008F8600600A000D482409000227BDFFE0A2
-:10881000AFB000108F900038AFB10014AFBF001898
-:108820008E0900040E000499000921C08E0800047E
-:108830008F84FF208F82FF28000839C03C0680000B
-:10884000ACC70020948500DA904300131460001C2C
-:1088500030B1FFFF8F8CFF24918B0008316A0040FC
-:108860001540000B000000008E0D00040220302196
-:108870008FBF00188FB100148FB0001024040022A5
-:1088800000003821000D29C00A000BE227BD00209E
-:108890000E000063000000008E0D00040220302155
-:1088A0008FBF00188FB100148FB000102404002275
-:1088B00000003821000D29C00A000BE227BD00206E
-:1088C0000E00005B000000008E0D0004022030212D
-:1088D0008FBF00188FB100148FB000102404002245
-:1088E00000003821000D29C00A000BE227BD00203E
-:1088F00027BDFFE0AFB200183092FFFFAFB000100D
-:10890000AFBF001CAFB100141240001E0000802158
-:108910008F8600388CC500002403000600053F0246
-:108920000005140230E4000714830016304500FFF0
-:108930002CA8000611000040000558803C0C0800DF
-:10894000258C532C016C50218D490000012000081A
-:10895000000000008F8E0078240D000111CD005022
-:1089600024020002AF820078260900013130FFFFA7
-:1089700024C800200212202B010030211480FFE5C2
-:10898000AF880038020010218FBF001C8FB2001882
-:108990008FB100148FB0001003E0000827BD002045
-:1089A0009387005E54E00034000030210E000C90EC
-:1089B000000000008F8600380A000DA82402000184
-:1089C0008F8700782405000210E50031240400138D
-:1089D0000000282100003021240700010E000BE2D6
-:1089E000000000000A000DA98F8600388F830078F0
-:1089F000240200021462FFF6240400120E000C454B
-:108A0000000000008F850074004030212404001213
-:108A10000E000BE2000038210A000DA98F860038F5
-:108A20008F8300782411000310710029241F000295
-:108A3000107FFFCE26090001240400100000282129
-:108A4000000030210A000DC6240700018F91007834
-:108A5000240600021626FFF9240400100E000CEA7A
-:108A600000000000144000238F9800388F860038E3
-:108A70000A000DA824020003240400140E000BE2D7
-:108A8000000028218F8600380A000DA82402000269
-:108A90000E000D52000000000A000DA98F8600385C
-:108AA0000E000BF200000000241900022404001440
-:108AB000000028210000302100003821AF99007803
-:108AC0000E000BE2000000000A000DA98F8600389E
-:108AD0000E000C02000000008F85007424190002B3
-:108AE0000040302124040010000038210A000DFF4E
-:108AF000AF9900780040382124040010970F00023D
-:108B0000000028210E000BE231E6FFFF8F860038BF
-:108B10000A000DA9AF9100788F84FF243C077FFFE6
-:108B200034E6FFFF8C8500182402000100A61824FB
-:108B3000AC83001803E00008A08200053084FFFF2A
-:108B400030A5FFFF108000070000182130820001CF
-:108B50001040000200042042006518211480FFFB31
-:108B60000005284003E000080060102110C0000745
-:108B7000000000008CA2000024C6FFFF24A5000412
-:108B8000AC82000014C0FFFB2484000403E0000852
-:108B90000000000010A0000824A3FFFFAC86000026
-:108BA00000000000000000002402FFFF2463FFFF1C
-:108BB0001462FFFA2484000403E0000800000000AF
-:108BC000000411C003E000082442024027BDFFE872
-:108BD000AFB0001000808021AFBF00140E000E3F28
-:108BE00000A0202100504821240AFF808FBF0014DC
-:108BF0008FB00010012A30243127007F3C08800A02
-:108C00003C04210000E8102100C428253C0380001A
-:108C100027BD0018AC650024AF820024AC400000E2
-:108C2000AC65002403E00008AC4000403C0D0800A7
-:108C30008DAD005800056180240AFF8001A45821F1
-:108C4000016C4821012A30243127007F3C08800C28
-:108C50003C04210000E8102100C428253C038000CA
-:108C6000AC650028AF82002003E00008AC4000247F
-:108C700030A5FFFF3C0680008CC201B80440FFFE17
-:108C80003C08601500A838253C031000ACC40180E6
-:108C9000ACC00184ACC7018803E00008ACC301B8D4
-:108CA0003C0D08008DAD005800056180240AFF804E
-:108CB00001A45821016C4021010A482400093140D7
-:108CC0003107007F00C728253C04200000A4182598
-:108CD0003C028000AC43083003E00008AF80002075
-:108CE00027BDFFE8AFB0001000808021AFBF0014A7
-:108CF0000E000E3F00A0202100504821240BFF80D1
-:108D0000012B5024000A39403128007F3C06200006
-:108D10008FBF00148FB0001000E8282534C2000176
-:108D200000A218253C04800027BD0018AC83083041
-:108D300003E00008AF8000243C0580088CA7006099
-:108D40003C0680080087102B144000112C83400043
-:108D50008CA800602D0340001060000F2403400029
-:108D60008CC900600089282B14A000020080182103
-:108D70008CC3006000035A42000B30803C0A08009C
-:108D8000254A53A000CA202103E000088C8200007D
-:108D90001460FFF32403400000035A42000B3080AC
-:108DA0003C0A0800254A53A000CA202103E000081D
-:108DB0008C8200003C05800890A6000893840088FF
-:108DC00024C20001304200FF3043007F1064000CD9
-:108DD00000023827A0A200083C0480008C8501789E
-:108DE00004A0FFFE8F8A0080240900023C081000C6
-:108DF000AC8A0140A089014403E00008AC880178F6
-:108E00000A000EC430E2008027BDFFD8AFB20018C0
-:108E10008F920084AFBF0020AFB3001CAFB0001032
-:108E2000AFB100148F9300208E5900283C100080B1
-:108E30003C0EFFEFAE7900008E580024A260000ABD
-:108E400035CDFFFFAE7800049251002C3C0BFF9F04
-:108E5000356AFFFFA271000C8E6F000C3C080040C9
-:108E6000A271000B01F06025018D4824012A3824ED
-:108E700000E83025AE66000C8E450004AE60001898
-:108E80003C0400FFAE6500148E43002C3482FFFFCB
-:108E9000A66000080062F824AE7F00108E5900081A
-:108EA0008F900080964E0012AE7900208E51000CFB
-:108EB00031D83FFF00187980AE7100248E4D001428
-:108EC00001F0602131CB0001AE6D00288E4A001800
-:108ED000000C41C2000B4B80AE6A002C8E46001C79
-:108EE00001093821A667001CAE66003096450002D5
-:108EF0008E440020A665001EAE6400349243003309
-:108F00003062000454400006924700003C02800892
-:108F1000344301008C7F00C0AE7F003092470000D8
-:108F20008F860024A0C700309245003330A4000291
-:108F300050800007925100018F880024240BFF808D
-:108F4000910A0030014B4825A109003092510001DF
-:108F50008F900024240CFFBF2404FFDFA2110031F6
-:108F60008F8D00243C1880083711008091AF003CA1
-:108F700031EE007FA1AE003C8F890024912B003C94
-:108F8000016C5024A12A003C8F9F00248E6800149D
-:108F900093E6003C2D0700010007114000C428247F
-:108FA00000A21825A3E3003C8F87002496590012E5
-:108FB000A4F900328E450004922E007C30B00003EC
-:108FC0000010782331ED000300AD102131CC0002F8
-:108FD0001580000224460034244600303C028008FC
-:108FE00034430080907F007C00BFC82433380004E5
-:108FF0001700000224C2000400C010218F98002432
-:1090000024190002ACE20034A3190000924F003F83
-:109010008F8E00243C0C8008358B0080A1CF00018E
-:109020008F910024924D003F8E440004A62D000233
-:10903000956A005C0E000E9D3150FFFF00024B80D0
-:10904000013038253C08420000E82825AE25000400
-:109050008E4400388F850024ACA400188E4600345E
-:10906000ACA6001CACA0000CACA00010A4A0001486
-:10907000A4A00016A4A00020A4A00022ACA000245C
-:109080008E62001450400001240200018FBF0020B6
-:109090008FB3001C8FB200188FB100148FB0001076
-:1090A000ACA200080A000EBC27BD002827BDFFC8DF
-:1090B0003C05800834A40080AFBF0034AFBE003050
-:1090C000AFB7002CAFB60028AFB50024AFB4002076
-:1090D000AFB3001CAFB20018AFB10014AFB00010B6
-:1090E000948300789482007A104300512405FFFF96
-:1090F0000080F0210A000FCC0080B821108B004DB9
-:109100008FBF00348F8600803C1808008F18005CE9
-:109110002411FF803C1680000306782101F1802491
-:10912000AED0002C96EE007A31EC007F3C0D800E24
-:1091300031CB7FFF018D5021000B4840012AA8212F
-:1091400096A400003C0808008D0800582405FF8004
-:1091500030953FFF01061821001539800067C821AE
-:109160000325F8243C02010003E290253338007FF8
-:109170003C11800CAED20028031190219250000DBA
-:10918000320F000411E0003702E0982196E3007AE4
-:1091900096E8007A96E5007A2404800031077FFF84
-:1091A00024E3000130627FFF00A4F82403E2C82515
-:1091B000A6F9007A96E6007A3C1408008E940060C6
-:1091C00030D67FFF12D400C1000000008E58001876
-:1091D0008F84008002A028212713FFFF0E000E7746
-:1091E000AE53002C97D5007897D4007A12950010D2
-:1091F000000028213C098008352401003C0A800831
-:1092000091480008908700C53114007F30E400FFCA
-:109210000284302B14C0FFB9268B0001938E008886
-:10922000268C0001008E682115ACFFB78F86008068
-:109230008FBF00348FBE00308FB7002C8FB6002850
-:109240008FB500248FB400208FB3001C8FB200189C
-:109250008FB100148FB0001000A0102103E00008AF
-:1092600027BD003800C020210E000E4202802821B8
-:109270008E4B00108E4C00308F8400242409000295
-:10928000016C5023AE4A0010A089000096E3005CF8
-:109290008E4400308F9100240E000E9D3070FFFF31
-:1092A00000024380011028253C07420000A710253A
-:1092B000AE2200048E5F00048F8A00248E590000C5
-:1092C000240B0008AD5F001CAD590018AD40000C28
-:1092D000AD4000109246000A240400052408C00096
-:1092E00030D000FFA550001496580008A55800166D
-:1092F0009251000A3C188008322F00FFA54F002031
-:10930000964E000837110100A54E0022AD40002402
-:10931000924D000B31AC00FFA54C0002A14B0001A7
-:109320008E4900308F830024240BFFBFAC690008F6
-:10933000A06400308F9000242403FFDF96070032E2
-:1093400000E8282400B51025A6020032921F003242
-:1093500033F9003F37260040A20600328F8C0024EC
-:10936000AD8000348E2F00C0AD8F0038918E003C50
-:109370003C0F7FFF31CD007FA18D003C8F84002406
-:1093800035EEFFFF908A003C014B4824A089003C49
-:109390008F85002490A8003C01033824A0A7003C3E
-:1093A0008E4200348F9100243C038008AE2200409E
-:1093B0008E59002C8E5F0030033F3023AE260044D0
-:1093C000923000483218007FA23800488F8800246D
-:1093D0008E4D00308D0C004801AE5824019650246B
-:1093E000014B4825AD0900489244000AA104004CF5
-:1093F000964700088F850024A4A7004E8E500030A9
-:109400008E4400300E0002E68C65006092F9007C0C
-:109410000002F940004028210002110003E230213F
-:109420003336000212C00003020680210005B0801E
-:1094300002168021926D007C31B30004126000029C
-:1094400000057080020E80218E4B003024058000C4
-:10945000316A0003000A4823312400030204182162
-:109460008F900024AE03003496E4007A96E8007AE8
-:1094700096F1007A31077FFF24E20001305F7FFF21
-:109480000225C824033F3025A6E6007A96F8007A24
-:109490003C1208008E520060330F7FFF11F200185B
-:1094A000000000008F8400800E000E7702A02821AB
-:1094B0008F8400800E000E87028028210E000EBCD3
-:1094C000000000000A000FC80000000096F1007ABA
-:1094D00002248024A6F0007A92EF007A92EB007AC0
-:1094E00031EE00FF000E69C2000D6027000C51C074
-:1094F0003169007F012A20250A000FC2A2E4007A08
-:1095000096E6007A00C5C024A6F8007A92EF007AA9
-:1095100092F3007A31F200FF001271C2000E682748
-:10952000000DB1C0326C007F01962825A2E5007ABB
-:109530000A0010798F8400803C0380003084FFFF94
-:1095400030A5FFFFAC640018AC65001C03E0000808
-:109550008C62001427BDFFA83C068008AFBE0050F7
-:10956000AFBF0054AFB7004CAFB60048AFB5004432
-:10957000AFB40040AFB3003CAFB20038AFB100347D
-:10958000AFB0003034C80100910500C590C7000895
-:10959000309EFFFF30A500FF30E2007F0045182A13
-:1095A000A7A00014A7A0001E10600053AFA00010D9
-:1095B00090C900083126007F00A620232493FFFFD6
-:1095C0000013802B001E882B0211782451E00084A8
-:1095D0008FB300103C19800897360052973700501F
-:1095E000001EC40002D7A8230015A4000014140311
-:1095F00003C2902A1640000200182C0300402821C4
-:10960000001314000002240300A4F82A57E000010C
-:1096100000A0202128830009146000020080A021FE
-:10962000241400083C0A80088D4500480014498035
-:109630008D48004C3C0380003124FFFF3C060010A5
-:109640000086382534710400AC650038AF91008481
-:10965000AC68003CAC670030000000000000000077
-:1096600000000000000000000000000000000000FA
-:1096700000000000000000008C6C0000318B002016
-:109680001160FFFD0014682A01B010241040003959
-:109690000000A8213C16800892D700083C128000E8
-:1096A0008E44010032F6007F0E000E4202C02821D7
-:1096B0008E2F00108E4401000000902131F73FFFF3
-:1096C0000E000E5A02E02821922E000031C2003F07
-:1096D0002C50000852000010000088210002F88081
-:1096E0003C0308002463535403E3C8218F3800006F
-:1096F000030000080000000090CE0008938B008853
-:1097000031CD007F00AD6023016C50210A0010BFF5
-:109710002553FFFF000088213C1080008E040100CB
-:109720000E000E7702E028218E0401000E000E8745
-:1097300002C028211220000F0013802B8F8A008482
-:1097400026A900010009AC00027298230015AC03A1
-:109750002545004002B4B02A0013802B24170001D5
-:1097600000A0882102D01024AF8500841440FFC9D6
-:10977000AFB700103C07800894F100503C05800012
-:109780003C06002002B1C821A4F90050ACA600306C
-:1097900094F4005094E3005203D560231074001D2C
-:1097A000319EFFFF8CE5004C8CE90048001561807C
-:1097B00000ACB0210000A02102CCA82B0134502124
-:1097C0000155B821ACF6004CACF70048001E882BC0
-:1097D0000211782415E0FF803C1980088FB3001037
-:1097E0008FBF00548FBE00503A6200018FB7004C0B
-:1097F0008FB600488FB500448FB400408FB3003C53
-:109800008FB200388FB100348FB0003003E0000811
-:1098100027BD005894F200548CEF0044325FFFFEE5
-:10982000001FC0C001F87021ACAE003C8CEB0044BE
-:109830008CAD003C016D40231900003B000000008E
-:109840008CE20040244200013C07005034E4001048
-:109850003C038000ACA20038AC6400300000000083
-:1098600000000000000000000000000000000000F8
-:109870000000000000000000000000008C760000E6
-:1098800032D7002012E0FFFD3C11800896280054DA
-:109890003C0A80003C06800831190001001960C0B4
-:1098A000018AA0218E8304003C0708008CE7004455
-:1098B0003C150020ACC300488E8904042405000137
-:1098C000ACC9004C10E50259AD550030963F00522E
-:1098D0003C0508008CA5004000BFC021A6380052FE
-:1098E000962F005425EE0001A62E00549626005413
-:1098F00030C4FFFF5487FF34001E882B30A5FFFFC4
-:109900000E00109DA62000543C0408008C84002406
-:10991000962700520044102300E29023A632005202
-:109920000A0010C1001E882B8CE200400A00116260
-:109930003C07005092280001240700013102007FFB
-:109940001447001C97AC001E8E2A0014240BC00084
-:1099500031443FFF018B48243C0608008CC6006060
-:109960000124282530A43FFF0086882B12200011F7
-:10997000A7A5001E3C1108008E3100588F82008080
-:10998000000441802407FF80022218210068F8218A
-:1099900003E7C82433EF007F3C1880003C12800EA0
-:1099A000AF19002C01F2682191AE000D35D00004F2
-:1099B000A1B0000D0E000ED12412000124110001EF
-:1099C0003C1080008E0401000E000E7702E028217A
-:1099D0008E0401000E000E8702C028211620FF58B9
-:1099E0008F8A00840A00112C0013802B8F8600843C
-:1099F00090C900013125002010A0018A2410000127
-:109A00003C048008348C0080918B007C8F91002076
-:109A100000009021316A00011140000FAFB000201A
-:109A20008CD000148C8E0060020E682B15A00003F1
-:109A3000020038218C8700603C0480083483008059
-:109A40008C72007000F2782B15E0000200E02021FB
-:109A50008C640070008090213C07800834E5008011
-:109A60008CD900148CBF0070033FC02B170000027C
-:109A7000032020218CA400700092182310600003A2
-:109A8000AFA3002824080002AFA800208FA5002063
-:109A90000265102B144000B5000018218CC400385A
-:109AA0008E2F000C3C180080AE2400008CCE0034B9
-:109AB0003C10FF9F01F86025AE2E000490CB003FC4
-:109AC000360DFFFF018D48243C0A00203C06FFEFC5
-:109AD000A22B000B012A382534C5FFFF00E54024E6
-:109AE0003C0200088F87008401022025AE24000C70
-:109AF0008CE30014AE2000188FAF0028AE230014B2
-:109B00008CF800183C1FFFFB37F9FFFFAE38001C34
-:109B10008CEE000800996824024F8021AE2E0024AC
-:109B20008CEC000CAE2D000CA6200038A620003ACC
-:109B3000AE30002CAE2C0020AE2000288CEB0014A0
-:109B40008FAA002801724823012A302310C0001177
-:109B5000AE26001090F0003D8E2C00048E2A0000EE
-:109B600000106900018D28210000102100AD302B6C
-:109B70000142482101264021AE250004AE28000004
-:109B800090E3003DA223000A8F9F008497F900060E
-:109B9000A63900088F8A0024240200023C068008AF
-:109BA000A142000034C900809525005C02402021BC
-:109BB0008F90002430A8FFFF0E000E9DAFA8002458
-:109BC0008FA300240002FB808F8500843C044200A8
-:109BD00003E3C8250324C025AE1800048F840024A5
-:109BE0008CAF0038AC8F00188CAE0034AC8E001CEB
-:109BF000AC80000CAC800010A4800014A48000167F
-:109C0000A4800020A4800022AC80002490A7003F04
-:109C1000A48700025240018C240700018FAB00286A
-:109C20005160000290A2003D90A2003E244C000131
-:109C3000A08C00018F840024AC9200083C1880089E
-:109C400037100080920F007C31EE000215C0000238
-:109C500024070034240700308F8500843C088008E6
-:109C60003509008090A300009128007C3259000340
-:109C7000A08300308F9F00848F9000242404000470
-:109C800093F8000100997823240DC000A218003138
-:109C90008F9900248F8E008431E50003972C0032C9
-:109CA00095CB001200F24821018D502431623FFF14
-:109CB00001423025A72600329323003201253821A6
-:109CC00031080004307F003F37E40040A324003215
-:109CD000124000028F85002400E838213C0C8008E7
-:109CE000ACA70034358B01008D6200C02E4400010A
-:109CF0002403FFDFACA2003890AA003C0004C94056
-:109D00003146007FA0A6003C8F8900242405FFBFB8
-:109D10009127003C00E54024A128003C8F8F0024BF
-:109D200091FF003C03E3C02403198025A1F0003C0F
-:109D30008F8B00848F8A00248D6E0020AD4E0040F2
-:109D40008D6D0024AD4D00448D6C0028AD4C004855
-:109D50008D62002C0E000EBCAD42004C8FA6002080
-:109D60002407000210C700118FA300200003202B3E
-:109D700000048023027098240060802100609021FC
-:109D80000A0011150010882B962700128F8400807E
-:109D90000000902130E5FFFFA7A700140E000E6B16
-:109DA000241100010A0011C03C1080003C19800001
-:109DB0003C0280088F240100905800080E000E42DB
-:109DC0003305007F8F8E00248FAF00208FA40028E2
-:109DD000A1CF00000E000E9D8F9000248FAD0024B7
-:109DE00000023B803C0B420000ED40258F87008441
-:109DF000010B2025AE0400048CE500388F90002470
-:109E000000005021000A1900AE0500188CEC003447
-:109E10003C087FFF3504FFFFAE0C001C90E9003EBC
-:109E20008E1F001C8E1800180009C9000009370297
-:109E300003F968210066102501B9782B030270210F
-:109E400001CF5821AE0D001CAE0B0018AE00000C67
-:109E5000AE00001090E5003E8FAF0028240E0005F4
-:109E6000A605001494EC00042405C00001E4582465
-:109E7000A60C001690EA003E01E02021A60A002070
-:109E800094E60004A6060022AE00002490E3003F02
-:109E9000A603000290E9003E90FF003D03E9C823BD
-:109EA00027380001A21800018F8D00243C10800883
-:109EB000ADAF0008A1AE00308F9800248F820084DF
-:109EC000360F0100970C0032944A00122410FF80D4
-:109ED00000AC382431463FFF00E61825A7030032C6
-:109EE000930900322405FFBF2403FFDF313F003F09
-:109EF00037F90040A31900328F8C00242418FFFF8B
-:109F0000AD8000348DEE00C0AD8E0038918D003CE8
-:109F100031A2007FA182003C8F87002490EA003CA0
-:109F200001453024A0E6003C8F9900249329003C91
-:109F30000123F824A33F003C8F8D00243C1F8008A0
-:109F4000ADB80040ADB2004491AF00483C12800073
-:109F500001F07025A1AE00488F8700248F86008411
-:109F60008CEC004801921024004B5025ACEA0048CC
-:109F700090C5003EA0E5004C8F8800848F830024AC
-:109F800095090004A469004E8FE500600E0002E60A
-:109F9000000000008F99FF2C8FAE00280002814046
-:109FA000932F007C0002C1000218682131F20002E8
-:109FB00000402821164000AA01CD30213C0A80082B
-:109FC000354300809069007C313F000413E00003BA
-:109FD0008FAE00280005608000CC3021240D0004E5
-:109FE0008F90002431C7000301A758233168000374
-:109FF00000C82021AE0400343C068008A6250038A5
-:10A000003C0580008CA4010090D100080E000E8752
-:10A010003225007F0E000EBC000000000A0012AACC
-:10A020008FA300208F8500208CC2003824180003E5
-:10A03000A4A00008ACA200008CDF0034A0A0000A9D
-:10A040008F920084ACBF00043C040080924F003F1C
-:10A05000A0B8000C8CAE000C3C0DFF9FA0AF000B15
-:10A0600001C4402535ABFFFF3C11FFEF8F98008402
-:10A07000010B30243639FFFF00D96024ACAC000C52
-:10A080008F030014971F00128F870080ACA300106D
-:10A090008F090014ACA00018ACA00020ACA90014DB
-:10A0A000ACA000248F0A001833E93FFF000911809B
-:10A0B000ACAA00288F1200080047782133EE000177
-:10A0C000ACB200308F08000C8F990024000F69C2D9
-:10A0D000000E238001A45821241100023C068008B0
-:10A0E000A4AB001CA4A00034ACA8002CA331000039
-:10A0F00034D90080972C005C8F8F00243C034200F1
-:10A10000318AFFFF01433825ADE700048F820084C8
-:10A11000241800012411C0008C5F0038240700348B
-:10A12000ADFF00188C520034ADF2001CADE0000C05
-:10A13000ADE00010A5E00014A5E00016A5E00020A9
-:10A14000A5E00022ADE00024A5F00002A1F8000186
-:10A150008F8B00248F8E0084AD70000891CD00009D
-:10A16000A16D00308F8800848F8400249105000148
-:10A17000A08500318F920024964C0032019150242A
-:10A1800001491825A6430032925F003233E2003FB6
-:10A19000A24200329338007C330F000215E0000227
-:10A1A0008F840024240700303C028008AC870034F0
-:10A1B000345201008E5F00C0240EFFBF02009021C8
-:10A1C000AC9F00389098003C330F007FA08F003C7C
-:10A1D0008F880024910D003C01AE5824A10B003C57
-:10A1E0008F86002490D1003C36390020A0D9003C55
-:10A1F0008F8A00848F8500240010882B8D4C0020CE
-:10A20000ACAC00408D430024ACA300448D49002831
-:10A21000ACA900488D47002CACA7004C0E000EBC2A
-:10A220003C1080000A0011160000000094CD00527E
-:10A230003C0B08008D6B0024016D8821A4D10052D5
-:10A240000A0010C1001E882BA08700018F84002403
-:10A25000240D0001AC8D00080A00125F3C18800834
-:10A26000000290800A00133E00D2302127BDFFE09B
-:10A270003C0D8008AFB20018AFB00010AFBF001C9B
-:10A28000AFB1001435B200808E4C001835A8010023
-:10A29000964B000695A70050910900EC000C560261
-:10A2A000016728233143007F312600FF2402000389
-:10A2B000A3830088AF84008010C2001B30B0FFFF72
-:10A2C000910600EC2412000530C200FF105200334A
-:10A2D00000000000160000098FBF001C8FB200189C
-:10A2E0008FB100148FB00010240D0C003C0C8000C6
-:10A2F00027BD002003E00008AD8D00240E0010A44F
-:10A30000020020218FBF001C8FB200188FB10014F3
-:10A310008FB00010240D0C003C0C800027BD0020E5
-:10A3200003E00008AD8D0024965800789651007A1D
-:10A33000924E007D0238782631E8FFFF31C400C01C
-:10A34000148000092D1100011600003700000000E4
-:10A350005620FFE28FBF001C0E000F7A00000000A5
-:10A360000A0014068FBF001C1620FFDA0000000050
-:10A370000E000F7A000000001440FFD88FBF001CB1
-:10A380001600002200000000925F007D33E2003FD3
-:10A39000A242007D0A0014068FBF001C950900DA56
-:10A3A0008F86006000802821240400050E000674BA
-:10A3B0003130FFFF978300723C0480002465FFFF6B
-:10A3C000A78500728C8A01B80540FFFE00000000DE
-:10A3D000AC8001808FBF001CAC9001848FB200184C
-:10A3E0008FB100148FB000103C0760133C0B1000BD
-:10A3F000240D0C003C0C800027BD0020AC87018898
-:10A40000AC8B01B803E00008AD8D00240E0010A451
-:10A41000020020215040FFB18FBF001C925F007DE1
-:10A420000A00143333E2003F0E0010A40200202182
-:10A430001440FFAA8FBF001C12200007000000007C
-:10A440009259007D3330003F36020040A242007D29
-:10A450000A0014068FBF001C0E000F7A00000000D7
-:10A460005040FF9E8FBF001C9259007D3330003F4B
-:08A470000A00146236020040EC
-:08A47800000000000000001BC1
-:10A480000000000F0000000A0000000800000006A5
-:10A4900000000005000000050000000400000004AA
-:10A4A00000000003000000030000000300000003A0
-:10A4B0000000000300000002000000020000000293
-:10A4C0000000000200000002000000020000000284
-:10A4D0000000000200000002000000020000000274
-:10A4E0000000000200000002000000020000000264
-:0CA4F0000000000100000001000000015D
-:04A4FC0080080100D3
-:10A50000800800808008000000000C0000003080FF
-:10A5100008000F4808000FF40800100C0800102075
-:10A520000800103408000F4808000F4808001068A1
-:10A53000080010A0080010B0080010D8080017C8C4
-:10A54000080017C8080018000800180008001814B0
-:10A55000080017E408001A3C08001A0808001A94BA
-:10A5600008001A9408001B1C08001A4C80080240BE
-:10A57000080021A808001FF4080021D00800226864
-:10A58000080023B808002404080025280800243007
-:10A59000080024B408002064080029D008002974A9
-:10A5A0000800201008002010080020100800259C3A
-:10A5B0000800259C08002010080020100800284CE6
-:10A5C00008002010080020100800201008002010AB
-:10A5D000080028AC080020100800201008002010F7
-:10A5E000080020100800201008002010080020108B
-:10A5F000080020100800201008002010080020107B
-:10A600000800201008002010080020100800242452
-:10A6100008002010080020100800291C0800201045
-:10A62000080020100800201008002010080020104A
-:10A63000080020100800201008002010080020103A
-:10A64000080020100800201008002010080020102A
-:10A65000080020100800201008002010080020101A
-:10A66000080027700800201008002010080026E4C9
-:10A6700008002640080037880800375C08003728A3
-:10A68000080036FC080036DC08003690800801001F
-:10A69000800800808008000080080080080046F0E4
-:10A6A0000800472808004670080046F0080046F0F9
-:0CA6B00008004450080046F008004AC4AE
-:04A6BC000A000C760E
-:10A6C00000000000000000000000000D72787035EE
-:10A6D0002E302E306A390000050000030000000013
-:10A6E0000000000100000000000000000000000069
-:10A6F000000000000000000000000000000000005A
-:10A700000000000000000000000000000000000049
-:10A710000000000000000000000000000000000039
-:10A720000000000000000000000000000000000029
-:10A730000000000000000000000000000000000019
-:10A740000000000000000000000000000000000009
-:10A7500000000000000000000000000000000000F9
-:10A7600000000000000000000000000000000000E9
-:10A7700000000000000000000000000000000000D9
-:10A7800000000000000000000000000000000000C9
-:10A7900000000000000000000000000000000000B9
-:10A7A00000000000000000000000000000000000A9
-:10A7B0000000000000000000000000000000000099
-:10A7C0000000000000000000000000000000000089
-:10A7D0000000000000000000000000000000000079
-:10A7E0000000000000000000000000000000000069
-:10A7F0000000000000000000000000000000000059
-:10A800000000000000000000000000000000000048
-:10A810000000000000000000000000000000000038
-:10A820000000000000000000000000000000000028
-:10A830000000000000000000000000000000000018
-:10A840000000000000000000000000000000000008
-:10A8500000000000000000000000000000000000F8
-:10A8600000000000000000000000000000000000E8
-:10A8700000000000000000000000000000000000D8
-:10A8800000000000000000000000000000000000C8
-:10A8900000000000000000000000000000000000B8
-:10A8A00000000000000000000000000000000000A8
-:10A8B0000000000000000000000000000000000098
-:10A8C0000000000000000000000000000000000088
-:10A8D0000000000000000000000000000000000078
-:10A8E0000000000000000000000000000000000068
-:10A8F0000000000000000000000000000000000058
-:10A900000000000000000000000000000000000047
-:10A910000000000000000000000000000000000037
-:10A920000000000000000000000000000000000027
-:10A930000000000000000000000000000000000017
-:10A940000000000000000000000000000000000007
-:10A9500000000000000000000000000000000000F7
-:10A9600000000000000000000000000000000000E7
-:10A9700000000000000000000000000000000000D7
-:10A9800000000000000000000000000000000000C7
-:10A9900000000000000000000000000000000000B7
-:10A9A00000000000000000000000000000000000A7
-:10A9B0000000000000000000000000000000000097
-:10A9C0000000000000000000000000000000000087
-:10A9D0000000000000000000000000000000000077
-:10A9E0000000000000000000000000000000000067
-:10A9F0000000000000000000000000000000000057
-:10AA00000000000000000000000000000000000046
-:10AA10000000000000000000000000000000000036
-:10AA20000000000000000000000000000000000026
-:10AA30000000000000000000000000000000000016
-:10AA40000000000000000000000000000000000006
-:10AA500000000000000000000000000000000000F6
-:10AA600000000000000000000000000000000000E6
-:10AA700000000000000000000000000000000000D6
-:10AA800000000000000000000000000000000000C6
-:10AA900000000000000000000000000000000000B6
-:10AAA00000000000000000000000000000000000A6
-:10AAB0000000000000000000000000000000000096
-:10AAC0000000000000000000000000000000000086
-:10AAD0000000000000000000000000000000000076
-:10AAE0000000000000000000000000000000000066
-:10AAF0000000000000000000000000000000000056
-:10AB00000000000000000000000000000000000045
-:10AB10000000000000000000000000000000000035
-:10AB20000000000000000000000000000000000025
-:10AB30000000000000000000000000000000000015
-:10AB40000000000000000000000000000000000005
-:10AB500000000000000000000000000000000000F5
-:10AB600000000000000000000000000000000000E5
-:10AB700000000000000000000000000000000000D5
-:10AB800000000000000000000000000000000000C5
-:10AB900000000000000000000000000000000000B5
-:10ABA00000000000000000000000000000000000A5
-:10ABB0000000000000000000000000000000000095
-:10ABC0000000000000000000000000000000000085
-:10ABD0000000000000000000000000000000000075
-:10ABE0000000000000000000000000000000000065
-:10ABF0000000000000000000000000000000000055
-:10AC00000000000000000000000000000000000044
-:10AC10000000000000000000000000000000000034
-:10AC20000000000000000000000000000000000024
-:10AC30000000000000000000000000000000000014
-:10AC40000000000000000000000000000000000004
-:10AC500000000000000000000000000000000000F4
-:10AC600000000000000000000000000000000000E4
-:10AC700000000000000000000000000000000000D4
-:10AC800000000000000000000000000000000000C4
-:10AC900000000000000000000000000000000000B4
-:10ACA00000000000000000000000000000000000A4
-:10ACB0000000000000000000000000000000000094
-:10ACC0000000000000000000000000000000000084
-:10ACD0000000000000000000000000000000000074
-:10ACE0000000000000000000000000000000000064
-:10ACF0000000000000000000000000000000000054
-:10AD00000000000000000000000000000000000043
-:10AD10000000000000000000000000000000000033
-:10AD20000000000000000000000000000000000023
-:10AD30000000000000000000000000000000000013
-:10AD40000000000000000000000000000000000003
-:10AD500000000000000000000000000000000000F3
-:10AD600000000000000000000000000000000000E3
-:10AD700000000000000000000000000000000000D3
-:10AD800000000000000000000000000000000000C3
-:10AD900000000000000000000000000000000000B3
-:10ADA00000000000000000000000000000000000A3
-:10ADB0000000000000000000000000000000000093
-:10ADC0000000000000000000000000000000000083
-:10ADD0000000000000000000000000000000000073
-:10ADE0000000000000000000000000000000000063
-:10ADF0000000000000000000000000000000000053
-:10AE00000000000000000000000000000000000042
-:10AE10000000000000000000000000000000000032
-:10AE20000000000000000000000000000000000022
-:10AE30000000000000000000000000000000000012
-:10AE40000000000000000000000000000000000002
-:10AE500000000000000000000000000000000000F2
-:10AE600000000000000000000000000000000000E2
-:10AE700000000000000000000000000000000000D2
-:10AE800000000000000000000000000000000000C2
-:10AE900000000000000000000000000000000000B2
-:10AEA00000000000000000000000000000000000A2
-:10AEB0000000000000000000000000000000000092
-:10AEC0000000000000000000000000000000000082
-:10AED0000000000000000000000000000000000072
-:10AEE0000000000000000000000000000000000062
-:10AEF0000000000000000000000000000000000052
-:10AF00000000000000000000000000000000000041
-:10AF10000000000000000000000000000000000031
-:10AF20000000000000000000000000000000000021
-:10AF30000000000000000000000000000000000011
-:10AF40000000000000000000000000000000000001
-:10AF500000000000000000000000000000000000F1
-:10AF600000000000000000000000000000000000E1
-:10AF700000000000000000000000000000000000D1
-:10AF800000000000000000000000000000000000C1
-:10AF900000000000000000000000000000000000B1
-:10AFA00000000000000000000000000000000000A1
-:10AFB0000000000000000000000000000000000091
-:10AFC0000000000000000000000000000000000081
-:10AFD0000000000000000000000000000000000071
-:10AFE0000000000000000000000000000000000061
-:10AFF0000000000000000000000000000000000051
-:10B000000000000000000000000000000000000040
-:10B010000000000000000000000000000000000030
-:10B020000000000000000000000000000000000020
-:10B030000000000000000000000000000000000010
-:10B040000000000000000000000000000000000000
-:10B0500000000000000000000000000000000000F0
-:10B0600000000000000000000000000000000000E0
-:10B0700000000000000000000000000000000000D0
-:10B0800000000000000000000000000000000000C0
-:10B0900000000000000000000000000000000000B0
-:10B0A00000000000000000000000000000000000A0
-:10B0B0000000000000000000000000000000000090
-:10B0C0000000000000000000000000000000000080
-:10B0D0000000000000000000000000000000000070
-:10B0E0000000000000000000000000000000000060
-:10B0F0000000000000000000000000000000000050
-:10B10000000000000000000000000000000000003F
-:10B11000000000000000000000000000000000002F
-:10B12000000000000000000000000000000000001F
-:10B13000000000000000000000000000000000000F
-:10B1400000000000000000000000000000000000FF
-:10B1500000000000000000000000000000000000EF
-:10B1600000000000000000000000000000000000DF
-:10B1700000000000000000000000000000000000CF
-:10B1800000000000000000000000000000000000BF
-:10B1900000000000000000000000000000000000AF
-:10B1A000000000000000000000000000000000009F
-:10B1B000000000000000000000000000000000008F
-:10B1C000000000000000000000000000000000007F
-:10B1D000000000000000000000000000000000006F
-:10B1E000000000000000000000000000000000005F
-:10B1F000000000000000000000000000000000004F
-:10B20000000000000000000000000000000000003E
-:10B21000000000000000000000000000000000002E
-:10B22000000000000000000000000000000000001E
-:10B23000000000000000000000000000000000000E
-:10B2400000000000000000000000000000000000FE
-:10B2500000000000000000000000000000000000EE
-:10B2600000000000000000000000000000000000DE
-:10B2700000000000000000000000000000000000CE
-:10B2800000000000000000000000000000000000BE
-:10B2900000000000000000000000000000000000AE
-:10B2A000000000000000000000000000000000009E
-:10B2B000000000000000000000000000000000008E
-:10B2C000000000000000000000000000000000007E
-:10B2D000000000000000000000000000000000006E
-:10B2E000000000000000000000000000000000005E
-:10B2F000000000000000000000000000000000004E
-:10B30000000000000000000000000000000000003D
-:10B31000000000000000000000000000000000002D
-:10B32000000000000000000000000000000000001D
-:10B33000000000000000000000000000000000000D
-:10B3400000000000000000000000000000000000FD
-:10B3500000000000000000000000000000000000ED
-:10B3600000000000000000000000000000000000DD
-:10B3700000000000000000000000000000000000CD
-:10B3800000000000000000000000000000000000BD
-:10B3900000000000000000000000000000000000AD
-:10B3A000000000000000000000000000000000009D
-:10B3B000000000000000000000000000000000008D
-:10B3C000000000000000000000000000000000007D
-:10B3D000000000000000000000000000000000006D
-:10B3E000000000000000000000000000000000005D
-:10B3F000000000000000000000000000000000004D
-:10B40000000000000000000000000000000000003C
-:10B41000000000000000000000000000000000002C
-:10B42000000000000000000000000000000000001C
-:10B43000000000000000000000000000000000000C
-:10B4400000000000000000000000000000000000FC
-:10B4500000000000000000000000000000000000EC
-:10B4600000000000000000000000000000000000DC
-:10B4700000000000000000000000000000000000CC
-:10B4800000000000000000000000000000000000BC
-:10B4900000000000000000000000000000000000AC
-:10B4A000000000000000000000000000000000009C
-:10B4B000000000000000000000000000000000008C
-:10B4C000000000000000000000000000000000007C
-:10B4D000000000000000000000000000000000006C
-:10B4E000000000000000000000000000000000005C
-:10B4F000000000000000000000000000000000004C
-:10B50000000000000000000000000000000000003B
-:10B51000000000000000000000000000000000002B
-:10B52000000000000000000000000000000000001B
-:10B53000000000000000000000000000000000000B
-:10B5400000000000000000000000000000000000FB
-:10B5500000000000000000000000000000000000EB
-:10B5600000000000000000000000000000000000DB
-:10B5700000000000000000000000000000000000CB
-:10B5800000000000000000000000000000000000BB
-:10B5900000000000000000000000000000000000AB
-:10B5A000000000000000000000000000000000009B
-:10B5B000000000000000000000000000000000008B
-:10B5C000000000000000000000000000000000007B
-:10B5D000000000000000000000000000000000006B
-:10B5E000000000000000000000000000000000005B
-:10B5F000000000000000000000000000000000004B
-:10B60000000000000000000000000000000000003A
-:10B61000000000000000000000000000000000002A
-:10B62000000000000000000000000000000000001A
-:10B63000000000000000000000000000000000000A
-:10B6400000000000000000000000000000000000FA
-:10B6500000000000000000000000000000000000EA
-:10B6600000000000000000000000000000000000DA
-:10B6700000000000000000000000000000000000CA
-:10B6800000000000000000000000000000000000BA
-:10B6900000000000000000000000000000000000AA
-:10B6A000000000000000000000000000000000009A
-:10B6B000000000000000000000000000000000008A
-:10B6C000000000000000000000000000000000007A
-:10B6D000000000000000000000000000000000006A
-:10B6E000000000000000000000000000000000005A
-:10B6F000000000000000000000000000000000004A
-:10B700000000000000000000000000000000000039
-:10B710000000000000000000000000000000000029
-:10B720000000000000000000000000000000000019
-:10B730000000000000000000000000000000000009
-:10B7400000000000000000000000000000000000F9
-:10B7500000000000000000000000000000000000E9
-:10B7600000000000000000000000000000000000D9
-:10B7700000000000000000000000000000000000C9
-:10B7800000000000000000000000000000000000B9
-:10B7900000000000000000000000000000000000A9
-:10B7A0000000000000000000000000000000000099
-:10B7B0000000000000000000000000000000000089
-:10B7C0000000000000000000000000000000000079
-:10B7D0000000000000000000000000000000000069
-:10B7E0000000000000000000000000000000000059
-:10B7F0000000000000000000000000000000000049
-:10B800000000000000000000000000000000000038
-:10B810000000000000000000000000000000000028
-:10B820000000000000000000000000000000000018
-:10B830000000000000000000000000000000000008
-:10B8400000000000000000000000000000000000F8
-:10B8500000000000000000000000000000000000E8
-:10B8600000000000000000000000000000000000D8
-:10B8700000000000000000000000000000000000C8
-:10B8800000000000000000000000000000000000B8
-:10B8900000000000000000000000000000000000A8
-:10B8A0000000000000000000000000000000000098
-:10B8B0000000000000000000000000000000000088
-:10B8C0000000000000000000000000000000000078
-:10B8D0000000000000000000000000000000000068
-:10B8E0000000000000000000000000000000000058
-:10B8F0000000000000000000000000000000000048
-:10B900000000000000000000000000000000000037
-:10B910000000000000000000000000000000000027
-:10B920000000000000000000000000000000000017
-:10B930000000000000000000000000000000000007
-:10B9400000000000000000000000000000000000F7
-:10B9500000000000000000000000000000000000E7
-:10B9600000000000000000000000000000000000D7
-:10B9700000000000000000000000000000000000C7
-:10B9800000000000000000000000000000000000B7
-:10B9900000000000000000000000000000000000A7
-:10B9A0000000000000000000000000000000000097
-:10B9B0000000000000000000000000000000000087
-:10B9C0000000000000000000000000000000000077
-:10B9D0000000000000000000000000000000000067
-:10B9E0000000000000000000000000000000000057
-:10B9F0000000000000000000000000000000000047
-:10BA00000000000000000000000000000000000036
-:10BA10000000000000000000000000000000000026
-:10BA20000000000000000000000000000000000016
-:10BA30000000000000000000000000000000000006
-:10BA400000000000000000000000000000000000F6
-:10BA500000000000000000000000000000000000E6
-:10BA600000000000000000000000000000000000D6
-:10BA700000000000000000000000000000000000C6
-:10BA800000000000000000000000000000000000B6
-:10BA900000000000000000000000000000000000A6
-:10BAA0000000000000000000000000000000000096
-:10BAB0000000000000000000000000000000000086
-:10BAC0000000000000000000000000000000000076
-:10BAD0000000000000000000000000000000000066
-:10BAE0000000000000000000000000000000000056
-:10BAF0000000000000000000000000000000000046
-:10BB00000000000000000000000000000000000035
-:10BB10000000000000000000000000000000000025
-:10BB20000000000000000000000000000000000015
-:10BB30000000000000000000000000000000000005
-:10BB400000000000000000000000000000000000F5
-:10BB500000000000000000000000000000000000E5
-:10BB600000000000000000000000000000000000D5
-:10BB700000000000000000000000000000000000C5
-:10BB800000000000000000000000000000000000B5
-:10BB900000000000000000000000000000000000A5
-:10BBA0000000000000000000000000000000000095
-:10BBB0000000000000000000000000000000000085
-:10BBC0000000000000000000000000000000000075
-:10BBD0000000000000000000000000000000000065
-:10BBE0000000000000000000000000000000000055
-:10BBF0000000000000000000000000000000000045
-:10BC00000000000000000000000000000000000034
-:10BC10000000000000000000000000000000000024
-:10BC20000000000000000000000000000000000014
-:10BC30000000000000000000000000000000000004
-:10BC400000000000000000000000000000000000F4
-:10BC500000000000000000000000000000000000E4
-:10BC600000000000000000000000000000000000D4
-:10BC700000000000000000000000000000000000C4
-:10BC800000000000000000000000000000000000B4
-:10BC900000000000000000000000000000000000A4
-:10BCA0000000000000000000000000000000000094
-:10BCB0000000000000000000000000000000000084
-:10BCC0000000000000000000000000000000000074
-:10BCD0000000000000000000000000000000000064
-:10BCE0000000000000000000000000000000000054
-:10BCF0000000000000000000000000000000000044
-:10BD00000000000000000000000000000000000033
-:10BD10000000000000000000000000000000000023
-:10BD20000000000000000000000000000000000013
-:10BD30000000000000000000000000000000000003
-:10BD400000000000000000000000000000000000F3
-:10BD500000000000000000000000000000000000E3
-:10BD600000000000000000000000000000000000D3
-:10BD700000000000000000000000000000000000C3
-:10BD800000000000000000000000000000000000B3
-:10BD900000000000000000000000000000000000A3
-:10BDA0000000000000000000000000000000000093
-:10BDB0000000000000000000000000000000000083
-:10BDC0000000000000000000000000000000000073
-:10BDD0000000000000000000000000000000000063
-:10BDE0000000000000000000000000000000000053
-:10BDF0000000000000000000000000000000000043
-:10BE00000000000000000000000000000000000032
-:10BE10000000000000000000000000000000000022
-:10BE20000000000000000000000000000000000012
-:10BE30000000000000000000000000000000000002
-:10BE400000000000000000000000000000000000F2
-:10BE500000000000000000000000000000000000E2
-:10BE600000000000000000000000000000000000D2
-:10BE700000000000000000000000000000000000C2
-:10BE800000000000000000000000000000000000B2
-:10BE900000000000000000000000000000000000A2
-:10BEA0000000000000000000000000000000000092
-:10BEB0000000000000000000000000000000000082
-:10BEC0000000000000000000000000000000000072
-:10BED0000000000000000000000000000000000062
-:10BEE0000000000000000000000000000000000052
-:10BEF0000000000000000000000000000000000042
-:10BF00000000000000000000000000000000000031
-:10BF10000000000000000000000000000000000021
-:10BF20000000000000000000000000000000000011
-:10BF30000000000000000000000000000000000001
-:10BF400000000000000000000000000000000000F1
-:10BF500000000000000000000000000000000000E1
-:10BF600000000000000000000000000000000000D1
-:10BF700000000000000000000000000000000000C1
-:10BF800000000000000000000000000000000000B1
-:10BF900000000000000000000000000000000000A1
-:10BFA0000000000000000000000000000000000091
-:10BFB0000000000000000000000000000000000081
-:10BFC0000000000000000000000000000000000071
-:10BFD0000000000000000000000000000000000061
-:10BFE0000000000000000000000000000000000051
-:10BFF0000000000000000000000000000000000041
-:10C000000000000000000000000000000000000030
-:10C010000000000000000000000000000000000020
-:10C020000000000000000000000000000000000010
-:10C030000000000000000000000000000000000000
-:10C0400000000000000000000000000000000000F0
-:10C0500000000000000000000000000000000000E0
-:10C0600000000000000000000000000000000000D0
-:10C0700000000000000000000000000000000000C0
-:10C0800000000000000000000000000000000000B0
-:10C0900000000000000000000000000000000000A0
-:10C0A0000000000000000000000000000000000090
-:10C0B0000000000000000000000000000000000080
-:10C0C0000000000000000000000000000000000070
-:10C0D0000000000000000000000000000000000060
-:10C0E0000000000000000000000000000000000050
-:10C0F0000000000000000000000000000000000040
-:10C10000000000000000000000000000000000002F
-:10C11000000000000000000000000000000000001F
-:10C12000000000000000000000000000000000000F
-:10C1300000000000000000000000000000000000FF
-:10C1400000000000000000000000000000000000EF
-:10C1500000000000000000000000000000000000DF
-:10C1600000000000000000000000000000000000CF
-:10C1700000000000000000000000000000000000BF
-:10C1800000000000000000000000000000000000AF
-:10C19000000000000000000000000000000000009F
-:10C1A000000000000000000000000000000000008F
-:10C1B000000000000000000000000000000000007F
-:10C1C000000000000000000000000000000000006F
-:10C1D000000000000000000000000000000000005F
-:10C1E000000000000000000000000000000000004F
-:10C1F000000000000000000000000000000000003F
-:10C20000000000000000000000000000000000002E
-:10C21000000000000000000000000000000000001E
-:10C22000000000000000000000000000000000000E
-:10C2300000000000000000000000000000000000FE
-:10C2400000000000000000000000000000000000EE
-:10C2500000000000000000000000000000000000DE
-:10C2600000000000000000000000000000000000CE
-:10C2700000000000000000000000000000000000BE
-:10C2800000000000000000000000000000000000AE
-:10C29000000000000000000000000000000000009E
-:10C2A000000000000000000000000000000000008E
-:10C2B000000000000000000000000000000000007E
-:10C2C000000000000000000000000000000000006E
-:10C2D000000000000000000000000000000000005E
-:10C2E000000000000000000000000000000000004E
-:10C2F000000000000000000000000000000000003E
-:10C30000000000000000000000000000000000002D
-:10C31000000000000000000000000000000000001D
-:10C32000000000000000000000000000000000000D
-:10C3300000000000000000000000000000000000FD
-:10C3400000000000000000000000000000000000ED
-:10C3500000000000000000000000000000000000DD
-:10C3600000000000000000000000000000000000CD
-:10C3700000000000000000000000000000000000BD
-:10C3800000000000000000000000000000000000AD
-:10C39000000000000000000000000000000000009D
-:10C3A000000000000000000000000000000000008D
-:10C3B000000000000000000000000000000000007D
-:10C3C000000000000000000000000000000000006D
-:10C3D000000000000000000000000000000000005D
-:10C3E000000000000000000000000000000000004D
-:10C3F000000000000000000000000000000000003D
-:10C40000000000000000000000000000000000002C
-:10C41000000000000000000000000000000000001C
-:10C42000000000000000000000000000000000000C
-:10C4300000000000000000000000000000000000FC
-:10C4400000000000000000000000000000000000EC
-:10C4500000000000000000000000000000000000DC
-:10C4600000000000000000000000000000000000CC
-:10C4700000000000000000000000000000000000BC
-:10C4800000000000000000000000000000000000AC
-:10C49000000000000000000000000000000000009C
-:10C4A000000000000000000000000000000000008C
-:10C4B000000000000000000000000000000000007C
-:10C4C000000000000000000000000000000000006C
-:10C4D000000000000000000000000000000000005C
-:10C4E000000000000000000000000000000000004C
-:10C4F000000000000000000000000000000000003C
-:10C50000000000000000000000000000000000002B
-:10C51000000000000000000000000000000000001B
-:10C52000000000000000000000000000000000000B
-:10C5300000000000000000000000000000000000FB
-:10C5400000000000000000000000000000000000EB
-:10C5500000000000000000000000000000000000DB
-:10C5600000000000000000000000000000000000CB
-:10C5700000000000000000000000000000000000BB
-:10C5800000000000000000000000000000000000AB
-:10C59000000000000000000000000000000000009B
-:10C5A000000000000000000000000000000000008B
-:10C5B000000000000000000000000000000000007B
-:10C5C000000000000000000000000000000000006B
-:10C5D000000000000000000000000000000000005B
-:10C5E000000000000000000000000000000000004B
-:10C5F000000000000000000000000000000000003B
-:10C60000000000000000000000000000000000002A
-:10C61000000000000000000000000000000000001A
-:10C62000000000000000000000000000000000000A
-:10C6300000000000000000000000000000000000FA
-:10C6400000000000000000000000000000000000EA
-:10C6500000000000000000000000000000000000DA
-:10C6600000000000000000000000000000000000CA
-:10C6700000000000000000000000000000000000BA
-:10C6800000000000000000000000000000000000AA
-:10C69000000000000000000000000000000000009A
-:10C6A000000000000000000000000000000000008A
-:10C6B000000000000000000000000000000000007A
-:10C6C000000000000000000000000000000000006A
-:10C6D000000000000000000000000000000000005A
-:10C6E000000000000000000000000000000000004A
-:10C6F000000000000000000000000000000000003A
-:10C700000000000000000000000000000000000029
-:10C710000000000000000000000000000000000019
-:10C720000000000000000000000000000000000009
-:10C7300000000000000000000000000000000000F9
-:10C7400000000000000000000000000000000000E9
-:10C7500000000000000000000000000000000000D9
-:10C7600000000000000000000000000000000000C9
-:10C7700000000000000000000000000000000000B9
-:10C7800000000000000000000000000000000000A9
-:10C790000000000000000000000000000000000099
-:10C7A0000000000000000000000000000000000089
-:10C7B0000000000000000000000000000000000079
-:10C7C0000000000000000000000000000000000069
-:10C7D0000000000000000000000000000000000059
-:10C7E0000000000000000000000000000000000049
-:10C7F0000000000000000000000000000000000039
-:10C800000000000000000000000000000000000028
-:10C810000000000000000000000000000000000018
-:10C820000000000000000000000000000000000008
-:10C8300000000000000000000000000000000000F8
-:10C8400000000000000000000000000000000000E8
-:10C8500000000000000000000000000000000000D8
-:10C8600000000000000000000000000000000000C8
-:10C8700000000000000000000000000000000000B8
-:10C8800000000000000000000000000000000000A8
-:10C890000000000000000000000000000000000098
-:10C8A0000000000000000000000000000000000088
-:10C8B0000000000000000000000000000000000078
-:10C8C0000000000000000000000000000000000068
-:10C8D0000000000000000000000000000000000058
-:10C8E0000000000000000000000000000000000048
-:10C8F0000000000000000000000000000000000038
-:10C900000000000000000000000000000000000027
-:10C910000000000000000000000000000000000017
-:10C920000000000000000000000000000000000007
-:10C9300000000000000000000000000000000000F7
-:10C9400000000000000000000000000000000000E7
-:10C9500000000000000000000000000000000000D7
-:10C9600000000000000000000000000000000000C7
-:10C9700000000000000000000000000000000000B7
-:10C9800000000000000000000000000000000000A7
-:10C990000000000000000000000000000000000097
-:10C9A0000000000000000000000000000000000087
-:10C9B0000000000000000000000000000000000077
-:10C9C0000000000000000000000000000000000067
-:10C9D0000000000000000000000000000000000057
-:10C9E0000000000000000000000000000000000047
-:10C9F0000000000000000000000000000000000037
-:10CA00000000000000000000000000000000000026
-:10CA10000000000000000000000000000000000016
-:10CA20000000000000000000000000000000000006
-:10CA300000000000000000000000000000000000F6
-:10CA400000000000000000000000000000000000E6
-:10CA500000000000000000000000000000000000D6
-:10CA600000000000000000000000000000000000C6
-:10CA700000000000000000000000000000000000B6
-:10CA800000000000000000000000000000000000A6
-:10CA90000000000000000000000000000000000096
-:10CAA0000000000000000000000000000000000086
-:10CAB0000000000000000000000000000000000076
-:10CAC0000000000000000000000000000000000066
-:10CAD0000000000000000000000000000000000056
-:10CAE0000000000000000000000000000000000046
-:10CAF0000000000000000000000000000000000036
-:10CB00000000000000000000000000000000000025
-:10CB10000000000000000000000000000000000015
-:10CB20000000000000000000000000000000000005
-:10CB300000000000000000000000000000000000F5
-:10CB400000000000000000000000000000000000E5
-:10CB500000000000000000000000000000000000D5
-:10CB600000000000000000000000000000000000C5
-:10CB700000000000000000000000000000000000B5
-:10CB800000000000000000000000000000000000A5
-:10CB90000000000000000000000000000000000095
-:10CBA0000000000000000000000000000000000085
-:10CBB0000000000000000000000000000000000075
-:10CBC0000000000000000000000000000000000065
-:10CBD0000000000000000000000000000000000055
-:10CBE0000000000000000000000000000000000045
-:10CBF0000000000000000000000000000000000035
-:10CC00000000000000000000000000000000000024
-:10CC10000000000000000000000000000000000014
-:10CC20000000000000000000000000000000000004
-:10CC300000000000000000000000000000000000F4
-:10CC400000000000000000000000000000000000E4
-:10CC500000000000000000000000000000000000D4
-:10CC600000000000000000000000000000000000C4
-:10CC700000000000000000000000000000000000B4
-:10CC800000000000000000000000000000000000A4
-:10CC90000000000000000000000000000000000094
-:10CCA0000000000000000000000000000000000084
-:10CCB0000000000000000000000000000000000074
-:10CCC0000000000000000000000000000000000064
-:10CCD0000000000000000000000000000000000054
-:10CCE0000000000000000000000000000000000044
-:10CCF0000000000000000000000000000000000034
-:10CD00000000000000000000000000000000000023
-:10CD10000000000000000000000000000000000013
-:10CD20000000000000000000000000000000000003
-:10CD300000000000000000000000000000000000F3
-:10CD400000000000000000000000000000000000E3
-:10CD500000000000000000000000000000000000D3
-:10CD600000000000000000000000000000000000C3
-:10CD700000000000000000000000000000000000B3
-:10CD800000000000000000000000000000000000A3
-:10CD90000000000000000000000000000000000093
-:10CDA0000000000000000000000000000000000083
-:10CDB0000000000000000000000000000000000073
-:10CDC0000000000000000000000000000000000063
-:10CDD0000000000000000000000000000000000053
-:10CDE0000000000000000000000000000000000043
-:10CDF0000000000000000000000000000000000033
-:10CE00000000000000000000000000000000000022
-:10CE10000000000000000000000000000000000012
-:10CE20000000000000000000000000000000000002
-:10CE300000000000000000000000000000000000F2
-:10CE400000000000000000000000000000000000E2
-:10CE500000000000000000000000000000000000D2
-:10CE600000000000000000000000000000000000C2
-:10CE700000000000000000000000000000000000B2
-:10CE800000000000000000000000000000000000A2
-:10CE90000000000000000000000000000000000092
-:10CEA0000000000000000000000000000000000082
-:10CEB0000000000000000000000000000000000072
-:10CEC0000000000000000000000000000000000062
-:10CED0000000000000000000000000000000000052
-:10CEE0000000000000000000000000000000000042
-:10CEF0000000000000000000000000000000000032
-:10CF00000000000000000000000000000000000021
-:10CF10000000000000000000000000000000000011
-:10CF20000000000000000000000000000000000001
-:10CF300000000000000000000000000000000000F1
-:10CF400000000000000000000000000000000000E1
-:10CF500000000000000000000000000000000000D1
-:10CF600000000000000000000000000000000000C1
-:10CF700000000000000000000000000000000000B1
-:10CF800000000000000000000000000000000000A1
-:10CF90000000000000000000000000000000000091
-:10CFA0000000000000000000000000000000000081
-:10CFB0000000000000000000000000000000000071
-:10CFC0000000000000000000000000000000000061
-:10CFD0000000000000000000000000000000000051
-:10CFE0000000000000000000000000000000000041
-:10CFF0000000000000000000000000000000000031
-:10D000000000000000000000000000000000000020
-:10D010000000000000000000000000000000000010
-:10D020000000000000000000000000000000000000
-:10D0300000000000000000000000000000000000F0
-:10D0400000000000000000000000000000000000E0
-:10D0500000000000000000000000000000000000D0
-:10D0600000000000000000000000000000000000C0
-:10D0700000000000000000000000000000000000B0
-:10D0800000000000000000000000000000000000A0
-:10D090000000000000000000000000000000000090
-:10D0A0000000000000000000000000000000000080
-:10D0B0000000000000000000000000000000000070
-:10D0C0000000000000000000000000000000000060
-:10D0D0000000000000000000000000000000000050
-:10D0E0000000000000000000000000000000000040
-:10D0F0000000000000000000000000000000000030
-:10D10000000000000000000000000000000000001F
-:10D11000000000000000000000000000000000000F
-:10D1200000000000000000000000000000000000FF
-:10D1300000000000000000000000000000000000EF
-:10D1400000000000000000000000000000000000DF
-:10D1500000000000000000000000000000000000CF
-:10D1600000000000000000000000000000000000BF
-:10D1700000000000000000000000000000000000AF
-:10D18000000000000000000000000000000000009F
-:10D19000000000000000000000000000000000008F
-:10D1A000000000000000000000000000000000007F
-:10D1B000000000000000000000000000000000006F
-:10D1C000000000000000000000000000000000005F
-:10D1D000000000000000000000000000000000004F
-:10D1E000000000000000000000000000000000003F
-:10D1F000000000000000000000000000000000002F
-:10D20000000000000000000000000000000000001E
-:10D21000000000000000000000000000000000000E
-:10D2200000000000000000000000000000000000FE
-:10D2300000000000000000000000000000000000EE
-:10D2400000000000000000000000000000000000DE
-:10D2500000000000000000000000000000000000CE
-:10D2600000000000000000000000000000000000BE
-:10D2700000000000000000000000000000000000AE
-:10D28000000000000000000000000000000000009E
-:10D29000000000000000000000000000000000008E
-:10D2A000000000000000000000000000000000007E
-:10D2B000000000000000000000000000000000006E
-:10D2C000000000000000000000000000000000005E
-:10D2D000000000000000000000000000000000004E
-:10D2E000000000000000000000000000000000003E
-:10D2F000000000000000000000000000000000002E
-:10D30000000000000000000000000000000000001D
-:10D31000000000000000000000000000000000000D
-:10D3200000000000000000000000000000000000FD
-:10D3300000000000000000000000000000000000ED
-:10D3400000000000000000000000000000000000DD
-:10D3500000000000000000000000000000000000CD
-:10D3600000000000000000000000000000000000BD
-:10D3700000000000000000000000000000000000AD
-:10D38000000000000000000000000000000000009D
-:10D39000000000000000000000000000000000008D
-:10D3A000000000000000000000000000000000007D
-:10D3B000000000000000000000000000000000006D
-:10D3C000000000000000000000000000000000005D
-:10D3D000000000000000000000000000000000004D
-:10D3E000000000000000000000000000000000003D
-:10D3F000000000000000000000000000000000002D
-:10D40000000000000000000000000000000000001C
-:10D41000000000000000000000000000000000000C
-:10D4200000000000000000000000000000000000FC
-:10D4300000000000000000000000000000000000EC
-:10D4400000000000000000000000000000000000DC
-:10D4500000000000000000000000000000000000CC
-:10D4600000000000000000000000000000000000BC
-:10D4700000000000000000000000000000000000AC
-:10D48000000000000000000000000000000000009C
-:10D49000000000000000000000000000000000008C
-:10D4A000000000000000000000000000000000007C
-:10D4B000000000000000000000000000000000006C
-:10D4C000000000000000000000000000000000005C
-:10D4D000000000000000000000000000000000004C
-:10D4E000000000000000000000000000000000003C
-:10D4F000000000000000000000000000000000002C
-:10D50000000000000000000000000000000000001B
-:10D51000000000000000000000000000000000000B
-:10D5200000000000000000000000000000000000FB
-:10D5300000000000000000000000000000000000EB
-:10D5400000000000000000000000000000000000DB
-:10D5500000000000000000000000000000000000CB
-:10D5600000000000000000000000000000000000BB
-:10D5700000000000000000000000000000000000AB
-:10D58000000000000000000000000000000000009B
-:10D59000000000000000000000000000000000008B
-:10D5A000000000000000000000000000000000007B
-:10D5B000000000000000000000000000000000006B
-:10D5C000000000000000000000000000000000005B
-:10D5D000000000000000000000000000000000004B
-:10D5E000000000000000000000000000000000003B
-:10D5F000000000000000000000000000000000002B
-:10D60000000000000000000000000000000000001A
-:10D61000000000000000000000000000000000000A
-:10D6200000000000000000000000000000000000FA
-:10D6300000000000000000000000000000000000EA
-:10D6400000000000000000000000000000000000DA
-:10D6500000000000000000000000000000000000CA
-:10D6600000000000000000000000000000000000BA
-:10D6700000000000000000000000000000000000AA
-:10D68000000000000000000000000000000000009A
-:10D69000000000000000000000000000000000008A
-:10D6A000000000000000000000000000000000007A
-:10D6B000000000000000000000000000000000006A
-:10D6C000000000000000000000000000000000005A
-:10D6D000000000000000000000000000000000004A
-:10D6E000000000000000000000000000000000003A
-:10D6F000000000000000000000000000000000002A
-:10D700000000000000000000000000000000000019
-:10D710000000000000000000000000000000000009
-:10D7200000000000000000000000000000000000F9
-:10D7300000000000000000000000000000000000E9
-:10D7400000000000000000000000000000000000D9
-:10D7500000000000000000000000000000000000C9
-:10D7600000000000000000000000000000000000B9
-:10D7700000000000000000000000000000000000A9
-:10D780000000000000000000000000000000000099
-:10D790000000000000000000000000000000000089
-:10D7A0000000000000000000000000000000000079
-:10D7B0000000000000000000000000000000000069
-:10D7C0000000000000000000000000000000000059
-:10D7D0000000000000000000000000000000000049
-:10D7E0000000000000000000000000000000000039
-:10D7F0000000000000000000000000000000000029
-:10D800000000000000000000000000000000000018
-:10D810000000000000000000000000000000000008
-:10D8200000000000000000000000000000000000F8
-:10D8300000000000000000000000000000000000E8
-:10D8400000000000000000000000000000000000D8
-:10D8500000000000000000000000000000000000C8
-:10D8600000000000000000000000000000000000B8
-:10D8700000000000000000000000000000000000A8
-:10D880000000000000000000000000000000000098
-:10D890000000000000000000100000030000000075
-:10D8A0000000000D0000000D3C020801244282A08F
-:10D8B0003C03080124638360AC4000000043202B3C
-:10D8C0001480FFFD244200043C1D080037BD9FFC6E
-:10D8D00003A0F0213C100800261031D83C1C0801A0
-:10D8E000279C82A00E0011EA000000000000000D3D
-:10D8F0003C02800030A5FFFF30C600FF34430180AA
-:10D900003C0880008D0901B80520FFFE00000000E2
-:10D91000AC64000024040002A4650008A066000AAC
-:10D92000A064000BAC6700183C03100003E0000883
-:10D93000AD0301B83C0560008CA24FF80440FFFE27
-:10D9400000000000ACA44FC03C0310003C040200E7
-:10D95000ACA44FC403E00008ACA34FF89486000CBD
-:10D9600000A050212488001400062B02000510801E
-:10D97000004448210109182B10600011000000002C
-:10D98000910300002C6400095080000991190001E6
-:10D99000000360803C0D080125AD8154018D5821A4
-:10D9A0008D67000000E000080000000091190001F0
-:10D9B000011940210109302B54C0FFF291030000EE
-:10D9C00003E00008000010210A000CBE2508000139
-:10D9D000910F0001240E000A15EE00400128C82313
-:10D9E0002F38000A1700003D250D00028D58000059
-:10D9F000250F0006370E0100AD4E0000910C00020D
-:10DA000091AB000191A4000291A60003000C2E002E
-:10DA1000000B3C0000A7102500041A000043C82595
-:10DA20000326C025AD580004910E000691ED0001BB
-:10DA300091E7000291E50003000E5E00000D640016
-:10DA4000016C30250007220000C410250045182570
-:10DA50002508000A0A000CBEAD430008910F000122
-:10DA6000250400022408000255E8000101202021BD
-:10DA70000A000CBE00804021910C0001240B000321
-:10DA8000158B0016000000008D580000910E00025A
-:10DA900025080003370D0008A14E00100A000CBE37
-:10DAA000AD4D000091190001240F0004172F000B49
-:10DAB0000000000091070002910400038D43000064
-:10DAC00000072A0000A4102534660004250800047D
-:10DAD000AD42000C0A000CBEAD46000003E0000899
-:10DAE0002402000127BDFFE8AFBF0014AFB0001053
-:10DAF0000E0014FC008080213C04800834850080E6
-:10DB000090A600052403FFFE0200202100C310247C
-:10DB10008FBF00148FB00010A0A200050A001506E8
-:10DB200027BD001827BDFFE8AFB00010AFBF00143D
-:10DB30000E000F4E008080213C06800834C5008016
-:10DB400090A4000024020050308300FF1062000700
-:10DB50003C098000020020218FBF00148FB000100C
-:10DB6000AD2001800A00101027BD00182408010014
-:10DB70003C078000020020218FBF00148FB00010EE
-:10DB8000ACE801800A00101027BD001827BDFF7007
-:10DB90003C088008AFB60080AFB5007CAFB1006C28
-:10DBA000AFBF008CAFBE0088AFB70084AFB40078C1
-:10DBB000AFB30074AFB20070AFB00068350500803D
-:10DBC0003C0780008CF2012890A40009ACE000849E
-:10DBD00090A60005309100FF0000A821000618273C
-:10DBE000306200010000B02114400067AFA0005077
-:10DBF00090A9000024050020312400FF10850016A4
-:10DC0000240A0050108A008C000000003C0C080020
-:10DC10008D8C00DC258B00013C010800AC2B00DC66
-:10DC20000E0015F2000000008FBF008C8FBE008830
-:10DC30008FB700848FB600808FB5007C8FB40078DA
-:10DC40008FB300748FB200708FB1006C8FB000681A
-:10DC500003E0000827BD00900000000D3C1080008C
-:10DC6000AFA00030961F01168E1901043C1E002043
-:10DC700036130C00033EC0240018B82B00173140A7
-:10DC8000AFA600308E0E010433F4FFFF3C0F0040BE
-:10DC90000293802101CF68249213000D11A0004847
-:10DCA00034C40040326200201440000234860080F8
-:10DCB0000080302114C00093AFA600303C058008DE
-:10DCC00034A800809107000830E6004050C00006EC
-:10DCD0003C06800824090004122900A2240A00122C
-:10DCE000122A00293C06800834D401003C17800029
-:10DCF00096EF011A960D000E928E0008326B00040A
-:10DD000031F7FFFF01CD6004AFAC00548E14000466
-:10DD1000116000318E1E000834C300809079000825
-:10DD20003338004017000028000000008C730050BA
-:10DD300002939023064000063C0C80008C7E003449
-:10DD4000029E8023060200838EA200083C0C800005
-:10DD5000AD800044240200018FBF008C8FBE00887C
-:10DD60008FB700848FB600808FB5007C8FB40078A9
-:10DD70008FB300748FB200708FB1006C8FB00068E9
-:10DD800003E0000827BD00900E000D1A00002021BE
-:10DD90008FBF008C8FBE00888FB700848FB6008045
-:10DDA0008FB5007C8FB400788FB300748FB2007091
-:10DDB0008FB1006C8FB0006803E0000827BD0090B1
-:10DDC0000A000D7A00C020210E0016530280202187
-:10DDD0001440FFDF3C0C80003C038008346300806B
-:10DDE0008C6200340282F82307E000170000000074
-:10DDF0003C1508008EB5310026B100013C01080039
-:10DE0000AC3131000E0014FC024020213C0B800894
-:10DE100035700080920A002502402021354200041E
-:10DE20000E001506A20200250E000C9E02402021C5
-:10DE30000A000DA7240200013C15080126B58350F5
-:10DE40000A000D693C1080008C6600300286202399
-:10DE5000188000082409000C3C0808008D083100D7
-:10DE6000327300FC0000B821250700013C010800C6
-:10DE7000AC273100AFA900308C65003000B43823E6
-:10DE800018E000DB02E7502A1540FFDE000000002A
-:10DE900012E7002A02E768230287A02131B7FFFFBB
-:10DEA000326E000211C00034327F00103C14800832
-:10DEB00036900080920F000831F6004052C000CE2C
-:10DEC0008EA20008024020210E0014FC241300182A
-:10DED000A2130009921800052419FFFE0240202118
-:10DEE0000319B8240E001506A217000524040039F2
-:10DEF000000028210E00162E240600180A000DA787
-:10DF00002402000192B6000C3C0480083483008097
-:10DF10008C6700380016AB0036B10081024020212A
-:10DF20003225F0810E000C8D30C600FF3C0C8000C5
-:10DF3000AD8000440A000DA7240200013A6C0001E4
-:10DF4000318B00011560FFAF0287A0210A000DF898
-:10DF5000000000000040F809240400160A000DA784
-:10DF600024020001024020210E0017330200282164
-:10DF70000A000D5C8FBF008C13E0FF743C03800827
-:10DF8000346800808D0400388C66000403C61023BA
-:10DF90001C40FF6F3C0C800003C4282304A2000136
-:10DFA0000080F021AFB40010AFB70014AFA7001885
-:10DFB0003C1F800097E301208D0900309506005C2E
-:10DFC0008FB900548FAC00303062FFFF30D8FFFFB4
-:10DFD0000047702137EF40000338682B01CF5821EC
-:10DFE000018D5025AFAB0020AFA90028AFAA0030AB
-:10DFF000AFA90024AFA0002CAFBE003491070008E9
-:10E0000030E400081480008F020020218EA200045A
-:10E010000040F80927A400108FA900303128000221
-:10E0200055000001327300FE3C048008348C0080EF
-:10E03000918B0008316A0040514000128FA40024E7
-:10E040008C8D000411BE00BE240E00143265000148
-:10E0500010A0000C8FA400242404000C122400D46F
-:10E060002A27000D10E000CE2409000E2408000A23
-:10E0700052280001241600088FA200242444000125
-:10E08000AFA400248FA600143C03800834650080F0
-:10E090000086F8218CB10030ACBF003090B9004E42
-:10E0A0008CAE00303418FFFF0338780401CF6821AC
-:10E0B000ACAD00348FA600308FAC005430CA0008DD
-:10E0C00003CC58211140000CAFAB00588CA40020A9
-:10E0D0008FB000581090009430C600FF92A2000C40
-:10E0E0008FA700340240202100024B003528008019
-:10E0F0000E000C8D3105F0803C0C800835900080BE
-:10E100008E0B003001715023194000702659008099
-:10E110003C1808008F183198241FFF80033F782493
-:10E12000332D007F3C0680003C0E8004331100102C
-:10E13000ACCF00901220003401AE282190A3006BD8
-:10E14000546000323C10800824070001A0A7006B37
-:10E1500094C4007A2486000AA60600123C0D8008AA
-:10E1600035A5008090B10008322C004015800004D5
-:10E170003C038008326E000115C000620000000000
-:10E18000346400808C8F00208FB3005811F3000A94
-:10E19000346301008C7900000299C0231B000077D2
-:10E1A0008FA80058AC880020AC7400002414000133
-:10E1B000AC7E0004AFB4005016C000370000000071
-:10E1C0008FA40050148000300000000012E0000511
-:10E1D000000018218FA900303137000452E0FE9270
-:10E1E00000601021240300010A000D5B0060102173
-:10E1F0000A000DF9000038210040F8092404001736
-:10E200000A000DA7240200013C108008361000808F
-:10E2100024090001024020210E0014FCA60900126E
-:10E220009208002524050001AFA500503502000129
-:10E23000024020210E001506A20200250A000EA9A8
-:10E240003C0D800827A50038AFA800600E000CA880
-:10E25000AFA000381440FF6D8FA800608FA5003874
-:10E2600030B001005200FF6A8EA200048FA3003C70
-:10E270008D070058006720230483FF64AD03005816
-:10E280000A000E558EA200040E000C9E02402021B2
-:10E290000A000EC4000000000E0014FC0240202101
-:10E2A0003C05800834A30080024020210E001506A2
-:10E2B000A076000902C03021240400370E00162E7B
-:10E2C000000028210A000EC28FA400508FA200185F
-:10E2D0005840FFA33C0D80080E0014FC0240202192
-:10E2E000920A0025240B0001AFAB00503542000418
-:10E2F000024020210E001506A20200250A000EA9E8
-:10E300003C0D80088CB600308EBE00082404001836
-:10E3100026D5000103C0F809ACB500308FB200303B
-:10E320000A000D5B324200043C07800094E5011AAC
-:10E3300050A0FF6A34C600100A000E8992A2000C99
-:10E34000122E002A2A2F001511E0001E2419001693
-:10E350002418000C5638FF3E326500013C1F80082F
-:10E3600093E3001B2410FFBD2416000E0070302420
-:10E37000A3E6001B0A000E65326500018C7F0000D9
-:10E3800017F4FF8D000000008C67000403C73023E2
-:10E3900004C1FF848FA800580A000EBF00000000CF
-:10E3A0001629FF368FA200240A000E7024160010D2
-:10E3B0002411000E52D1FF30241600100A000E6FF7
-:10E3C000241600165639FF22326500013C1F8008D2
-:10E3D00093E3001B2410FFBD2416001000703024AE
-:10E3E000A3E6001B0A000E65326500010A000E64F8
-:10E3F000241600123C0380008C6201B80440FFFE2A
-:10E4000024040800AC6401B803E000080000000028
-:10E4100030A5FFFF30C6FFFF3C0780008CE201B84B
-:10E420000440FFFE34E80180AD040000ACE40020AD
-:10E430003C048008948300483063FFFF1060001D97
-:10E440003C0B800024AA0012006A482B5120001ABD
-:10E45000240A000394F901208F890000240C001A7B
-:10E460003338FFFF2707FFFE0067782B39EE0001E6
-:10E4700000096B8201AE5824A10C000B116000470B
-:10E480008F830004A50700148F880004350700015E
-:10E49000AF87000430CC00405580000F3C0880005E
-:10E4A0003C0C800035840180A485000E0A000F9882
-:10E4B0008F8F000C240A00033564018030CC0040AB
-:10E4C0008F8900008F870004A08A000B5180FFF520
-:10E4D0003C0C80003C088000950301203C0880082B
-:10E4E000951800403079FFFF272EFFFE330FFFFF06
-:10E4F00001CF682B11A0000301C02021950200402C
-:10E500003044FFFF3C0B800000A4502335650180A0
-:10E51000A4A4000EA4AA00248F8F000C3C05800048
-:10E5200034AE01802418000230ED8000A5D8000C24
-:10E53000A5C90010ADCF0028A5C6000811A0000E87
-:10E540003C04800094AA01163142FFFC24480004D8
-:10E55000010518218C7940003326FFFF14C0000705
-:10E56000240EBFFF3C0BFFFF35657FFF00E538241D
-:10E57000AF8700043C048000240EBFFF348C018070
-:10E5800000EE6824A58D0026AD89002C3C07100004
-:10E59000AC8701B803E00008000000002402FFFE81
-:10E5A000006238240A000F76AF8700043C05800023
-:10E5B00034A400708C8A000090A601128F840000A1
-:10E5C00027BDFFF030C300FF000318823082010036
-:10E5D00000003821104000392466000330874000D5
-:10E5E00050E0003930882000000610800045C82126
-:10E5F0008F2F40002478000400187080AFAF000017
-:10E6000001C568218DAC4000AFAC000494AB01168D
-:10E610003169FFFC012540218D054000AFA50008B0
-:10E620008FA9000800003021000028213C070800C5
-:10E6300024E701000A000FE92408000890420000C6
-:10E6400024A500012CAD000C0062C8210019C08077
-:10E65000030778218DEE000011A0000600CE3026C1
-:10E6600003A5102114A8FFF500051A005520FFF49A
-:10E67000904200003C048000348700703C05080094
-:10E680008CA531048CE300002CA8002011000009A7
-:10E69000006A3823000558803C0C0800258C31089E
-:10E6A000016C482124AA0001AD2700003C010800AC
-:10E6B000AC2A3104AF86000C2407000100E01021D1
-:10E6C00003E0000827BD00101100FFFC0000382106
-:10E6D00000066080018558218D6440002469000493
-:10E6E00000093880AFA4000000E518218C664000C6
-:10E6F000AFA000080A000FD9AFA6000427BDFFD8BD
-:10E70000AFB20018AFB00010AFBF0024AFB400200C
-:10E71000AFB3001CAFB100148F8700003C04800031
-:10E720009483010E30E24000000080211040001070
-:10E730003072FFFF3C06002000E6282410A0000DE8
-:10E7400030EA80008F8800042409BFFF00E93824E4
-:10E7500035031000AF87000030F120001620000BB9
-:10E760003C1400042418FFBF0A001038007810245D
-:10E7700030EA8000154000863C0C002030F120007B
-:10E780001220FFF88F8300043C14000400F4982446
-:10E790001260FFF52418FFBF3462004030F9010019
-:10E7A0001320000FAF8200043C02002000E2F82496
-:10E7B00013E000053C0B80003C04000400E4182436
-:10E7C000106000CF00000000956A011E9569011CD1
-:10E7D0003146FFFF0009440000C82825AF85000C22
-:10E7E0003C0E800095CD010C8DC44000340CFFFF21
-:10E7F000108C00B031A5FFFF308F010055E0000103
-:10E800002410001030F110005220000836110001D1
-:10E8100030F300201660009F3C18100000F8A02480
-:10E82000168000963C040C003611000130E801000F
-:10E830001500000B3C0A00018F88000431094000DC
-:10E840001520000800EA30243C0C1F0100EC58247D
-:10E850003C0A1000516A00AE30AD02003C0A0001D3
-:10E8600000EA302414C000953C05100000E5202487
-:10E8700000004021108000070000902100079E0248
-:10E880003272000F001278803C0E080125CE830002
-:10E8900001EE40218F94001C12800047022080214D
-:10E8A00010800091000000003C0980009539010EA5
-:10E8B00091030000022030213338FFFF27050004B8
-:10E8C000106000080000A021241F0003107F013AFF
-:10E8D00024040002910C00011184011830EA004068
-:10E8E0000012A1C08F920020524000013626004045
-:10E8F0003C1380008E6F400031F10100122000CBEC
-:10E9000030D1FFFB3C1808008F18002430D20004DF
-:10E910003306000414C000CC30B0FFFF56400001A5
-:10E920003631000402802021020028210E000F55FC
-:10E93000022030211640000D0000202136650180A4
-:10E940003C0480008C9301B80660FFFE241920006F
-:10E9500024140002A4B90008A0B4000BA4A0001065
-:10E960003C051000AC8501B8000020218FBF0024B9
-:10E970008FB400208FB3001C8FB200188FB1001429
-:10E980008FB000100080102103E0000827BD002890
-:10E9900000EC58241160FF7A30F120008F8D0004C4
-:10E9A0003C0FFFFF35EE7FFF00EE382435A38000DB
-:10E9B0000A001027AF8700003C0208008C42003894
-:10E9C0003C040800248400381040004B2449FFFF19
-:10E9D0003C038000946C010E318BFFFF110000A0FE
-:10E9E000257300043C1008008E1000301200000A4D
-:10E9F00030E601008F8A00043143400010600006B9
-:10EA00003C0F0F0000EF70243C0D010001AE402BC5
-:10EA1000110000DF3265FFFF10C000693C140F00D9
-:10EA200000F428243C18020010B800658F99000CEF
-:10EA30003270FFFF03299824026490219249000458
-:10EA400025270004000721C00200282136260002E5
-:10EA50000E000F55000000008FBF00248FB400206F
-:10EA60008FB3001C8FB200188FB100148FB000104C
-:10EA70000000102103E0000827BD00283C020BFF26
-:10EA800000E41824345FFFFF03E3C82B5320FF6723
-:10EA9000361100013C0608008CC6002C361100051A
-:10EAA00024D000013C010800AC30002C0A00105DAD
-:10EAB00030E801000A0010522410002002402821F2
-:10EAC0003C1208008E5200D824040080264D00011C
-:10EAD0003C010800AC2D00D80E000F5524060003A1
-:10EAE0000A0010E88FBF00243C08080125088300B5
-:10EAF0000A00107C3C0980000A0010C50000482173
-:10EB00000E000FBC000000000A0010498F870000B3
-:10EB100015A0FF533C0A00012645000430AAFFFF60
-:10EB2000362600023C0380008C7201B80640FFFECE
-:10EB30008F85000834690180AD20000010A000AF6F
-:10EB40003C048000254F001200AF702B51C000AC78
-:10EB500024030003947801202414001A30F14000AB
-:10EB60003313FFFFA134000B122000B62663FFFE13
-:10EB700000A3C82B572000B4241FFFFE3508000156
-:10EB8000A5230014AF8800043C108000240CBFFFB4
-:10EB9000010C4824240B000236080180A50B000C50
-:10EBA000A50A000EA5060008A5090026A507001065
-:10EBB0003C071000AE0701B80A0010E88FBF002420
-:10EBC0003C0308008C6300D02E45000C001221C0CD
-:10EBD000386B00012D6200010045F82417E0FF9A10
-:10EBE0003270FFFF264CFFFC2D840004548000503F
-:10EBF00000002021386A00022D43000100658024B6
-:10EC00001600004A3270FFFF00076A420012702BA4
-:10EC100001AE40245500006300002021001221C0F5
-:10EC2000020028210A0010E53626000234DF000227
-:10EC30000280202133E6FFFF0E000F5530A5FFFFB5
-:10EC40000A0010AC00002021240401000200282149
-:10EC50000E000F55022030210A001098000000001D
-:10EC60008C66400030CF010011E0003D30F801001B
-:10EC70003C1208008E5200241300001132340004AC
-:10EC80003C1F0F0000FFC8243C0502001325000CA8
-:10EC90008F8C000C022030213265FFFF018958243F
-:10ECA00001641021904900043230FFFB2411FFFE63
-:10ECB000252700040E000F55000721C002519024A3
-:10ECC0002404000112440052324300011460005831
-:10ECD00002003021324A0004114000048F8D0000F0
-:10ECE00031A808001500005A3265FFFF1680FF5B4F
-:10ECF0008FBF00243C138000366501803C048000F7
-:10ED00008C9001B80600FFFE24062000240F0002AC
-:10ED1000A4A60008A0AF000BA4A000103C0E100099
-:10ED2000AC8E01B80A0010E88FBF0024000020213B
-:10ED3000020028210A0010E5362600021140FEE9F3
-:10ED40000000A021952E0110950D000231C8FFFF93
-:10ED500051A8FEE40012A1C00A00108B8F9200207F
-:10ED60003C0508008CA5002430B800015300FF3B8F
-:10ED70008FBF00243265FFFF3626000200002021ED
-:10ED80000E000F55000000000A0010E88FBF00249D
-:10ED9000362600020E000F55240400800A0010E8F9
-:10EDA0008FBF0024020028210E000F553226FFFBE2
-:10EDB0000A001159001221C0910300012402000130
-:10EDC0001062FEEA24040001241000021470FEC543
-:10EDD0000000A02130E300401060FEC38F920020AD
-:10EDE000952B0110950900023167FFFF1127FEE006
-:10EDF0008FBF00240A00108B0000000024030003D2
-:10EE000034820180A043000B0A0011343C108000C2
-:10EE100032140004168000033265FFFF3612000230
-:10EE20003250FFFF020030210A0011B10000202102
-:10EE3000000020210E000F553265FFFF0A001186E9
-:10EE40003210FFFB241FFFFE0A001132011F402475
-:10EE5000020030210E000F55240401000A00118C1D
-:10EE60000000000027BDFFC8AFB00010AFBF0034E6
-:10EE70003C10600CAFBE0030AFB7002CAFB600281E
-:10EE8000AFB50024AFB40020AFB3001CAFB2001880
-:10EE9000AFB100148E0E5000240FFF7F3C0680009F
-:10EEA00001CF682435AC380C240B0003AE0C5000A5
-:10EEB000ACCB00083C010800AC2000200E00175F1E
-:10EEC000000000003C0A001035498051AE09537C17
-:10EED0003C0660168CC700003C0860148D0500A03D
-:10EEE0003C03FFFF00E320243C02535300052FC2E4
-:10EEF0001482000634D07C000005A0800286982190
-:10EF00008E7200043C116000025180218E1E007838
-:10EF10008E17007C3C0260003C05080124A581841A
-:10EF2000344420202406000AAF9E00100E0016086C
-:10EF3000AF9700143C180098260503883C1F00106A
-:10EF40003C19600C371600C03C158000AF3F53FCE5
-:10EF50003C1E080027DE00383C17080126F7830214
-:10EF6000AEB6013CAF8500183C047FFF3488FFFF3C
-:10EF70003C0780000A0012373C0660008CAB0000A2
-:10EF8000316A00011540000235630001ACA30000A6
-:10EF900054800009320500018CF000008CC9180C67
-:10EFA000320400030521FFF501281824ACC3180C16
-:10EFB0000A0012300000000014A000553C1180002F
-:10EFC0003206000210C0FFE88F8500183C04800064
-:10EFD0008C99014024100040AC9900208C98014885
-:10EFE00000187E0231E300701070022C0000000057
-:10EFF0002C67004150E000782404006024110020B8
-:10F00000107100063C1F40003C138000AE7F017869
-:10F01000000000000A00122B8F8500188C93014815
-:10F02000241600043488018000134C02312500FFAF
-:10F030008C83014010B6017324B2FFFA2E4B0006F8
-:10F04000516000133C0580008C86014430A400FF11
-:10F0500030D400FF30C300FF2E85000814A000024A
-:10F060002467000424070003240C0009108C01AC61
-:10F07000288D000A11A001982415000A240E00080A
-:10F08000108E00158F91001C000719C03C058000F0
-:10F090008CA701B804E0FFFE24160002AD030000B7
-:10F0A000A5090008A116000B8CA401483C1F4000D4
-:10F0B0003C138000A50400108CA90144AD09002474
-:10F0C0003C081000ACA801B8AE7F01780000000039
-:10F0D0000A00122B8F8500180006CA020007208044
-:10F0E0003C16080126D683000096C021262F000179
-:10F0F000332500FF24100001A319000014B0FFE223
-:10F10000AF8F001C000719C00A001274AF850020E1
-:10F110008E3301283C0D8008AE3300208E2C010474
-:10F120008E26010095A80048AF8C0000AF86000431
-:10F130003103FFFF0E000F4EAF8300083C070800AD
-:10F140008CE700C010E0002D8F8700003C0F080006
-:10F150008DEF00C425EE00013C010800AC2E00C478
-:10F160003C0480008C9101243C076020ACF1001429
-:10F17000000000003C0680003C164000ACD6013880
-:10F18000000000005260FF8F320600022669014035
-:10F19000266D00802415FF800135602401B57024A0
-:10F1A000000E194031B4007F000C91403128007FDF
-:10F1B0003C05200034A20002007450250248582566
-:10F1C000016298250142F825ACDF0830ACD3083045
-:10F1D0000A001242320600021464FF8B3C1F4000FA
-:10F1E0000E001F793C1380003C1F4000AE7F017869
-:10F1F000000000000A00122B8F8500183C1400103C
-:10F2000000F49024164000A78F8300043C180800E7
-:10F210008F1800209636010E30F5400027110001AE
-:10F220003C010800AC31002032D2FFFF12A000B335
-:10F23000000088213C1F002000FFC824132000B0DC
-:10F2400030E980008F8200042404BFFF00E43824EA
-:10F2500034431000AF87000030E6200010C000A546
-:10F26000240EFFBF3C0D000400ED6024118000025D
-:10F27000006E10243462004030EF010011E0000FF6
-:10F28000AF8200043C15002000F5A0241280000588
-:10F290003C0480003C18000400F8B02412C0012F88
-:10F2A00000000000948A011E9489011C315FFFFF59
-:10F2B0000009140003E2C825AF99000C3C0580004A
-:10F2C00094A3010C8CA44000340BFFFF108B00CBE7
-:10F2D0003065FFFF30880100550000012411001047
-:10F2E00030E6100010C000133635000130EC00206D
-:10F2F0001580000A3C0E100000EE682411A0000DDD
-:10F300003C180C003C160BFF00F8A82436D4FFFF75
-:10F310000295782B11E00007363500013C190800F2
-:10F320008F39002C36350005273100013C010800DB
-:10F33000AC31002C30FF010017E0000B3C0A00014B
-:10F340008F880004310240001440000800EA302495
-:10F350003C041F0100E450243C0910001149010342
-:10F3600030AB02003C0A000100EA302414C00098CF
-:10F370003C03100000E3202400004021108000071F
-:10F380000000A02100076E0231B4000F001460805D
-:10F390003C12080126528300019240218F8E001CEE
-:10F3A00011C0006202A08821148000033C09800083
-:10F3B0003C08080125088300952F010E91030000E9
-:10F3C00002A0302131E4FFFF248500041060000812
-:10F3D0000000B0212416000310760109240A00025F
-:10F3E000910B0001116A002630E300400014B1C007
-:10F3F0008F9200205240000136A600403C1480004D
-:10F400008E8C40003195010012A000BE30D5000462
-:10F410003C0D08008DAD002430D2FFFB31A6000466
-:10F4200014C000F130B1FFFF56A0000136520004B5
-:10F4300002C02021022028210E000F550240302159
-:10F4400016A0000D00002021368401803C058000BC
-:10F450008CAE01B805C0FFFE24162000240F000268
-:10F46000A4960008A08F000BA48000103C0410009C
-:10F47000ACA401B8000020210A00138600801021EE
-:10F480001060FFDB0000B0219527011095090002F4
-:10F4900030E8FFFF5128FFD60014B1C00A00134E18
-:10F4A0008F920020240EBFFF006E682411A0000779
-:10F4B000240F87FF006FA82416A0000A3C190060E3
-:10F4C00000F9C02413000007000000000E000D34F6
-:10F4D000000000001040FF283C0680000A0012AA2D
-:10F4E0003C0480000E0014E5000000000A001386B2
-:10F4F000000000000A0012EF006E102430E98000C6
-:10F500001120FF558F8300043C0B002000EB50249A
-:10F510001140FF518F8500043C08FFFF35037FFF3A
-:10F5200000E338240A0012E634A380003C050800FA
-:10F530008CA5003814A0000224A4FFFF00002021A5
-:10F540003C0380009479010E3338FFFF110000DA8C
-:10F55000271200043C1108008E3100301220000AEE
-:10F5600030E901008F820004305F400013E00006A4
-:10F570003C080F0000E818243C0B01000163502BED
-:10F58000114000C13245FFFF1120002E3C0D0F003D
-:10F5900000ED30243C0C020010CC002A8F96000CA9
-:10F5A0003251FFFF02C4782401FE702191D2000481
-:10F5B00026470004000721C00220282136A60002A9
-:10F5C0000E000F55000000000A00138600001021F5
-:10F5D0003C0B08008D6B00D80240282124040080D9
-:10F5E000256700013C010800AC2700D80E000F552C
-:10F5F000240600030A001386000010210A001309E4
-:10F60000241100208C840140010028213C0380004B
-:10F610008C7F01B807E0FFFE2402001CACA40000B0
-:10F62000A0A2000B3C0A1000AC6A01B83C1F4000CD
-:10F630003C138000AE7F0178000000000A00122B0E
-:10F640008F8500183C0308008C6300D02E85000CC9
-:10F65000001421C0387100012E3900010325C02497
-:10F660001700FFD53251FFFF269FFFFC2FE4000457
-:10F670001480000800002021386B00022D6A000170
-:10F680000145102410400006000742423251FFFF9E
-:10F6900000002021022028210A0013C136A6000202
-:10F6A0000014182B0103282414A000053251FFFF79
-:10F6B000001421C0022028210A0013C136A600022E
-:10F6C00000002021022028210E000F5532A6FFFB4A
-:10F6D0000A0013FE001421C01095005A000768802C
-:10F6E0002406000B1486FE69000719C00007C880B5
-:10F6F0003C11080126318300033130210A001274C5
-:10F70000A0C0000134D4000202C0202130A5FFFFB8
-:10F710000E000F553286FFFF0A00136F00002021F4
-:10F720000007F8803C0A0801254A830003EA1021FB
-:10F73000905300001260FE55000719C0A040000061
-:10F740008F8B001C2562FFFF1440FE50AF82001C0F
-:10F75000000719C00A001274AF8000200E000FBC11
-:10F76000000000000A0013008F8700001560FEFEF5
-:10F770003C0A000126430004306AFFFF36A600025F
-:10F780003C0380008C7201B80640FFFE34690180A2
-:10F790008F850008AD20000010A0008B3C19800070
-:10F7A000254D001200AD602B11800088241100034C
-:10F7B000947501202414001A30EE400032AFFFFF90
-:10F7C000A134000B11C0009125E3FFFE00A3B02B74
-:10F7D00016C0008F2405FFFE35080001A523001484
-:10F7E0000A0014C6AF880004240401000220282166
-:10F7F0000E000F55024030210A00135B000000008C
-:10F8000091030001241400011074FF1B2404000163
-:10F81000241800021478FEF60000B02130F10040F8
-:10F820001220FEF48F92002095220110951F0002F5
-:10F830003059FFFF13F9FF27008010210A00134EF3
-:10F84000000000003C1808012718830001B880213F
-:10F8500000067A02A20F00013C1260008E431820BD
-:10F860002415000100F57004006E282501B7A021C1
-:10F8700000066402000719C0A68C0000AE451820DF
-:10F880000A0012753C05800036A600020E000F55D6
-:10F89000240400800A001386000010210E00150BBE
-:10F8A0003C1380003C1F4000AE7F01780000000048
-:10F8B0000A00122B8F8500188C694000313401003A
-:10F8C0001280003530EC01003C1408008E940024B6
-:10F8D0001180001132B600043C0E0F0000EE6824C7
-:10F8E0003C06020011A6000C02A030218F91000CF2
-:10F8F0003245FFFF0224C824033EC021930F0004B9
-:10F9000032B1FFFB2415FFFE25E700040E000F5562
-:10F91000000721C00295A024240400011284003FA6
-:10F920003282000110400007328A00040220302198
-:10F93000000020210E000F553245FFFF3231FFFB42
-:10F94000328A0004114000048F85000030AB0800AB
-:10F950001560003A3245FFFF16C0FEDE00001021A0
-:10F960003C128000364401803C0580008CA801B820
-:10F970000500FFFE2414200024030002A4940008C4
-:10F98000A083000BA48000103C091000ACA901B8B2
-:10F990000A001386000010213C0608008CC60024D3
-:10F9A00030CC00015180FECB000010213245FFFF1A
-:10F9B00036A60002000020210E000F5500000000B6
-:10F9C0000A0013860000102124110003373801803B
-:10F9D000A311000B3C0580002409BFFF0109F82496
-:10F9E0002402000234A80180A502000CA50A000E22
-:10F9F000A5060008A51F0026A50700103C09100059
-:10FA0000ACA901B80A001386000010212405FFFEEE
-:10FA1000010540240A0014C6AF88000432360004F1
-:10FA200016C000033245FFFF363F000233F1FFFFEF
-:10FA3000022030210A0014BF0000202102203021C2
-:10FA40000E000F55240401000A0014A70000000056
-:10FA50003C0380008C6401003082003E14400008AA
-:10FA600000000000AC6000488C66010030C507C093
-:10FA700010A0000500000000AC60004CAC6000501D
-:10FA800003E0000824020001AC600054AC600040B8
-:10FA90008C6801003107380010E0FFF90000000019
-:10FAA0002402000103E00008AC6000443C03900025
-:10FAB00034620001008220253C038000AC640020F9
-:10FAC0008C65002004A0FFFE0000000003E0000899
-:10FAD000000000003C028000344300010083202528
-:10FAE00003E00008AC44002027BDFFD8AFB10014EC
-:10FAF0003C048000AFBF0020AFB3001CAFB20018C1
-:10FB0000AFB000108C9201408C9001482402000E8E
-:10FB100000108C02322300FF1062005902042824D6
-:10FB20002866000F10C00013286A0037240700065B
-:10FB30001067008E286800075100002D240400097A
-:10FB4000106000783C06800024090001106900B0B4
-:10FB5000000000000000000D8FBF00208FB3001CCC
-:10FB60008FB200188FB100148FB0001003E00008AE
-:10FB700027BD002811400059240D0038286B00359E
-:10FB8000116000053C058000240C001F146CFFF17F
-:10FB9000000000003C0580008CB801B80700FFFEA3
-:10FBA00034B90180AF320000241F0001241200028A
-:10FBB0003C021000AF200004A7310008A33F000A58
-:10FBC000A332000BA7300010AF200024AF20002884
-:10FBD000ACA201B88FBF00208FB3001C8FB20018F9
-:10FBE0008FB100148FB0001003E0000827BD00287B
-:10FBF000106400232405000B1465FFD63218FFFFA4
-:10FC0000170000203C0580008F93FEDC927F0005EA
-:10FC100033F900041720FFCF000000000E0014FC91
-:10FC2000024020219269000502402021352800046D
-:10FC30000E001506A26800059267000530E2000478
-:10FC400014400002000000000000000D926B000054
-:10FC500024060020316A00FF1546000A3C0580009A
-:10FC60008CA401B80480FFFE34AD0180240E000591
-:10FC70003C0C1000ADB20000A1AE000BACAC01B862
-:10FC80003C0580008CA301B80460FFFE34AF018006
-:10FC900024130002ADF20000ADF20004A5F100084B
-:10FCA000A1F3000AA1F3000BA5F00010ADE00024C1
-:10FCB0008CB101443C101000ADF10028ACB001B88B
-:10FCC0008FBF00208FB3001C8FB200188FB10014BB
-:10FCD0008FB0001003E0000827BD0028106DFFADB5
-:10FCE000240E0080146EFF9B000000003C05800085
-:10FCF0008CA301B80460FFFE34AF0180241200021F
-:10FD0000A1F2000BA5F10008A5F000108CB301448E
-:10FD10003C021000A5F30012ACA201B80A0015477E
-:10FD20008FBF00208CC301B80460FFFE34D3018074
-:10FD3000AE720000AE60000424120001A67100083B
-:10FD400024110002A272000AA271000BA67000101A
-:10FD50008CD001443C0F1000AE700024AE6000282F
-:10FD6000ACCF01B80A0015828FBF00203C03800091
-:10FD70008C6601B804C0FFFE346201803C060801B5
-:10FD800090C68340AC52000010C000030000382130
-:10FD90003C0708018CE783483C05800034AA0180B9
-:10FDA0002404000234CC0001AC470004A551000833
-:10FDB000A14C000AA144000BA55000108CAB0144DB
-:10FDC0000000202101402821AD4B002410C0000379
-:10FDD0008FBF00203C0408018C8483448FB3001C37
-:10FDE0008FB200188FB100148FB000103C0E1000BD
-:10FDF0003C0D800027BD0028ACA40028ADAE01B8A2
-:10FE00003C010801A020834003E00008000000003E
-:10FE100010A0000B3C0680008C98014424190002BD
-:10FE20003C010801A03983403C010801AC32834801
-:10FE30003C010801AC3883440A0015828FBF0020C2
-:10FE40008CDF01B807E0FFFE34C7018024090002FF
-:10FE5000ACF20000ACF20004A4F10008A0E9000A32
-:10FE6000A0E9000BA4F00010ACE000248CC8014411
-:10FE70003C021000ACE80028ACC201B80A001582B0
-:10FE80008FBF002027BDFFE8AFBF00100E000F4E50
-:10FE9000000000003C0280008FBF00100000202105
-:10FEA000AC4001800A00101027BD00183084FFFF0D
-:10FEB00030A5FFFF108000070000182130820001EC
-:10FEC0001040000200042042006518211480FFFB4E
-:10FED0000005284003E000080060102110C0000762
-:10FEE000000000008CA2000024C6FFFF24A500042F
-:10FEF000AC82000014C0FFFB2484000403E000086F
-:10FF00000000000010A0000824A3FFFFAC86000042
-:10FF100000000000000000002402FFFF2463FFFF38
-:10FF20001462FFFA2484000403E0000800000000CB
-:10FF300027BDFFE8AFBF0014AFB000100E0014FCE7
-:10FF4000008080213C048008348300809065002577
-:10FF50000200202134A200200E001506A062002518
-:10FF6000020020218FBF00148FB000100A000C9EE9
-:10FF700027BD00183C03800027BDFFF834620180D4
-:10FF8000AFA20000308C00FF30AD00FF30CE00FF8C
-:10FF90003C0B80008D6401B80480FFFE000000006F
-:10FFA0008FA900008D6801288FAA00008FA700008C
-:10FFB0008FA400002405000124020002A085000A8D
-:10FFC0008FA30000359940003C051000A062000B93
-:10FFD0008FB800008FAC00008FA600008FAF00002C
-:10FFE00027BD0008AD280000AD400004AD8000240E
-:10FFF000ACC00028A4F90008A70D0010A5EE00125F
-:020000040001F9
-:1000000003E00008AD6501B83C06800827BDFFE8A5
-:1000100034C50080AFBF001090A700092402001271
-:1000200030E300FF1062000B008030218CA80050EC
-:1000300000882023048000088FBF00108CAA0034A1
-:10004000240400390000282100CA482305200005A7
-:10005000240600128FBF00102402000103E00008F4
-:1000600027BD00180E00162E000000008FBF0010E4
-:100070002402000103E0000827BD001827BDFFC8C7
-:10008000AFB1002C00A08821AFB2003027A500102E
-:100090000080902102202021AFBF0034AFB00028A3
-:1000A0000E000CA8AFA000101440009B3C07800875
-:1000B00034E400809086000830C5000814A0006970
-:1000C0008FA700103C18800837100080920F00089E
-:1000D00031EE000815C00002240800030000402192
-:1000E0003C0B800891650011916A00123566008012
-:1000F0008CDF0054314900FF0128202130A300FF8C
-:10010000000410800062282100BFC82B13200008C3
-:100110000000000094D0005C8CCF0054320DFFFF33
-:1001200001E5702301AE602B1180009400000000F7
-:1001300094D9005C3323FFFF30FF000413E0007408
-:10014000000830808FA8001C0068102B5040004F22
-:1001500030E30004006610232C46008010C000022B
-:1001600000408021241000800E0014FC0240202159
-:100170003C0380083466008024070001ACC7000CF3
-:1001800090C800080010684034670100311F007FEC
-:10019000A0DF00088E39000427380001ACD80030F9
-:1001A000A4D0005C8CCF003C9630000E01F0702192
-:1001B000ACCE00208CCC003C018D5821ACCB001C77
-:1001C0008E2A0004ACEA00008E290008ACE9000485
-:1001D0008FA5001030A400085480003293A60020A0
-:1001E000A0C0004E90C9004E2402FFDF3C188008DA
-:1001F000A0E9000890C50008370D0080240A0050CF
-:1002000000A22024A0C400088E390008ADB900382F
-:100210008F0F00148DB0003001F07021ADAE0034AE
-:1002200091AC0000318B00FF116A002C26450100C3
-:100230000E00150602402021240400380000282169
-:100240000E00162E2406000A8FBF00348FB2003035
-:100250008FB1002C8FB000282402000103E00008B9
-:1002600027BD003830E801001100003D8FA30014C5
-:100270008C8A0058006A48230520FF933C188008A8
-:10028000AC8300580A0016828FA7001024070218BA
-:100290001060FFB100E610238FA2001C0A0016A711
-:1002A000004610233C188008370D0080A0E60008A7
-:1002B0008E390008240A0050ADB900388F0F0014A1
-:1002C0008DB0003001F07021ADAE003491AC000073
-:1002D000318B00FF156AFFD6264501002406FF80FA
-:1002E00000A610243C098000AD2200288E270008BB
-:1002F00030A3007F3C04800C0064F821AFE700D0FD
-:100300008E280008AF9F002C0A0016DDAFE800D44D
-:100310000A0016A42C6202188E2300083C048008F0
-:1003200034820080AC430054024020210E00161D90
-:10033000AC400030240400382405008D0E00162E39
-:10034000240600128FBF00348FB200308FB1002C12
-:100350008FB000282402000103E0000827BD003808
-:10036000AC800058908C0008240DFFF7018D5824B4
-:10037000A08B00080A0016828FA700108CD80054AA
-:100380000A00169F0305182327BDFFE8AFBF001022
-:1003900090A6000D30C7001010E0000C0080402136
-:1003A0003C0280088C4400048CA300081064000800
-:1003B00030C9000530C5000510A0001C8FBF00101B
-:1003C0002402000103E0000827BD001830C9000521
-:1003D0001120001030CB001210E0FFF98FBF001089
-:1003E0003C0880088CA700088D06000414E6FFF581
-:1003F00024020001240400382405008D0E00162E6E
-:10040000240600128FBF00102402000103E0000840
-:1004100027BD0018240A0012156AFFE98FBF0010DB
-:10042000010020210A00167027BD001800002021BD
-:100430000A000D1A27BD00183C05080024A55DC060
-:100440003C04080024847B803C02080024425DC8F0
-:10045000240300063C010801AC2583503C0108013F
-:10046000AC2483543C010801AC2283583C010801B0
-:10047000A023835C03E000080000000003E0000804
-:10048000240200013C028000308800FF34470180D4
-:100490003C0680008CC301B80460FFFE0000000031
-:1004A0008CC501282418FF803C0D800A24AF010070
-:1004B00001F8702431EC007FACCE0024018D2021A6
-:1004C000ACE50000948B00DA3509600024080002D6
-:1004D000316AFFFFACEA000424020001A4E900082D
-:1004E000A0E8000BACE000243C071000ACC701B84A
-:1004F000AF84002C03E00008AF85005C8C990004F9
-:100500008F8D002C2409FFBF0325C023AC98000465
-:1005100091AF00C42403FFEF31EE007FA1AE00C411
-:100520008C8C0020938B00388F86002C358A00023B
-:10053000AF8B0050A780004CAC8A0020A4C000AC58
-:1005400090C800C401093824A0C700C48F84002CBF
-:10055000AC8000DC908500C400A3102403E00008F8
-:10056000A08200C43C028000344501803C0480002D
-:100570008C8301B80460FFFE8F89005C24076083D0
-:1005800024060002ACA900008C880124ACA8000459
-:10059000A4A70008A0A6000B3C05100003E000087B
-:1005A000AC8501B8938800388F8900508F82002C69
-:1005B00030C600FF0109382330E900FF012218216D
-:1005C00030A500FF2468007810C000020124382103
-:1005D0000080382130E400031480000330AA0003B7
-:1005E0001140000D312B000310A000090000102164
-:1005F00090ED0000244E000131C200FF0045602B49
-:10060000A10D000024E700011580FFF92508000175
-:1006100003E00008000000001560FFF30000000088
-:1006200010A0FFFB000010218CF8000024590004EA
-:10063000332200FF0045782BAD18000024E70004AA
-:1006400015E0FFF92508000403E0000800000000A1
-:1006500093850038938800488F870050000432004B
-:100660003103007F00E5102B30C47F001040000FE5
-:10067000006428258F84002C3C0980008C8A00DCD3
-:10068000AD2A00A43C03800000A35825AC6B00A059
-:100690008C6C00A00580FFFE000000008C6D00AC9B
-:1006A000AC8D00DC03E000088C6200A80A0017F2A1
-:1006B0008F84002C938800493C02800000805021E8
-:1006C000310300FEA383004930ABFFFF30CC00FFB5
-:1006D00030E7FFFF344801803C0980008D2401B8D9
-:1006E0000480FFFE8F8D005C24180016AD0D000005
-:1006F0008D2201248F8D002CAD0200048D59002025
-:10070000A5070008240201B4A119000AA118000BD2
-:10071000952F01208D4E00088D4700049783004CD3
-:100720008D59002401CF302100C7282100A32023A8
-:100730002418FFFFA504000CA50B000EA502001055
-:10074000A50C0012AD190018AD18002495AF00D803
-:100750003C0B10002407FFF731EEFFFFAD0E002821
-:100760008DAC0074AD0C002CAD2B01B88D46002073
-:1007700000C7282403E00008AD4500208F88002C26
-:100780000080582130E7FFFF910900C63C0280003D
-:1007900030A5FFFF312400FF00041A000067502538
-:1007A00030C600FF344701803C0980008D2C01B821
-:1007B0000580FFFE8F82005C240F0017ACE2000072
-:1007C0008D390124ACF900048D780020A4EA0008DA
-:1007D000241901B4A0F8000AA0EF000B9523012012
-:1007E0008D6E00088D6D00049784004C01C350216C
-:1007F000014D602101841023A4E2000CA4E5000E49
-:10080000A4F90010A4E60012ACE000148D780024D6
-:10081000240DFFFFACF800188D0F006CACEF001C2E
-:100820008D0E00683C0F1000ACEE0020ACED0024F3
-:10083000950A00AE240DFFF73146FFFFACE6002815
-:10084000950C00709504007231837FFF0003CA008D
-:100850003082FFFF0322C021ACF8002CAD2F01B87D
-:10086000950E00728D6A002000AE3021014D2824C3
-:10087000A506007203E00008AD6500203C02800080
-:10088000344601803C0580008CA301B80460FFFE63
-:1008900024090018ACC40000A0C9000B8F88002CEC
-:1008A0003C041000950700AEA4C70010ACC0003097
-:1008B00003E00008ACA401B83C028000344501808C
-:1008C0003C0480008C8301B80460FFFE8F8A0034F2
-:1008D000240600199549001C3128FFFF000839C083
-:1008E000ACA70000A0A6000B3C05100003E0000828
-:1008F000AC8501B88F87003C0080402130C400FFE8
-:100900003C0680008CC201B80440FFFE8F89005C69
-:100910009383005834996000ACA90000A0A300059F
-:100920008CE20010240F00022403FFF7A4A20006AB
-:10093000A4B900088D180020A0B8000AA0AF000BD1
-:100940008CEE0000ACAE00108CED0004ACAD0014D9
-:100950008CEC001CACAC00248CEB0020ACAB002871
-:100960008CEA002C3C071000ACAA002C8D09002456
-:10097000ACA90018ACC701B88D05002000A3202445
-:1009800003E00008AD040020938500582403000113
-:1009900027BDFFE800A330042CA20020AFB0001058
-:1009A000AFBF001400C01821104000132410FFFE38
-:1009B0003C0708008CE7319000E610243C088000DA
-:1009C0003505018014400005240600848F89002C21
-:1009D000240A00042410FFFFA12A00EC0E00188E48
-:1009E00000000000020010218FBF00148FB0001023
-:1009F00003E0000827BD00183C0608008CC63194AF
-:100A00000A0018C000C310248F87003427BDFFE000
-:100A1000AFB20018AFB10014AFB00010AFBF001CF0
-:100A200030D000FF90E6000D00A0882100809021CA
-:100A300030C5007FA0E5000D8F85002C8E230018A7
-:100A40008CA200C01062002E240A000E0E0018B303
-:100A5000A38A00582409FFFF104900222404FFFF45
-:100A600052000020000020218E2600003C0C0010C7
-:100A700000CC5824156000393C0E000800CE6824D4
-:100A800055A0003F024020213C18000200D88024DD
-:100A90001200001F3C0A00048F8700348CE200140F
-:100AA0008CE300108CE500140043F82303E5C82B09
-:100AB00013200005024020218E24002C8CF1001010
-:100AC000109100310240202124020012A38200581C
-:100AD0000E0018B32412FFFF105200022404FFFF7F
-:100AE000000020218FBF001C8FB200188FB10014AE
-:100AF0008FB000100080102103E0000827BD002007
-:100B000090A800C4350400200A0018E9A0A400C47D
-:100B100000CA48241520000B8F8B00348F8D0034C1
-:100B20008DAC00101580000B024020218E2E002C71
-:100B300051C0FFEC00002021024020210A001904CE
-:100B4000240200178D66001050C0FFE6000020212F
-:100B5000024020210A001904240200110240202131
-:100B6000240200150E0018B3A3820058240FFFFFC3
-:100B7000104FFFDC2404FFFF0A0018F38E2600004C
-:100B80000A00192A240200143C08000400C8382472
-:100B900050E0FFD400002021024020210A00190467
-:100BA000240200138F86002C27BDFFE0AFB1001494
-:100BB000AFBF0018AFB0001090C300C430A500FF55
-:100BC0003062002010400008008088218CCB00C0DB
-:100BD0002409FFDF256A0001ACCA00C090C800C428
-:100BE00001093824A0C700C414A000403C0C8000B8
-:100BF0008F84002C908700C42418FFBF2406FFEFC9
-:100C000030E3007FA08300C4979F004C8F82005088
-:100C10008F8D002C03E2C823A799004CA5A000AC3F
-:100C200091AF00C401F87024A1AE00C48F8C002CD9
-:100C3000A18000C78F8A002CA5400072AD4000DC67
-:100C4000914500C400A65824A14B00C48F900028F1
-:100C50008F8400509786004C0204282110C0000F9A
-:100C6000AF850028A38000483C0780008E2C000838
-:100C700094ED01208E2B0004018D5021014B802129
-:100C8000020620233086FFFF30C8000F390900011B
-:100C90003131000116200009A388004893860038EE
-:100CA0008FBF00188FB100148FB0001027BD002037
-:100CB000AF85005403E00008AF86005000C87023E1
-:100CC0008FBF0018938600388FB100148FB00010CA
-:100CD00034EF0C00010F282127BD0020ACEE00846A
-:100CE000AF85005403E00008AF86005035900180C6
-:100CF000020028210E00188E240600828F84002C0A
-:100D0000908600C430C5004050A0FFBAA3800058B0
-:100D10008F85003C3C0680008CCD01B805A0FFFE0D
-:100D20008F89005C2408608224070002AE0900005D
-:100D3000A6080008A207000B8CA300083C0E1000B8
-:100D4000AE0300108CA2000CAE0200148CBF001485
-:100D5000AE1F00188CB90018AE1900248CB80024FE
-:100D6000AE1800288CAF0028AE0F002CACCE01B816
-:100D70000A00194EA38000588F8A002C27BDFFE07F
-:100D8000AFB10014AFB000108F880050AFBF001893
-:100D900093890030954200AC30D100FF0109182B37
-:100DA0000080802130AC00FF3047FFFF0000582159
-:100DB00014600003310600FF01203021010958238F
-:100DC0009783004C0068202B1480001B000000005B
-:100DD00010680043240A0001118A004834E70880A3
-:100DE0003165FFFF0E001830020020210E00187040
-:100DF0008F84005C8F84002C948D007025AC0001E2
-:100E0000A48C0070948B00703C0608008CC631885E
-:100E100031677FFF10E6004F000000000200202134
-:100E2000022028218FBF00188FB100148FB000104E
-:100E30000A00193A27BD0020914400C42406FF800F
-:100E400000868825A15100C49784004C3088FFFF9C
-:100E50001100001C938900308F8E002C2419EFFFA5
-:100E6000008BF82395D800AC0168682B33E900FFAC
-:100E700003197824A5CF00AC51A0002A0100582105
-:100E80008E0500202408FFFB2403000100A8102485
-:100E9000AE0200201183002534E7800002002021EB
-:100EA0003165FFFF0E00183001203021978B004C78
-:100EB0008F870050A780004C00EB8023AF9000503C
-:100EC000938900308F8C002C8FBF00188FB10014D5
-:100ED0008FB0001027BD002003E00008A18900C7E3
-:100EE0008E0800202409FFFB34E780000109282434
-:100EF000AE050020158AFFBA34E7088002002021E1
-:100F00000E0017FE3165FFFF02002021022028217C
-:100F10008FBF00188FB100148FB000100A00193A6B
-:100F200027BD00200A0019F10000482102002021FD
-:100F30003165FFFF0E0017FE01203021978B004C1A
-:100F40008F870050A780004C00EB80230A001A0115
-:100F5000AF90005094890070240A8000012A402438
-:100F6000A4880070908500709099007030A200FFF6
-:100F7000000219C20003F827001FC1C0332F007FF1
-:100F800001F87025A08E00700A0019D902002021F6
-:100F90008F88002C24030001910A0078910500C776
-:100FA000250900783147003F24E6FFE000C318041C
-:100FB0002CC2002030670019A38500301040001AB1
-:100FC000AF89003C3C0A8000354B0002240500013B
-:100FD0002406000114E00016006B102400002821F4
-:100FE0001440000F306300201060000F2405000142
-:100FF0008D0600748D1900742403FF8000C3102433
-:10100000000279403338007F01F868253C0E10005B
-:1010100001AE6025AD4C0830912800013106000179
-:101020000A0019AF0000000003E000080000000003
-:101030008D0F00748D0D00742418FF8001F870244A
-:10104000000E414031AC007F010C50253C0B1000DC
-:10105000014B38253C0980000A0019AFAD27083044
-:1010600027BDFFD8AFB000108F90003CAFB4002078
-:10107000AFB10014AFBF0024AFB3001CAFB2001873
-:101080008E0500103C0208008C4231B08F86004073
-:1010900030A73FFF00E2182B8CD20014008088217B
-:1010A0008CD30020106000070000A02190CB000D21
-:1010B000240AFF80014B4824312800FF1500000C52
-:1010C00000056382022020212411000DA391005805
-:1010D0008FBF00248FB400208FB3001C8FB2001884
-:1010E0008FB100148FB000100A0018B327BD00287C
-:1010F0003185000354A0FFF40220202194CF001C6E
-:101100008F8E002C8E070028A5CF00D88CCD001024
-:10111000024D302310E6005C2402001F0E0018B3BD
-:10112000A3820058241FFFFF105F004E2404FFFF1E
-:101130008F8300448F880034026398218D0900104A
-:10114000012310238F830024AD020010AD13002073
-:101150008C67007400F3202B148000620220202191
-:101160008F8600408E0C00248CC50024118500075A
-:1011700002202021240E001C0E0018B3A38E00585C
-:10118000240DFFFF104D00372404FFFF8F8400342F
-:101190008C980024270F0001AC8F002412720044A9
-:1011A0008F9900248F320074125300413C0A008052
-:1011B0008E090000012A10241440003A00000000AB
-:1011C0008E0400142412FFFF10920006240B001B53
-:1011D000022020210E0018B3A38B005810520021CA
-:1011E0002404FFFF8E0300003C0C0001006C282447
-:1011F00010A000133C0600800066A02416800009A1
-:101200000200282102202021240E001A0E0018B30B
-:10121000A38E0058240DFFFF104D00122404FFFF81
-:1012200002002821022020210E0018D324060001EC
-:101230002410FFFF2404FFFF1050000A24140001B3
-:101240008F8F0034022020210280302195F200345B
-:1012500024050001265800010E0019AFA5F800343E
-:10126000000020218FBF00248FB400208FB3001C0A
-:101270008FB200188FB100148FB0001000801021C1
-:1012800003E0000827BD00288F83004400E3C82145
-:101290000259C02B1300FFA88F8800340A001A9847
-:1012A00024020018AC8000200A001AC28E04001428
-:1012B0008E1F00003C07008003E798241660FFF9AA
-:1012C0002408001A022020210E0018B3A388005819
-:1012D0002403FFFF1443FFBA2404FFFF0A001AEBA4
-:1012E0008FBF0024240B001D0E0018B3A38B0058E1
-:1012F000240AFFFF144AFF9A2404FFFF0A001AEB96
-:101300008FBF00248F85002C27BDFFD8AFB3001CF2
-:10131000AFB20018AFB10014AFB00010AFBF0020E3
-:1013200090A700C48F90003C2412FFFF34E20040DD
-:1013300092060000A0A200C48E0300100080982135
-:101340001072000630D1003F2408000D0E0018B3C3
-:10135000A3880058105200262406FFFF8F8A002C15
-:101360008E0900188D4400C011240007240C000EC3
-:10137000026020210E0018B3A38C0058240BFFFF3D
-:10138000104B001B2406FFFF24040020122400043D
-:101390008F8D002C91AF00C435EE0020A1AE00C4AB
-:1013A0008F85004410A0001A000000001224004B9A
-:1013B0008F98002C8F92FEDC2406FFFD97100070A2
-:1013C0009651000A1230000B8FBF00203C1F08000E
-:1013D0008FFF318C03E5C82B1720001E02602021EF
-:1013E000000028210E0019AF240600010000302162
-:1013F0008FBF00208FB3001C8FB200188FB1001474
-:101400008FB0001000C0102103E0000827BD0028A5
-:101410005224002A8E0300148F84002C94890070BB
-:1014200025280001A4880070948700703C050800FE
-:101430008CA5318830E27FFF1045000E00000000CF
-:10144000026020210E00193A240500010A001B4DFC
-:10145000000030212402002DA38200580E0018B392
-:101460002413FFFF1453FFE12406FFFF0A001B4E65
-:101470008FBF00209498007024198000240500017B
-:1014800003199024A492007090910070908D0070C8
-:10149000323000FF001079C2000F7027000E61C0CB
-:1014A00031AB007F016C5025A08A00700E00193A04
-:1014B000026020210A001B4D000030212406FFFF9E
-:1014C0001466FFD68F84002C026020210E00193A8A
-:1014D000240500010A001B4D00003021026020217C
-:1014E0000A001B672402000A8F88002C27BDFFE832
-:1014F000AFB00010AFBF0014910A00C48F87003C4A
-:1015000000808021354900408CE60010A10900C40C
-:101510003C0208008C4231B030C53FFF00A2182BBE
-:10152000106000078F850040240DFF8090AE000DF5
-:1015300001AE6024318B00FF156000080006C382F5
-:10154000020020212403000D8FBF00148FB0001073
-:1015500027BD00180A0018B3A38300583306000300
-:10156000240F000254CFFFF70200202194A2001C98
-:101570008F85002C24190023A4A200D88CE8000039
-:1015800000081E02307F003F13F900353C0A00833B
-:101590008CE800188CA600C01106000800000000AE
-:1015A0002405000E0E0018B3A38500582407FFFF82
-:1015B000104700182404FFFF8F85002C90A900C459
-:1015C00035240020A0A400C48F8C0034918E000D1F
-:1015D00031CD007FA18D000D8F8300441060001C71
-:1015E000020020218F8400408C9800100303782B88
-:1015F00011E0000D2419001802002021A3990058C1
-:101600000E0018B32410FFFF105000022404FFFF47
-:10161000000020218FBF00148FB000100080102127
-:1016200003E0000827BD00188C8600108F9F00344F
-:101630000200202100C31023AFE2001024050001A6
-:101640000E0019AF240600010A001BD6000020215D
-:101650000E00193A240500010A001BD600002021C3
-:10166000010A5824156AFFD98F8C0034A0A600EC1B
-:101670000A001BC3A386004A27BDFFD8AFB00010E5
-:101680008F90003CAFB20018AFBF0020AFB3001C7A
-:10169000AFB100148E1100103C0308008C6331B010
-:1016A00032253FFF00A3102B10400008008090213E
-:1016B0008F8600402409FF8090CA000D012A402433
-:1016C000310700FF14E0000B00116B820240202163
-:1016D0002412000DA39200588FBF00208FB3001C6E
-:1016E0008FB200188FB100148FB000100A0018B329
-:1016F00027BD002831AC0003240B0001558BFFF4FB
-:101700000240202190CF000D31EE000811C0006092
-:101710008F93004416600009240200278E19000CE4
-:101720008CD8002017380005240200208E02000803
-:101730008CDF0024105F0040240200200E0018B34C
-:10174000A38200582406FFFF104600332404FFFF45
-:101750008F990034240AFFF73C13800E9329000D63
-:101760002404FF803C0D8000012AF824A33F000DD3
-:101770008F9900243C0808008D0831AC8F83005CF1
-:10178000972700788F9F00340103102130E57FFFF9
-:10179000000530400046782131F8007F03136021B6
-:1017A00001E47024ADAE002CA59100008FEB002861
-:1017B000256A0001AFEA00288FE3002C8E09002C77
-:1017C00000694021AFE8002C8E07002CAFE7003005
-:1017D0008E050014AFE5003497E6003A24C20001FC
-:1017E000A7E2003A973300783C1008008E1031B021
-:1017F0002663000130717FFF123000270060302126
-:101800008F8F002402402021240500010E00193A88
-:10181000A5E60078000020218FBF00208FB3001CB8
-:101820008FB200188FB100148FB00010008010210B
-:1018300003E0000827BD00288E0500142413FFFFD5
-:1018400010B3001D8F83002C8E0800188C6700C019
-:10185000150700092402000E8E0A00248CC90028F6
-:1018600015490005240200218E0700288CCB002C8E
-:1018700010EB00132402001F0E0018B3A3820058BF
-:101880001453FFB32404FFFF0A001C588FBF00202D
-:101890000A001C2024020024240E8000006E68240C
-:1018A00031ACFFFF000C5BC2317100FF00118027DB
-:1018B0000A001C51001033C00A001C6F24020025CE
-:1018C0008E05002C10A0FFEC240200238F8E002434
-:1018D0008DCD007401A5602B1580FFE72402002642
-:1018E0008CCF001400A7C02101F8202B1080FF9995
-:1018F0008F990034024020210A001C6F240200222C
-:1019000027BDFFE0AFB000108F90003CAFB10014D6
-:10191000AFBF00188E0500103C0308008C6331B087
-:101920000080882130A43FFF0083102B1040000767
-:101930008F8600402409FF8090CA000D012A4024B0
-:10194000310700FF14E000098F8B00442410000DC4
-:1019500002202021A39000588FBF00188FB10014DF
-:101960008FB000100A0018B327BD002011600008D6
-:101970000005C3828F8F002C8F8EFEDC2407FFFDB5
-:1019800095EC007095CD000A11AC00388FBF00189F
-:101990003305000314A0001000000000921900029B
-:1019A00013200041000000008E06002450C0000FEC
-:1019B00092040003022020212402000F0E0018B31D
-:1019C000A38200582408FFFF144800072407FFFFE4
-:1019D0000A001CEC8FBF001890C3000D3064000893
-:1019E0001080003702202021920400032407000207
-:1019F000308900FF15270005308F00FF8F8A0044D3
-:101A000011400031240C002C308F00FF39E500100C
-:101A10002CAD00012DEE00010200282101CD302562
-:101A20000E0018D3022020212410FFFF1050000EBA
-:101A30002407FFFF8F83004410600017022020213D
-:101A40003C1908008F39318C0323C02B5700000C40
-:101A50002411002D02202021000028210E0019AFA2
-:101A600024060001000038218FBF00188FB1001438
-:101A70008FB0001000E0102103E0000827BD002017
-:101A80000E0018B3A39100581450FFF62407FFFF6F
-:101A90000A001CEC8FBF00180E00193A2405000143
-:101AA0000A001CEB000038218CDF00248E02002489
-:101AB000545FFFC1022020210A001CCC92040003C5
-:101AC0000A001CC024020010022020210E0018B3BE
-:101AD000A38C0058240BFFFF104BFFE32407FFFFEC
-:101AE0000A001CD39204000330A500FF2406000165
-:101AF00024A9000100C9102B1040000C0000402157
-:101B0000240A000100A61823308B000124C600011E
-:101B1000006A3804000420421160000200C9182B3A
-:101B2000010740251460FFF800A6182303E0000811
-:101B30000100102127BDFFD8AFB000188F90003CE6
-:101B4000AFB1001CAFBF00202403FFFF2411002F02
-:101B5000AFA3001092060000240500082610000123
-:101B6000006620260E001D0B308400FF00021E00C0
-:101B70003C021EDC34466F410A001D330000102178
-:101B800010A00009008018212445000130A2FFFFA9
-:101B90002C4500080461FFFA00032040008620263F
-:101BA00014A0FFF9008018210E001D0B2405002051
-:101BB0008FA300102629FFFF313100FF00034202EE
-:101BC000240700FF1627FFE2010218260003502712
-:101BD000AFAA0014AFAA00100000302127A80010FF
-:101BE00027A7001400E6782391ED000324CE00011E
-:101BF00000C8602131C600FF2CCB00041560FFF93E
-:101C0000A18D00008FA200108FBF00208FB1001C9B
-:101C10008FB0001803E0000827BD00289383003828
-:101C200027BDFFE024020034AFB10014AFB00010B4
-:101C3000AFBF001CAFB200180080802110620064AA
-:101C400000A0882192240004148000478F88002C73
-:101C5000A38000308E2500048D0700C83C0600FFDD
-:101C600034C3FFFF00A3302400E6102B1440004FC4
-:101C7000AF860044978A004C8F8800500148382373
-:101C800010C00034A787004C8F99002430DF000378
-:101C9000001F20239332007C309000030206702145
-:101CA0000012C082331200010012788001CF682137
-:101CB00030ECFFFF018D582B1160005F8F87002CE7
-:101CC0008F8900288F8200541049005C3C033F013B
-:101CD0008E2500003C11250000A3382414F1007665
-:101CE0008F84003C8F88003C8F87002C8D0A000079
-:101CF000ACEA00788D060010ACE600888F880050B2
-:101D00008F860044938B0030012860210206282131
-:101D1000020B1821A383003094E900ACAF8C00289B
-:101D200035301000A4F000AC1640005024780004B8
-:101D3000AF850050000020218FBF001C8FB200181B
-:101D40008FB100148FB000100080102103E0000854
-:101D500027BD00208F840028AF800050008890218C
-:101D60000A001D9EAF920028241F000CA39F00585C
-:101D70000E0018B3020020212419FFFF1059FFEEB6
-:101D80002404FFFF8F88002CA38000308E250004E0
-:101D90008D0700C83C0600FF34C3FFFF00A33024BA
-:101DA00000E6102B1040FFB3AF8600440200202154
-:101DB00024090019A38900580E0018B32410FFFF4E
-:101DC0001050FFDD2404FFFF0A001D6E8F860044C3
-:101DD0008F84002C8F87003C8CF20030908600C4EA
-:101DE00030C5001014A000108F8300502C6800052F
-:101DF0001500002600000000908A00C4246BFFFC40
-:101E00003149001015200008316400FF8F8D005407
-:101E10008F8C002811AC0004388F000131EE0001D6
-:101E200015C0002D000000000E001D1E0000000067
-:101E30000A001DF5000000008F890028938B0030F8
-:101E40000128602102062821020B1821A3830030FB
-:101E500094E900ACAF8C002835301000A4F000AC41
-:101E60005240FFB4AF85005024780004A39800309E
-:101E700094EE00AC24AF0004AF8F005035CD2000AD
-:101E8000A4ED00AC0A001D9F000020218C8200DC24
-:101E90001242FF6C0200202124180005A39800586C
-:101EA0000E0018B32412FFFF1452FF662404FFFF34
-:101EB0000A001DA08FBF001C310500FF0E0017BADD
-:101EC000000030218F87002C8F8800508F890028D8
-:101ED0000A001D928F8600440E0017E500000000E6
-:101EE0000A001DF5000000009383004A27BDFFE0B3
-:101EF00024020002AFB20018AFB10014AFBF001C43
-:101F000000808821AFB000100000902110620055C1
-:101F10002404FFFD9783004C8F8500503066FFFF3F
-:101F200000C5202B1480005B938700383C0880009C
-:101F30009504012010E500528F8A00288F840054F8
-:101F400030A500FF0E0017BA240600018F9F005C29
-:101F50003C0580003C19408027ED017831B00078C5
-:101F6000240EFF800219582534AF090031B800074C
-:101F700001AE6024ACAC0800030F8021ACAB0810AC
-:101F800002202021020028210E001D58AF90003CA5
-:101F90002403FFFF104300332404FFFF8E0C0010C6
-:101FA0003C0708008CE731B09206000031843FFF07
-:101FB0000087102B1040002330CD003F8F98005C2D
-:101FC000000471803C0408008C8431A82409FF803F
-:101FD0009390004900984021010E2021008970242F
-:101FE000000E51403C0980003099007F3C0F00807A
-:101FF0008F88002C3525094035E20001015938252C
-:10200000308B0078308600073C0310003C1F800CAA
-:1020100000C5C0210162582500E35025033F782107
-:1020200036050001AD2E0804AF980040AD2B081412
-:10203000AF8F0034AD2E0028AD040074AD2A0830F7
-:10204000A38500499383004A2410000350700027A1
-:1020500025A3FFE0240C0001106C001C24060023C3
-:10206000024020218FBF001C8FB200188FB10014D6
-:102070008FB000100080102103E0000827BD002071
-:10208000314900035520FFAE8F8400540A001E31F1
-:102090008F9000548F840054306500FF0E0017BAF3
-:1020A00024060001938B00382405003411650018C4
-:1020B0009783004C8F8500503062FFFF00A25823A9
-:1020C000AF8B00500A001E69A780004C11A6003794
-:1020D00000000000022020212411000B0E0018B384
-:1020E000A39100580A001E69004090212C72002024
-:1020F0001240FFF80003F8803C07080124E781AC98
-:1021000003E7C8218F2D000001A000080000000097
-:102110008F8500502CA200055440001DA780004C64
-:10212000978A004C3148FFFF00A848232D2F000557
-:1021300011E00003314400FF24AEFFFC31C400FF76
-:102140008F9000548F9800281218000438990001CD
-:10215000332D000115A00029000000008F91002CF4
-:10216000922500C434A30010A22300C49783004C1E
-:102170008F8500508F84002C3062FFFF00A258230F
-:10218000AC8000DCA780004C0A001E69AF8B0050B9
-:102190003062FFFF00A258230A001E69AF8B005077
-:1021A0002403FFFF11830005000000000E001B8BBD
-:1021B000022020210A001E69004090210E001B12FF
-:1021C000022020210A001E69004090210E001BEF12
-:1021D000022020210A001E69004090210E001A6989
-:1021E000022020210A001E69004090210E001C914F
-:1021F000022020210A001E69004090210E0017E5F0
-:10220000000000009783004C8F850050306CFFFF6A
-:1022100000AC38232CFF000553E0FFA83062FFFF1D
-:102220008F86002CA780004CACC200DC3062FFFF20
-:1022300000A258230A001E69AF8B005027BDFFD0B3
-:10224000AFB20018AFB00010AFBF0028AFB5002488
-:10225000AFB40020AFB3001CAFB100143C0C800041
-:102260008D880128240FFF803C07800A251001007B
-:10227000250B0080020F68243205007F016F702457
-:10228000AD8E009000A72821AD8D002490A700EC12
-:102290003169007F3C0A8004012A1821A387004A83
-:1022A0009066007C00809021AF83002430C2000241
-:1022B000AF88005CAF85002C00A0182114400002FC
-:1022C0002404003424040030A38400388C6600CC3D
-:1022D00030F100FF24040004AF86005012240004F3
-:1022E000A38000588E5300041660001D3C08800037
-:1022F0009387004930F200011240000F8FBF002881
-:102300008CB800748CA400742419FF8003198824ED
-:1023100000117140308F007F01CF60253C0D2000FF
-:10232000018D582530F500FE3C0A8000AD4B083089
-:10233000A39500498FBF00288FB500248FB40020DB
-:102340008FB3001C8FB200188FB100148FB0001033
-:102350002402000127BD003003E00008ACA600CC39
-:102360008E590008951F01208E460010033FC021A2
-:102370003307FFFF30F5000F32B40001AF860028AD
-:102380001680003BA395004835060C0002A61021DC
-:1023900000F51823AD030084AF8200548E49000479
-:1023A0003128FFFF1100002BA789004C2410FF806B
-:1023B0003C1580003C1420000A001F572413FFFE28
-:1023C00090AE00C4020E682431AC00FF1580002AD4
-:1023D00002402021938400499786004C308F0001F1
-:1023E00011E0000B026428248F89002C8D230074D7
-:1023F0008D280074A3850049007010240002C94094
-:10240000311F007F033FC02503148825AEB108307B
-:1024100010C000108F85002C90A700C4020758241C
-:10242000316A00FF1540FFE6024020210E001E0B1E
-:102430009791004C1040FFE8938400492405FFFD6C
-:10244000544500058E430020022028210E001790DD
-:10245000024020218E430020307000041600000A44
-:102460002414FFFB8F85002C0A001F0D8F8600505F
-:102470000A001F38AF8600540E001A350000000015
-:102480000A001F4793840049007498240E0017AA7D
-:10249000AE5300208F85002C0A001F0D8F86005040
-:1024A00027BDFFD8AFB3001CAFB10014AFBF0020F1
-:1024B000AFB20018AFB000103C0280008C52014057
-:1024C0008C4B01483C048000000B8C02322300FF3F
-:1024D000317300FF8C8501B804A0FFFE34900180A9
-:1024E000AE1200008C8701442464FFF02406000231
-:1024F0002C830013AE070004A6110008A206000BEF
-:10250000AE1300241060004F8FBF002000044880ED
-:102510003C0A0801254A822C012A40218D04000032
-:1025200000800008000000003C1008008E1031A858
-:1025300031733FFF001389800212C8212405FF80F8
-:1025400003312021264C0100264700803C1F8000DB
-:1025500000E51824318F007F30E9007F308A007F4A
-:102560003C18800A3C0E80043C0D800C0085102431
-:1025700001853024014D8021AFE6002401F840217F
-:10258000AFE30090012E9821AFE20028AF90003415
-:10259000AF88002CAF9300240E00187F01608021CB
-:1025A0003C0380008C6B01B80560FFFE8F87003410
-:1025B000346501808F86002C90E3000DACB20000E2
-:1025C000A4B00006000316000002FE03001F9027BF
-:1025D000001227C21080007A24C200782419608279
-:1025E000A4B90008A0A00005241F0002A0BF000B92
-:1025F00000041C008F8B00243C0227000062902501
-:10260000ACB20010ACA00014ACA00024ACA0002818
-:10261000ACA0002C8D7300382410FF80ACB30018E0
-:1026200090E4000D02048824322500FF10A000056C
-:102630008FBF002090EC000D3188007FA0E8000DD6
-:102640008FBF00208FB3001C8FB200188FB1001411
-:102650008FB000103C0D10003C0A800027BD002800
-:1026600003E00008AD4D01B8265F01002405FF809E
-:1026700033F8007F3C06800003E578243C19800A8B
-:1026800003192021ACCF0024908E00C400AE682432
-:1026900031AC00FF1180FFEAAF84002C248E00785B
-:1026A00095CD00123C0C08008D8C31A831AB3FFF5A
-:1026B00001924821000B5180012A4021010520246C
-:1026C000ACC400283107007F3C06800C00E62021C6
-:1026D0009083000D00A31024304500FF10A0FFD808
-:1026E000AF8400349098000D330F001015E0FFD533
-:1026F0008FBF00200E00187F000000003C03800008
-:102700008C7901B80720FFFE00000000AE12000027
-:102710008C720144AE120004A611000824110002BC
-:10272000A211000BAE1300240A001FE28FBF00208D
-:102730003C1260008E452C083C03F0033462FFFF1E
-:1027400000A2F824AE5F2C088E582C083C1901B06A
-:1027500003199825AE532C080A001FE28FBF0020F2
-:10276000264D010031AF007F3C10800A240EFF800F
-:1027700001F0282101AE60243C0B8000AD6C0024E8
-:102780001660FFAFAF85002C24110003A0B100EC50
-:102790000A001FE28FBF002026480100310A007F97
-:1027A0003C0B800A2409FF80014B302101092024C1
-:1027B0003C078000ACE400240A001FE1AF86002C37
-:1027C000944A001232083FFF314C3FFF1588FF84C6
-:1027D0002419608290CF00C4240EFF8001CF4824CA
-:1027E000312D00FF11A0FF7E00000000240700042F
-:1027F000A0C700EC8F870034241860842406000DE5
-:10280000A4B80008A0A600050A001FCC241F0002DF
-:102810000800330C0800330C080033E8080033BC10
-:10282000080033A0080032F0080032F0080032F04F
-:102830000800331480080100800800808008000030
-:102840005F865437E4AC62CC50103A453662198545
-:10285000BF14C0E81BC27A1E84F4B556094EA6FE0A
-:102860007DDA01E7C04D748108007AE408007B300E
-:1028700008007AF008007A1808007AF008007B2037
-:1028800008007AF008007A1808007A1808007A1808
-:1028900008007A1808007A1808007A1808007A18D0
-:1028A00008007A1808007A1808007A1808007B10C7
-:1028B00008007B0008007A1808007A1808007A18C7
-:1028C00008007A1808007A1808007A1808007A18A0
-:1028D00008007A1808007A1808007A1808007A1890
-:1028E00008007A1808007B00080080DC08007F845C
-:1028F000080080A408007F840800807408007E6CB3
-:1029000008007F8408007F8408007F8408007F849B
-:1029100008007F8408007F8408007F8408007F848B
-:1029200008007F8408007F8408007F8408007F847B
-:0429300008007FAC70
-:0C2934000A00012200000000000000006A
-:102940000000000D747061352E302E306A390000A1
-:102950000500000100000000000000000000000071
-:102960000000000000000000000000000000000067
-:102970000000000000000000000000000000000057
-:102980000000000000000000000000000000000047
-:102990000000000000000000000000000000000037
-:1029A0000000000000000000000000000000000027
-:1029B0000000000000000000000000000000000017
-:1029C00010000003000000000000000D0000000DDA
-:1029D0003C02080024421C203C03080024631FA082
-:1029E000AC4000000043202B1480FFFD2442000473
-:1029F0003C1D080037BD2FFC03A0F0213C1008004F
-:102A0000261004883C1C0800279C1C200E0002E2B3
-:102A1000000000000000000D2402FF8027BDFFE041
-:102A200000821024AFB00010AF420020AFBF0018EA
-:102A3000AFB10014936500043084007F0344182173
-:102A40003C0200080062182130A5002003608021AC
-:102A50003C080111277B000814A000022466005CDA
-:102A60002466005892020004974301049204000473
-:102A70003047000F3063FFFF308400400067282399
-:102A80001080000900004821920200053042000435
-:102A9000104000050000000010A00003000000002E
-:102AA00024A5FFFC24090004920200053042000422
-:102AB000104000120000000010A0001000000000F4
-:102AC0009602000200A72021010440252442FFFEB7
-:102AD000A7421016920300042402FF800043102432
-:102AE000304200FF104000033C0204000A00017263
-:102AF000010240258CC20000AF4210188F420178BD
-:102B00000440FFFE2402000AA74201409602000290
-:102B1000240400093042000700021023304200075D
-:102B2000A7420142960200022442FFFEA74201444E
-:102B3000A740014697420104A74201488F4201087D
-:102B400030420020504000012404000192020004A1
-:102B5000304200101440000234830010008018211D
-:102B6000A743014A00000000000000000000000030
-:102B700000000000AF48100000000000000000004E
-:102B800000000000000000008F4210000441FFFE22
-:102B90003102FFFF10400007000000009202000415
-:102BA0003042004014400003000000008F42101823
-:102BB000ACC20000960200063042FFFF2442000231
-:102BC0000002104300021040036288219622000098
-:102BD0001120000D3044FFFF00A710218F83003823
-:102BE0008F45101C0002108200021080004310214B
-:102BF000AC45000030A6FFFF0E0002D100052C02FC
-:102C000000402021A6220000920300042402FF803D
-:102C100000431024304200FF1040001F000000005D
-:102C200092020005304200021040001B000000002C
-:102C30009742100C2442FFFEA7421016000000002D
-:102C40003C02040034420030AF421000000000009B
-:102C50000000000000000000000000008F42100093
-:102C60000441FFFE000000009742100C8F45101C2D
-:102C70003042FFFF24420030000210820002108028
-:102C8000005B1021AC45000030A6FFFF0E0002D112
-:102C900000052C02A62200009604000224840008ED
-:102CA0000E0001E73084FFFF974401040E0001F598
-:102CB0003084FFFF8FBF00188FB100148FB0001059
-:102CC0003C02100027BD002003E00008AF4201785D
-:102CD0003084FFFF308200078F85002410400002FF
-:102CE000248300073064FFF800A4102130421FFF46
-:102CF00003421821247B4000AF850028AF820024C6
-:102D000003E00008AF4200843084FFFF3082000FF0
-:102D10008F85002C8F860034104000022483000F22
-:102D20003064FFF000A410210046182BAF8500305E
-:102D30000046202314600002AF82002CAF84002CD8
-:102D40008F82002C34048000034218210064182173
-:102D5000AF83003803E00008AF4200808F82001488
-:102D6000104000088F8200048F82FFCC14400005C1
-:102D70008F8200043C02FFBF3442FFFF0082202408
-:102D80008F82000430430006240200021062000F0C
-:102D90003C0201012C6200035040000524020004A3
-:102DA0001060000F3C0200010A00022E000000002B
-:102DB00010620005240200061462000C3C0201119E
-:102DC0000A000227008210253C0200110082102513
-:102DD000AF421000240200010A00022EAF82000C54
-:102DE00000821025AF421000AF80000C00000000F0
-:102DF000000000000000000003E0000800000000E8
-:102E00008F82000C10400004000000008F42100070
-:102E10000441FFFE0000000003E000080000000085
-:102E20008F8200102443F800000229C224A2FFF080
-:102E30002C63030110600003000210420A000255D7
-:102E4000AC8200008F83001800A3102B1440000BED
-:102E50000000382100A31023244600018F82001CAB
-:102E6000006210212442FFFF0045102B5440000453
-:102E70002402FFFF0A000255AC8600002402FFFF77
-:102E80000A00025AAC8200008C8200003C03080059
-:102E900024631C5C000211400043382103E0000859
-:102EA00000E010213C0908008D291D8000045140DC
-:102EB0003C19080027391C5C00C078210080602183
-:102EC000240EFFFF00003821015940211120003657
-:102ED000000030213C18080027181D983C0D080000
-:102EE00025AD1D9C000F582B0006118000461021B7
-:102EF000000218C0007810218C42000015820020CA
-:102F0000006D20218CA20000544000098D020018A1
-:102F10003C0208008C421D8424420001AC82000067
-:102F20003C010800AC221D840A0002CF00002021D1
-:102F30008F47002000003021000211C01160004ABC
-:102F4000AF4200208D08001C3C0900088CA3000043
-:102F50000066182100031880007A10210049102112
-:102F60008C44000024C600010068182100CF102BFB
-:102F70001440FFF6AC6400000A0002CD000000001F
-:102F80008C840000008E102B5040000424C60001E9
-:102F90000080702100C0382124C6000100C9102B18
-:102FA0001440FFD20006118024020001ACA20000F0
-:102FB0003C0208008C421D7C3C0308008C631D8091
-:102FC0000043102B1440002A2404FFFE0159102155
-:102FD0008C420018104000262404FFFF00072180C7
-:102FE0003C0508008CA51D84008720218D06001853
-:102FF000000420C03C02080024421D9800821021D9
-:103000003C03080024631D9CAC4C000024A5000177
-:10301000008318213C02080024421DA0AC6500007A
-:10302000000631C03C010800AC251D84008220212F
-:103030008F470020AD04001CAF46002011E0000ABD
-:10304000000030213C020008034228218CA200002D
-:1030500024C6000100CF182BAC82000024A5000478
-:103060001460FFFA24840004AF47002000002021F0
-:1030700003E00008008010213084FFFF30C6FFFF0E
-:1030800000052C0000A628253882FFFF00451021EE
-:103090000045282B0045102100021C023042FFFF92
-:1030A0000043102100021C023042FFFF00431021A8
-:1030B0003842FFFF03E000083042FFFF27BDFFC892
-:1030C000AFBF0030AFB3002CAFB20028AFB10024C7
-:1030D000AFB000203C0460088C8250002403FF7FC6
-:1030E0003C066000004310243442380CAC8250008F
-:1030F0008CC24C1C3C1A8000000216023042000FA9
-:1031000010400007AF82001C8CC34C1C3C02001F07
-:103110003442FC0000621824000319C2AF83001877
-:103120008F420008275B400034420001AF42000894
-:10313000AF8000243C02601CAF400080AF400084A0
-:103140008C4500088CC3080834028000034220210B
-:103150002402FFF0006218243C0200803C010800B9
-:10316000AC2204203C025709AF84003814620004EA
-:10317000AF850034240200010A000314AF8200145A
-:10318000AF8000142403003D240200043C01080029
-:10319000AC221D943C010800AC231D903C010800AA
-:1031A000AC231D8C3C010800AC231D883C13080097
-:1031B00026731C5C240400043C02080024421C7496
-:1031C000240300082463FFFFAC400004AC4000006F
-:1031D0000461FFFC24420020000410C000441021C0
-:1031E0002442003D3C010800AC221D902402000155
-:1031F0003C010800AC221D7C2402FFFF3C010800BA
-:10320000AC221D983C010800AC201D848F420000B8
-:1032100038420001304200011440FFFC8F8200144C
-:103220001040001600000000974201041040000505
-:103230008F830000146000072462FFFF0A00034B25
-:103240002C62000A2C620010504000048F830000A2
-:1032500024620001AF8200008F8300002C62000A0C
-:10326000144000032C6200070A000352AF80FFCC19
-:103270001040000224020001AF82FFCC8F430108FE
-:103280008F44010030622000AF830004104000082A
-:10329000AF8400103C0208008C42042C2442000140
-:1032A0003C010800AC22042C0A0006D73C02400076
-:1032B0003065020014A0000324020F0014820309E9
-:1032C00024020D0097420104104003713C024000AB
-:1032D00030624000144000AD8F8200388C440008FA
-:1032E0008F4201780440FFFE24020800AF420178BB
-:1032F00024020008A7420140A7400142974201046E
-:103300008F8400043051FFFF30820001104000071D
-:10331000022080212623FFFE240200023070FFFFDE
-:10332000A74201460A00037FA7430148A740014680
-:103330003C0208008C42043C1440000D8F830010B6
-:1033400030820020144000022403000924030001FD
-:10335000006020218F8300102402090050620001C8
-:1033600034840004A744014A0A00039A00000000C4
-:1033700024020F0014620005308200201440000671
-:103380002403000D0A0003992403000514400002E1
-:103390002403000924030001A743014A3C0208005A
-:1033A0008C4204203C0400480E00020A0044202500
-:1033B0000E000233000000008F82000C1040003E1F
-:1033C000000000008F4210003C0300200043102446
-:1033D000104000398F820004304200021040003655
-:1033E0000000000097421014144000330000000059
-:1033F000974210088F8800383042FFFF24420006B1
-:10340000000218820003388000E8302130430001B8
-:103410008CC4000010600004304200030000000D66
-:103420000A0003DB00E81021544000103084FFFF45
-:103430003C05FFFF00852024008518260003182B7B
-:103440000004102B00431024104000050000000071
-:10345000000000000000000D000000002400021C1D
-:103460008CC200000A0003DA004520253883FFFFE4
-:103470000003182B0004102B0043102410400005FB
-:1034800000000000000000000000000D000000002F
-:10349000240002258CC200003444FFFF00E8102104
-:1034A000AC4400003C0208008C420430244200017D
-:1034B0003C010800AC2204308F6200008F84003889
-:1034C000AF8200088C8300003402FFFF1462000FFB
-:1034D000000010213C0508008CA504543C040800A1
-:1034E0008C84045000B0282100B0302B00822021B1
-:1034F000008620213C010800AC2504543C01080052
-:10350000AC2404500A0006CD240400088C8200007C
-:10351000304201001040000F000010213C0508005F
-:103520008CA5044C3C0408008C84044800B028217D
-:1035300000B0302B00822021008620213C010800B1
-:10354000AC25044C3C010800AC2404480A0006CD1C
-:10355000240400083C0508008CA504443C04080031
-:103560008C84044000B0282100B0302B0082202140
-:10357000008620213C010800AC2504443C010800E1
-:10358000AC2404400A0006CD240400088F62000821
-:103590008F62000000021602304300F02402003067
-:1035A00010620005240200401062016B8F8200202F
-:1035B0000A0006D52442000114A000050000000006
-:1035C000000000000000000D000000002400025078
-:1035D0008F4201780440FFFE000000000E00023B15
-:1035E00027A40010144000050040802100000000C6
-:1035F0000000000D00000000240002578E020000B1
-:103600001040000500000000000000000000000D58
-:10361000000000002400025A8F62000C04430003E3
-:10362000240200010A00055DAE000000AE020000A9
-:103630008F8200388C450008A20000078F65000CBF
-:103640008F64000430A3FFFF0004240200852023C0
-:10365000308200FF004310212442000500028883CD
-:103660002E220081A605000A14400005A2040004D1
-:10367000000000000000000D0000000024000272A5
-:103680003C0708008CE71D808FA800102409FFFF6D
-:103690000000502110E00013000030213C0C080015
-:1036A000258C1D9C01802821000018218CA2FFFC84
-:1036B0005102002F006C18218CA400002463020822
-:1036C0000089102B1040000324A502080080482127
-:1036D00000C0502124C6000100C7102B5440FFF445
-:1036E0008CA2FFFC3C0508008CA51D803C02080054
-:1036F0008C421D7C3C09080025291C603C03080005
-:1037000024631D9800A2102B3C0C0800258C1D9CE6
-:103710003C0408008C841D843C0B0800256B1DA014
-:103720001040001A000831400005118000451021AA
-:10373000000210C000C9382124840001004B302150
-:103740000043182124A50001004C1021AC680000A2
-:10375000ACE600183C010800AC241D84AC44000019
-:103760003C010800AC251D800A0004A88E04001C42
-:103770003C0208008C421D84244200013C010800E8
-:10378000AC221D840A0004A7AC620000000A11806C
-:10379000004A1021000210C0004328218CA3000021
-:1037A000004C3821248400010003194000C9302155
-:1037B00000691821004B1021ACA80000AC60001873
-:1037C0003C010800AC241D84ACC20018ACE400002D
-:1037D0008E04001C8F8500380E0006E70220302181
-:1037E0008F6200048F430108A60200083C0210000B
-:1037F00000621824106000080000000097420104D5
-:10380000920300072442FFEC346300023045FFFFBF
-:103810000A0004BCA2030007974201042442FFF0FF
-:103820003045FFFF960600082CC2001354400005E7
-:10383000920300079202000734420001A20200072F
-:103840009203000724020001106200052402000315
-:103850001062000B30C7FFFF0A0004DB24E2000205
-:103860008F8200383C04FFFF8C43000C0064182456
-:1038700000651825AC43000C0A0004DA30C7FFFFCE
-:103880008F8200383C04FFFF8C4300100064182432
-:1038900000651825AC43001030C7FFFF24E200028A
-:1038A00000021083A20200058F830038304200FF1F
-:1038B00000021080004330218CC500008CC2000043
-:1038C0002403000400021702144300130000000048
-:1038D000974201043C03FFFF00A318243042FFFF7E
-:1038E000004710232442FFFE00622825ACC50000DB
-:1038F000920400058E03001C308200FF000210803D
-:1039000000431021904200003042000F004410217B
-:103910000A000510A20200068CC4000497420104AC
-:103920009603000A3085FFFF3042FFFF0047102357
-:103930002442FFD60002140000A22825ACC50004D2
-:1039400092020007920400052463002800031883F4
-:103950000064182134420004A2030006A2020007FA
-:103960008F8200042403FFFB344200020043102432
-:10397000AF820004920300068E07001C8F86003879
-:1039800000031880006710218C44000C3C02FFF6F5
-:103990003442FFFF0082282400661821AE04000C88
-:1039A000AC65000C920300068E04000C3C02FF7F05
-:1039B0003442FFFF0003188000A228240082202444
-:1039C00000671821AE04000CAC65000C92020006E2
-:1039D000000210800047102194450012AC450010F1
-:1039E000920200060002108000461021AC45001033
-:1039F0008FA20010920300050002114000031880FE
-:103A000000671821005320218C6200048C83001869
-:103A10001460000EAE0200143C0308008C631D8C81
-:103A2000AC8300183C0208008C421D900062102BF1
-:103A300010400019000000003C0208008C421D9458
-:103A4000006210213C010800AC221D8C8E0200187F
-:103A50008F48002000003021000211C01220000B0E
-:103A6000AF4200203C0200080342282100E0202150
-:103A70008C82000024C6000100D1182BACA20000EB
-:103A8000248400041460FFFA24A50004AF48002039
-:103A90000A00055E24020010000000000000000D76
-:103AA00000000000240002D424020010A7420140BC
-:103AB00024020002A7400142A7400144A742014658
-:103AC000974201043C0400082442FFFEA74201483B
-:103AD000240200010E00020AA742014A9603000ACE
-:103AE00092020004004310212442000230420007E9
-:103AF00000021023304200070E000233AE02001015
-:103B00008F6200003C0308008C630444240400100E
-:103B1000AF820008974201043042FFFF2442FFFEBB
-:103B200000403821000237C33C0208008C420440A8
-:103B3000006718210067282B00461021004510213E
-:103B40003C010800AC2304443C010800AC220440C2
-:103B50000A0006620000000014A00005000000003A
-:103B6000000000000000000D00000000240003041D
-:103B70008F4201780440FFFE000000000E00023B6F
-:103B800027A400141440000500408021000000001C
-:103B90000000000D000000002400030B920600044A
-:103BA0008FA4001427A50018000630820E00025CC6
-:103BB000AFA00018504000068E0200000000000078
-:103BC0000000000D00000000240003118E02000020
-:103BD0005440000692020007000000000000000DA3
-:103BE0000000000024000316920200073042000487
-:103BF000104000058F8200042403FFFB34420002C2
-:103C000000431024AF8200048F62000404430009C3
-:103C100092020007920200068E03001C8E04000C24
-:103C20000002108000431021AC44000CAE000000E4
-:103C300092020007304200045440000B920300043B
-:103C4000920300058E0400148E05001C00031880EA
-:103C50003C0200010082202100651821AE040014FE
-:103C6000AC640004920300049602000A0062102172
-:103C700024420005000290838FA200181040000D1E
-:103C8000277100088FA40014000310820242302321
-:103C900027A500180E00025CAFA2001850400006D5
-:103CA0008E05001C000000000000000D0000000058
-:103CB0002400033F8E05001C022020210E0006E791
-:103CC00002403021920400068F6500043C027FFF11
-:103CD00000042080009120218C8300043442FFFFE7
-:103CE00000A2282400651821AC830004920200077A
-:103CF00092030004920500053042000410400014B5
-:103D00009607000830A500FF0005288000B1282193
-:103D10008CA40004974201049606000A306300FF59
-:103D20003042FFFF004310210046102130E3FFFF27
-:103D3000004310232442FFD83084FFFF0002140008
-:103D400000822025ACA400040A0006169203000796
-:103D500030A500FF0005288000B128218CA40000B8
-:103D600097420104306300FF3042FFFF00431021FF
-:103D7000004710233C03FFFF008320243042FFFF55
-:103D800000822025ACA40000920300072402000159
-:103D900010620006000000002402000310620011FF
-:103DA000000000000A0006398E030010974201044B
-:103DB000920300049605000A8E24000C0043102193
-:103DC000004510212442FFF23C03FFFF0083202422
-:103DD0003042FFFF00822025AE24000C0A00063985
-:103DE0008E03001097420104920300049605000A16
-:103DF0008E24001000431021004510212442FFEEC4
-:103E00003C03FFFF008320243042FFFF0082202577
-:103E1000AE2400108E0300102402000AA7420140C5
-:103E2000A74301429603000A920200043C040040AA
-:103E300000431021A7420144A740014697420104D4
-:103E4000A7420148240200010E00020AA742014ACB
-:103E50000E000233000000008F6200009203000495
-:103E600000002021AF820008974201049606000A54
-:103E70003042FFFF00621821006028213C03080047
-:103E80008C6304443C0208008C4204400065182105
-:103E9000004410210065382B004710213C01080028
-:103EA000AC2304443C010800AC220440920400040A
-:103EB000008620212484000A3084FFFF0E0001E7E1
-:103EC00000000000974401043084FFFF0E0001F55C
-:103ED000000000003C021000AF4201780A0006D446
-:103EE0008F8200201482002730620006974201046E
-:103EF000104000673C024000306240001040000566
-:103F000000000000000000000000000D00000000A4
-:103F10002400041A8F4201780440FFFE24020800A6
-:103F2000AF42017824020008A7420140A7400142A5
-:103F30008F820004974301043042000110400007C3
-:103F40003070FFFF2603FFFE24020002A742014655
-:103F5000A74301480A00068C2402000DA740014631
-:103F60002402000DA742014A8F62000024040008C9
-:103F7000AF8200080E0001E7000000000A0006669C
-:103F800002002021104000423C02400093620000E9
-:103F9000304300F02402001010620005240200707B
-:103FA000106200358F8200200A0006D524420001ED
-:103FB0008F620000974301043050FFFF3071FFFF14
-:103FC0008F4201780440FFFE3202000700021023F6
-:103FD000304200072403000A2604FFFEA7430140E5
-:103FE000A7420142A7440144A7400146A751014806
-:103FF0008F420108304200201440000224030009CF
-:1040000024030001A743014A0E00020A3C040040B9
-:104010000E000233000000003C0708008CE7044457
-:10402000021110212442FFFE3C0608008CC6044009
-:104030000040182100E33821000010218F650000A6
-:1040400000E3402B00C230212604000800C83021C4
-:104050003084FFFFAF8500083C010800AC27044412
-:104060003C010800AC2604400E0001E700000000FF
-:104070000A000666022020210E000139000000001F
-:104080008F82002024420001AF8200203C024000C9
-:10409000AF4201380A000336000000003084FFFF01
-:1040A00030A5FFFF0000182110800007000000006D
-:1040B00030820001104000020004204200651821F7
-:1040C0000A0006DD0005284003E00008006010211A
-:1040D00010C0000624C6FFFF8CA2000024A5000427
-:1040E000AC8200000A0006E72484000403E0000814
-:1040F0000000000010A0000824A3FFFFAC86000011
-:1041000000000000000000002402FFFF2463FFFF06
-:104110001462FFFA2484000403E000080000000099
-:04412000000000019A
-:0C4124000A00002A00000000000000005B
-:104130000000000D747870352E302E306A39000082
-:10414000050000000000000A000001360000EA60DF
-:10415000000000000000000000000000000000005F
-:10416000000000000000000000000000000000004F
-:10417000000000000000000000000000000000003F
-:104180000000000000000016000000000000000019
-:10419000000000000000000000000000000000001F
-:1041A000000000000000000000000000000000000F
-:1041B0000000000000000000000000000000138864
-:1041C00000000000000005DC00000000000000000E
-:1041D00010000003000000000000000D0000000DB2
-:1041E0003C020800244238603C03080024633B146E
-:1041F000AC4000000043202B1480FFFD244200044B
-:104200003C1D080037BD7FFC03A0F0213C100800D6
-:10421000261000A83C1C0800279C38600E000407EC
-:10422000000000000000000D8F86003C3C03900061
-:104230003C0280000086282500A32025AC440020F5
-:104240003C0380008C67002004E0FFFE00000000BB
-:1042500003E00008000000000A00004124040001FF
-:104260008F85003C3C0480003483000100A31025AE
-:1042700003E00008AC82002003E0000800001021E9
-:104280003084FFFF30A5FFFF1080000700001821D9
-:104290003082000110400002000420420065182115
-:1042A0001480FFFB0005284003E000080060102197
-:1042B00010C00007000000008CA2000024C6FFFF11
-:1042C00024A50004AC82000014C0FFFB2484000479
-:1042D00003E000080000000010A0000824A3FFFF76
-:1042E000AC86000000000000000000002402FFFF78
-:1042F0002463FFFF1462FFFA2484000403E0000833
-:104300000000000090AA00318FAB00108CAC004080
-:104310003C0300FF8D680004AD6C00208CAD0044B0
-:1043200000E060213462FFFFAD6D00248CA70048DF
-:104330003C09FF000109C024AD6700288CAE004C89
-:104340000182C82403197825AD6F0004AD6E002CDE
-:104350008CAD0038314A00FFAD6D001C94A90032CD
-:104360003128FFFFAD68001090A70030A560000263
-:10437000A1600004A167000090A30032306200FF3A
-:104380000002198210600005240500011065000E6E
-:104390000000000003E00008A16A00018CD800289A
-:1043A000354A0080AD7800188CCF0014AD6F001432
-:1043B0008CCE0030AD6E00088CC4002CA16A0001C8
-:1043C00003E00008AD64000C8CCD001CAD6D00183E
-:1043D0008CC90014AD6900148CC80024AD680008B5
-:1043E0008CC70020AD67000C8CC200148C83007059
-:1043F0000043C82B13200007000000008CC20014EB
-:10440000144CFFE400000000354A008003E000087F
-:10441000A16A00018C8200700A0000B70000000051
-:104420009089003027BDFFF88FA8001CA3A90000C9
-:104430008FA300003C0DFF8035A2FFFF8CAC002C49
-:1044400000625824AFAB0000A100000400C0582156
-:10445000A7A000028D06000400A048210167C82122
-:104460008FA50000008050213C18FF7F032C2026E0
-:104470003C0E00FF2C8C0001370FFFFF35CDFFFFF6
-:104480003C02FF0000AFC82400EDC02400C2782425
-:10449000000C1DC00323682501F87025AD0D000038
-:1044A000AD0E00048D240024AFAD0000AD04000863
-:1044B0008D2C00202404FFFFAD0C000C954700322A
-:1044C00030E6FFFFAD0600109145004830A200FF26
-:1044D000000219C2506000018D240034AD040014A4
-:1044E0008D4700388FAA001827BD0008AD0B0028A3
-:1044F000AD0A0024AD07001CAD00002CAD00001873
-:1045000003E00008AD00002027BDFFE0AFB20018B7
-:10451000AFB10014AFB00010AFBF001C90980030D6
-:1045200000C088213C0D00FF330F007FA0CF0000AA
-:10453000908E003135ACFFFF3C0AFF00A0CE000199
-:1045400094A6001EA22000048CAB00148E29000447
-:1045500000A08021016C2824012A402400809021A1
-:1045600001052025A6260002AE2400042605002011
-:10457000262400080E000063240600029247003043
-:10458000260500282624001400071E000003160339
-:1045900024060004044000032403FFFF9659003260
-:1045A0003323FFFF0E000063AE23001026240024F7
-:1045B0008FBF001C8FB200188FB100148FB0001095
-:1045C00024050003000030210A00006D27BD0020F3
-:1045D00027BDFFD8AFB1001CAFB00018AFBF00209F
-:1045E00090A900302402000100E050213123003F57
-:1045F00000A040218FB000400080882100C04821E9
-:10460000106200148FA70038240B000500A02021A1
-:1046100000C02821106B0013020030210E0000F9A9
-:10462000000000009225007C30A4000210800003EE
-:1046300026030030AE000030260300348FBF002078
-:104640008FB1001C8FB000180060102103E000083B
-:1046500027BD00280E000078AFB000100A0001400E
-:10466000000000008FA3003C010020210120282130
-:1046700001403021AFA300100E0000BFAFB0001406
-:104680000A000140000000003C0580008CA30E10D1
-:104690008F840044AC8300208CA20E1803E0000835
-:1046A000AC8200243C0580008CA30E148F8400444F
-:1046B000AC8300208CA20E1C03E00008AC82002416
-:1046C0009382000C1040001B2483000F2404FFF091
-:1046D0000064382410E00019978B00109784000EB6
-:1046E0009389000D3C0A601C0A00017B0164402391
-:1046F00001037021006428231126000231C2FFFF4C
-:1047000030A2FFFF0047302B50C0000E00E44821CC
-:104710008D4D000C31A3FFFF00036400000C2C033F
-:1047200004A1FFF30000302130637FFF0A00017312
-:104730002406000103E00008000000009784000E3A
-:1047400000E448213123FFFF3168FFFF0068382B68
-:1047500054E0FFF8A783000E938A000D1140000576
-:10476000240F0001006BC023A380000D03E00008AC
-:10477000A798000E006BC023A38F000D03E0000874
-:10478000A798000E03E000080000000027BDFFE826
-:10479000AFB000103084FFFF3C10800093A8002BC6
-:1047A000AFBF0014A6040144960A0E1630C600FFDF
-:1047B0008FA90030A60A0146AE050148A2060152A3
-:1047C000A608015AAE0701608FA3002CA609015864
-:1047D000012020210E000167AE0301543C021000AD
-:1047E000AE0201788FBF00148FB0001003E0000804
-:1047F00027BD00188F8500002484000727BDFFF81F
-:104800003084FFF83C06800094CB008A316AFFFFB9
-:10481000AFAA00008FA90000012540232507FFFF54
-:1048200030E31FFF0064102B1440FFF7000568827F
-:10483000000D288034CC400000AC102103E00008BB
-:1048400027BD00088F8200002486000730C5FFF8CE
-:1048500000A2182130641FFF03E00008AF840000AD
-:104860008F8500448F8A003C27BDFFB03C04800048
-:10487000AFB70044AFB40038AFB1002CAFBF0048B1
-:10488000AFB60040AFB5003CAFB30034AFB20030BC
-:10489000AFB000288C8701048CA90024AC8A00806A
-:1048A0008CA8002000E988230000B821AC880E10F5
-:1048B0008CA600240000A021AC860E188C820E105D
-:1048C000AC820E148C830E18AC830E1C122000FBDD
-:1048D0003C168000936B0008116000F1000000009E
-:1048E000976E001031CDFFFF022D602B158000EC7C
-:1048F0000000000097700010320FFFFFAECF0E00D7
-:104900003C0580008CB30000327200081240FFFDAD
-:104910000000000094B50E088CA70E0432A5FFFF1E
-:1049200030B40001128000E1000000000000000D22
-:1049300030B9A040241800401338011730B4A0004B
-:10494000128000DC00000000937300081260000871
-:1049500000000000976900103122FFFF00E2202BC9
-:104960001080000330A6004010C000D200000000FC
-:10497000A7850040AF870038936A000802203821DD
-:10498000AFB10020154000F127B40020AF60000C4B
-:104990009785004030B14000162000022403001625
-:1049A0002403000E24154007A363000AAF7500140A
-:1049B000939000428F6F0014321900010019C24019
-:1049C00001F84025AF680014978700408F630014FA
-:1049D00030EE0010006E6825AF6D0014978C00401B
-:1049E000318B000811600165000000008F65001424
-:1049F0003C0B10003C0A800000AB8825AF7100140E
-:104A000095460E0A3C0981002413000E30C2FFFFB8
-:104A100000492025AF640004A3730002937F000ABD
-:104A20003406FFFC27F20004A372000A978D0040B1
-:104A300031AC200011800157000000003C078000CD
-:104A4000978D004094EC0E0C97910040000D584259
-:104A50003185C000316A00030005130332291000BC
-:104A600001429825000922030264F825001F90C026
-:104A7000A7720012979500409379000A0015818271
-:104A80003218003C0319782125E8003CA36800098E
-:104A900094EE0E0C31C33FFFA76300109763001222
-:104AA0009367000900E3702125CD000231AC0007B7
-:104AB000000C582331650007A365000B93710009B2
-:104AC00097640012976A0010322200FF8F9100381D
-:104AD000979F004000444821012A982102669021B6
-:104AE00033F5004012A000053246FFFF00D1402BF5
-:104AF0003C12800011000016000098210226782B3D
-:104B000015E001368FA700203C1880008F100E148E
-:104B10003C058000AF100E108F190E1CAF190E1837
-:104B2000AF060E008CB200003255000812A0FFFD47
-:104B30000000000094BF0E0800C0882100009021F2
-:104B4000A79F00408CA60E0424130001AF860038F6
-:104B5000976900103135FFFF8E8C000001912023F2
-:104B600010800118AE8400009367000814E000D89C
-:104B7000000000000E0001B4240400108F8E0048D5
-:104B80003C0332000040282131C600FF00063C00F3
-:104B900000E3602525CD0001AF8D0048AC4C00003E
-:104BA0009362000997640012937F000A304A00FF65
-:104BB000308BFFFF014B48210009CC0033F000FF90
-:104BC0000330C025ACB800048F8F004897880040A0
-:104BD0003103200010600103ACAF0008976F001292
-:104BE00031E8FFFF06400101ACA8000C979000409F
-:104BF0003205000814A0000226280006262800021C
-:104C00003C048000948B0E148C850E1C8F6700046E
-:104C1000936A00023164FFFF314900FFAFA9001021
-:104C20008F7F0014AFA80018AFBF00140E00019AC8
-:104C300000000000240400100E0001C80000000065
-:104C40008E92000016400005000000008F790014CD
-:104C50002405FFBF0325A024AF7400148F69000C46
-:104C60000135F821AF7F000C9375000816A00008ED
-:104C70000000000012600006000000008F6B0014AE
-:104C80003C0CEFFF3584FFFE01645024AF6A001432
-:104C9000A37300088FA700200A000316022020211A
-:104CA000AED10E000A0001F83C05800014E0FF219F
-:104CB00030B9A0400E0001600000A0212E9100013B
-:104CC0000237B02512C000178FBF00488F85003C07
-:104CD00024170F0010B700CD3C0480008C99017898
-:104CE0000720FFFE24150F0050B500EB3C048000A8
-:104CF0008C890E14240502403C141000AC89014438
-:104D00008C9F0E1CAC9F0148A0800152A480015AC8
-:104D1000AC800160A4800158AC850154AC9401784A
-:104D20008FBF00488FB700448FB600408FB5003C5E
-:104D30008FB400388FB300348FB200308FB1002CA5
-:104D40008FB0002803E0000827BD00508F91003885
-:104D5000979300403C1280000220A821326A004054
-:104D60001540FF7D00009821976B00108F8500385B
-:104D70003162FFFF104500A2000020210080A02129
-:104D8000108000E500E088211620FED2000000001F
-:104D90000A0002E72E9100013C0380008C7F01781D
-:104DA00007E0FFFE240408008F860000AC64017851
-:104DB0003C038000946C008A318BFFFF0166502316
-:104DC0002549FFFF31281FFF2D0200081440FFF97D
-:104DD000000000008F8E0048346F40008F83003C3D
-:104DE00000E0A021240D0F0025C70001AF87004877
-:104DF00000CF3021023488233C08800031D500FFE9
-:104E0000106D0005240700019393004232720001E7
-:104E10000012824036070001001514003C09010011
-:104E200000492025ACC400008F9F004830B90036EF
-:104E300030B80008ACDF00041300009000F998259A
-:104E400095070E0A8F8E00003C03810030EDFFFFB6
-:104E500025CB000801A328253C0C1000316A1FFF58
-:104E6000269200062406000EAD050160026C98250E
-:104E7000A506015AAF8A0000A512015816200008A5
-:104E80003C1080008F99003C24180F00533800021A
-:104E900024170001367300400E0001593C108000B9
-:104EA0008E1F0E1402402021AE1F01448E120E1CD4
-:104EB000AE120148A2150152AE1301540E00016753
-:104EC0003C151000AE1501780A000319000000001F
-:104ED00093780009976300129368000B330F00FF6B
-:104EE00001E33821310200FF00E2702125D0000AE1
-:104EF0003210FFFF0E0001B4020020218F8600480F
-:104F00003C1941003C07800024CD0001AF8D0048D2
-:104F1000936C00099764001230C600FF318A00FFCD
-:104F2000308BFFFF014B482100062C00253F00027B
-:104F300000BFC02503197825AC4F00008F68000C16
-:104F400094EE0E1401121825AC4300048CE50E1CDF
-:104F50008F670004936D000231C4FFFF31AC00FF86
-:104F6000AFAC00108F620014AFB100180E00019AB0
-:104F7000AFA200140A0002C502002021AF600004A5
-:104F8000A3600002978D004031AC20001580FEAB7D
-:104F900000003021A7600012979000409378000A2B
-:104FA0003C03800032191F000019798301F8402169
-:104FB00025070028A3670009946E0E0C0A00025E04
-:104FC000A76E00108F6E001435CD00400E00015901
-:104FD000AF6D00140A000291000000000A000316E1
-:104FE000000020210641FF01ACA0000C8CB8000C91
-:104FF0003C198000031990250A0002B2ACB2000CE3
-:10500000000090210A00028D241300011280000587
-:105010003C0D800095A60E0830D30040126000427F
-:10502000000000008C9001780600FFFE00000000E8
-:1050300094920E103C030500240720003258FFFF15
-:1050400003037825AC8F014C8C880E143C0E1000A5
-:10505000AC8801448C820E1CAC820148A0800152B5
-:10506000A480015AAC800160A4800158AC8701542F
-:10507000AC8E01780A0002EE3C0480008F900000A4
-:1050800026920002A5120158260F000831E81FFFE2
-:105090000A000356AF880000AC80014C1280001952
-:1050A000000000008C8A0E10AC8A01448C830E181C
-:1050B0003C0C800024160040AC8301488FBF0048A0
-:1050C000A18001528FB70044A580015A8FB5003CE2
-:1050D000AD8001608FB40038A58001588FB30034D3
-:1050E000AD9601548FB200308FB600408FB1002CC6
-:1050F0008FB000283C04100027BD005003E00008DA
-:10510000AD8401788C8B0E14AC8B01448C830E1C07
-:105110000A0003E43C0C80000E0001602E910001A7
-:105120000A0002E80237B025000000000000000D70
-:10513000000000002400033A0A0003C03C04800081
-:1051400027BDFFE0AFBF001C3C1F20FF3C076000F5
-:105150003C0980002402001037F9FFFDACE2300862
-:10516000AFB20018AFB10014AFB00010AD390E00EF
-:10517000000000000000000000000000000000002F
-:10518000000000003C1800FF3712FFFDAD320E009A
-:105190003C0B60048D7050002411FF7F3C0E000218
-:1051A0000211782435EC380C35CD0109ACED4C18E2
-:1051B000240A0009AD6C50008CE80438AD2A0008C0
-:1051C000AD2000148CE54C1C3106FFFF38C42F7154
-:1051D00000051E023062000F2486C0B31040000795
-:1051E000AF8200088CE54C1C3C09001F3528FC00F0
-:1051F00000A81824000321C2AF8400048CF1080821
-:105200003C0F57092412F0000232702435F00010D0
-:1052100001D0602601CF68262DAA00012D8B000148
-:10522000014B382550E00009A380000C3C02601CB3
-:105230008C590008241F0001A39F000C33387C0008
-:10524000A7980010A780000EA380000DAF80004833
-:1052500014C00003AF8000003C066000ACC0442CCA
-:105260000E0004B63C1080000E000DDF00000000B0
-:105270003C110800263138C83C1208002652394833
-:105280008E05000038A30001306400011480FFFC8B
-:10529000000000008E0601003C0C800A240AFF80FA
-:1052A00024C7024030EB007F016C482100EA402413
-:1052B000AE060020AF890044AE0800243C03800005
-:1052C000AF86003C8C6D017805A0FFFE2419080014
-:1052D000AC79017890780108A3980042938F00423E
-:1052E00031EE000111C0000F240D0D0024C2F800A2
-:1052F0002C5F030113E0001C000629C224A3FFF069
-:1053000000032042000431400E0001CF00D1D8211B
-:105310003C0440003C068000ACC401380A0004573D
-:105320000000000010CD0026240E0F0010CE002A31
-:105330003C028008345F008093F90000240F005085
-:10534000333800FF170FFFF33C0440000E00091232
-:10535000000000003C0440003C068000ACC4013862
-:105360000A000457000000008F83000400A3402BB4
-:105370001500000B8F8B0008006B50212547FFFFA5
-:1053800000E5482B1520000600A36023000C2940EF
-:105390000E0001CF00B2D8210A00047C3C0440007A
-:1053A000000000000000000D00000000240003AD1C
-:1053B0000E0001CF000000000A00047C3C04400005
-:1053C0003C1B0800277B3A480E0001CF000000007C
-:1053D0000A00047C3C0440003C1B0800277B3A6820
-:1053E0000E0001CF000000000A00047C3C044000D5
-:1053F000000411C003E00008244202403C040800FD
-:1054000024843AAC2405001A0A00006D0000302103
-:1054100027BDFFE0AFBF001CAFB20018AFB1001452
-:10542000AFB000103C108000920B01092412FF80E5
-:105430000E0004B33164007F8F91003C0051502175
-:1054400001524024AE080024920301090E0004B367
-:105450003064007F24060080240700C0240400403C
-:10546000AE000810AE040814AE060818AE07081CFB
-:10547000920C01090051F82133F8007F3C19800A91
-:10548000031910213184007F0E0004B3AF82004461
-:105490008E1101003C0C008035850001022278212C
-:1054A00001F24824AE0908048E0E0100359800026E
-:1054B0003609090001C2682131AB00780165502529
-:1054C000AE0A08208E0501008E080100360509800D
-:1054D000010218212464004000923024AE0608081E
-:1054E0008E07010000E2F82127F9004033320078EE
-:1054F00002588825AE1108248E040100952F000C57
-:105500008FBF001C8FB2001831EEFFFF000E69C084
-:10551000AE0D0800AE0C0828952B000C8FB10014BE
-:10552000316AFFFF000A41C0AE08002C8CA3005076
-:105530008FB000108CA2003C8D2400048CA6001CAF
-:105540008CA7003827BD0020AF830060AF820050D9
-:10555000AF84004CAF86005803E00008AF87005CC2
-:105560003C0A0800914A3AD13C09080095293ACAF8
-:105570003C051100000A3C002528000200E8302507
-:1055800000C5182524820008AC83000003E0000851
-:10559000AC8000043C098000352809009107001107
-:1055A000240200280080502130E300FF00A0682181
-:1055B00000C0602110620002340B86DD240B08005D
-:1055C0003C07800034E20A9A9443000034F80A9CB5
-:1055D00034E60AA03079FFFFAD5900008F0F0000BC
-:1055E00034E80A8024040001AD4F00048CCE000092
-:1055F000AD4E00089105001930A300031064004669
-:1056000028690002152000B52404000210640090EF
-:10561000240500031065009B34E40AA43C0908003B
-:1056200095293AC024070800516700503C188000B3
-:105630003C0280003459090093280012932E00196F
-:1056400034580980310F00FF8F06002801EC182123
-:10565000000338803124FFFF31CB00FF00E410212C
-:10566000000B2D0000A6C02500027C003C08600055
-:105670000308182535E906FFAD430000AD490004D5
-:105680008F2E002C3C0380003478093CAD4E00087E
-:105690008F27003025490028346E0900AD47000CE3
-:1056A0008F2B0034AD4B00108F240038AD44001414
-:1056B0008F25001CAD4500188F220020AD42001C34
-:1056C0008F26002425220014AD4600208F280028B4
-:1056D000AD4800248F0F0000AD2D0004AD2F000059
-:1056E0008C64010CAD24000891C700123C05080031
-:1056F00090A53AD0AD20001030EB00FF016C3021B6
-:1057000000066F000005CC0001B96025358AFFFF57
-:1057100003E00008AD2A000C3C09080095293AC0B6
-:105720003C19080097393ACA34E20AA43C0608003A
-:1057300094C63ABC944F00003123FFFF0323C021DD
-:1057400003067023000F3C0025C8FFF200E828255F
-:1057500024070800AD45000CAD400010AD4B00140F
-:105760001567FFB3254A00183C1880003708090068
-:10577000910F00119107001937030A8031EE00FFE5
-:105780003C19080097393AC6946F002A000E5882D7
-:1057900030E400FF97870054000B160000042C0033
-:1057A0003126FFFF0326C02100454825013870251A
-:1057B00001E758213C03400001C32025000B2C00C9
-:1057C000AD440000AD450004910200183C060006FF
-:1057D0003C0380000002CE000326C025AD5800081F
-:1057E0008D0F002C3478093C24E90001AD4F000CEA
-:1057F0008D0B001C312E7FFF25490014AD4B00108E
-:105800008F0F0000AD2D0004A78E0054AD2F0000B7
-:105810008C64010C346E090025220014AD240008AC
-:1058200091C700123C05080090A53AD0AD200010A9
-:1058300030EB00FF016C302100066F000005CC004A
-:1058400001B96025358AFFFF03E00008AD2A000C8E
-:1058500034E90AA495240000950200283C090800B8
-:1058600095293AC000041C000002CC003478810065
-:10587000032B7825AD58000CAD4F00100A000540F1
-:10588000254A00143C09080095293AC03C05080047
-:1058900094A53ACA3C06080094C63ABC9499000004
-:1058A0003123FFFF9518002800A31021004678231C
-:1058B00000193C000018440025EEFFEE010E2825DB
-:1058C00034E48100AD44000CAD450010AD4000143F
-:1058D000AD4B00180A000540254A001C1460FF4F1C
-:1058E00034E60AA494CE00003C09080095293AC089
-:1058F000000E4400010B3825AD47000C0A0005409E
-:10590000254A001003E00008240207D027BDFFE06D
-:10591000AFB20018AFB10014AFB00010AFBF001CA1
-:105920000E00004D008088218F8800508F87004C2A
-:105930003C05800834B20080011128213C10800011
-:1059400024020080240300C000A72023AE02081810
-:105950003C068008AE03081C18800004AF85005088
-:10596000ACC500048CC90004AF89004C12200009AA
-:10597000360409800E0005F800000000924C002754
-:105980008E0B007401825004014B3021AE46000C96
-:10599000360409808C8E001C8F8F005801CF68233D
-:1059A00019A000048FBF001C8C90001CAF90005801
-:1059B0008FBF001C8FB200188FB100148FB0001081
-:1059C0000A00004F27BD00208F8600608F830050A3
-:1059D0008F82004C3C05800834A40080AC860050C7
-:1059E000AC83003C03E00008ACA200043C030800C8
-:1059F0008C63005427BDFFF8308400FF246200014F
-:105A000030A500FF3C010800AC22005430C600FF66
-:105A10003C0780008CE801780500FFFE3C0A7FFF10
-:105A2000A3A400038FA400003549FFFF00891824B8
-:105A3000000647C000681025AFA2000090F9010AD7
-:105A4000A3A000023C1880FFA3B900018FAE0000A4
-:105A500030AD007F370FFFFF01CF5824000D6600E7
-:105A60003C090020016C5025352620002405FF80CC
-:105A70003C04100027BD0008ACEA014CACE6015420
-:105A8000A4E00158A0E5015203E00008ACE401786D
-:105A9000308800FF3C03800030A400FF8C62017856
-:105AA0000440FFFE000000003C03800034660A0052
-:105AB0008CCA0020346709800004482BAC6A01447A
-:105AC0008CC5002400091540AC650148A068015050
-:105AD00090E4004CA064016D03E00008A46001584C
-:105AE00027BDFFE8308400FFAFBF00100E00065B4B
-:105AF00030A500FF8F8300508FBF00103C05800051
-:105B0000344600402404FF903C02100027BD0018DA
-:105B1000ACA3014CA0A40152ACA6015403E00008C0
-:105B2000ACA2017827BDFFE03C088008AFBF001C95
-:105B3000AFB20018AFB10014AFB000103510008044
-:105B40008E0600183C078000309200FF00C7202519
-:105B5000AE0400180E00004D30B100FF92030005A6
-:105B6000346200080E00004FA2020005024020210E
-:105B70000E00066F02202821024020218FBF001C4A
-:105B80008FB200188FB100148FB0001024050005EB
-:105B9000240600010A00063227BD00203C058000D3
-:105BA00034A309809066000830C200081040000F3E
-:105BB0003C0A01013549080AAC8900008CA8007430
-:105BC000AC8800043C07080090E73AD030E50010AC
-:105BD00050A00008AC8000083C0D800835AC008067
-:105BE0008D8B0058AC8B00082484000C03E0000867
-:105BF000008010210A0006B22484000C27BDFFE8B3
-:105C00003C088000AFB00010AFBF0014350609801B
-:105C100090C70009240200063509090030E300FF9F
-:105C20000080802100A06021240B00041062007914
-:105C30002407000294CF005C3C0E020431EDFFFF0C
-:105C400001AE5025AE0A000090C5000830A4002027
-:105C5000108000080000000090C2004E3C1F0103AD
-:105C600037F90300305800FF03193025240B0008D2
-:105C7000AE06000491390011912600129124001102
-:105C8000333800FF0018708230CF00FF01CF502161
-:105C9000014C6821308800FF31AAFFFF390300283A
-:105CA000000A28801460002B020540239124001272
-:105CB0003C0E800035D90980308500FF00AC1821EA
-:105CC00000031080004BF821001F8400360906FFF6
-:105CD000AD09000435C9090091260011912F001269
-:105CE000000BC0828F2B003431ED00FF8DC4010CFE
-:105CF00001AC282100B810210164F82300078400BA
-:105D000000021F000070C82533E9FFFF30CF00FC00
-:105D1000032970250158202101E8682100045080E2
-:105D2000ADAE000C0E00004D010A80213C0780083A
-:105D3000240C000434EB00800E00004FA16C00091D
-:105D4000020010218FBF00148FB0001003E0000884
-:105D500027BD001891250011912300193C18080057
-:105D600097183AC630A200FF0002F882307000FF98
-:105D7000001FCE0000104C000329302500D87025EC
-:105D80003C0F400001CF68253C0E8000AD0D0000A7
-:105D900035C9090091260011912F001235D90980CB
-:105DA000000BC08231ED00FF8F2B00348DC4010C3D
-:105DB00001AC282100B810210164F82300078400F9
-:105DC00000021F000070C82533E9FFFF30CF00FC40
-:105DD000032970250158202101E868210004508022
-:105DE000ADAE000C0E00004D010A80213C0780087A
-:105DF000240C000434EB00800E00004FA16C00095D
-:105E0000020010218FBF00148FB0001003E00008C3
-:105E100027BD00180A0006C42407001227BDFFD0C2
-:105E2000AFB50024AFB40020AFB3001CAFB000107A
-:105E3000AFBF0028AFB20018AFB100143C0680001D
-:105E400090C3010B309300FF30B400FF306200308C
-:105E50000000A821104000820000802134C4098085
-:105E60009088000800083E0000072E0304A000A947
-:105E7000240400048F8700503C010800A0243AD07D
-:105E80003C0C8000AD8000483C038000906E010B0C
-:105E900031C5002010A000073C0C80003478098038
-:105EA0009312000800128E0000117E0305E000AE80
-:105EB0003C028008918B010B3586098090C4000854
-:105EC000316A0040000A482B308800082411000382
-:105ED0001500000200E99023000088213C038000A7
-:105EE00034780A80346A09009707002C9144001125
-:105EF0009149001293050018309F00FF312800FFE0
-:105F0000022810210002C880930D0018033F782159
-:105F100001F0702130B000FF01D01821A787005494
-:105F20003C010800A42E3AC63C010800A4233AC84C
-:105F300015A00003246B000A0000000D246B000A6A
-:105F40003170FFFF3C010800A4233ACA3C0108005D
-:105F5000A4203AC03C010800A4203ABC0E0001B4C1
-:105F6000020020210E00050F0040202100402021CA
-:105F7000024028210E00051C022030210E00069E42
-:105F80000040202116A0005F004020210E0001C823
-:105F9000020020213C11080092313AD03235000332
-:105FA00012A000163C0A80088F8700503C0E800823
-:105FB00035CD008024EC0001ADAC003C3C058008F0
-:105FC0008CA600040180202100CC90231A400002FE
-:105FD000AF8C00508CA400040E0005F8ACA40004A3
-:105FE0003C1980008F3800743C0F800835F0008029
-:105FF00000582821AE05000C3C0A8008354200807C
-:106000000260202102802821A040006B0E00065B68
-:106010003C1380008F840050345F0006AE64014C56
-:106020008F8800483C1410008FB50024250900011A
-:10603000AF8900488FB20018A26801528FB10014D6
-:10604000AE7F01548FB00010AE7401788FBF00286E
-:106050008FB400208FB3001C03E0000827BD003080
-:1060600034C30980906F0008000F7600000E6E03A5
-:1060700005A0003334C209009059001B241F0010F2
-:106080003C010800A03F3AD0333800021300FF7EE5
-:106090008F8700508F83005C1467FF7C3C03800077
-:1060A0000E00004D000000003C09800835250080EE
-:1060B00090A4000924070016308800FF1107000D86
-:1060C0000000000090A600093C0C0800918C3AD01A
-:1060D000240A000830C400FF358B00013C01080091
-:1060E000A02B3AD0108A002F240D000A108D002812
-:1060F0002402000C0E00004F000000000A000759A7
-:106100008F8700500E0006B6022028210A00079A49
-:10611000000000003C0B8008356A00808D47005469
-:106120008CC9010C1120FF54AF87005024060014C5
-:106130003C010800A0263AD00A0007583C0C800019
-:1061400090710008241200023C010800A0323AD0ED
-:10615000323000201200000B241500018F87005000
-:106160000A00075924100008345900808F23003892
-:10617000AC4300048C5F0004AF3F003C0A0007649E
-:106180003C0C80008F8700500A000759241000043F
-:10619000A0A200090E00004F000000000A000759ED
-:1061A0008F870050240200140A00081CA0A20009D6
-:1061B00027BDFFE8AFBF0014AFB000103C10800057
-:1061C00092020109240500010E00065B304400FF25
-:1061D0003C1F800893F8000E37E3008093F9000F0E
-:1061E000906E002693E9000A332F00FF0018660026
-:1061F000000F6C0031CB00FF018D5025000B3200E9
-:1062000001463825312800FF3445600000E820258C
-:106210002402FF813C031000AE04014C8FBF001428
-:10622000AE050154A2020152AE0301788FB00010F6
-:1062300003E0000827BD001827BDFFE8308400FFF9
-:10624000AFBF00100E00065B30A500FF34460040D3
-:106250003C0480002405FF92AC860154A0850152C5
-:106260008F8300508FBF00103C02100027BD001824
-:10627000AC83014C03E00008AC82017827BDFFD855
-:10628000AFB20018AFB10014AFB00010AFBF002024
-:10629000AFB3001C3C07800090E20109308600FF8C
-:1062A00030B000FF000618C2320400023071000155
-:1062B00014800007305200FF3C098008353300800D
-:1062C000926800053105000810A0000C30CA0010CB
-:1062D000024020210E000680022028212402000115
-:1062E0008FBF00208FB3001C8FB200188FB1001435
-:1062F0008FB0001003E0000827BD002815400030D3
-:1063000034E50A008CB900248CB800081338004723
-:10631000000040213C0E800835D30080926D00685B
-:10632000240B000231AC00FF118B00803C06800082
-:10633000927F004C90C40109509F00043213007CEE
-:1063400011000067000000003213007C1660005A44
-:106350000240202116200008320C00013C0780007A
-:1063600034EB0A008D6500248CE8010414A8FFDCDE
-:1063700000001021320C00011180000D024020218C
-:106380003C1080008E0E010C8F8D006011CD000836
-:10639000000000000E00073E022028218E0F010C95
-:1063A0003C18800837100080AE0F005002402021BA
-:1063B0000E00066F022028210A00086F2402000147
-:1063C0003C0708008CE7006424E600013C0108005B
-:1063D000AC2600641600000D0000000002202821F9
-:1063E0000E00066F02402021926F0068240D00020B
-:1063F00031EE00FF11CD0022024020210E000823C3
-:10640000000000000A00086F240200010E00004195
-:1064100024040001926C0025020C58250E00004F48
-:10642000A26B00250A0008AF022028218E63001805
-:106430008CE401048CBF002400031602149FFFB5F6
-:106440003045007F9269004C264400013093007F64
-:1064500012650040312300FF1464FFAF3C0E80083A
-:10646000264800013111007F310200FF1225000B88
-:1064700024080001004090210A00087C241100013A
-:10648000240500040E000632240600010E00082335
-:10649000000000000A00086F240200012407FF80AA
-:1064A0000247282400A79026324200FF0040902196
-:1064B0000A00087C241100010E00073E022028215A
-:1064C0003206003010C0FFA33210008202402021AB
-:1064D0000E000680022028210A00086F2402000115
-:1064E0008E6300180240202102202821006610251A
-:1064F0000E000845AE6200189264004C24050003AB
-:10650000240600010E000632308400FF0E00004118
-:1065100024040001926A0025020A48250E00004F5B
-:10652000A26900250A00086F240200018E78001875
-:106530003C198000024020210319782502202821DF
-:106540000E00066FAE6F00189264004C0A0008F748
-:10655000240500043246008038CA0080146AFF6EA9
-:106560003C0E80080A0008D02648000127BDFFC065
-:10657000AFB000183C108000AFBF0038AFB7003498
-:10658000AFB60030AFB5002CAFB40028AFB30024D5
-:10659000AFB200200E0004BBAFB1001C9204010892
-:1065A0009205010B308400FF0E00085630A500FF55
-:1065B000144000E38FBF00383C0980083528008074
-:1065C000A100006B3607098090E60000240200500D
-:1065D0003C17080026F73A8830C300FF3C13080038
-:1065E00026733A98106200033C1080000000B82126
-:1065F00000009821241F001036110A00361409806B
-:106600008E1601048F8D00508E38002436190A80B2
-:106610008E9200203C010800A03F3AD0972C002C1D
-:106620008EF50000932B0018024D702302D87823BA
-:106630003C010800AC2F3AAC3C010800AC2E3AB04B
-:106640003C010800AC2D3AD4A78C005402A0F809F4
-:10665000317200FF304A0002154000E6304500016B
-:1066600010A000C100000000928A0008315000080C
-:1066700016000002241400030000A0213C06800044
-:1066800034C4090034C30A008C6E002490850011C4
-:10669000908200129099001130B800FF305100FF35
-:1066A0000291F821001FB080332F00FF02D858213B
-:1066B000024FA82126AC0010017268213C15800011
-:1066C0003C010800AC2E3AD83C010800A42D3AC881
-:1066D0003C010800A42C3AC43C010800A42B3AC693
-:1066E00036B609808F8700508F8900588ED20020DF
-:1066F0002408000601273023024728233C01080014
-:10670000AC283ACC04C000B30000902104A000B132
-:1067100000C5802B120000B3000000003C010800FF
-:10672000AC263AB08E7100000220F809000000008B
-:10673000304A00021540007400408021304B0001B7
-:10674000556000118E7100043C0D08008DAD3AB407
-:106750003C0EC0003C04800001AE6025AEAC0E00D3
-:106760008C980000330F000811E0FFFD00000000CE
-:10677000949F0E0824120001A79F00408C990E04DC
-:10678000AF9900388E7100040220F8090000000063
-:106790000202802532020002144000A9000000001D
-:1067A0003C08080095083ABC3C11080096313AC8EC
-:1067B0003C09080095293ABE3C0308008C633AB4B2
-:1067C000011168213C1F08008FFF3AD83C070800E0
-:1067D00094E73AD23C11800001A920218E38010CA7
-:1067E000006828212499000200A7702103E3782182
-:1067F000AF9800603C010800AC2F3AD83C0108007B
-:10680000A42E3AC03C010800A42D3ACA0E0001B4DF
-:106810003324FFFF8F8C0048004020213C010800FA
-:10682000A02C3AD18E620008258B0001AF8B004866
-:106830000040F809000000008F85005002803021E0
-:106840000E00051C004020210E00069E0040202165
-:106850008E6A000C0140F809004020213C08080025
-:1068600095083ACA3C09080095293ABE0109382121
-:1068700024E600020E0001C830C4FFFF3C040800FB
-:106880008C843AAC3C0308008C633AB40083282320
-:106890003C010800AC253AAC14A000060000000042
-:1068A0003C0A08008D4A3ACC354600403C010800BD
-:1068B000AC263ACC124000418F8C00448E2B0E1037
-:1068C0008F920044AE4B00208E220E18AE42002460
-:1068D0003C04080094843AC00E0005FA0000000051
-:1068E0008F9900508E7800103C010800AC393AD4E2
-:1068F0000300F809000000003C0F08008DEF3AACDF
-:1069000015E0FF798F870050979400543C13800E58
-:10691000321500100E000629A674002C56A0004463
-:106920008EF60004321F004057E0001D8EF0000874
-:106930008EE3000C0060F809000000008FBF0038F3
-:106940008FB700348FB600308FB5002C8FB400287D
-:106950008FB300248FB200208FB1001C8FB00018BD
-:1069600003E0000827BD0040920901098F88003C20
-:1069700000093E0000E83025AE0600808E2300208E
-:106980008E240024AFA30010AE030E148FA20010BB
-:10699000AE020E10AE040E1C0A000951AE040E1811
-:1069A0000200F809000000008EE3000C0060F80906
-:1069B000000000000A000A078FBF0038240E000103
-:1069C000240D0001A5800020A58E00220A0009EBFD
-:1069D000AD8D00243C010800AC203AB00A000981CA
-:1069E0008E7100003C010800AC253AB00A00098114
-:1069F0008E71000092110109000028210E00066F1F
-:106A0000322400FF8FBF00388FB700348FB60030BC
-:106A10008FB5002C8FB400288FB300248FB20020D4
-:106A20008FB1001C8FB0001803E0000827BD0040A4
-:106A300002C0F809000000000A000A01321F0040ED
-:106A40005240FFB2979400548EB60E148F930044B8
-:106A5000AE7600208EB40E1CAE7400240A0009FA33
-:106A6000979400548F8200140004218003E00008F2
-:106A7000008210213C07800834E2008090430069C6
-:106A800000804021106000093C0401003C07080020
-:106A90008CE73AD48F83003000E320230480000881
-:106AA0009389001C14E300030100202103E0000887
-:106AB000008010213C04010003E000080080102148
-:106AC0001120000B006738233C0D800035AC098095
-:106AD000918B007C316A00021140002024090034AF
-:106AE00000E9702B15C0FFF10100202100E93823D7
-:106AF0002403FFFC00A3C82400E3C02400F9782B82
-:106B000015E0FFEA0308202130C40003000410232D
-:106B100014C00014304900030000302100A978217E
-:106B200001E6702100EE682B11A0FFE03C0401009B
-:106B30002D3800010006C82B01054821031938240F
-:106B400014E0FFDA2524FFFC2402FFFC00A2182435
-:106B50000068202103E00008008010210A000A6F6D
-:106B6000240900303C0C80003586098090CB007CE5
-:106B7000316A00041540FFE9240600040A000A7E79
-:106B8000000030213C0308008C63005C8F820018F9
-:106B900027BDFFE8AFBF001410620005AFB00010C2
-:106BA000000329C024A40280AF840014AF8300181E
-:106BB0003C10800036030A00946500320E000A5033
-:106BC00030A43FFF8E0401003C180080370F000303
-:106BD0000082C8212402FF80032260243329007F21
-:106BE000000CF94003E94025332E00783C0D1000DD
-:106BF000010D502501CF5825AE0C0028360809801C
-:106C0000AE0C080CAE0B082CAE0A083091030069DC
-:106C10003C06800C0126382110600006AF87003446
-:106C20008D09003C8D06006C0126382318E0007F9A
-:106C3000000000003C0C8008358B00803C0A80007E
-:106C4000A1600069355009808E0200383C06800042
-:106C500034C50A0090AD003C31A800201100001995
-:106C6000AF820030240E00013C19800037300A004A
-:106C7000A38E001CAF8000248E0400248F85002486
-:106C800024180008AF800020AF8000283C010800D5
-:106C9000A4383ABE3C010800A4203AD20E000A549F
-:106CA00000003021920F003C8FBF00148FB0001005
-:106CB000000F7142AF82002C27BD001803E00008CE
-:106CC00031C2000190B90032240F0001333800FFB7
-:106CD00000182182108F003F241F0002109F0062C5
-:106CE00034C20AC03C03800034640A008C9900243A
-:106CF0001720001D3466090090830030241F000512
-:106D00003062003F105F004C240500018F86002098
-:106D1000A385001CAF860028AF8600243C198000A4
-:106D200037300A008E0400248F85002424180008C0
-:106D30003C010800A4383ABE3C010800A4203AD225
-:106D40000E000A5400000000920F003C8FBF001498
-:106D50008FB00010000F7142AF82002C27BD0018C9
-:106D600003E0000831C200018C8800088C8D0024EB
-:106D70008CCB00643C19800037300A00AF8B0024B4
-:106D8000A380001C8E0400248F8600208F850024A1
-:106D9000010D602324180008AF8C00283C01080076
-:106DA000A4383ABE3C010800A4203AD20E000A548E
-:106DB00000000000920F003C8FBF00148FB0001045
-:106DC000000F7142AF82002C27BD001803E00008BD
-:106DD00031C2000190A7003030E3003F506400282A
-:106DE00034C50AC08CAA00241540002234C809000A
-:106DF0008CAB00483C0C7FFF3585FFFF01651024FC
-:106E00003C188000AF820020370509008F8E0020DB
-:106E10008CAF006001CF682B15A0000201C02021BB
-:106E20008CA400600A000AF0AF8400208D02006C80
-:106E30000A000ACB3C0680008C8900488F8600201F
-:106E40003C0A7FFF3550FFFF013038243C048008A6
-:106E500024050001AF870028AC80006CA385001CCE
-:106E60000A000AFEAF8600248C4400140A000AF0CF
-:106E7000AF8400208D0200680A000B383C188000A7
-:106E800034C409808C8600708CB0001400D0482B6C
-:106E900011200004000000008C8200700A000B38F2
-:106EA0003C1880008CA200140A000B383C188000AB
-:106EB0008F85002427BDFFE0AFBF0018AFB10014DD
-:106EC00014A00008AFB000103C04800034870A0012
-:106ED00090E600302402000530C3003F106200B786
-:106EE000348409008F91002000A080213C048000A0
-:106EF000348E0A008DCD00043C0608008CC63AB0E2
-:106F000031A73FFF00E6602B5580000100E03021F3
-:106F1000938F001C11E0007600D0102B349909806B
-:106F20009338007C3304000210800077240300347F
-:106F300000C3F82B17E000D600C3302300D0102B7D
-:106F40003C010800A4233ABC1440006D0200182143
-:106F50003C0408008C843AAC0064282B54A0000147
-:106F6000006020213C05800034A90A009128003CE3
-:106F70003C010800AC243AB4310300201460000244
-:106F8000000048218CA90E188F88002C0128502B56
-:106F90001140005F000000003C0508008CA53AB4D9
-:106FA00000A96021010C582B1160005C00B0682B17
-:106FB0000109382300E028213C010800AC273AB43D
-:106FC000120000032402FFFC10B0008C322A0003E0
-:106FD00000A2F8243C010800A4203AD23C01080099
-:106FE000AC3F3AB403E028218F8400241204000649
-:106FF0003C0380088C6A006C02002021AF910020C5
-:1070000025500001AC70006C8F8B00280085882310
-:10701000AF91002401652023AF84002812200002D4
-:1070200024070018240700103C0E800835C6008095
-:1070300090CD0068240C00013C010800A0273AD044
-:1070400031A700FF10EC004700000000148000187A
-:10705000000028213C0B80009165010935710980F1
-:107060008E23001830A500FF0003560224A3000160
-:107070003146007F3070007F1206007E240CFF80B6
-:107080003C0F800835E90080A123004C3C08080033
-:107090008D083ACC240E00023C010800A02E3B11C2
-:1070A000350D00083C010800AC2D3ACC2405001039
-:1070B0003C1F800037E40A009099003C33380020E0
-:1070C0001300000500A02021240200013C0108005B
-:1070D000AC223AB434A400018FBF00188FB1001461
-:1070E0008FB000100080102103E0000827BD0020B1
-:1070F0003C010800A4203ABC1040FF950200182172
-:107100000A000B8B00C018210A000B8324030030F7
-:107110003C0508008CA53AB400B0682B11A0FFA86C
-:10712000000000003C04080094843ABC00857821EB
-:1071300001E7702B11C000072CA200043C1F600067
-:107140008FF954043338003F1700FFE32404004252
-:107150002CA200041040FF9A240400420A000BEE07
-:107160008FBF00181528FFB9000000008CC200185E
-:107170003C188000241900020058F825ACDF0018E4
-:1071800037040A00A0D900689089003C240F00044D
-:1071900000A01021312800203C010800A02F3B1145
-:1071A0001100000224050010240200013C01080027
-:1071B000AC223AAC0A000BE43C1F80008F88002808
-:1071C0008C8900600109282B14A00002010088218D
-:1071D0008C9100603C0B80008D640E18240A000125
-:1071E0000220282102203021A38A001C0E000A540C
-:1071F000022080210A000B72AF82002C000A1823A3
-:1072000012200007306400033C0D800035A7098080
-:1072100090EC007C318B000415600019248E000472
-:107220003C010800A4243AD23C18080097183AD22E
-:107230000305202100C4782B11E0FF6C8F8400240B
-:107240002CA6000514C0FFA42404004230B900039A
-:107250001720000200B9182324A3FFFC3C010800FA
-:10726000AC233AB43C010800A4203AD20A000BB186
-:107270000060282100AC38240A000BD700EC182647
-:107280003C010800A42E3AD20A000C410000000084
-:107290003C010800AC203AB40A000BED2404004283
-:1072A0008F8300283C0B8000356A0A0014600006BA
-:1072B00000001021914600302405000530C400FF75
-:1072C000108500030000000003E00008000000003B
-:1072D00091490048312800FF000839C214E0FFFA44
-:1072E0003C0480083C06080094C63ABC3C030800F5
-:1072F0008C633AD43C0508008CA53AB43C180800CD
-:1073000097183AD20066C8218C8E00040325782194
-:1073100001F8682101AE60231980001D0000000003
-:107320009158004C8F8D0034956E0E10330F00FF76
-:107330008DA9000401CF30238DAA000030CFFFFFBC
-:10734000000F6100012C2821000038210147202175
-:1073500000AC182B0083C821ADA50004ADB9000016
-:1073600091B8000A01F87021A1AE000A956C0E12C6
-:107370008F8A0034A54C0008954900382528000163
-:10738000A54800389147000D34EB0008A14B000DD3
-:1073900003E000080000000027BDFFD8AFB00018D0
-:1073A000938F001C8FB000143C087FFF8F87002450
-:1073B0003C0C80003518FFFFAFBF0020AFB1001CB0
-:1073C00035990A0002181824932A003C000F5FC068
-:1073D0003C02BFFF2CF000013449FFFF006BF82591
-:1073E0003C0808008D083AD48F9900303C180800FA
-:1073F00097183ACA03E9582400107F803C07EFFF32
-:107400003C05F0FF016F18253C1180003149002038
-:1074100034E2FFFF34ADFFFF362E098027A50010B0
-:107420002406000201194023270A000200621824E2
-:107430000080802115200002000058218D8B0E1C39
-:10744000A7AA00120500003A2407000030EF00FF51
-:10745000000F3F00006740253C028008AFA80014E1
-:10746000344B0080916A00683C0F080091EF3AD1DC
-:107470003C09DFFF353FFFFF000A602B3C0208009C
-:1074800094423AC4A3AF0011011FC024000CCF40A6
-:10749000031918258FA70010AFA300143C1F080084
-:1074A00093FF3AD3A7A200168FA8001400ED48243A
-:1074B0003C0B01003C0A0FFF012BC82533F80003E9
-:1074C000354CFFFF010D78243C027000032C38245A
-:1074D00000181E0000E2482501E35825AFAB001458
-:1074E000AFA9001091DF007CA3BF00150E00006360
-:1074F00000000000362D0A0091A6003C30C4002098
-:1075000010800006260200083C11080096313AC09F
-:10751000262EFFFF3C010800A42E3AC08FBF00209A
-:107520008FB1001C8FB0001803E0000827BD0028B1
-:107530008F8A002C016A602B5580FFC4240700014C
-:107540000A000CCB30EF00FF9383001C3C0280004C
-:1075500027BDFFD834480A0000805021AFBF00206B
-:1075600034460AC0010028211060000E344409800E
-:1075700091070030240B00058F89002030EC003F7C
-:10758000118B000B00003821AFA900103C0B8008C4
-:107590008D69006CAFAA00180E00012BAFA9001472
-:1075A000A380001C8FBF002003E0000827BD002837
-:1075B0008D1F00483C1808008F183AB48F99002896
-:1075C0003C027FFF8D0800443443FFFFAFA9001049
-:1075D0003C0B80088D69006C03E37024031978214B
-:1075E00001CF682301A83821AFAA00180E00012B93
-:1075F000AFA900140A000D20A380001C3C058000E8
-:1076000034A60A0090C7003C3C06080094C63AD253
-:107610003C0208008C423ACC30E3002000062400F3
-:107620001060001E004438253C08800835050080A5
-:1076300090A30068000030212408000100002021F0
-:10764000240300013C0580008CAC01780580FFFE1E
-:1076500000000000ACA80148A4A40144A4A3014672
-:107660003C0308008C633AD43C188008370F008034
-:10767000ACA3014C3C19080093393AD13C0D1000E1
-:10768000A0B90152ACA70154A4A6015891EE004C38
-:10769000A0AE016D03E00008ACAD01788CA80E1C13
-:1076A0003C0B08008D6B3AB494AA0E1694A90E14E4
-:1076B000016630213143FFFF0A000D483124FFFFEE
-:1076C0003C04800034830A009065003C30A2002016
-:1076D0001040001C000000000000302100002021AC
-:1076E000000018213C0580008CA901780520FFFED0
-:1076F00000000000ACA601483C0E08008DCE3AD434
-:10770000240DFF91240C00403C0B8008A4A30144ED
-:10771000356A0080A4A40146ACAE014CA0AD015274
-:10772000ACAC0154A4A0015890A301099144004CB1
-:1077300090A601093C041000A0A6016D03E000081A
-:10774000ACA401788C860E1894880E1294870E10C3
-:107750003104FFFF0A000D7030E3FFFF3C0480009E
-:1077600034830A009065003C30A2002010400026BF
-:1077700027BDFFF82409000100003821240800017A
-:107780003C0680008CC401780480FFFE00000000ED
-:1077900090CA01093C04080090843B113C1880FF0A
-:1077A000A3AA00038FA300003085007F370FFFFFDF
-:1077B00000661025AFA2000090D9010AA3A0000224
-:1077C00000056E00A3B900018FAE0000240A30004E
-:1077D00027BD000801CF6024018D5825ACCB014C9A
-:1077E000ACCA0154A4C00158ACC90148A4C70144A3
-:1077F0002409FF80A4C801463C081000A0C901521A
-:1078000003E00008ACC801788C890E1894870E122A
-:1078100094860E1030E8FFFF0A000D9730C7FFFF77
-:1078200027BDFFE8AFB000103C108000AFBF0014D0
-:1078300036180A00970F00320E000A5031E43FFF5D
-:107840008E0E0100240DFF803C04200001C258214F
-:10785000016D6024000C4940316A007F012A4025F7
-:10786000010438253C048008AE07083034860080C7
-:1078700090C500682403000230A200FF10430004FA
-:107880008F9F00208F990024AC9F0068AC99006402
-:107890008FBF00148FB0001003E0000827BD001850
-:1078A0003C0A0800254A359C3C0908002529363841
-:1078B0003C08080025082A603C07080024E736FC3D
-:1078C0003C06080024C634243C05080024A5317C6D
-:1078D0003C04080024842D8C3C030800246334D825
-:1078E0003C020800244232743C010800AC2A3A9061
-:1078F0003C010800AC293A8C3C010800AC283A88CD
-:107900003C010800AC273A943C010800AC263AA49C
-:107910003C010800AC253A9C3C010800AC243A9894
-:107920003C010800AC233AA83C010800AC223AA074
-:0879300003E000080000000064
-:087938008000094080000900F5
-:10794000800801008008008080080000800E000090
-:10795000800800808008000080000A8080000A0003
-:0879600080000980800009008D
-:00000001FF
-/*
- * This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2004 - 2009 Broadcom Corporation.
- *
- * Permission is hereby granted for the distribution of this firmware data
- * in hexadecimal or equivalent format, provided this copyright notice is
- * accompanying it.
- */
index 452d02f9075ea19861d6d6bd00de12afd19a65eb..0a140741b39e40a124d8c41690dc50ef41e374da 100644 (file)
@@ -614,9 +614,15 @@ int send_sigurg(struct fown_struct *fown)
        return ret;
 }
 
-static DEFINE_RWLOCK(fasync_lock);
+static DEFINE_SPINLOCK(fasync_lock);
 static struct kmem_cache *fasync_cache __read_mostly;
 
+static void fasync_free_rcu(struct rcu_head *head)
+{
+       kmem_cache_free(fasync_cache,
+                       container_of(head, struct fasync_struct, fa_rcu));
+}
+
 /*
  * Remove a fasync entry. If successfully removed, return
  * positive and clear the FASYNC flag. If no entry exists,
@@ -625,8 +631,6 @@ static struct kmem_cache *fasync_cache __read_mostly;
  * NOTE! It is very important that the FASYNC flag always
  * match the state "is the filp on a fasync list".
  *
- * We always take the 'filp->f_lock', in since fasync_lock
- * needs to be irq-safe.
  */
 static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
 {
@@ -634,17 +638,22 @@ static int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp)
        int result = 0;
 
        spin_lock(&filp->f_lock);
-       write_lock_irq(&fasync_lock);
+       spin_lock(&fasync_lock);
        for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
                if (fa->fa_file != filp)
                        continue;
+
+               spin_lock_irq(&fa->fa_lock);
+               fa->fa_file = NULL;
+               spin_unlock_irq(&fa->fa_lock);
+
                *fp = fa->fa_next;
-               kmem_cache_free(fasync_cache, fa);
+               call_rcu(&fa->fa_rcu, fasync_free_rcu);
                filp->f_flags &= ~FASYNC;
                result = 1;
                break;
        }
-       write_unlock_irq(&fasync_lock);
+       spin_unlock(&fasync_lock);
        spin_unlock(&filp->f_lock);
        return result;
 }
@@ -666,25 +675,30 @@ static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fa
                return -ENOMEM;
 
        spin_lock(&filp->f_lock);
-       write_lock_irq(&fasync_lock);
+       spin_lock(&fasync_lock);
        for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
                if (fa->fa_file != filp)
                        continue;
+
+               spin_lock_irq(&fa->fa_lock);
                fa->fa_fd = fd;
+               spin_unlock_irq(&fa->fa_lock);
+
                kmem_cache_free(fasync_cache, new);
                goto out;
        }
 
+       spin_lock_init(&new->fa_lock);
        new->magic = FASYNC_MAGIC;
        new->fa_file = filp;
        new->fa_fd = fd;
        new->fa_next = *fapp;
-       *fapp = new;
+       rcu_assign_pointer(*fapp, new);
        result = 1;
        filp->f_flags |= FASYNC;
 
 out:
-       write_unlock_irq(&fasync_lock);
+       spin_unlock(&fasync_lock);
        spin_unlock(&filp->f_lock);
        return result;
 }
@@ -704,37 +718,41 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
 
 EXPORT_SYMBOL(fasync_helper);
 
-void __kill_fasync(struct fasync_struct *fa, int sig, int band)
+/*
+ * rcu_read_lock() is held
+ */
+static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band)
 {
        while (fa) {
-               struct fown_struct * fown;
+               struct fown_struct *fown;
                if (fa->magic != FASYNC_MAGIC) {
                        printk(KERN_ERR "kill_fasync: bad magic number in "
                               "fasync_struct!\n");
                        return;
                }
-               fown = &fa->fa_file->f_owner;
-               /* Don't send SIGURG to processes which have not set a
-                  queued signum: SIGURG has its own default signalling
-                  mechanism. */
-               if (!(sig == SIGURG && fown->signum == 0))
-                       send_sigio(fown, fa->fa_fd, band);
-               fa = fa->fa_next;
+               spin_lock(&fa->fa_lock);
+               if (fa->fa_file) {
+                       fown = &fa->fa_file->f_owner;
+                       /* Don't send SIGURG to processes which have not set a
+                          queued signum: SIGURG has its own default signalling
+                          mechanism. */
+                       if (!(sig == SIGURG && fown->signum == 0))
+                               send_sigio(fown, fa->fa_fd, band);
+               }
+               spin_unlock(&fa->fa_lock);
+               fa = rcu_dereference(fa->fa_next);
        }
 }
 
-EXPORT_SYMBOL(__kill_fasync);
-
 void kill_fasync(struct fasync_struct **fp, int sig, int band)
 {
        /* First a quick test without locking: usually
         * the list is empty.
         */
        if (*fp) {
-               read_lock(&fasync_lock);
-               /* reread *fp after obtaining the lock */
-               __kill_fasync(*fp, sig, band);
-               read_unlock(&fasync_lock);
+               rcu_read_lock();
+               kill_fasync_rcu(rcu_dereference(*fp), sig, band);
+               rcu_read_unlock();
        }
 }
 EXPORT_SYMBOL(kill_fasync);
index b93ec51fa7ace3ee4a9931512761ba7dcf0207ed..942f239a2132c8b12d47c1258bb02cfbd17a2726 100644 (file)
@@ -261,3 +261,4 @@ const struct inode_operations sysfs_symlink_inode_operations = {
 
 EXPORT_SYMBOL_GPL(sysfs_create_link);
 EXPORT_SYMBOL_GPL(sysfs_remove_link);
+EXPORT_SYMBOL_GPL(sysfs_rename_link);
index e2ea0b2159cd23c1a29662fe98907c9370883048..2fc8e14cc24a8b6ce36a39d4d929539d38a5710e 100644 (file)
@@ -94,6 +94,7 @@ header-y += if_ppp.h
 header-y += if_slip.h
 header-y += if_strip.h
 header-y += if_tun.h
+header-y += if_x25.h
 header-y += in_route.h
 header-y += ioctl.h
 header-y += ip6_tunnel.h
diff --git a/include/linux/caif/caif_socket.h b/include/linux/caif/caif_socket.h
new file mode 100644 (file)
index 0000000..2a61eb1
--- /dev/null
@@ -0,0 +1,165 @@
+/* linux/caif_socket.h
+ * CAIF Definitions for CAIF socket and network layer
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:      Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _LINUX_CAIF_SOCKET_H
+#define _LINUX_CAIF_SOCKET_H
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+#include <linux/socket.h>
+#else
+#include <sys/socket.h>
+#endif
+
+/**
+ * enum caif_link_selector -    Physical Link Selection.
+ * @CAIF_LINK_HIGH_BANDW:      Physical interface for high-bandwidth
+ *                             traffic.
+ * @CAIF_LINK_LOW_LATENCY:     Physical interface for low-latency
+ *                             traffic.
+ *
+ * CAIF Link Layers can register their link properties.
+ * This enum is used for choosing between CAIF Link Layers when
+ * setting up CAIF Channels when multiple CAIF Link Layers exists.
+ */
+enum caif_link_selector {
+       CAIF_LINK_HIGH_BANDW,
+       CAIF_LINK_LOW_LATENCY
+};
+
+/**
+ * enum caif_channel_priority - CAIF channel priorities.
+ *
+ * @CAIF_PRIO_MIN:     Min priority for a channel.
+ * @CAIF_PRIO_LOW:     Low-priority channel.
+ * @CAIF_PRIO_NORMAL:  Normal/default priority level.
+ * @CAIF_PRIO_HIGH:    High priority level
+ * @CAIF_PRIO_MAX:     Max priority for channel
+ *
+ * Priority can be set on CAIF Channels in order to
+ * prioritize between traffic on different CAIF Channels.
+ * These priority levels are recommended, but the priority value
+ * is not restricted to the values defined in this enum, any value
+ * between CAIF_PRIO_MIN and CAIF_PRIO_MAX could be used.
+ */
+enum caif_channel_priority {
+       CAIF_PRIO_MIN    = 0x01,
+       CAIF_PRIO_LOW    = 0x04,
+       CAIF_PRIO_NORMAL = 0x0f,
+       CAIF_PRIO_HIGH   = 0x14,
+       CAIF_PRIO_MAX    = 0x1F
+};
+
+/**
+ * enum caif_protocol_type  -  CAIF Channel type.
+ * @CAIFPROTO_AT:              Classic AT channel.
+ * @CAIFPROTO_DATAGRAM:        Datagram channel.
+ * @CAIFPROTO_DATAGRAM_LOOP:   Datagram loopback channel, used for testing.
+ * @CAIFPROTO_UTIL:            Utility (Psock) channel.
+ * @CAIFPROTO_RFM:             Remote File Manager
+ *
+ * This enum defines the CAIF Channel type to be used. This defines
+ * the service to connect to on the modem.
+ */
+enum caif_protocol_type {
+       CAIFPROTO_AT,
+       CAIFPROTO_DATAGRAM,
+       CAIFPROTO_DATAGRAM_LOOP,
+       CAIFPROTO_UTIL,
+       CAIFPROTO_RFM,
+       _CAIFPROTO_MAX
+};
+#define        CAIFPROTO_MAX _CAIFPROTO_MAX
+
+/**
+ * enum caif_at_type - AT Service Endpoint
+ * @CAIF_ATTYPE_PLAIN:      Connects to a plain vanilla AT channel.
+ */
+enum caif_at_type {
+       CAIF_ATTYPE_PLAIN = 2
+};
+
+/**
+ * struct sockaddr_caif - the sockaddr structure for CAIF sockets.
+ * @family:                 Address family number, must be AF_CAIF.
+ * @u:                      Union of address data 'switched' by family.
+ * :
+ * @u.at:                    Applies when family = CAIFPROTO_AT.
+ *
+ * @u.at.type:               Type of AT link to set up (enum caif_at_type).
+ *
+ * @u.util:                  Applies when family = CAIFPROTO_UTIL
+ *
+ * @u.util.service:          Utility service name.
+ *
+ * @u.dgm:                   Applies when family = CAIFPROTO_DATAGRAM
+ *
+ * @u.dgm.connection_id:     Datagram connection id.
+ *
+ * @u.dgm.nsapi:             NSAPI of the PDP-Context.
+ *
+ * @u.rfm:                   Applies when family = CAIFPROTO_RFM
+ *
+ * @u.rfm.connection_id:     Connection ID for RFM.
+ *
+ * @u.rfm.volume:            Volume to mount.
+ *
+ * Description:
+ * This structure holds the connect parameters used for setting up a
+ * CAIF Channel. It defines the service to connect to on the modem.
+ */
+struct sockaddr_caif {
+       sa_family_t  family;
+       union {
+               struct {
+                       __u8  type;             /* type: enum caif_at_type */
+               } at;                           /* CAIFPROTO_AT */
+               struct {
+                       char      service[16];
+               } util;                         /* CAIFPROTO_UTIL */
+               union {
+                       __u32 connection_id;
+                       __u8  nsapi;
+               } dgm;                          /* CAIFPROTO_DATAGRAM(_LOOP)*/
+               struct {
+                       __u32 connection_id;
+                       char      volume[16];
+               } rfm;                          /* CAIFPROTO_RFM */
+       } u;
+};
+
+/**
+ * enum caif_socket_opts - CAIF option values for getsockopt and setsockopt.
+ *
+ * @CAIFSO_LINK_SELECT:                Selector used if multiple CAIF Link layers are
+ *                             available. Either a high bandwidth
+ *                             link can be selected (CAIF_LINK_HIGH_BANDW) or
+ *                             or a low latency link (CAIF_LINK_LOW_LATENCY).
+ *                              This option is of type __u32.
+ *                             Alternatively SO_BINDTODEVICE can be used.
+ *
+ * @CAIFSO_REQ_PARAM:          Used to set the request parameters for a
+ *                             utility channel. (maximum 256 bytes). This
+ *                             option must be set before connecting.
+ *
+ * @CAIFSO_RSP_PARAM:          Gets the response parameters for a utility
+ *                             channel. (maximum 256 bytes). This option
+ *                             is valid after a successful connect.
+ *
+ *
+ * This enum defines the CAIF Socket options to be used on a socket
+ * of type PF_CAIF.
+ *
+ */
+enum caif_socket_opts {
+       CAIFSO_LINK_SELECT      = 127,
+       CAIFSO_REQ_PARAM        = 128,
+       CAIFSO_RSP_PARAM        = 129,
+};
+
+#endif /* _LINUX_CAIF_SOCKET_H */
diff --git a/include/linux/caif/if_caif.h b/include/linux/caif/if_caif.h
new file mode 100644 (file)
index 0000000..5e7eed4
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef IF_CAIF_H_
+#define IF_CAIF_H_
+#include <linux/sockios.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+
+/**
+ * enum ifla_caif - CAIF NetlinkRT parameters.
+ * @IFLA_CAIF_IPV4_CONNID:  Connection ID for IPv4 PDP Context.
+ *                         The type of attribute is NLA_U32.
+ * @IFLA_CAIF_IPV6_CONNID:  Connection ID for IPv6 PDP Context.
+ *                         The type of attribute is NLA_U32.
+ * @IFLA_CAIF_LOOPBACK:            If different from zero, device is doing loopback
+ *                         The type of attribute is NLA_U8.
+ *
+ * When using RT Netlink to create, destroy or configure a CAIF IP interface,
+ * enum ifla_caif is used to specify the configuration attributes.
+ */
+enum ifla_caif {
+       __IFLA_CAIF_UNSPEC,
+       IFLA_CAIF_IPV4_CONNID,
+       IFLA_CAIF_IPV6_CONNID,
+       IFLA_CAIF_LOOPBACK,
+       __IFLA_CAIF_MAX
+};
+#define        IFLA_CAIF_MAX (__IFLA_CAIF_MAX-1)
+
+#endif /*IF_CAIF_H_*/
index 6e5a7f00223d28afc366d189fa2e9df1ad261cf1..cc0bb4961669a94a6abc15c81909b6c6d230fb8d 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef CAN_DEV_H
 #define CAN_DEV_H
 
+#include <linux/can.h>
 #include <linux/can/netlink.h>
 #include <linux/can/error.h>
 
index 1448177d86d54a4fedc0b74f8f8813408982aa88..dba28268e651931d8b3094438158d15c10d3ca2c 100644 (file)
@@ -26,8 +26,8 @@
 struct mcp251x_platform_data {
        unsigned long oscillator_frequency;
        int model;
-#define CAN_MCP251X_MCP2510 0
-#define CAN_MCP251X_MCP2515 1
+#define CAN_MCP251X_MCP2510 0x2510
+#define CAN_MCP251X_MCP2515 0x2515
        int (*board_specific_setup)(struct spi_device *spi);
        int (*transceiver_enable)(int enable);
        int (*power_enable) (int enable);
index 01ee2aeb048df36e535982e20b30c7b004e1a5c9..96f8fcc78d787a3b826967b77328ea6f4e1dc8ef 100644 (file)
@@ -26,7 +26,7 @@
 #define OCR_TX_SHIFT      2
 
 struct sja1000_platform_data {
-       u32 clock;      /* CAN bus oscillator frequency in Hz */
+       u32 osc_freq;   /* CAN bus oscillator frequency in Hz */
 
        u8 ocr;         /* output control register */
        u8 cdr;         /* clock divider register */
index b7cdbb4373df1270a565916547afb7284bf65cd8..8723491f7dfd2c0d8c9e3a349d38316c38a40da8 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <linux/types.h>
 
-#define DCB_PROTO_VERSION 1
-
 struct dcbmsg {
        __u8               dcb_family;
        __u8               cmd;
index b33f316bb92e0f984c5ed593ed48e845fb242cba..276b40a168357ed5d4b793ccae7cbf387ba12711 100644 (file)
@@ -310,6 +310,7 @@ struct ethtool_perm_addr {
 enum ethtool_flags {
        ETH_FLAG_LRO            = (1 << 15),    /* LRO is enabled */
        ETH_FLAG_NTUPLE         = (1 << 27),    /* N-tuple filters enabled */
+       ETH_FLAG_RXHASH         = (1 << 28),
 };
 
 /* The following structures are for supporting RX network flow
@@ -490,12 +491,12 @@ void ethtool_ntuple_flush(struct net_device *dev);
  * get_ufo: Report whether UDP fragmentation offload is enabled
  * set_ufo: Turn UDP fragmentation offload on or off
  * self_test: Run specified self-tests
- * get_strings: Return a set of strings that describe the requested objects 
+ * get_strings: Return a set of strings that describe the requested objects
  * phys_id: Identify the device
  * get_stats: Return statistics about the device
  * get_flags: get 32-bit flags bitmap
  * set_flags: set 32-bit flags bitmap
- * 
+ *
  * Description:
  *
  * get_settings:
@@ -531,14 +532,20 @@ struct ethtool_ops {
        int     (*nway_reset)(struct net_device *);
        u32     (*get_link)(struct net_device *);
        int     (*get_eeprom_len)(struct net_device *);
-       int     (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
-       int     (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
+       int     (*get_eeprom)(struct net_device *,
+                             struct ethtool_eeprom *, u8 *);
+       int     (*set_eeprom)(struct net_device *,
+                             struct ethtool_eeprom *, u8 *);
        int     (*get_coalesce)(struct net_device *, struct ethtool_coalesce *);
        int     (*set_coalesce)(struct net_device *, struct ethtool_coalesce *);
-       void    (*get_ringparam)(struct net_device *, struct ethtool_ringparam *);
-       int     (*set_ringparam)(struct net_device *, struct ethtool_ringparam *);
-       void    (*get_pauseparam)(struct net_device *, struct ethtool_pauseparam*);
-       int     (*set_pauseparam)(struct net_device *, struct ethtool_pauseparam*);
+       void    (*get_ringparam)(struct net_device *,
+                                struct ethtool_ringparam *);
+       int     (*set_ringparam)(struct net_device *,
+                                struct ethtool_ringparam *);
+       void    (*get_pauseparam)(struct net_device *,
+                                 struct ethtool_pauseparam*);
+       int     (*set_pauseparam)(struct net_device *,
+                                 struct ethtool_pauseparam*);
        u32     (*get_rx_csum)(struct net_device *);
        int     (*set_rx_csum)(struct net_device *, u32);
        u32     (*get_tx_csum)(struct net_device *);
@@ -550,21 +557,24 @@ struct ethtool_ops {
        void    (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
        void    (*get_strings)(struct net_device *, u32 stringset, u8 *);
        int     (*phys_id)(struct net_device *, u32);
-       void    (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
+       void    (*get_ethtool_stats)(struct net_device *,
+                                    struct ethtool_stats *, u64 *);
        int     (*begin)(struct net_device *);
        void    (*complete)(struct net_device *);
-       u32     (*get_ufo)(struct net_device *);
-       int     (*set_ufo)(struct net_device *, u32);
-       u32     (*get_flags)(struct net_device *);
-       int     (*set_flags)(struct net_device *, u32);
-       u32     (*get_priv_flags)(struct net_device *);
-       int     (*set_priv_flags)(struct net_device *, u32);
+       u32     (*get_ufo)(struct net_device *);
+       int     (*set_ufo)(struct net_device *, u32);
+       u32     (*get_flags)(struct net_device *);
+       int     (*set_flags)(struct net_device *, u32);
+       u32     (*get_priv_flags)(struct net_device *);
+       int     (*set_priv_flags)(struct net_device *, u32);
        int     (*get_sset_count)(struct net_device *, int);
-       int     (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *);
+       int     (*get_rxnfc)(struct net_device *,
+                            struct ethtool_rxnfc *, void *);
        int     (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
-       int     (*flash_device)(struct net_device *, struct ethtool_flash *);
+       int     (*flash_device)(struct net_device *, struct ethtool_flash *);
        int     (*reset)(struct net_device *, u32 *);
-       int     (*set_rx_ntuple)(struct net_device *, struct ethtool_rx_ntuple *);
+       int     (*set_rx_ntuple)(struct net_device *,
+                                struct ethtool_rx_ntuple *);
        int     (*get_rx_ntuple)(struct net_device *, u32 stringset, void *);
 };
 #endif /* __KERNEL__ */
@@ -576,29 +586,29 @@ struct ethtool_ops {
 #define ETHTOOL_GREGS          0x00000004 /* Get NIC registers. */
 #define ETHTOOL_GWOL           0x00000005 /* Get wake-on-lan options. */
 #define ETHTOOL_SWOL           0x00000006 /* Set wake-on-lan options. */
-#define ETHTOOL_GMSGLVL                0x00000007 /* Get driver message level */
-#define ETHTOOL_SMSGLVL                0x00000008 /* Set driver msg level. */
+#define ETHTOOL_GMSGLVL        0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL        0x00000008 /* Set driver msg level. */
 #define ETHTOOL_NWAY_RST       0x00000009 /* Restart autonegotiation. */
 #define ETHTOOL_GLINK          0x0000000a /* Get link status (ethtool_value) */
-#define ETHTOOL_GEEPROM                0x0000000b /* Get EEPROM data */
-#define ETHTOOL_SEEPROM                0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GEEPROM        0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM        0x0000000c /* Set EEPROM data. */
 #define ETHTOOL_GCOALESCE      0x0000000e /* Get coalesce config */
 #define ETHTOOL_SCOALESCE      0x0000000f /* Set coalesce config. */
 #define ETHTOOL_GRINGPARAM     0x00000010 /* Get ring parameters */
 #define ETHTOOL_SRINGPARAM     0x00000011 /* Set ring parameters. */
 #define ETHTOOL_GPAUSEPARAM    0x00000012 /* Get pause parameters */
 #define ETHTOOL_SPAUSEPARAM    0x00000013 /* Set pause parameters. */
-#define ETHTOOL_GRXCSUM                0x00000014 /* Get RX hw csum enable (ethtool_value) */
-#define ETHTOOL_SRXCSUM                0x00000015 /* Set RX hw csum enable (ethtool_value) */
-#define ETHTOOL_GTXCSUM                0x00000016 /* Get TX hw csum enable (ethtool_value) */
-#define ETHTOOL_STXCSUM                0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GRXCSUM        0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM        0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM        0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM        0x00000017 /* Set TX hw csum enable (ethtool_value) */
 #define ETHTOOL_GSG            0x00000018 /* Get scatter-gather enable
                                            * (ethtool_value) */
 #define ETHTOOL_SSG            0x00000019 /* Set scatter-gather enable
                                            * (ethtool_value). */
 #define ETHTOOL_TEST           0x0000001a /* execute NIC self-test. */
 #define ETHTOOL_GSTRINGS       0x0000001b /* get specified string set */
-#define ETHTOOL_PHYS_ID                0x0000001c /* identify the NIC */
+#define ETHTOOL_PHYS_ID        0x0000001c /* identify the NIC */
 #define ETHTOOL_GSTATS         0x0000001d /* get NIC-specific statistics */
 #define ETHTOOL_GTSO           0x0000001e /* Get TSO enable (ethtool_value) */
 #define ETHTOOL_STSO           0x0000001f /* Set TSO enable (ethtool_value) */
@@ -609,24 +619,24 @@ struct ethtool_ops {
 #define ETHTOOL_SGSO           0x00000024 /* Set GSO enable (ethtool_value) */
 #define ETHTOOL_GFLAGS         0x00000025 /* Get flags bitmap(ethtool_value) */
 #define ETHTOOL_SFLAGS         0x00000026 /* Set flags bitmap(ethtool_value) */
-#define ETHTOOL_GPFLAGS                0x00000027 /* Get driver-private flags bitmap */
-#define ETHTOOL_SPFLAGS                0x00000028 /* Set driver-private flags bitmap */
+#define ETHTOOL_GPFLAGS        0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS        0x00000028 /* Set driver-private flags bitmap */
 
-#define        ETHTOOL_GRXFH           0x00000029 /* Get RX flow hash configuration */
-#define        ETHTOOL_SRXFH           0x0000002a /* Set RX flow hash configuration */
+#define ETHTOOL_GRXFH          0x00000029 /* Get RX flow hash configuration */
+#define ETHTOOL_SRXFH          0x0000002a /* Set RX flow hash configuration */
 #define ETHTOOL_GGRO           0x0000002b /* Get GRO enable (ethtool_value) */
 #define ETHTOOL_SGRO           0x0000002c /* Set GRO enable (ethtool_value) */
-#define        ETHTOOL_GRXRINGS        0x0000002d /* Get RX rings available for LB */
-#define        ETHTOOL_GRXCLSRLCNT     0x0000002e /* Get RX class rule count */
-#define        ETHTOOL_GRXCLSRULE      0x0000002f /* Get RX classification rule */
-#define        ETHTOOL_GRXCLSRLALL     0x00000030 /* Get all RX classification rule */
-#define        ETHTOOL_SRXCLSRLDEL     0x00000031 /* Delete RX classification rule */
-#define        ETHTOOL_SRXCLSRLINS     0x00000032 /* Insert RX classification rule */
-#define        ETHTOOL_FLASHDEV        0x00000033 /* Flash firmware to device */
-#define        ETHTOOL_RESET           0x00000034 /* Reset hardware */
-#define        ETHTOOL_SRXNTUPLE       0x00000035 /* Add an n-tuple filter to device */
-#define        ETHTOOL_GRXNTUPLE       0x00000036 /* Get n-tuple filters from device */
-#define        ETHTOOL_GSSET_INFO      0x00000037 /* Get string set info */
+#define ETHTOOL_GRXRINGS       0x0000002d /* Get RX rings available for LB */
+#define ETHTOOL_GRXCLSRLCNT    0x0000002e /* Get RX class rule count */
+#define ETHTOOL_GRXCLSRULE     0x0000002f /* Get RX classification rule */
+#define ETHTOOL_GRXCLSRLALL    0x00000030 /* Get all RX classification rule */
+#define ETHTOOL_SRXCLSRLDEL    0x00000031 /* Delete RX classification rule */
+#define ETHTOOL_SRXCLSRLINS    0x00000032 /* Insert RX classification rule */
+#define ETHTOOL_FLASHDEV       0x00000033 /* Flash firmware to device */
+#define ETHTOOL_RESET          0x00000034 /* Reset hardware */
+#define ETHTOOL_SRXNTUPLE      0x00000035 /* Add an n-tuple filter to device */
+#define ETHTOOL_GRXNTUPLE      0x00000036 /* Get n-tuple filters from device */
+#define ETHTOOL_GSSET_INFO     0x00000037 /* Get string set info */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
@@ -635,18 +645,18 @@ struct ethtool_ops {
 /* Indicates what features are supported by the interface. */
 #define SUPPORTED_10baseT_Half         (1 << 0)
 #define SUPPORTED_10baseT_Full         (1 << 1)
-#define SUPPORTED_100baseT_Half                (1 << 2)
-#define SUPPORTED_100baseT_Full                (1 << 3)
+#define SUPPORTED_100baseT_Half        (1 << 2)
+#define SUPPORTED_100baseT_Full        (1 << 3)
 #define SUPPORTED_1000baseT_Half       (1 << 4)
 #define SUPPORTED_1000baseT_Full       (1 << 5)
 #define SUPPORTED_Autoneg              (1 << 6)
 #define SUPPORTED_TP                   (1 << 7)
 #define SUPPORTED_AUI                  (1 << 8)
 #define SUPPORTED_MII                  (1 << 9)
-#define SUPPORTED_FIBRE                        (1 << 10)
+#define SUPPORTED_FIBRE                (1 << 10)
 #define SUPPORTED_BNC                  (1 << 11)
 #define SUPPORTED_10000baseT_Full      (1 << 12)
-#define SUPPORTED_Pause                        (1 << 13)
+#define SUPPORTED_Pause                (1 << 13)
 #define SUPPORTED_Asym_Pause           (1 << 14)
 #define SUPPORTED_2500baseX_Full       (1 << 15)
 #define SUPPORTED_Backplane            (1 << 16)
@@ -656,8 +666,8 @@ struct ethtool_ops {
 #define SUPPORTED_10000baseR_FEC       (1 << 20)
 
 /* Indicates what features are advertised by the interface. */
-#define ADVERTISED_10baseT_Half                (1 << 0)
-#define ADVERTISED_10baseT_Full                (1 << 1)
+#define ADVERTISED_10baseT_Half        (1 << 0)
+#define ADVERTISED_10baseT_Full        (1 << 1)
 #define ADVERTISED_100baseT_Half       (1 << 2)
 #define ADVERTISED_100baseT_Full       (1 << 3)
 #define ADVERTISED_1000baseT_Half      (1 << 4)
@@ -696,12 +706,12 @@ struct ethtool_ops {
 #define DUPLEX_FULL            0x01
 
 /* Which connector port. */
-#define PORT_TP                        0x00
+#define PORT_TP                0x00
 #define PORT_AUI               0x01
 #define PORT_MII               0x02
 #define PORT_FIBRE             0x03
 #define PORT_BNC               0x04
-#define PORT_DA                        0x05
+#define PORT_DA                0x05
 #define PORT_NONE              0xef
 #define PORT_OTHER             0xff
 
@@ -715,7 +725,7 @@ struct ethtool_ops {
 /* Enable or disable autonegotiation.  If this is set to enable,
  * the forced link modes above are completely ignored.
  */
-#define AUTONEG_DISABLE                0x00
+#define AUTONEG_DISABLE        0x00
 #define AUTONEG_ENABLE         0x01
 
 /* Mode MDI or MDI-X */
@@ -746,8 +756,8 @@ struct ethtool_ops {
 #define        AH_V6_FLOW      0x0b
 #define        ESP_V6_FLOW     0x0c
 #define        IP_USER_FLOW    0x0d
-#define IPV4_FLOW       0x10
-#define IPV6_FLOW       0x11
+#define        IPV4_FLOW       0x10
+#define        IPV6_FLOW       0x11
 
 /* L3-L4 network traffic flow hash options */
 #define        RXH_L2DA        (1 << 1)
index 29a0e3db9f4389f8b5d66bc8c7ebe34656a64028..151f5d703b7e19d158e500d8ebdf688b3d3dd047 100644 (file)
@@ -123,7 +123,8 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
 #define SKF_AD_NLATTR_NEST     16
 #define SKF_AD_MARK    20
 #define SKF_AD_QUEUE   24
-#define SKF_AD_MAX     28
+#define SKF_AD_HATYPE  28
+#define SKF_AD_MAX     32
 #define SKF_NET_OFF   (-0x100000)
 #define SKF_LL_OFF    (-0x200000)
 
index 948bd2bfb1deee0c4e3ec1b8ccef428207f4be0f..4079ef99900fcd4ca5d37a13da64ad2d6c54113d 100644 (file)
@@ -1280,10 +1280,12 @@ static inline int lock_may_write(struct inode *inode, loff_t start,
 
 
 struct fasync_struct {
-       int     magic;
-       int     fa_fd;
-       struct  fasync_struct   *fa_next; /* singly linked list */
-       struct  file            *fa_file;
+       spinlock_t              fa_lock;
+       int                     magic;
+       int                     fa_fd;
+       struct fasync_struct    *fa_next; /* singly linked list */
+       struct file             *fa_file;
+       struct rcu_head         fa_rcu;
 };
 
 #define FASYNC_MAGIC 0x4601
@@ -1292,8 +1294,6 @@ struct fasync_struct {
 extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
 /* can be called from interrupts */
 extern void kill_fasync(struct fasync_struct **, int, int);
-/* only for net: no internal synchronization */
-extern void __kill_fasync(struct fasync_struct *, int, int);
 
 extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
 extern int f_setown(struct file *filp, unsigned long arg, int force);
index b834ef6d59fa459ca793a004c311fe363e5a68fa..61549b26ad6f4dd114250ac00b170a1f734fd21b 100644 (file)
@@ -80,4 +80,12 @@ enum {
 
 #define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
 
+#ifdef __KERNEL__
+
+/* All generic netlink requests are serialized by a global lock.  */
+extern void genl_lock(void);
+extern void genl_unlock(void);
+
+#endif /* __KERNEL__ */
+
 #endif /* __LINUX_GENERIC_NETLINK_H */
index 19984958ab7b65fc5507f100edfd50c8d6a2acd7..97b2eae6a22cfe302d9a5956830a93c8cc37dab0 100644 (file)
@@ -876,6 +876,7 @@ struct ieee80211_ht_cap {
 #define IEEE80211_HT_CAP_SGI_40                        0x0040
 #define IEEE80211_HT_CAP_TX_STBC               0x0080
 #define IEEE80211_HT_CAP_RX_STBC               0x0300
+#define                IEEE80211_HT_CAP_RX_STBC_SHIFT  8
 #define IEEE80211_HT_CAP_DELAY_BA              0x0400
 #define IEEE80211_HT_CAP_MAX_AMSDU             0x0800
 #define IEEE80211_HT_CAP_DSSSCCK40             0x1000
@@ -1211,6 +1212,8 @@ enum ieee80211_category {
        WLAN_CATEGORY_SA_QUERY = 8,
        WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
        WLAN_CATEGORY_WMM = 17,
+       WLAN_CATEGORY_MESH_PLINK = 30,          /* Pending ANA approval */
+       WLAN_CATEGORY_MESH_PATH_SEL = 32,       /* Pending ANA approval */
        WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
        WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
 };
@@ -1324,7 +1327,6 @@ enum ieee80211_back_actioncode {
 enum ieee80211_back_parties {
        WLAN_BACK_RECIPIENT = 0,
        WLAN_BACK_INITIATOR = 1,
-       WLAN_BACK_TIMER = 2,
 };
 
 /* SA Query action */
index 3a9f410a296b35291150d27e900fb73d27d0c3d6..be350e62a905438533b0231439d8d65fd53d7de4 100644 (file)
@@ -71,6 +71,8 @@
                                         * release skb->dst
                                         */
 #define IFF_DONT_BRIDGE 0x800          /* disallow bridging this ether dev */
+#define IFF_IN_NETPOLL 0x1000          /* whether we are processing netpoll */
+#define IFF_DISABLE_NETPOLL    0x2000  /* disable netpoll at run-time */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
index e80b7f88f7c6cda4c2cb8e42c0675b868124afc7..6d722f41ee7c760010ae26f3deea4fea1c9ca4aa 100644 (file)
@@ -90,6 +90,7 @@
 
 #define ARPHRD_PHONET  820             /* PhoNet media type            */
 #define ARPHRD_PHONET_PIPE 821         /* PhoNet pipe header           */
+#define ARPHRD_CAIF    822             /* CAIF media type              */
 
 #define ARPHRD_VOID      0xFFFF        /* Void type, nothing is known */
 #define ARPHRD_NONE      0xFFFE        /* zero header length */
index 299b4121f91486b90780601f2e6bc389674131e8..bed7a4682b90734935e3dd6680d5e646b0b895c0 100644 (file)
 #define ETH_P_TRAILER  0x001C          /* Trailer switch tagging       */
 #define ETH_P_PHONET   0x00F5          /* Nokia Phonet frames          */
 #define ETH_P_IEEE802154 0x00F6                /* IEEE802.15.4 frame           */
+#define ETH_P_CAIF     0x00F7          /* ST-Ericsson CAIF protocol    */
 
 /*
  *     This is an Ethernet frame header.
index d94963b379d93133b19947df42ca8d5841aa3b2c..85c812db5a3f09e75f6bebc646c86300d6621594 100644 (file)
@@ -37,6 +37,38 @@ struct rtnl_link_stats {
        __u32   tx_compressed;
 };
 
+struct rtnl_link_stats64 {
+       __u64   rx_packets;             /* total packets received       */
+       __u64   tx_packets;             /* total packets transmitted    */
+       __u64   rx_bytes;               /* total bytes received         */
+       __u64   tx_bytes;               /* total bytes transmitted      */
+       __u64   rx_errors;              /* bad packets received         */
+       __u64   tx_errors;              /* packet transmit problems     */
+       __u64   rx_dropped;             /* no space in linux buffers    */
+       __u64   tx_dropped;             /* no space available in linux  */
+       __u64   multicast;              /* multicast packets received   */
+       __u64   collisions;
+
+       /* detailed rx_errors: */
+       __u64   rx_length_errors;
+       __u64   rx_over_errors;         /* receiver ring buff overflow  */
+       __u64   rx_crc_errors;          /* recved pkt with crc error    */
+       __u64   rx_frame_errors;        /* recv'd frame alignment error */
+       __u64   rx_fifo_errors;         /* recv'r fifo overrun          */
+       __u64   rx_missed_errors;       /* receiver missed packet       */
+
+       /* detailed tx_errors */
+       __u64   tx_aborted_errors;
+       __u64   tx_carrier_errors;
+       __u64   tx_fifo_errors;
+       __u64   tx_heartbeat_errors;
+       __u64   tx_window_errors;
+
+       /* for cslip etc */
+       __u64   rx_compressed;
+       __u64   tx_compressed;
+};
+
 /* The struct should be in sync with struct ifmap */
 struct rtnl_link_ifmap {
        __u64   mem_start;
@@ -80,6 +112,9 @@ enum {
        IFLA_IFALIAS,
        IFLA_NUM_VF,            /* Number of VFs if device is SR-IOV PF */
        IFLA_VFINFO_LIST,
+       IFLA_STATS64,
+       IFLA_VF_PORTS,
+       IFLA_PORT_SELF,
        __IFLA_MAX
 };
 
@@ -241,4 +276,77 @@ struct ifla_vf_info {
        __u32 qos;
        __u32 tx_rate;
 };
+
+/* VF ports management section
+ *
+ *     Nested layout of set/get msg is:
+ *
+ *             [IFLA_NUM_VF]
+ *             [IFLA_VF_PORTS]
+ *                     [IFLA_VF_PORT]
+ *                             [IFLA_PORT_*], ...
+ *                     [IFLA_VF_PORT]
+ *                             [IFLA_PORT_*], ...
+ *                     ...
+ *             [IFLA_PORT_SELF]
+ *                     [IFLA_PORT_*], ...
+ */
+
+enum {
+       IFLA_VF_PORT_UNSPEC,
+       IFLA_VF_PORT,                   /* nest */
+       __IFLA_VF_PORT_MAX,
+};
+
+#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1)
+
+enum {
+       IFLA_PORT_UNSPEC,
+       IFLA_PORT_VF,                   /* __u32 */
+       IFLA_PORT_PROFILE,              /* string */
+       IFLA_PORT_VSI_TYPE,             /* 802.1Qbg (pre-)standard VDP */
+       IFLA_PORT_INSTANCE_UUID,        /* binary UUID */
+       IFLA_PORT_HOST_UUID,            /* binary UUID */
+       IFLA_PORT_REQUEST,              /* __u8 */
+       IFLA_PORT_RESPONSE,             /* __u16, output only */
+       __IFLA_PORT_MAX,
+};
+
+#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1)
+
+#define PORT_PROFILE_MAX       40
+#define PORT_UUID_MAX          16
+#define PORT_SELF_VF           -1
+
+enum {
+       PORT_REQUEST_PREASSOCIATE = 0,
+       PORT_REQUEST_PREASSOCIATE_RR,
+       PORT_REQUEST_ASSOCIATE,
+       PORT_REQUEST_DISASSOCIATE,
+};
+
+enum {
+       PORT_VDP_RESPONSE_SUCCESS = 0,
+       PORT_VDP_RESPONSE_INVALID_FORMAT,
+       PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES,
+       PORT_VDP_RESPONSE_UNUSED_VTID,
+       PORT_VDP_RESPONSE_VTID_VIOLATION,
+       PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION,
+       PORT_VDP_RESPONSE_OUT_OF_SYNC,
+       /* 0x08-0xFF reserved for future VDP use */
+       PORT_PROFILE_RESPONSE_SUCCESS = 0x100,
+       PORT_PROFILE_RESPONSE_INPROGRESS,
+       PORT_PROFILE_RESPONSE_INVALID,
+       PORT_PROFILE_RESPONSE_BADSTATE,
+       PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES,
+       PORT_PROFILE_RESPONSE_ERROR,
+};
+
+struct ifla_port_vsi {
+       __u8 vsi_mgr_id;
+       __u8 vsi_type_id[3];
+       __u8 vsi_type_version;
+       __u8 pad[3];
+};
+
 #endif /* _LINUX_IF_LINK_H */
index b78a712247da071d03b207515936b9b28408fcf8..9ea047aca7955e7c654512b37648617d8c76c904 100644 (file)
@@ -85,6 +85,7 @@ extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
                                      struct net_device *dev);
 
 
-extern struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *);
+extern struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *,
+                                                   struct sk_buff *);
 
 #endif /* _LINUX_IF_MACVLAN_H */
index aa57a5f993fc0257d343ba78b47fae46251cfa6f..6ac23ef1801aaf9945dfdecfe386be51d7d9ac44 100644 (file)
@@ -47,6 +47,7 @@ struct sockaddr_ll {
 #define PACKET_TX_RING                 13
 #define PACKET_LOSS                    14
 #define PACKET_VNET_HDR                        15
+#define PACKET_TX_TIMESTAMP            16
 
 struct tpacket_stats {
        unsigned int    tp_packets;
index c58baea4a25b0f50c36841ffe125d6703c32d8dc..184bc5566207c0c6471b691ee7f00b32875f41f2 100644 (file)
@@ -2,7 +2,7 @@
  * Linux PPP over L2TP (PPPoL2TP) Socket Implementation (RFC 2661)
  *
  * This file supplies definitions required by the PPP over L2TP driver
- * (pppol2tp.c).  All version information wrt this file is located in pppol2tp.c
+ * (l2tp_ppp.c).  All version information wrt this file is located in l2tp_ppp.c
  *
  * License:
  *             This program is free software; you can redistribute it and/or
@@ -35,6 +35,20 @@ struct pppol2tp_addr {
        __u16 d_tunnel, d_session;      /* For sending outgoing packets */
 };
 
+/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
+ * bits. So we need a different sockaddr structure.
+ */
+struct pppol2tpv3_addr {
+       pid_t   pid;                    /* pid that owns the fd.
+                                        * 0 => current */
+       int     fd;                     /* FD of UDP or IP socket to use */
+
+       struct sockaddr_in addr;        /* IP address and port to send to */
+
+       __u32 s_tunnel, s_session;      /* For matching incoming packets */
+       __u32 d_tunnel, d_session;      /* For sending outgoing packets */
+};
+
 /* Socket options:
  * DEBUG       - bitmask of debug message categories
  * SENDSEQ     - 0 => don't send packets with sequence numbers
index 90b5fae5d714ae71f0c51fddb5e9a621501092c9..a6577af0c4e64de0f93e6c88e70264eab77c3fc5 100644 (file)
@@ -72,6 +72,15 @@ struct sockaddr_pppol2tp {
        struct pppol2tp_addr pppol2tp;
 }__attribute__ ((packed));
 
+/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
+ * bits. So we need a different sockaddr structure.
+ */
+struct sockaddr_pppol2tpv3 {
+       sa_family_t     sa_family;      /* address family, AF_PPPOX */
+       unsigned int    sa_protocol;    /* protocol identifier */
+       struct pppol2tpv3_addr pppol2tp;
+} __attribute__ ((packed));
+
 /*********************************************************************
  *
  * ioctl interface for defining forwarding of connections
index 1350a246893a179675fe7cc529e1ebb52f20dcf0..06b1829731fd6f6c7f4864463c0ee2b73b4e15bf 100644 (file)
@@ -51,6 +51,8 @@
 #define TUNSETSNDBUF   _IOW('T', 212, int)
 #define TUNATTACHFILTER _IOW('T', 213, struct sock_fprog)
 #define TUNDETACHFILTER _IOW('T', 214, struct sock_fprog)
+#define TUNGETVNETHDRSZ _IOR('T', 215, int)
+#define TUNSETVNETHDRSZ _IOW('T', 216, int)
 
 /* TUNSETIFF ifr flags */
 #define IFF_TUN                0x0001
diff --git a/include/linux/if_x25.h b/include/linux/if_x25.h
new file mode 100644 (file)
index 0000000..897765f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *  Linux X.25 packet to device interface
+ *
+ *  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.
+ */
+
+#ifndef _IF_X25_H
+#define _IF_X25_H
+
+#include <linux/types.h>
+
+/* Documentation/networking/x25-iface.txt */
+#define X25_IFACE_DATA         0x00
+#define X25_IFACE_CONNECT      0x01
+#define X25_IFACE_DISCONNECT   0x02
+#define X25_IFACE_PARAMS       0x03
+
+#endif /* _IF_X25_H */
index bd55c6e46b2ea6bbe72f582eac8cda8c14c0bd60..c4bf46f764bf34bffab67e6de3ec9c8ddee70b0e 100644 (file)
@@ -221,10 +221,10 @@ struct in6_flowlabel_req {
 #define IPV6_RTHDR             57
 #define IPV6_RECVDSTOPTS       58
 #define IPV6_DSTOPTS           59
-#if 0  /* not yet */
 #define IPV6_RECVPATHMTU       60
 #define IPV6_PATHMTU           61
 #define IPV6_DONTFRAG          62
+#if 0  /* not yet */
 #define IPV6_USE_MIN_MTU       63
 #endif
 
@@ -265,6 +265,9 @@ struct in6_flowlabel_req {
 #define IPV6_PREFER_SRC_CGA            0x0008
 #define IPV6_PREFER_SRC_NONCGA         0x0800
 
+/* RFC5082: Generalized Ttl Security Mechanism */
+#define IPV6_MINHOPCOUNT               73
+
 /*
  * Multicast Routing:
  * see include/linux/mroute6.h.
index e0cc9a7db2b5fdc689bceb7d2a3fb5d00aea6ede..99e1ab7e3eec2639720858471af957e42bdb05e9 100644 (file)
@@ -21,6 +21,10 @@ struct in6_pktinfo {
        int             ipi6_ifindex;
 };
 
+struct ip6_mtuinfo {
+       struct sockaddr_in6     ip6m_addr;
+       __u32                   ip6m_mtu;
+};
 
 struct in6_ifreq {
        struct in6_addr ifr6_addr;
@@ -250,9 +254,11 @@ struct inet6_skb_parm {
 
 #define IP6SKB_XFRM_TRANSFORMED        1
 #define IP6SKB_FORWARDED       2
+#define IP6SKB_REROUTED                4
 };
 
 #define IP6CB(skb)     ((struct inet6_skb_parm*)((skb)->cb))
+#define IP6CBMTU(skb)  ((struct ip6_mtuinfo *)((skb)->cb))
 
 static inline int inet6_iif(const struct sk_buff *skb)
 {
@@ -334,21 +340,25 @@ struct ipv6_pinfo {
                                dstopts:1,
                                odstopts:1,
                                 rxflow:1,
-                               rxtclass:1;
+                               rxtclass:1,
+                               rxpmtu:1;
                } bits;
                __u16           all;
        } rxopt;
 
        /* sockopt flags */
-       __u                   recverr:1,
+       __u16                   recverr:1,
                                sndflow:1,
                                pmtudisc:2,
                                ipv6only:1,
-                               srcprefs:3;     /* 001: prefer temporary address
+                               srcprefs:3,     /* 001: prefer temporary address
                                                 * 010: prefer public address
                                                 * 100: prefer care-of address
                                                 */
+                               dontfrag:1;
+       __u8                    min_hopcount;
        __u8                    tclass;
+       __u8                    padding;
 
        __u32                   dst_cookie;
 
@@ -358,6 +368,7 @@ struct ipv6_pinfo {
 
        struct ipv6_txoptions   *opt;
        struct sk_buff          *pktoptions;
+       struct sk_buff          *rxpmtu;
        struct {
                struct ipv6_txoptions *opt;
                u8 hop_limit;
@@ -372,6 +383,7 @@ struct raw6_sock {
        __u32                   checksum;       /* perform checksum */
        __u32                   offset;         /* checksum offset  */
        struct icmp6_filter     filter;
+       __u32                   ip6mr_table;
        /* ipv6_pinfo has to be the last member of raw6_sock, see inet6_sk_generic */
        struct ipv6_pinfo       inet6;
 };
index 9fb1c1299032ca8a051d969b8ab2bde46ea707b1..fc33af9118520e6a04376fbe96b9d7a85d9e478d 100644 (file)
@@ -4,6 +4,8 @@
 /*
  * 'kernel.h' contains some often-used function prototypes etc
  */
+#define __ALIGN_KERNEL(x, a)           __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
+#define __ALIGN_KERNEL_MASK(x, mask)   (((x) + (mask)) & ~(mask))
 
 #ifdef __KERNEL__
 
@@ -37,8 +39,8 @@ extern const char linux_proc_banner[];
 
 #define STACK_MAGIC    0xdeadbeef
 
-#define ALIGN(x,a)             __ALIGN_MASK(x,(typeof(x))(a)-1)
-#define __ALIGN_MASK(x,mask)   (((x)+(mask))&~(mask))
+#define ALIGN(x, a)            __ALIGN_KERNEL((x), (a))
+#define __ALIGN_MASK(x, mask)  __ALIGN_KERNEL_MASK((x), (mask))
 #define PTR_ALIGN(p, a)                ((typeof(p))ALIGN((unsigned long)(p), (a)))
 #define IS_ALIGNED(x, a)               (((x) & ((typeof(x))(a) - 1)) == 0)
 
diff --git a/include/linux/ks8842.h b/include/linux/ks8842.h
new file mode 100644 (file)
index 0000000..da0341b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * ks8842.h KS8842 platform data struct definition
+ * Copyright (c) 2010 Intel Corporation
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_KS8842_H
+#define _LINUX_KS8842_H
+
+#include <linux/if_ether.h>
+
+/**
+ * struct ks8842_platform_data - Platform data of the KS8842 network driver
+ * @macaddr:   The MAC address of the device, set to all 0:s to use the on in
+ *             the chip.
+ *
+ */
+struct ks8842_platform_data {
+       u8 macaddr[ETH_ALEN];
+};
+
+#endif
diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h
new file mode 100644 (file)
index 0000000..4bdb31d
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * L2TP-over-IP socket for L2TPv3.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ */
+
+#ifndef _LINUX_L2TP_H_
+#define _LINUX_L2TP_H_
+
+#include <linux/types.h>
+#ifdef __KERNEL__
+#include <linux/socket.h>
+#include <linux/in.h>
+#else
+#include <netinet/in.h>
+#endif
+
+#define IPPROTO_L2TP           115
+
+/**
+ * struct sockaddr_l2tpip - the sockaddr structure for L2TP-over-IP sockets
+ * @l2tp_family:  address family number AF_L2TPIP.
+ * @l2tp_addr:    protocol specific address information
+ * @l2tp_conn_id: connection id of tunnel
+ */
+#define __SOCK_SIZE__  16              /* sizeof(struct sockaddr)      */
+struct sockaddr_l2tpip {
+       /* The first fields must match struct sockaddr_in */
+       sa_family_t     l2tp_family;    /* AF_INET */
+       __be16          l2tp_unused;    /* INET port number (unused) */
+       struct in_addr  l2tp_addr;      /* Internet address */
+
+       __u32           l2tp_conn_id;   /* Connection ID of tunnel */
+
+       /* Pad to size of `struct sockaddr'. */
+       unsigned char   __pad[sizeof(struct sockaddr) - sizeof(sa_family_t) -
+                             sizeof(__be16) - sizeof(struct in_addr) -
+                             sizeof(__u32)];
+};
+
+/*****************************************************************************
+ *  NETLINK_GENERIC netlink family.
+ *****************************************************************************/
+
+/*
+ * Commands.
+ * Valid TLVs of each command are:-
+ * TUNNEL_CREATE       - CONN_ID, pw_type, netns, ifname, ipinfo, udpinfo, udpcsum, vlanid
+ * TUNNEL_DELETE       - CONN_ID
+ * TUNNEL_MODIFY       - CONN_ID, udpcsum
+ * TUNNEL_GETSTATS     - CONN_ID, (stats)
+ * TUNNEL_GET          - CONN_ID, (...)
+ * SESSION_CREATE      - SESSION_ID, PW_TYPE, offset, data_seq, cookie, peer_cookie, offset, l2spec
+ * SESSION_DELETE      - SESSION_ID
+ * SESSION_MODIFY      - SESSION_ID, data_seq
+ * SESSION_GET         - SESSION_ID, (...)
+ * SESSION_GETSTATS    - SESSION_ID, (stats)
+ *
+ */
+enum {
+       L2TP_CMD_NOOP,
+       L2TP_CMD_TUNNEL_CREATE,
+       L2TP_CMD_TUNNEL_DELETE,
+       L2TP_CMD_TUNNEL_MODIFY,
+       L2TP_CMD_TUNNEL_GET,
+       L2TP_CMD_SESSION_CREATE,
+       L2TP_CMD_SESSION_DELETE,
+       L2TP_CMD_SESSION_MODIFY,
+       L2TP_CMD_SESSION_GET,
+       __L2TP_CMD_MAX,
+};
+
+#define L2TP_CMD_MAX                   (__L2TP_CMD_MAX - 1)
+
+/*
+ * ATTR types defined for L2TP
+ */
+enum {
+       L2TP_ATTR_NONE,                 /* no data */
+       L2TP_ATTR_PW_TYPE,              /* u16, enum l2tp_pwtype */
+       L2TP_ATTR_ENCAP_TYPE,           /* u16, enum l2tp_encap_type */
+       L2TP_ATTR_OFFSET,               /* u16 */
+       L2TP_ATTR_DATA_SEQ,             /* u16 */
+       L2TP_ATTR_L2SPEC_TYPE,          /* u8, enum l2tp_l2spec_type */
+       L2TP_ATTR_L2SPEC_LEN,           /* u8, enum l2tp_l2spec_type */
+       L2TP_ATTR_PROTO_VERSION,        /* u8 */
+       L2TP_ATTR_IFNAME,               /* string */
+       L2TP_ATTR_CONN_ID,              /* u32 */
+       L2TP_ATTR_PEER_CONN_ID,         /* u32 */
+       L2TP_ATTR_SESSION_ID,           /* u32 */
+       L2TP_ATTR_PEER_SESSION_ID,      /* u32 */
+       L2TP_ATTR_UDP_CSUM,             /* u8 */
+       L2TP_ATTR_VLAN_ID,              /* u16 */
+       L2TP_ATTR_COOKIE,               /* 0, 4 or 8 bytes */
+       L2TP_ATTR_PEER_COOKIE,          /* 0, 4 or 8 bytes */
+       L2TP_ATTR_DEBUG,                /* u32 */
+       L2TP_ATTR_RECV_SEQ,             /* u8 */
+       L2TP_ATTR_SEND_SEQ,             /* u8 */
+       L2TP_ATTR_LNS_MODE,             /* u8 */
+       L2TP_ATTR_USING_IPSEC,          /* u8 */
+       L2TP_ATTR_RECV_TIMEOUT,         /* msec */
+       L2TP_ATTR_FD,                   /* int */
+       L2TP_ATTR_IP_SADDR,             /* u32 */
+       L2TP_ATTR_IP_DADDR,             /* u32 */
+       L2TP_ATTR_UDP_SPORT,            /* u16 */
+       L2TP_ATTR_UDP_DPORT,            /* u16 */
+       L2TP_ATTR_MTU,                  /* u16 */
+       L2TP_ATTR_MRU,                  /* u16 */
+       L2TP_ATTR_STATS,                /* nested */
+       __L2TP_ATTR_MAX,
+};
+
+#define L2TP_ATTR_MAX                  (__L2TP_ATTR_MAX - 1)
+
+/* Nested in L2TP_ATTR_STATS */
+enum {
+       L2TP_ATTR_STATS_NONE,           /* no data */
+       L2TP_ATTR_TX_PACKETS,           /* u64 */
+       L2TP_ATTR_TX_BYTES,             /* u64 */
+       L2TP_ATTR_TX_ERRORS,            /* u64 */
+       L2TP_ATTR_RX_PACKETS,           /* u64 */
+       L2TP_ATTR_RX_BYTES,             /* u64 */
+       L2TP_ATTR_RX_SEQ_DISCARDS,      /* u64 */
+       L2TP_ATTR_RX_OOS_PACKETS,       /* u64 */
+       L2TP_ATTR_RX_ERRORS,            /* u64 */
+       __L2TP_ATTR_STATS_MAX,
+};
+
+#define L2TP_ATTR_STATS_MAX            (__L2TP_ATTR_STATS_MAX - 1)
+
+enum l2tp_pwtype {
+       L2TP_PWTYPE_NONE = 0x0000,
+       L2TP_PWTYPE_ETH_VLAN = 0x0004,
+       L2TP_PWTYPE_ETH = 0x0005,
+       L2TP_PWTYPE_PPP = 0x0007,
+       L2TP_PWTYPE_PPP_AC = 0x0008,
+       L2TP_PWTYPE_IP = 0x000b,
+       __L2TP_PWTYPE_MAX
+};
+
+enum l2tp_l2spec_type {
+       L2TP_L2SPECTYPE_NONE,
+       L2TP_L2SPECTYPE_DEFAULT,
+};
+
+enum l2tp_encap_type {
+       L2TP_ENCAPTYPE_UDP,
+       L2TP_ENCAPTYPE_IP,
+};
+
+enum l2tp_seqmode {
+       L2TP_SEQ_NONE = 0,
+       L2TP_SEQ_IP = 1,
+       L2TP_SEQ_ALL = 2,
+};
+
+/*
+ * NETLINK_GENERIC related info
+ */
+#define L2TP_GENL_NAME         "l2tp"
+#define L2TP_GENL_VERSION      0x1
+
+#endif
index 0ebaef577ff59ef0666e68357f4e61fa08f2a864..329a8faa6e37bb32bd6e65f1b8fd758ac45baa36 100644 (file)
@@ -94,6 +94,8 @@
 
 #define  SDIO_BUS_WIDTH_1BIT   0x00
 #define  SDIO_BUS_WIDTH_4BIT   0x02
+#define  SDIO_BUS_ECSI         0x20    /* Enable continuous SPI interrupt */
+#define  SDIO_BUS_SCSI         0x40    /* Support continuous SPI interrupt */
 
 #define  SDIO_BUS_ASYNC_INT    0x20
 
index 56fde4364e4c062b8ce47f31155dfdc8db087177..007fbaafead0843aa3f125e805549926be249b01 100644 (file)
@@ -474,6 +474,32 @@ struct platform_device_id {
                        __attribute__((aligned(sizeof(kernel_ulong_t))));
 };
 
+#define MDIO_MODULE_PREFIX     "mdio:"
+
+#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d"
+#define MDIO_ID_ARGS(_id) \
+       (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1,   \
+       ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \
+       ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \
+       ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \
+       ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \
+       ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \
+       ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \
+       ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1
+
+/**
+ * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus
+ * @phy_id: The result of
+ *     (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&PHYSID2)) & @phy_id_mask
+ *     for this PHY type
+ * @phy_id_mask: Defines the significant bits of @phy_id.  A value of 0
+ *     is used to terminate an array of struct mdio_device_id.
+ */
+struct mdio_device_id {
+       __u32 phy_id;
+       __u32 phy_id_mask;
+};
+
 struct zorro_device_id {
        __u32 id;                       /* Device ID or ZORRO_WILDCARD */
        kernel_ulong_t driver_data;     /* Data private to the driver */
index c5f3d53548e2a41bcd6088db5cafbfd7e9f59054..fa04b246c9ae997f18b8030fa7b5650d19956e7e 100644 (file)
@@ -27,7 +27,8 @@
 #define MRT_DEL_MFC    (MRT_BASE+5)    /* Delete a multicast forwarding entry  */
 #define MRT_VERSION    (MRT_BASE+6)    /* Get the kernel multicast version     */
 #define MRT_ASSERT     (MRT_BASE+7)    /* Activate PIM assert mode             */
-#define MRT_PIM                (MRT_BASE+8)    /* enable PIM code      */
+#define MRT_PIM                (MRT_BASE+8)    /* enable PIM code                      */
+#define MRT_TABLE      (MRT_BASE+9)    /* Specify mroute table ID              */
 
 #define SIOCGETVIFCNT  SIOCPROTOPRIVATE        /* IP protocol privates */
 #define SIOCGETSGCNT   (SIOCPROTOPRIVATE+1)
@@ -191,10 +192,7 @@ struct vif_device {
 #define VIFF_STATIC 0x8000
 
 struct mfc_cache {
-       struct mfc_cache *next;                 /* Next entry on cache line     */
-#ifdef CONFIG_NET_NS
-       struct net *mfc_net;
-#endif
+       struct list_head list;
        __be32 mfc_mcastgrp;                    /* Group the entry belongs to   */
        __be32 mfc_origin;                      /* Source of packet             */
        vifi_t mfc_parent;                      /* Source interface             */
@@ -217,18 +215,6 @@ struct mfc_cache {
        } mfc_un;
 };
 
-static inline
-struct net *mfc_net(const struct mfc_cache *mfc)
-{
-       return read_pnet(&mfc->mfc_net);
-}
-
-static inline
-void mfc_net_set(struct mfc_cache *mfc, struct net *net)
-{
-       write_pnet(&mfc->mfc_net, hold_net(net));
-}
-
 #define MFC_STATIC             1
 #define MFC_NOTIFY             2
 
index 2caa1a8e525d128cf7154411d12d6a42fd8660ca..6091ab77f3889c6a6db39d37be2298715324f597 100644 (file)
@@ -24,7 +24,8 @@
 #define MRT6_DEL_MFC   (MRT6_BASE+5)   /* Delete a multicast forwarding entry  */
 #define MRT6_VERSION   (MRT6_BASE+6)   /* Get the kernel multicast version     */
 #define MRT6_ASSERT    (MRT6_BASE+7)   /* Activate PIM assert mode             */
-#define MRT6_PIM       (MRT6_BASE+8)   /* enable PIM code      */
+#define MRT6_PIM       (MRT6_BASE+8)   /* enable PIM code                      */
+#define MRT6_TABLE     (MRT6_BASE+9)   /* Specify mroute table ID              */
 
 #define SIOCGETMIFCNT_IN6      SIOCPROTOPRIVATE        /* IP protocol privates */
 #define SIOCGETSGCNT_IN6       (SIOCPROTOPRIVATE+1)
@@ -182,10 +183,7 @@ struct mif_device {
 #define VIFF_STATIC 0x8000
 
 struct mfc6_cache {
-       struct mfc6_cache *next;                /* Next entry on cache line     */
-#ifdef CONFIG_NET_NS
-       struct net *mfc6_net;
-#endif
+       struct list_head list;
        struct in6_addr mf6c_mcastgrp;                  /* Group the entry belongs to   */
        struct in6_addr mf6c_origin;                    /* Source of packet             */
        mifi_t mf6c_parent;                     /* Source interface             */
@@ -208,18 +206,6 @@ struct mfc6_cache {
        } mfc_un;
 };
 
-static inline
-struct net *mfc6_net(const struct mfc6_cache *mfc)
-{
-       return read_pnet(&mfc->mfc6_net);
-}
-
-static inline
-void mfc6_net_set(struct mfc6_cache *mfc, struct net *net)
-{
-       write_pnet(&mfc->mfc6_net, hold_net(net));
-}
-
 #define MFC_STATIC             1
 #define MFC_NOTIFY             2
 
@@ -244,14 +230,17 @@ extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
                           struct rtmsg *rtm, int nowait);
 
 #ifdef CONFIG_IPV6_MROUTE
-static inline struct sock *mroute6_socket(struct net *net)
-{
-       return net->ipv6.mroute6_sk;
-}
+extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb);
 extern int ip6mr_sk_done(struct sock *sk);
 #else
-static inline struct sock *mroute6_socket(struct net *net) { return NULL; }
-static inline int ip6mr_sk_done(struct sock *sk) { return 0; }
+static inline struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
+{
+       return NULL;
+}
+static inline int ip6mr_sk_done(struct sock *sk)
+{
+       return 0;
+}
 #endif
 #endif
 
index 4157b5d42bd6cb76469cf449d67fb8bb27aa1b16..2b4deeeb8646e7c6621261e24e2e3a94bb123f2a 100644 (file)
@@ -59,6 +59,7 @@ typedef enum {
 #include <linux/wait.h>
 #include <linux/fcntl.h>       /* For O_CLOEXEC and O_NONBLOCK */
 #include <linux/kmemcheck.h>
+#include <linux/rcupdate.h>
 
 struct poll_table_struct;
 struct pipe_inode_info;
@@ -116,6 +117,12 @@ enum sock_shutdown_cmd {
        SHUT_RDWR       = 2,
 };
 
+struct socket_wq {
+       wait_queue_head_t       wait;
+       struct fasync_struct    *fasync_list;
+       struct rcu_head         rcu;
+} ____cacheline_aligned_in_smp;
+
 /**
  *  struct socket - general BSD socket
  *  @state: socket state (%SS_CONNECTED, etc)
@@ -135,11 +142,8 @@ struct socket {
        kmemcheck_bitfield_end(type);
 
        unsigned long           flags;
-       /*
-        * Please keep fasync_list & wait fields in the same cache line
-        */
-       struct fasync_struct    *fasync_list;
-       wait_queue_head_t       wait;
+
+       struct socket_wq        *wq;
 
        struct file             *file;
        struct sock             *sk;
index 3857517f1ca59a621f9a57381497b59b0c559b8c..a1bff65181669f36fe2b16a8990072e30ef74314 100644 (file)
@@ -219,34 +219,6 @@ struct neighbour;
 struct neigh_parms;
 struct sk_buff;
 
-struct netif_rx_stats {
-       unsigned total;
-       unsigned dropped;
-       unsigned time_squeeze;
-       unsigned cpu_collision;
-};
-
-DECLARE_PER_CPU(struct netif_rx_stats, netdev_rx_stat);
-
-struct dev_addr_list {
-       struct dev_addr_list    *next;
-       u8                      da_addr[MAX_ADDR_LEN];
-       u8                      da_addrlen;
-       u8                      da_synced;
-       int                     da_users;
-       int                     da_gusers;
-};
-
-/*
- *     We tag multicasts with these structures.
- */
-
-#define dev_mc_list    dev_addr_list
-#define dmi_addr       da_addr
-#define dmi_addrlen    da_addrlen
-#define dmi_users      da_users
-#define dmi_gusers     da_gusers
-
 struct netdev_hw_addr {
        struct list_head        list;
        unsigned char           addr[MAX_ADDR_LEN];
@@ -255,8 +227,10 @@ struct netdev_hw_addr {
 #define NETDEV_HW_ADDR_T_SAN           2
 #define NETDEV_HW_ADDR_T_SLAVE         3
 #define NETDEV_HW_ADDR_T_UNICAST       4
+#define NETDEV_HW_ADDR_T_MULTICAST     5
        int                     refcount;
        bool                    synced;
+       bool                    global_use;
        struct rcu_head         rcu_head;
 };
 
@@ -265,16 +239,20 @@ 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)
+#define netdev_hw_addr_list_count(l) ((l)->count)
+#define netdev_hw_addr_list_empty(l) (netdev_hw_addr_list_count(l) == 0)
+#define netdev_hw_addr_list_for_each(ha, l) \
+       list_for_each_entry(ha, &(l)->list, list)
 
-#define netdev_mc_count(dev) ((dev)->mc_count)
-#define netdev_mc_empty(dev) (netdev_mc_count(dev) == 0)
+#define netdev_uc_count(dev) netdev_hw_addr_list_count(&(dev)->uc)
+#define netdev_uc_empty(dev) netdev_hw_addr_list_empty(&(dev)->uc)
+#define netdev_for_each_uc_addr(ha, dev) \
+       netdev_hw_addr_list_for_each(ha, &(dev)->uc)
 
-#define netdev_for_each_mc_addr(mclist, dev) \
-       for (mclist = dev->mc_list; mclist; mclist = mclist->next)
+#define netdev_mc_count(dev) netdev_hw_addr_list_count(&(dev)->mc)
+#define netdev_mc_empty(dev) netdev_hw_addr_list_empty(&(dev)->mc)
+#define netdev_for_each_mc_addr(ha, dev) \
+       netdev_hw_addr_list_for_each(ha, &(dev)->mc)
 
 struct hh_cache {
        struct hh_cache *hh_next;       /* Next entry                        */
@@ -531,6 +509,85 @@ struct netdev_queue {
        unsigned long           tx_dropped;
 } ____cacheline_aligned_in_smp;
 
+#ifdef CONFIG_RPS
+/*
+ * This structure holds an RPS map which can be of variable length.  The
+ * map is an array of CPUs.
+ */
+struct rps_map {
+       unsigned int len;
+       struct rcu_head rcu;
+       u16 cpus[0];
+};
+#define RPS_MAP_SIZE(_num) (sizeof(struct rps_map) + (_num * sizeof(u16)))
+
+/*
+ * The rps_dev_flow structure contains the mapping of a flow to a CPU and the
+ * tail pointer for that CPU's input queue at the time of last enqueue.
+ */
+struct rps_dev_flow {
+       u16 cpu;
+       u16 fill;
+       unsigned int last_qtail;
+};
+
+/*
+ * The rps_dev_flow_table structure contains a table of flow mappings.
+ */
+struct rps_dev_flow_table {
+       unsigned int mask;
+       struct rcu_head rcu;
+       struct work_struct free_work;
+       struct rps_dev_flow flows[0];
+};
+#define RPS_DEV_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_dev_flow_table) + \
+    (_num * sizeof(struct rps_dev_flow)))
+
+/*
+ * The rps_sock_flow_table contains mappings of flows to the last CPU
+ * on which they were processed by the application (set in recvmsg).
+ */
+struct rps_sock_flow_table {
+       unsigned int mask;
+       u16 ents[0];
+};
+#define        RPS_SOCK_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_sock_flow_table) + \
+    (_num * sizeof(u16)))
+
+#define RPS_NO_CPU 0xffff
+
+static inline void rps_record_sock_flow(struct rps_sock_flow_table *table,
+                                       u32 hash)
+{
+       if (table && hash) {
+               unsigned int cpu, index = hash & table->mask;
+
+               /* We only give a hint, preemption can change cpu under us */
+               cpu = raw_smp_processor_id();
+
+               if (table->ents[index] != cpu)
+                       table->ents[index] = cpu;
+       }
+}
+
+static inline void rps_reset_sock_flow(struct rps_sock_flow_table *table,
+                                      u32 hash)
+{
+       if (table && hash)
+               table->ents[hash & table->mask] = RPS_NO_CPU;
+}
+
+extern struct rps_sock_flow_table *rps_sock_flow_table;
+
+/* This structure contains an instance of an RX queue. */
+struct netdev_rx_queue {
+       struct rps_map *rps_map;
+       struct rps_dev_flow_table *rps_flow_table;
+       struct kobject kobj;
+       struct netdev_rx_queue *first;
+       atomic_t count;
+} ____cacheline_aligned_in_smp;
+#endif /* CONFIG_RPS */
 
 /*
  * This structure defines the management hooks for network devices.
@@ -630,6 +687,9 @@ struct netdev_queue {
  * int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate);
  * int (*ndo_get_vf_config)(struct net_device *dev,
  *                         int vf, struct ifla_vf_info *ivf);
+ * int (*ndo_set_vf_port)(struct net_device *dev, int vf,
+ *                       struct nlattr *port[]);
+ * int (*ndo_get_vf_port)(struct net_device *dev, int vf, struct sk_buff *skb);
  */
 #define HAVE_NET_DEVICE_OPS
 struct net_device_ops {
@@ -668,6 +728,7 @@ struct net_device_ops {
                                                        unsigned short vid);
 #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*ndo_poll_controller)(struct net_device *dev);
+       void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
                                                  int queue, u8 *mac);
@@ -678,6 +739,11 @@ struct net_device_ops {
        int                     (*ndo_get_vf_config)(struct net_device *dev,
                                                     int vf,
                                                     struct ifla_vf_info *ivf);
+       int                     (*ndo_set_vf_port)(struct net_device *dev,
+                                                  int vf,
+                                                  struct nlattr *port[]);
+       int                     (*ndo_get_vf_port)(struct net_device *dev,
+                                                  int vf, struct sk_buff *skb);
 #if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
        int                     (*ndo_fcoe_enable)(struct net_device *dev);
        int                     (*ndo_fcoe_disable)(struct net_device *dev);
@@ -768,6 +834,7 @@ struct net_device {
 #define NETIF_F_SCTP_CSUM      (1 << 25) /* SCTP checksum offload */
 #define NETIF_F_FCOE_MTU       (1 << 26) /* Supports max FCoE MTU, 2158 bytes*/
 #define NETIF_F_NTUPLE         (1 << 27) /* N-tuple filters supported */
+#define NETIF_F_RXHASH         (1 << 28) /* Receive hashing offload */
 
        /* Segmentation offload features */
 #define NETIF_F_GSO_SHIFT      16
@@ -824,7 +891,7 @@ struct net_device {
        unsigned char           operstate; /* RFC2863 operstate */
        unsigned char           link_mode; /* mapping policy to operstate */
 
-       unsigned                mtu;    /* interface MTU value          */
+       unsigned int            mtu;    /* interface MTU value          */
        unsigned short          type;   /* interface hardware type      */
        unsigned short          hard_header_len;        /* hardware hdr length  */
 
@@ -844,12 +911,10 @@ struct net_device {
        unsigned char           addr_len;       /* hardware address length      */
        unsigned short          dev_id;         /* for shared network cards */
 
-       struct netdev_hw_addr_list      uc;     /* Secondary unicast
-                                                  mac addresses */
-       int                     uc_promisc;
        spinlock_t              addr_list_lock;
-       struct dev_addr_list    *mc_list;       /* Multicast mac addresses      */
-       int                     mc_count;       /* Number of installed mcasts   */
+       struct netdev_hw_addr_list      uc;     /* Unicast mac addresses */
+       struct netdev_hw_addr_list      mc;     /* Multicast mac addresses */
+       int                     uc_promisc;
        unsigned int            promiscuity;
        unsigned int            allmulti;
 
@@ -882,6 +947,15 @@ struct net_device {
 
        unsigned char           broadcast[MAX_ADDR_LEN];        /* hw bcast add */
 
+#ifdef CONFIG_RPS
+       struct kset             *queues_kset;
+
+       struct netdev_rx_queue  *_rx;
+
+       /* Number of RX queues allocated at alloc_netdev_mq() time  */
+       unsigned int            num_rx_queues;
+#endif
+
        struct netdev_queue     rx_queue;
 
        struct netdev_queue     *_tx ____cacheline_aligned_in_smp;
@@ -1310,19 +1384,44 @@ static inline int unregister_gifconf(unsigned int family)
 }
 
 /*
- * Incoming packets are placed on per-cpu queues so that
- * no locking is needed.
+ * Incoming packets are placed on per-cpu queues
  */
 struct softnet_data {
        struct Qdisc            *output_queue;
-       struct sk_buff_head     input_pkt_queue;
+       struct Qdisc            **output_queue_tailp;
        struct list_head        poll_list;
        struct sk_buff          *completion_queue;
-
+       struct sk_buff_head     process_queue;
+
+       /* stats */
+       unsigned int            processed;
+       unsigned int            time_squeeze;
+       unsigned int            cpu_collision;
+       unsigned int            received_rps;
+
+#ifdef CONFIG_RPS
+       struct softnet_data     *rps_ipi_list;
+
+       /* Elements below can be accessed between CPUs for RPS */
+       struct call_single_data csd ____cacheline_aligned_in_smp;
+       struct softnet_data     *rps_ipi_next;
+       unsigned int            cpu;
+       unsigned int            input_queue_head;
+#endif
+       unsigned                dropped;
+       struct sk_buff_head     input_pkt_queue;
        struct napi_struct      backlog;
 };
 
-DECLARE_PER_CPU(struct softnet_data,softnet_data);
+static inline void input_queue_head_add(struct softnet_data *sd,
+                                       unsigned int len)
+{
+#ifdef CONFIG_RPS
+       sd->input_queue_head += len;
+#endif
+}
+
+DECLARE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
 
 #define HAVE_NETIF_QUEUE
 
@@ -1949,6 +2048,22 @@ extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 extern int             register_netdev(struct net_device *dev);
 extern void            unregister_netdev(struct net_device *dev);
 
+/* General hardware address lists handling functions */
+extern int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
+                                 struct netdev_hw_addr_list *from_list,
+                                 int addr_len, unsigned char addr_type);
+extern void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
+                                  struct netdev_hw_addr_list *from_list,
+                                  int addr_len, unsigned char addr_type);
+extern int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
+                         struct netdev_hw_addr_list *from_list,
+                         int addr_len);
+extern void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
+                            struct netdev_hw_addr_list *from_list,
+                            int addr_len);
+extern void __hw_addr_flush(struct netdev_hw_addr_list *list);
+extern void __hw_addr_init(struct netdev_hw_addr_list *list);
+
 /* Functions used for device addresses handling */
 extern int dev_addr_add(struct net_device *dev, unsigned char *addr,
                        unsigned char addr_type);
@@ -1960,26 +2075,34 @@ extern int dev_addr_add_multiple(struct net_device *to_dev,
 extern int dev_addr_del_multiple(struct net_device *to_dev,
                                 struct net_device *from_dev,
                                 unsigned char addr_type);
+extern void dev_addr_flush(struct net_device *dev);
+extern int dev_addr_init(struct net_device *dev);
+
+/* Functions used for unicast addresses handling */
+extern int dev_uc_add(struct net_device *dev, unsigned char *addr);
+extern int dev_uc_del(struct net_device *dev, unsigned char *addr);
+extern int dev_uc_sync(struct net_device *to, struct net_device *from);
+extern void dev_uc_unsync(struct net_device *to, struct net_device *from);
+extern void dev_uc_flush(struct net_device *dev);
+extern void dev_uc_init(struct net_device *dev);
+
+/* Functions used for multicast addresses handling */
+extern int dev_mc_add(struct net_device *dev, unsigned char *addr);
+extern int dev_mc_add_global(struct net_device *dev, unsigned char *addr);
+extern int dev_mc_del(struct net_device *dev, unsigned char *addr);
+extern int dev_mc_del_global(struct net_device *dev, unsigned char *addr);
+extern int dev_mc_sync(struct net_device *to, struct net_device *from);
+extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
+extern void dev_mc_flush(struct net_device *dev);
+extern void dev_mc_init(struct net_device *dev);
 
 /* Functions used for secondary unicast and multicast support */
 extern void            dev_set_rx_mode(struct net_device *dev);
 extern void            __dev_set_rx_mode(struct net_device *dev);
-extern int             dev_unicast_delete(struct net_device *dev, void *addr);
-extern int             dev_unicast_add(struct net_device *dev, void *addr);
-extern int             dev_unicast_sync(struct net_device *to, struct net_device *from);
-extern void            dev_unicast_unsync(struct net_device *to, struct net_device *from);
-extern int             dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
-extern int             dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
-extern int             dev_mc_sync(struct net_device *to, struct net_device *from);
-extern void            dev_mc_unsync(struct net_device *to, struct net_device *from);
-extern int             __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
-extern int             __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
-extern int             __dev_addr_sync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
-extern void            __dev_addr_unsync(struct dev_addr_list **to, int *to_count, struct dev_addr_list **from, int *from_count);
 extern int             dev_set_promiscuity(struct net_device *dev, int inc);
 extern int             dev_set_allmulti(struct net_device *dev, int inc);
 extern void            netdev_state_change(struct net_device *dev);
-extern void            netdev_bonding_change(struct net_device *dev,
+extern int             netdev_bonding_change(struct net_device *dev,
                                              unsigned long event);
 extern void            netdev_features_change(struct net_device *dev);
 /* Load a device via the kmod */
@@ -1989,6 +2112,7 @@ extern const struct net_device_stats *dev_get_stats(struct net_device *dev);
 extern void            dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats);
 
 extern int             netdev_max_backlog;
+extern int             netdev_tstamp_prequeue;
 extern int             weight_p;
 extern int             netdev_set_master(struct net_device *dev, struct net_device *master);
 extern int skb_checksum_help(struct sk_buff *skb);
@@ -2049,54 +2173,14 @@ static inline void netif_set_gso_max_size(struct net_device *dev,
        dev->gso_max_size = size;
 }
 
-static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
-                                             struct net_device *master)
-{
-       if (skb->pkt_type == PACKET_HOST) {
-               u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
+extern int __skb_bond_should_drop(struct sk_buff *skb,
+                                 struct net_device *master);
 
-               memcpy(dest, master->dev_addr, ETH_ALEN);
-       }
-}
-
-/* On bonding slaves other than the currently active slave, suppress
- * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
- * ARP on active-backup slaves with arp_validate enabled.
- */
 static inline int skb_bond_should_drop(struct sk_buff *skb,
                                       struct net_device *master)
 {
-       if (master) {
-               struct net_device *dev = skb->dev;
-
-               if (master->priv_flags & IFF_MASTER_ARPMON)
-                       dev->last_rx = jiffies;
-
-               if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) {
-                       /* Do address unmangle. The local destination address
-                        * will be always the one master has. Provides the right
-                        * functionality in a bridge.
-                        */
-                       skb_bond_set_mac_by_master(skb, master);
-               }
-
-               if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
-                       if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
-                           skb->protocol == __cpu_to_be16(ETH_P_ARP))
-                               return 0;
-
-                       if (master->priv_flags & IFF_MASTER_ALB) {
-                               if (skb->pkt_type != PACKET_BROADCAST &&
-                                   skb->pkt_type != PACKET_MULTICAST)
-                                       return 0;
-                       }
-                       if (master->priv_flags & IFF_MASTER_8023AD &&
-                           skb->protocol == __cpu_to_be16(ETH_P_SLOW))
-                               return 0;
-
-                       return 1;
-               }
-       }
+       if (master)
+               return __skb_bond_should_drop(skb, master);
        return 0;
 }
 
index a5a63e41b8af8a10ac8cd05a06ae426cf3f4a3d7..48767cd164537760d6e8bd99db88d971afbef88d 100644 (file)
@@ -16,6 +16,7 @@ header-y += xt_RATEEST.h
 header-y += xt_SECMARK.h
 header-y += xt_TCPMSS.h
 header-y += xt_TCPOPTSTRIP.h
+header-y += xt_TEE.h
 header-y += xt_TPROXY.h
 header-y += xt_comment.h
 header-y += xt_connbytes.h
index c608677dda60ac4eda7d96945f68ee22897529c1..14e6d32002c43d5a104bd45878c7671f9cbc20bc 100644 (file)
@@ -113,6 +113,7 @@ struct ip_conntrack_stat {
        unsigned int expect_new;
        unsigned int expect_create;
        unsigned int expect_delete;
+       unsigned int search_restart;
 };
 
 /* call to create an explicit dependency on nf_conntrack. */
index 8e145f0d61cb1c7aed4c7f23476086c16f9b99af..2ea22b018a874ae3b6356ebeb63cfc20f45ddbe3 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef _NF_CONNTRACK_TUPLE_COMMON_H
 #define _NF_CONNTRACK_TUPLE_COMMON_H
 
-enum ip_conntrack_dir
-{
+enum ip_conntrack_dir {
        IP_CT_DIR_ORIGINAL,
        IP_CT_DIR_REPLY,
        IP_CT_DIR_MAX
index 84c7c928e9ebb5ab3108e02b797f55645ef5e088..c2ee5d8550cf13bc84ac69fde5733b3ddf631577 100644 (file)
@@ -1,9 +1,10 @@
 #ifndef _X_TABLES_H
 #define _X_TABLES_H
-
+#include <linux/kernel.h>
 #include <linux/types.h>
 
 #define XT_FUNCTION_MAXNAMELEN 30
+#define XT_EXTENSION_MAXNAMELEN 29
 #define XT_TABLE_MAXNAMELEN 32
 
 struct xt_entry_match {
@@ -12,8 +13,7 @@ struct xt_entry_match {
                        __u16 match_size;
 
                        /* Used by userspace */
-                       char name[XT_FUNCTION_MAXNAMELEN-1];
-
+                       char name[XT_EXTENSION_MAXNAMELEN];
                        __u8 revision;
                } user;
                struct {
@@ -36,8 +36,7 @@ struct xt_entry_target {
                        __u16 target_size;
 
                        /* Used by userspace */
-                       char name[XT_FUNCTION_MAXNAMELEN-1];
-
+                       char name[XT_EXTENSION_MAXNAMELEN];
                        __u8 revision;
                } user;
                struct {
@@ -70,8 +69,7 @@ struct xt_standard_target {
 /* The argument to IPT_SO_GET_REVISION_*.  Returns highest revision
  * kernel supports, if >= revision. */
 struct xt_get_revision {
-       char name[XT_FUNCTION_MAXNAMELEN-1];
-
+       char name[XT_EXTENSION_MAXNAMELEN];
        __u8 revision;
 };
 
@@ -93,7 +91,7 @@ struct _xt_align {
        __u64 u64;
 };
 
-#define XT_ALIGN(s) ALIGN((s), __alignof__(struct _xt_align))
+#define XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _xt_align))
 
 /* Standard return verdict, or do jump. */
 #define XT_STANDARD_TARGET ""
@@ -185,40 +183,53 @@ struct xt_counters_info {
 #include <linux/netdevice.h>
 
 /**
- * struct xt_match_param - parameters for match extensions' match functions
+ * struct xt_action_param - parameters for matches/targets
  *
+ * @match:     the match extension
+ * @target:    the target extension
+ * @matchinfo: per-match data
+ * @targetinfo:        per-target data
  * @in:                input netdevice
  * @out:       output netdevice
- * @match:     struct xt_match through which this function was invoked
- * @matchinfo: per-match data
  * @fragoff:   packet is a fragment, this is the data offset
  * @thoff:     position of transport header relative to skb->data
  * @hook:      hook number given packet came from
  * @family:    Actual NFPROTO_* through which the function is invoked
  *             (helpful when match->family == NFPROTO_UNSPEC)
+ *
+ * Fields written to by extensions:
+ *
  * @hotdrop:   drop packet if we had inspection problems
+ * Network namespace obtainable using dev_net(in/out)
  */
-struct xt_match_param {
+struct xt_action_param {
+       union {
+               const struct xt_match *match;
+               const struct xt_target *target;
+       };
+       union {
+               const void *matchinfo, *targinfo;
+       };
        const struct net_device *in, *out;
-       const struct xt_match *match;
-       const void *matchinfo;
        int fragoff;
        unsigned int thoff;
        unsigned int hooknum;
        u_int8_t family;
-       bool *hotdrop;
+       bool hotdrop;
 };
 
 /**
  * struct xt_mtchk_param - parameters for match extensions'
  * checkentry functions
  *
+ * @net:       network namespace through which the check was invoked
  * @table:     table the rule is tried to be inserted into
  * @entryinfo: the family-specific rule data
- *             (struct ipt_ip, ip6t_ip, ebt_entry)
+ *             (struct ipt_ip, ip6t_ip, arpt_arp or (note) ebt_entry)
  * @match:     struct xt_match through which this function was invoked
  * @matchinfo: per-match data
  * @hook_mask: via which hooks the new rule is reachable
+ * Other fields as above.
  */
 struct xt_mtchk_param {
        struct net *net;
@@ -230,7 +241,10 @@ struct xt_mtchk_param {
        u_int8_t family;
 };
 
-/* Match destructor parameters */
+/**
+ * struct xt_mdtor_param - match destructor parameters
+ * Fields as above.
+ */
 struct xt_mtdtor_param {
        struct net *net;
        const struct xt_match *match;
@@ -238,23 +252,6 @@ struct xt_mtdtor_param {
        u_int8_t family;
 };
 
-/**
- * struct xt_target_param - parameters for target extensions' target functions
- *
- * @hooknum:   hook through which this target was invoked
- * @target:    struct xt_target through which this function was invoked
- * @targinfo:  per-target data
- *
- * Other fields see above.
- */
-struct xt_target_param {
-       const struct net_device *in, *out;
-       const struct xt_target *target;
-       const void *targinfo;
-       unsigned int hooknum;
-       u_int8_t family;
-};
-
 /**
  * struct xt_tgchk_param - parameters for target extensions'
  * checkentry functions
@@ -285,7 +282,7 @@ struct xt_tgdtor_param {
 struct xt_match {
        struct list_head list;
 
-       const char name[XT_FUNCTION_MAXNAMELEN-1];
+       const char name[XT_EXTENSION_MAXNAMELEN];
        u_int8_t revision;
 
        /* Return true or false: return FALSE and set *hotdrop = 1 to
@@ -294,10 +291,10 @@ struct xt_match {
           non-linear skb, using skb_header_pointer and
           skb_ip_make_writable. */
        bool (*match)(const struct sk_buff *skb,
-                     const struct xt_match_param *);
+                     struct xt_action_param *);
 
        /* Called when user tries to insert an entry of this type. */
-       bool (*checkentry)(const struct xt_mtchk_param *);
+       int (*checkentry)(const struct xt_mtchk_param *);
 
        /* Called when entry of this type deleted. */
        void (*destroy)(const struct xt_mtdtor_param *);
@@ -309,9 +306,6 @@ struct xt_match {
        /* Set this to THIS_MODULE if you are a module, otherwise NULL */
        struct module *me;
 
-       /* Free to use by each match */
-       unsigned long data;
-
        const char *table;
        unsigned int matchsize;
 #ifdef CONFIG_COMPAT
@@ -327,19 +321,20 @@ struct xt_match {
 struct xt_target {
        struct list_head list;
 
-       const char name[XT_FUNCTION_MAXNAMELEN-1];
+       const char name[XT_EXTENSION_MAXNAMELEN];
+       u_int8_t revision;
 
        /* Returns verdict. Argument order changed since 2.6.9, as this
           must now handle non-linear skbs, using skb_copy_bits and
           skb_ip_make_writable. */
        unsigned int (*target)(struct sk_buff *skb,
-                              const struct xt_target_param *);
+                              const struct xt_action_param *);
 
        /* Called when user tries to insert an entry of this type:
            hook_mask is a bitmask of hooks from which it can be
            called. */
-       /* Should return true or false. */
-       bool (*checkentry)(const struct xt_tgchk_param *);
+       /* Should return true or false, or an error code (-Exxxx). */
+       int (*checkentry)(const struct xt_tgchk_param *);
 
        /* Called when entry of this type deleted. */
        void (*destroy)(const struct xt_tgdtor_param *);
@@ -360,7 +355,6 @@ struct xt_target {
        unsigned short proto;
 
        unsigned short family;
-       u_int8_t revision;
 };
 
 /* Furniture shopping... */
@@ -398,6 +392,13 @@ struct xt_table_info {
        unsigned int hook_entry[NF_INET_NUMHOOKS];
        unsigned int underflow[NF_INET_NUMHOOKS];
 
+       /*
+        * Number of user chains. Since tables cannot have loops, at most
+        * @stacksize jumps (number of user chains) can possibly be made.
+        */
+       unsigned int stacksize;
+       unsigned int *stackptr;
+       void ***jumpstack;
        /* ipt_entry tables: one per CPU */
        /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */
        void *entries[1];
@@ -433,6 +434,8 @@ extern struct xt_table_info *xt_replace_table(struct xt_table *table,
 
 extern struct xt_match *xt_find_match(u8 af, const char *name, u8 revision);
 extern struct xt_target *xt_find_target(u8 af, const char *name, u8 revision);
+extern struct xt_match *xt_request_find_match(u8 af, const char *name,
+                                             u8 revision);
 extern struct xt_target *xt_request_find_target(u8 af, const char *name,
                                                u8 revision);
 extern int xt_find_revision(u8 af, const char *name, u8 revision,
@@ -598,7 +601,7 @@ struct _compat_xt_align {
        compat_u64 u64;
 };
 
-#define COMPAT_XT_ALIGN(s) ALIGN((s), __alignof__(struct _compat_xt_align))
+#define COMPAT_XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _compat_xt_align))
 
 extern void xt_compat_lock(u_int8_t af);
 extern void xt_compat_unlock(u_int8_t af);
index 0a854586675245f236fc940aa3b0cdb4b00e26d0..2f2e48ec80238ad5fa0dc26f5d2f5a8355b8d8e5 100644 (file)
@@ -1,26 +1,6 @@
 #ifndef _XT_CONNMARK_H_target
 #define _XT_CONNMARK_H_target
 
-#include <linux/types.h>
-
-/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
- * by Henrik Nordstrom <hno@marasystems.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-enum {
-       XT_CONNMARK_SET = 0,
-       XT_CONNMARK_SAVE,
-       XT_CONNMARK_RESTORE
-};
-
-struct xt_connmark_tginfo1 {
-       __u32 ctmark, ctmask, nfmask;
-       __u8 mode;
-};
+#include <linux/netfilter/xt_connmark.h>
 
 #endif /*_XT_CONNMARK_H_target*/
index bc9561bdef7902a6115392679d2c623daa86c66a..41c456deba222e25ab188559fb81605cd42353d5 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _XT_MARK_H_target
 #define _XT_MARK_H_target
 
-#include <linux/types.h>
-
-struct xt_mark_tginfo2 {
-       __u32 mark, mask;
-};
+#include <linux/netfilter/xt_mark.h>
 
 #endif /*_XT_MARK_H_target */
diff --git a/include/linux/netfilter/xt_TEE.h b/include/linux/netfilter/xt_TEE.h
new file mode 100644 (file)
index 0000000..5c21d5c
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _XT_TEE_TARGET_H
+#define _XT_TEE_TARGET_H
+
+struct xt_tee_tginfo {
+       union nf_inet_addr gw;
+       char oif[16];
+
+       /* used internally by the kernel */
+       struct xt_tee_priv *priv __attribute__((aligned(8)));
+};
+
+#endif /* _XT_TEE_TARGET_H */
index 619e47cde01a8921110f57a903d1330b1a6b6f3f..efc17a8305fb71f93741ad1579dae6f9da3075d1 100644 (file)
  * (at your option) any later version.
  */
 
+enum {
+       XT_CONNMARK_SET = 0,
+       XT_CONNMARK_SAVE,
+       XT_CONNMARK_RESTORE
+};
+
+struct xt_connmark_tginfo1 {
+       __u32 ctmark, ctmask, nfmask;
+       __u8 mode;
+};
+
 struct xt_connmark_mtinfo1 {
        __u32 mark, mask;
        __u8 invert;
index 6607c8f38ea528cbf43ac4764bcfad8d280cd1a7..ecadc40d5cdedcfc3ec4b17ecdc8273c46395316 100644 (file)
@@ -3,6 +3,10 @@
 
 #include <linux/types.h>
 
+struct xt_mark_tginfo2 {
+       __u32 mark, mask;
+};
+
 struct xt_mark_mtinfo1 {
        __u32 mark, mask;
        __u8 invert;
index d2c276609925c59a2dad78213094c1c984ff9ed5..83318e01425e74494f5c48fb25f83d015e522d01 100644 (file)
@@ -9,6 +9,7 @@ enum {
        XT_RECENT_UPDATE   = 1 << 2,
        XT_RECENT_REMOVE   = 1 << 3,
        XT_RECENT_TTL      = 1 << 4,
+       XT_RECENT_REAP     = 1 << 5,
 
        XT_RECENT_SOURCE   = 0,
        XT_RECENT_DEST     = 1,
@@ -16,6 +17,12 @@ enum {
        XT_RECENT_NAME_LEN = 200,
 };
 
+/* Only allowed with --rcheck and --update */
+#define XT_RECENT_MODIFIERS (XT_RECENT_TTL|XT_RECENT_REAP)
+
+#define XT_RECENT_VALID_FLAGS (XT_RECENT_CHECK|XT_RECENT_SET|XT_RECENT_UPDATE|\
+                              XT_RECENT_REMOVE|XT_RECENT_TTL|XT_RECENT_REAP)
+
 struct xt_recent_mtinfo {
        __u32 seconds;
        __u32 hit_count;
index f8105e54716a76bccdfbbcdcf9b7c34a974d2906..0ddd161f3b060c2e2ec0d665c1ddc719213443f7 100644 (file)
@@ -41,10 +41,10 @@ enum nf_br_hook_priorities {
 
 #define BRNF_PKT_TYPE                  0x01
 #define BRNF_BRIDGED_DNAT              0x02
-#define BRNF_DONT_TAKE_PARENT          0x04
-#define BRNF_BRIDGED                   0x08
-#define BRNF_NF_BRIDGE_PREROUTING      0x10
-
+#define BRNF_BRIDGED                   0x04
+#define BRNF_NF_BRIDGE_PREROUTING      0x08
+#define BRNF_8021Q                     0x10
+#define BRNF_PPPoE                     0x20
 
 /* Only used in br_forward.c */
 extern int nf_bridge_copy_header(struct sk_buff *skb);
@@ -68,6 +68,27 @@ static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
        }
 }
 
+static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
+{
+       if (unlikely(skb->nf_bridge->mask & BRNF_PPPoE))
+               return PPPOE_SES_HLEN;
+       return 0;
+}
+
+extern int br_handle_frame_finish(struct sk_buff *skb);
+/* Only used in br_device.c */
+static inline int br_nf_pre_routing_finish_bridge_slow(struct sk_buff *skb)
+{
+       struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+
+       skb_pull(skb, ETH_HLEN);
+       nf_bridge->mask ^= BRNF_BRIDGED_DNAT;
+       skb_copy_to_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN),
+                                      skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
+       skb->dev = nf_bridge->physindev;
+       return br_handle_frame_finish(skb);
+}
+
 /* This is called by the IP fragmenting code and it ensures there is
  * enough room for the encapsulating header (if there is one). */
 static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
index e5ba03d783c68ecb558c155afb249bb2b4757a1e..18442ff19c07ce1a213d5a4f81244907af8cd178 100644 (file)
@@ -316,10 +316,6 @@ extern int ip6t_ext_hdr(u8 nexthdr);
 extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                         int target, unsigned short *fragoff);
 
-extern int ip6_masked_addrcmp(const struct in6_addr *addr1,
-                             const struct in6_addr *mask,
-                             const struct in6_addr *addr2);
-
 #define IP6T_ALIGN(s) XT_ALIGN(s)
 
 #ifdef CONFIG_COMPAT
index a765ea89854989318d50d2371ad71dee60566048..e9e231215865bd6218abd37c320784ab3976235e 100644 (file)
@@ -14,6 +14,7 @@
 
 struct netpoll {
        struct net_device *dev;
+       struct net_device *real_dev;
        char dev_name[IFNAMSIZ];
        const char *name;
        void (*rx_hook)(struct netpoll *, int, char *, int);
@@ -36,8 +37,11 @@ struct netpoll_info {
        struct sk_buff_head txq;
 
        struct delayed_work tx_work;
+
+       struct netpoll *netpoll;
 };
 
+void netpoll_poll_dev(struct net_device *dev);
 void netpoll_poll(struct netpoll *np);
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
 void netpoll_print_options(struct netpoll *np);
@@ -47,22 +51,23 @@ int netpoll_trap(void);
 void netpoll_set_trap(int trap);
 void netpoll_cleanup(struct netpoll *np);
 int __netpoll_rx(struct sk_buff *skb);
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
 
 
 #ifdef CONFIG_NETPOLL
-static inline int netpoll_rx(struct sk_buff *skb)
+static inline bool netpoll_rx(struct sk_buff *skb)
 {
        struct netpoll_info *npinfo = skb->dev->npinfo;
        unsigned long flags;
-       int ret = 0;
+       bool ret = false;
 
        if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
-               return 0;
+               return false;
 
        spin_lock_irqsave(&npinfo->rx_lock, flags);
        /* check rx_flags again with the lock held */
        if (npinfo->rx_flags && __netpoll_rx(skb))
-               ret = 1;
+               ret = true;
        spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 
        return ret;
index 28ba20fda3e2c18fa5d95475f9391a58cb7a4378..b7c77f9712f4bedd172ac9ef9ecdfd23a8ac084b 100644 (file)
@@ -52,6 +52,8 @@
  *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
  *     %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
  *     and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ *     However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
+ *     instead, the support here is for backward compatibility only.
  * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
  *     or rename notification. Has attributes %NL80211_ATTR_WIPHY and
  *     %NL80211_ATTR_WIPHY_NAME.
  *     the TX command and %NL80211_ATTR_FRAME includes the contents of the
  *     frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
  *     the frame.
+ * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
+ *     is used to configure connection quality monitoring notification trigger
+ *     levels.
+ * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
+ *     command is used as an event to indicate the that a trigger level was
+ *     reached.
+ * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
+ *     and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
+ *     by %NL80211_ATTR_IFINDEX) shall operate on.
+ *     In case multiple channels are supported by the device, the mechanism
+ *     with which it switches channels is implementation-defined.
+ *     When a monitor interface is given, it can only switch channel while
+ *     no other interfaces are operating to avoid disturbing the operation
+ *     of any other interfaces, and other interfaces will again take
+ *     precedence when they are used.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -419,6 +436,11 @@ enum nl80211_commands {
        NL80211_CMD_SET_POWER_SAVE,
        NL80211_CMD_GET_POWER_SAVE,
 
+       NL80211_CMD_SET_CQM,
+       NL80211_CMD_NOTIFY_CQM,
+
+       NL80211_CMD_SET_CHANNEL,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -691,6 +713,18 @@ enum nl80211_commands {
  * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was
  *     acknowledged by the recipient.
  *
+ * @NL80211_ATTR_CQM: connection quality monitor configuration in a
+ *     nested attribute with %NL80211_ATTR_CQM_* sub-attributes.
+ *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
+ *     is requesting a local authentication/association state change without
+ *     invoking actual management frame exchange. This can be used with
+ *     NL80211_CMD_AUTHENTICATE, NL80211_CMD_DEAUTHENTICATE,
+ *     NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations
+ *     connected to this BSS.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -842,6 +876,12 @@ enum nl80211_attrs {
 
        NL80211_ATTR_PS_STATE,
 
+       NL80211_ATTR_CQM,
+
+       NL80211_ATTR_LOCAL_STATE_CHANGE,
+
+       NL80211_ATTR_AP_ISOLATE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1583,4 +1623,40 @@ enum nl80211_ps_state {
        NL80211_PS_ENABLED,
 };
 
+/**
+ * enum nl80211_attr_cqm - connection quality monitor attributes
+ * @__NL80211_ATTR_CQM_INVALID: invalid
+ * @NL80211_ATTR_CQM_RSSI_THOLD: RSSI threshold in dBm. This value specifies
+ *     the threshold for the RSSI level at which an event will be sent. Zero
+ *     to disable.
+ * @NL80211_ATTR_CQM_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
+ *     the minimum amount the RSSI level must change after an event before a
+ *     new event may be issued (to reduce effects of RSSI oscillation).
+ * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @__NL80211_ATTR_CQM_AFTER_LAST: internal
+ * @NL80211_ATTR_CQM_MAX: highest key attribute
+ */
+enum nl80211_attr_cqm {
+       __NL80211_ATTR_CQM_INVALID,
+       NL80211_ATTR_CQM_RSSI_THOLD,
+       NL80211_ATTR_CQM_RSSI_HYST,
+       NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+
+       /* keep last */
+       __NL80211_ATTR_CQM_AFTER_LAST,
+       NL80211_ATTR_CQM_MAX = __NL80211_ATTR_CQM_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW - The RSSI level is lower than the
+ *      configured threshold
+ * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH - The RSSI is higher than the
+ *      configured threshold
+ */
+enum nl80211_cqm_rssi_threshold_event {
+       NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+       NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+};
+
 #endif /* __LINUX_NL80211_H */
index fee6c2f68075c90fe77cea11138d627bd9efa4f5..7c36096223340a1d674b253430e5128b71f7abaa 100644 (file)
@@ -182,7 +182,10 @@ static inline int notifier_to_errno(int ret)
  *     VC switch chains (for loadable kernel svgalib VC switch helpers) etc...
  */
  
-/* netdevice notifier chain */
+/* netdevice notifier chain. Please remember to update the rtnetlink
+ * notification exclusion list in rtnetlink_event() when adding new
+ * types.
+ */
 #define NETDEV_UP      0x0001  /* For now you can't veto a device up/down */
 #define NETDEV_DOWN    0x0002
 #define NETDEV_REBOOT  0x0003  /* Tell a protocol stack a network interface
@@ -199,10 +202,11 @@ static inline int notifier_to_errno(int ret)
 #define NETDEV_FEAT_CHANGE     0x000B
 #define NETDEV_BONDING_FAILOVER 0x000C
 #define NETDEV_PRE_UP          0x000D
-#define NETDEV_BONDING_OLDTYPE  0x000E
-#define NETDEV_BONDING_NEWTYPE  0x000F
+#define NETDEV_PRE_TYPE_CHANGE 0x000E
+#define NETDEV_POST_TYPE_CHANGE        0x000F
 #define NETDEV_POST_INIT       0x0010
 #define NETDEV_UNREGISTER_BATCH 0x0011
+#define NETDEV_BONDING_DESLAVE  0x0012
 
 #define SYS_DOWN       0x0001  /* Notify of system down */
 #define SYS_RESTART    SYS_DOWN
index c8f302991b669c37ff8226b60f0b2307703c86f9..c4c3d68be19ad150561d9e885bd35cb0d0825993 100644 (file)
 #define  PCI_EXP_LNKCTL_LABIE  0x0800  /* Lnk Autonomous Bandwidth Interrupt Enable */
 #define PCI_EXP_LNKSTA         18      /* Link Status */
 #define  PCI_EXP_LNKSTA_CLS    0x000f  /* Current Link Speed */
+#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */
 #define  PCI_EXP_LNKSTA_NLW    0x03f0  /* Nogotiated Link Width */
+#define  PCI_EXP_LNKSTA_NLW_SHIFT 4    /* start of NLW mask in link status */
 #define  PCI_EXP_LNKSTA_LT     0x0800  /* Link Training */
 #define  PCI_EXP_LNKSTA_SLC    0x1000  /* Slot Clock Configuration */
 #define  PCI_EXP_LNKSTA_DLLLA  0x2000  /* Data Link Layer Link Active */
index 14d7fdf6a90ae229af04e755cd4e25f73f209f1b..987e111f7b112ec1c72ab86243819666614c0676 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mii.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
+#include <linux/mod_devicetable.h>
 
 #include <asm/atomic.h>
 
@@ -81,6 +82,10 @@ typedef enum {
  */
 #define MII_BUS_ID_SIZE        (20 - 3)
 
+/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
+   IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */
+#define MII_ADDR_C45 (1<<30)
+
 /*
  * The Bus class for PHYs.  Devices which provide access to
  * PHYs should register using this structure
@@ -127,8 +132,8 @@ int mdiobus_register(struct mii_bus *bus);
 void mdiobus_unregister(struct mii_bus *bus);
 void mdiobus_free(struct mii_bus *bus);
 struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
-int mdiobus_read(struct mii_bus *bus, int addr, u16 regnum);
-int mdiobus_write(struct mii_bus *bus, int addr, u16 regnum, u16 val);
+int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
+int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
 
 
 #define PHY_INTERRUPT_DISABLED 0x0
@@ -422,7 +427,7 @@ struct phy_fixup {
  * because the bus read/write functions may wait for an interrupt
  * to conclude the operation.
  */
-static inline int phy_read(struct phy_device *phydev, u16 regnum)
+static inline int phy_read(struct phy_device *phydev, u32 regnum)
 {
        return mdiobus_read(phydev->bus, phydev->addr, regnum);
 }
@@ -437,7 +442,7 @@ static inline int phy_read(struct phy_device *phydev, u16 regnum)
  * because the bus read/write functions may wait for an interrupt
  * to conclude the operation.
  */
-static inline int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
+static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)
 {
        return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
 }
index 0d3fa63e90ea28fc8494447aaeaa5eda27bb38c4..bff98ec1bfed2aa86e791ef7c6192cf37d29d2c0 100644 (file)
@@ -72,6 +72,9 @@ extern int ppp_channel_index(struct ppp_channel *);
 /* Get the unit number associated with a channel, or -1 if none */
 extern int ppp_unit_number(struct ppp_channel *);
 
+/* Get the device name associated with a channel, or NULL if none */
+extern char *ppp_dev_name(struct ppp_channel *);
+
 /*
  * SMP locking notes:
  * The channel code must ensure that when it calls ppp_unregister_channel,
index 2c9b46cff3d70bc61f4f1273897b47a694a94796..4ec3b38ce9c584049229b71bbf537770d6fbe263 100644 (file)
@@ -428,5 +428,47 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
                pos = rcu_dereference_raw(pos->next))
 
+/**
+ * hlist_for_each_entry_rcu_bh - iterate over rcu list of given type
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @head:      the head for your list.
+ * @member:    the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_head_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu_bh(tpos, pos, head, member)            \
+       for (pos = rcu_dereference_bh((head)->first);                    \
+               pos && ({ prefetch(pos->next); 1; }) &&                  \
+               ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+               pos = rcu_dereference_bh(pos->next))
+
+/**
+ * hlist_for_each_entry_continue_rcu - iterate over a hlist continuing after current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue_rcu(tpos, pos, member)           \
+       for (pos = rcu_dereference((pos)->next);                        \
+            pos && ({ prefetch(pos->next); 1; }) &&                    \
+            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });  \
+            pos = rcu_dereference(pos->next))
+
+/**
+ * hlist_for_each_entry_continue_rcu_bh - iterate over a hlist continuing after current point
+ * @tpos:      the type * to use as a loop cursor.
+ * @pos:       the &struct hlist_node to use as a loop cursor.
+ * @member:    the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue_rcu_bh(tpos, pos, member)                \
+       for (pos = rcu_dereference_bh((pos)->next);                     \
+            pos && ({ prefetch(pos->next); 1; }) &&                    \
+            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; });  \
+            pos = rcu_dereference_bh(pos->next))
+
+
 #endif /* __KERNEL__ */
 #endif
index d1c7c90e9cd46e8b8ebcc315d190e961368e3f98..fbc8cb0d48c336d4e71f458ad3f8b8d842a1c918 100644 (file)
@@ -7,6 +7,13 @@
 #include <linux/if_addr.h>
 #include <linux/neighbour.h>
 
+/* rtnetlink families. Values up to 127 are reserved for real address
+ * families, values above 128 may be used arbitrarily.
+ */
+#define RTNL_FAMILY_IPMR               128
+#define RTNL_FAMILY_IP6MR              129
+#define RTNL_FAMILY_MAX                        129
+
 /****
  *             Routing/neighbour discovery messages.
  ****/
index 124f90cd5a38bd39ab88af0563aa0d0ff9aa06d2..7cdfb4d52847e6f733df1538f48fc73508e3d13e 100644 (file)
@@ -187,7 +187,6 @@ union skb_shared_tx {
  * the end of the header data, ie. at skb->end.
  */
 struct skb_shared_info {
-       atomic_t        dataref;
        unsigned short  nr_frags;
        unsigned short  gso_size;
        /* Warning: this field is not always filled in (UFO)! */
@@ -197,6 +196,12 @@ struct skb_shared_info {
        union skb_shared_tx tx_flags;
        struct sk_buff  *frag_list;
        struct skb_shared_hwtstamps hwtstamps;
+
+       /*
+        * Warning : all fields before dataref are cleared in __alloc_skb()
+        */
+       atomic_t        dataref;
+
        skb_frag_t      frags[MAX_SKB_FRAGS];
        /* Intermediate layers must ensure that destructor_arg
         * remains valid until skb destructor */
@@ -259,7 +264,7 @@ typedef unsigned char *sk_buff_data_t;
  *     @transport_header: Transport layer header
  *     @network_header: Network layer header
  *     @mac_header: Link layer header
- *     @_skb_dst: destination entry
+ *     @_skb_refdst: destination entry (with norefcount bit)
  *     @sp: the security path, used for xfrm
  *     @cb: Control buffer. Free for use by every layer. Put private vars here
  *     @len: Length of actual data
@@ -294,6 +299,7 @@ typedef unsigned char *sk_buff_data_t;
  *     @nfct_reasm: netfilter conntrack re-assembly pointer
  *     @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
  *     @skb_iif: ifindex of device we arrived on
+ *     @rxhash: the packet hash computed on receive
  *     @queue_mapping: Queue mapping for multiqueue devices
  *     @tc_index: Traffic control index
  *     @tc_verd: traffic control verdict
@@ -322,7 +328,7 @@ struct sk_buff {
         */
        char                    cb[48] __aligned(8);
 
-       unsigned long           _skb_dst;
+       unsigned long           _skb_refdst;
 #ifdef CONFIG_XFRM
        struct  sec_path        *sp;
 #endif
@@ -369,6 +375,8 @@ struct sk_buff {
 #endif
 #endif
 
+       __u32                   rxhash;
+
        kmemcheck_bitfield_begin(flags2);
        __u16                   queue_mapping:16;
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -411,14 +419,64 @@ struct sk_buff {
 
 #include <asm/system.h>
 
+/*
+ * skb might have a dst pointer attached, refcounted or not.
+ * _skb_refdst low order bit is set if refcount was _not_ taken
+ */
+#define SKB_DST_NOREF  1UL
+#define SKB_DST_PTRMASK        ~(SKB_DST_NOREF)
+
+/**
+ * skb_dst - returns skb dst_entry
+ * @skb: buffer
+ *
+ * Returns skb dst_entry, regardless of reference taken or not.
+ */
 static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
 {
-       return (struct dst_entry *)skb->_skb_dst;
+       /* If refdst was not refcounted, check we still are in a 
+        * rcu_read_lock section
+        */
+       WARN_ON((skb->_skb_refdst & SKB_DST_NOREF) &&
+               !rcu_read_lock_held() &&
+               !rcu_read_lock_bh_held());
+       return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK);
 }
 
+/**
+ * skb_dst_set - sets skb dst
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was taken on dst and should
+ * be released by skb_dst_drop()
+ */
 static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
 {
-       skb->_skb_dst = (unsigned long)dst;
+       skb->_skb_refdst = (unsigned long)dst;
+}
+
+/**
+ * skb_dst_set_noref - sets skb dst, without a reference
+ * @skb: buffer
+ * @dst: dst entry
+ *
+ * Sets skb dst, assuming a reference was not taken on dst
+ * skb_dst_drop() should not dst_release() this dst
+ */
+static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
+{
+       WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
+       skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
+}
+
+/**
+ * skb_dst_is_noref - Test if skb dst isnt refcounted
+ * @skb: buffer
+ */
+static inline bool skb_dst_is_noref(const struct sk_buff *skb)
+{
+       return (skb->_skb_refdst & SKB_DST_NOREF) && skb_dst(skb);
 }
 
 static inline struct rtable *skb_rtable(const struct sk_buff *skb)
@@ -467,11 +525,6 @@ extern int        skb_cow_data(struct sk_buff *skb, int tailbits,
                                    struct sk_buff **trailer);
 extern int            skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)       consume_skb(a)
-#define dev_consume_skb(a)     kfree_skb_clean(a)
-extern void          skb_over_panic(struct sk_buff *skb, int len,
-                                    void *here);
-extern void          skb_under_panic(struct sk_buff *skb, int len,
-                                     void *here);
 
 extern int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
                        int getfrag(void *from, char *to, int offset,
@@ -1130,6 +1183,11 @@ static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len)
        return skb->data += len;
 }
 
+static inline unsigned char *skb_pull_inline(struct sk_buff *skb, unsigned int len)
+{
+       return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
+}
+
 extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta);
 
 static inline unsigned char *__pskb_pull(struct sk_buff *skb, unsigned int len)
@@ -1353,9 +1411,12 @@ static inline int skb_network_offset(const struct sk_buff *skb)
  *
  * Various parts of the networking layer expect at least 32 bytes of
  * headroom, you should not reduce this.
+ * With RPS, we raised NET_SKB_PAD to 64 so that get_rps_cpus() fetches span
+ * a 64 bytes aligned block to fit modern (>= 64 bytes) cache line sizes
+ * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
  */
 #ifndef NET_SKB_PAD
-#define NET_SKB_PAD    32
+#define NET_SKB_PAD    64
 #endif
 
 extern int ___pskb_trim(struct sk_buff *skb, unsigned int len);
index 4435d1084755f07a3cbf7439a55d98aa5c0f7b4c..52797714ade7a737b974b39fe2c2df9859318768 100644 (file)
@@ -100,6 +100,7 @@ enum
        ICMP6_MIB_INMSGS,                       /* InMsgs */
        ICMP6_MIB_INERRORS,                     /* InErrors */
        ICMP6_MIB_OUTMSGS,                      /* OutMsgs */
+       ICMP6_MIB_OUTERRORS,                    /* OutErrors */
        __ICMP6_MIB_MAX
 };
 
@@ -227,6 +228,7 @@ enum
        LINUX_MIB_SACKSHIFTFALLBACK,
        LINUX_MIB_TCPBACKLOGDROP,
        LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
+       LINUX_MIB_TCPDEFERACCEPTDROP,
        __LINUX_MIB_MAX
 };
 
index 354cc5617f8b87304b97eebeec2c4b3e8a52428a..032a19eb61b12077a3f8c8f5942d4ac3d4c52806 100644 (file)
@@ -189,7 +189,8 @@ struct ucred {
 #define AF_ISDN                34      /* mISDN sockets                */
 #define AF_PHONET      35      /* Phonet sockets               */
 #define AF_IEEE802154  36      /* IEEE802154 sockets           */
-#define AF_MAX         37      /* For now.. */
+#define AF_CAIF                37      /* CAIF sockets                 */
+#define AF_MAX         38      /* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC      AF_UNSPEC
@@ -229,6 +230,7 @@ struct ucred {
 #define PF_ISDN                AF_ISDN
 #define PF_PHONET      AF_PHONET
 #define PF_IEEE802154  AF_IEEE802154
+#define PF_CAIF                AF_CAIF
 #define PF_MAX         AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
@@ -301,6 +303,7 @@ struct ucred {
 #define SOL_PNPIPE     275
 #define SOL_RDS                276
 #define SOL_IUCV       277
+#define SOL_CAIF       278
 
 /* IPX options */
 #define IPX_TYPE       1
index aed64ed3dc8a4f2d32839c34a442217dea4bc81b..a223ecbc71eff8160c0c0b96921cd4e81e0e9d4f 100644 (file)
@@ -26,6 +26,8 @@
 
 struct wl12xx_platform_data {
        void (*set_power)(bool enable);
+       /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */
+       int irq;
        bool use_eeprom;
 };
 
index 24f9885473610d66c01d0a8e0bc8d056bca3ba12..a2608bff9c78a3a3c69544dbb6c187572535e902 100644 (file)
@@ -305,6 +305,7 @@ struct ssb_bus {
        /* ID information about the Chip. */
        u16 chip_id;
        u16 chip_rev;
+       u16 sprom_offset;
        u16 sprom_size;         /* number of words in sprom */
        u8 chip_package;
 
@@ -394,6 +395,9 @@ extern int ssb_bus_sdiobus_register(struct ssb_bus *bus,
 
 extern void ssb_bus_unregister(struct ssb_bus *bus);
 
+/* Does the device have an SPROM? */
+extern bool ssb_is_sprom_available(struct ssb_bus *bus);
+
 /* Set a fallback SPROM.
  * See kdoc at the function definition for complete documentation. */
 extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
index 4e27acf0a92f91f3f3052f96dcdfa4d142ca369e..2cdf249b4e5f0627980e4140bf96170cb8546ad0 100644 (file)
@@ -53,6 +53,7 @@
 #define  SSB_CHIPCO_CAP_64BIT          0x08000000      /* 64-bit Backplane */
 #define  SSB_CHIPCO_CAP_PMU            0x10000000      /* PMU available (rev >= 20) */
 #define  SSB_CHIPCO_CAP_ECI            0x20000000      /* ECI available (rev >= 20) */
+#define  SSB_CHIPCO_CAP_SPROM          0x40000000      /* SPROM present */
 #define SSB_CHIPCO_CORECTL             0x0008
 #define  SSB_CHIPCO_CORECTL_UARTCLK0   0x00000001      /* Drive UART with internal clock */
 #define         SSB_CHIPCO_CORECTL_SE          0x00000002      /* sync clk out enable (corerev >= 3) */
 
 
 /** Chip specific Chip-Status register contents. */
+#define SSB_CHIPCO_CHST_4322_SPROM_EXISTS      0x00000040 /* SPROM present */
 #define SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL     0x00000003
 #define SSB_CHIPCO_CHST_4325_DEFCIS_SEL                0 /* OTP is powered up, use def. CIS, no SPROM */
 #define SSB_CHIPCO_CHST_4325_SPROM_SEL         1 /* OTP is powered up, SPROM is present */
 #define SSB_CHIPCO_CHST_4325_RCAL_VALUE_SHIFT  4
 #define SSB_CHIPCO_CHST_4325_PMUTOP_2B                 0x00000200 /* 1 for 2b, 0 for to 2a */
 
+/** Macros to determine SPROM presence based on Chip-Status register. */
+#define SSB_CHIPCO_CHST_4312_SPROM_PRESENT(status) \
+       ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+               SSB_CHIPCO_CHST_4325_OTP_SEL)
+#define SSB_CHIPCO_CHST_4322_SPROM_PRESENT(status) \
+       (status & SSB_CHIPCO_CHST_4322_SPROM_EXISTS)
+#define SSB_CHIPCO_CHST_4325_SPROM_PRESENT(status) \
+       (((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+               SSB_CHIPCO_CHST_4325_DEFCIS_SEL) && \
+        ((status & SSB_CHIPCO_CHST_4325_SPROM_OTP_SEL) != \
+               SSB_CHIPCO_CHST_4325_OTP_SEL))
+
 
 
 /** Clockcontrol masks and values **/
@@ -564,6 +578,7 @@ struct ssb_chipcommon_pmu {
 struct ssb_chipcommon {
        struct ssb_device *dev;
        u32 capabilities;
+       u32 status;
        /* Fast Powerup Delay constant */
        u16 fast_pwrup_delay;
        struct ssb_chipcommon_pmu pmu;
index 9ae9082eaeb46eb2f9d9573a2706d339ab8c06ab..a6d5225b9275e73b2d4beaf2c0017df325bb054b 100644 (file)
 #define SSB_SPROMSIZE_WORDS_R4         220
 #define SSB_SPROMSIZE_BYTES_R123       (SSB_SPROMSIZE_WORDS_R123 * sizeof(u16))
 #define SSB_SPROMSIZE_BYTES_R4         (SSB_SPROMSIZE_WORDS_R4 * sizeof(u16))
-#define SSB_SPROM_BASE                 0x1000
-#define SSB_SPROM_REVISION             0x107E
+#define SSB_SPROM_BASE1                        0x1000
+#define SSB_SPROM_BASE31               0x0800
+#define SSB_SPROM_REVISION             0x007E
 #define  SSB_SPROM_REVISION_REV                0x00FF  /* SPROM Revision number */
 #define  SSB_SPROM_REVISION_CRC                0xFF00  /* SPROM CRC8 value */
 #define  SSB_SPROM_REVISION_CRC_SHIFT  8
 
 /* SPROM Revision 1 */
-#define SSB_SPROM1_SPID                        0x1004  /* Subsystem Product ID for PCI */
-#define SSB_SPROM1_SVID                        0x1006  /* Subsystem Vendor ID for PCI */
-#define SSB_SPROM1_PID                 0x1008  /* Product ID for PCI */
-#define SSB_SPROM1_IL0MAC              0x1048  /* 6 bytes MAC address for 802.11b/g */
-#define SSB_SPROM1_ET0MAC              0x104E  /* 6 bytes MAC address for Ethernet */
-#define SSB_SPROM1_ET1MAC              0x1054  /* 6 bytes MAC address for 802.11a */
-#define SSB_SPROM1_ETHPHY              0x105A  /* Ethernet PHY settings */
+#define SSB_SPROM1_SPID                        0x0004  /* Subsystem Product ID for PCI */
+#define SSB_SPROM1_SVID                        0x0006  /* Subsystem Vendor ID for PCI */
+#define SSB_SPROM1_PID                 0x0008  /* Product ID for PCI */
+#define SSB_SPROM1_IL0MAC              0x0048  /* 6 bytes MAC address for 802.11b/g */
+#define SSB_SPROM1_ET0MAC              0x004E  /* 6 bytes MAC address for Ethernet */
+#define SSB_SPROM1_ET1MAC              0x0054  /* 6 bytes MAC address for 802.11a */
+#define SSB_SPROM1_ETHPHY              0x005A  /* Ethernet PHY settings */
 #define  SSB_SPROM1_ETHPHY_ET0A                0x001F  /* MII Address for enet0 */
 #define  SSB_SPROM1_ETHPHY_ET1A                0x03E0  /* MII Address for enet1 */
 #define  SSB_SPROM1_ETHPHY_ET1A_SHIFT  5
 #define  SSB_SPROM1_ETHPHY_ET0M                (1<<14) /* MDIO for enet0 */
 #define  SSB_SPROM1_ETHPHY_ET1M                (1<<15) /* MDIO for enet1 */
-#define SSB_SPROM1_BINF                        0x105C  /* Board info */
+#define SSB_SPROM1_BINF                        0x005C  /* Board info */
 #define  SSB_SPROM1_BINF_BREV          0x00FF  /* Board Revision */
 #define  SSB_SPROM1_BINF_CCODE         0x0F00  /* Country Code */
 #define  SSB_SPROM1_BINF_CCODE_SHIFT   8
 #define  SSB_SPROM1_BINF_ANTBG_SHIFT   12
 #define  SSB_SPROM1_BINF_ANTA          0xC000  /* Available A-PHY antennas */
 #define  SSB_SPROM1_BINF_ANTA_SHIFT    14
-#define SSB_SPROM1_PA0B0               0x105E
-#define SSB_SPROM1_PA0B1               0x1060
-#define SSB_SPROM1_PA0B2               0x1062
-#define SSB_SPROM1_GPIOA               0x1064  /* General Purpose IO pins 0 and 1 */
+#define SSB_SPROM1_PA0B0               0x005E
+#define SSB_SPROM1_PA0B1               0x0060
+#define SSB_SPROM1_PA0B2               0x0062
+#define SSB_SPROM1_GPIOA               0x0064  /* General Purpose IO pins 0 and 1 */
 #define  SSB_SPROM1_GPIOA_P0           0x00FF  /* Pin 0 */
 #define  SSB_SPROM1_GPIOA_P1           0xFF00  /* Pin 1 */
 #define  SSB_SPROM1_GPIOA_P1_SHIFT     8
-#define SSB_SPROM1_GPIOB               0x1066  /* General Purpuse IO pins 2 and 3 */
+#define SSB_SPROM1_GPIOB               0x0066  /* General Purpuse IO pins 2 and 3 */
 #define  SSB_SPROM1_GPIOB_P2           0x00FF  /* Pin 2 */
 #define  SSB_SPROM1_GPIOB_P3           0xFF00  /* Pin 3 */
 #define  SSB_SPROM1_GPIOB_P3_SHIFT     8
-#define SSB_SPROM1_MAXPWR              0x1068  /* Power Amplifier Max Power */
+#define SSB_SPROM1_MAXPWR              0x0068  /* Power Amplifier Max Power */
 #define  SSB_SPROM1_MAXPWR_BG          0x00FF  /* B-PHY and G-PHY (in dBm Q5.2) */
 #define  SSB_SPROM1_MAXPWR_A           0xFF00  /* A-PHY (in dBm Q5.2) */
 #define  SSB_SPROM1_MAXPWR_A_SHIFT     8
-#define SSB_SPROM1_PA1B0               0x106A
-#define SSB_SPROM1_PA1B1               0x106C
-#define SSB_SPROM1_PA1B2               0x106E
-#define SSB_SPROM1_ITSSI               0x1070  /* Idle TSSI Target */
+#define SSB_SPROM1_PA1B0               0x006A
+#define SSB_SPROM1_PA1B1               0x006C
+#define SSB_SPROM1_PA1B2               0x006E
+#define SSB_SPROM1_ITSSI               0x0070  /* Idle TSSI Target */
 #define  SSB_SPROM1_ITSSI_BG           0x00FF  /* B-PHY and G-PHY*/
 #define  SSB_SPROM1_ITSSI_A            0xFF00  /* A-PHY */
 #define  SSB_SPROM1_ITSSI_A_SHIFT      8
-#define SSB_SPROM1_BFLLO               0x1072  /* Boardflags (low 16 bits) */
-#define SSB_SPROM1_AGAIN               0x1074  /* Antenna Gain (in dBm Q5.2) */
+#define SSB_SPROM1_BFLLO               0x0072  /* Boardflags (low 16 bits) */
+#define SSB_SPROM1_AGAIN               0x0074  /* Antenna Gain (in dBm Q5.2) */
 #define  SSB_SPROM1_AGAIN_BG           0x00FF  /* B-PHY and G-PHY */
 #define  SSB_SPROM1_AGAIN_BG_SHIFT     0
 #define  SSB_SPROM1_AGAIN_A            0xFF00  /* A-PHY */
 #define  SSB_SPROM1_AGAIN_A_SHIFT      8
 
 /* SPROM Revision 2 (inherits from rev 1) */
-#define SSB_SPROM2_BFLHI               0x1038  /* Boardflags (high 16 bits) */
-#define SSB_SPROM2_MAXP_A              0x103A  /* A-PHY Max Power */
+#define SSB_SPROM2_BFLHI               0x0038  /* Boardflags (high 16 bits) */
+#define SSB_SPROM2_MAXP_A              0x003A  /* A-PHY Max Power */
 #define  SSB_SPROM2_MAXP_A_HI          0x00FF  /* Max Power High */
 #define  SSB_SPROM2_MAXP_A_LO          0xFF00  /* Max Power Low */
 #define  SSB_SPROM2_MAXP_A_LO_SHIFT    8
-#define SSB_SPROM2_PA1LOB0             0x103C  /* A-PHY PowerAmplifier Low Settings */
-#define SSB_SPROM2_PA1LOB1             0x103E  /* A-PHY PowerAmplifier Low Settings */
-#define SSB_SPROM2_PA1LOB2             0x1040  /* A-PHY PowerAmplifier Low Settings */
-#define SSB_SPROM2_PA1HIB0             0x1042  /* A-PHY PowerAmplifier High Settings */
-#define SSB_SPROM2_PA1HIB1             0x1044  /* A-PHY PowerAmplifier High Settings */
-#define SSB_SPROM2_PA1HIB2             0x1046  /* A-PHY PowerAmplifier High Settings */
-#define SSB_SPROM2_OPO                 0x1078  /* OFDM Power Offset from CCK Level */
+#define SSB_SPROM2_PA1LOB0             0x003C  /* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1LOB1             0x003E  /* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1LOB2             0x0040  /* A-PHY PowerAmplifier Low Settings */
+#define SSB_SPROM2_PA1HIB0             0x0042  /* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_PA1HIB1             0x0044  /* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_PA1HIB2             0x0046  /* A-PHY PowerAmplifier High Settings */
+#define SSB_SPROM2_OPO                 0x0078  /* OFDM Power Offset from CCK Level */
 #define  SSB_SPROM2_OPO_VALUE          0x00FF
 #define  SSB_SPROM2_OPO_UNUSED         0xFF00
-#define SSB_SPROM2_CCODE               0x107C  /* Two char Country Code */
+#define SSB_SPROM2_CCODE               0x007C  /* Two char Country Code */
 
 /* SPROM Revision 3 (inherits most data from rev 2) */
-#define SSB_SPROM3_IL0MAC              0x104A  /* 6 bytes MAC address for 802.11b/g */
-#define SSB_SPROM3_OFDMAPO             0x102C  /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
-#define SSB_SPROM3_OFDMALPO            0x1030  /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
-#define SSB_SPROM3_OFDMAHPO            0x1034  /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
-#define SSB_SPROM3_GPIOLDC             0x1042  /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMAPO             0x002C  /* A-PHY OFDM Mid Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMALPO            0x0030  /* A-PHY OFDM Low Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_OFDMAHPO            0x0034  /* A-PHY OFDM High Power Offset (4 bytes, BigEndian) */
+#define SSB_SPROM3_GPIOLDC             0x0042  /* GPIO LED Powersave Duty Cycle (4 bytes, BigEndian) */
 #define  SSB_SPROM3_GPIOLDC_OFF                0x0000FF00      /* Off Count */
 #define  SSB_SPROM3_GPIOLDC_OFF_SHIFT  8
 #define  SSB_SPROM3_GPIOLDC_ON         0x00FF0000      /* On Count */
 #define  SSB_SPROM3_GPIOLDC_ON_SHIFT   16
-#define SSB_SPROM3_CCKPO               0x1078  /* CCK Power Offset */
+#define SSB_SPROM3_IL0MAC              0x004A  /* 6 bytes MAC address for 802.11b/g */
+#define SSB_SPROM3_CCKPO               0x0078  /* CCK Power Offset */
 #define  SSB_SPROM3_CCKPO_1M           0x000F  /* 1M Rate PO */
 #define  SSB_SPROM3_CCKPO_2M           0x00F0  /* 2M Rate PO */
 #define  SSB_SPROM3_CCKPO_2M_SHIFT     4
 #define  SSB_SPROM3_OFDMGPO            0x107A  /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
 
 /* SPROM Revision 4 */
-#define SSB_SPROM4_IL0MAC              0x104C  /* 6 byte MAC address for a/b/g/n */
-#define SSB_SPROM4_ETHPHY              0x105A  /* Ethernet PHY settings ?? */
+#define SSB_SPROM4_BFLLO               0x0044  /* Boardflags (low 16 bits) */
+#define SSB_SPROM4_BFLHI               0x0046  /* Board Flags Hi */
+#define SSB_SPROM4_IL0MAC              0x004C  /* 6 byte MAC address for a/b/g/n */
+#define SSB_SPROM4_CCODE               0x0052  /* Country Code (2 bytes) */
+#define SSB_SPROM4_GPIOA               0x0056  /* Gen. Purpose IO # 0 and 1 */
+#define  SSB_SPROM4_GPIOA_P0           0x00FF  /* Pin 0 */
+#define  SSB_SPROM4_GPIOA_P1           0xFF00  /* Pin 1 */
+#define  SSB_SPROM4_GPIOA_P1_SHIFT     8
+#define SSB_SPROM4_GPIOB               0x0058  /* Gen. Purpose IO # 2 and 3 */
+#define  SSB_SPROM4_GPIOB_P2           0x00FF  /* Pin 2 */
+#define  SSB_SPROM4_GPIOB_P3           0xFF00  /* Pin 3 */
+#define  SSB_SPROM4_GPIOB_P3_SHIFT     8
+#define SSB_SPROM4_ETHPHY              0x005A  /* Ethernet PHY settings ?? */
 #define  SSB_SPROM4_ETHPHY_ET0A                0x001F  /* MII Address for enet0 */
 #define  SSB_SPROM4_ETHPHY_ET1A                0x03E0  /* MII Address for enet1 */
 #define  SSB_SPROM4_ETHPHY_ET1A_SHIFT  5
 #define  SSB_SPROM4_ETHPHY_ET0M                (1<<14) /* MDIO for enet0 */
 #define  SSB_SPROM4_ETHPHY_ET1M                (1<<15) /* MDIO for enet1 */
-#define SSB_SPROM4_CCODE               0x1052  /* Country Code (2 bytes) */
-#define SSB_SPROM4_ANTAVAIL            0x105D  /* Antenna available bitfields */
-#define SSB_SPROM4_ANTAVAIL_A          0x00FF  /* A-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_A_SHIFT    0
-#define SSB_SPROM4_ANTAVAIL_BG         0xFF00  /* B-PHY and G-PHY bitfield */
-#define SSB_SPROM4_ANTAVAIL_BG_SHIFT   8
-#define SSB_SPROM4_BFLLO               0x1044  /* Boardflags (low 16 bits) */
-#define SSB_SPROM4_AGAIN01             0x105E  /* Antenna Gain (in dBm Q5.2) */
+#define SSB_SPROM4_ANTAVAIL            0x005D  /* Antenna available bitfields */
+#define  SSB_SPROM4_ANTAVAIL_A         0x00FF  /* A-PHY bitfield */
+#define  SSB_SPROM4_ANTAVAIL_A_SHIFT   0
+#define  SSB_SPROM4_ANTAVAIL_BG                0xFF00  /* B-PHY and G-PHY bitfield */
+#define  SSB_SPROM4_ANTAVAIL_BG_SHIFT  8
+#define SSB_SPROM4_AGAIN01             0x005E  /* Antenna Gain (in dBm Q5.2) */
 #define  SSB_SPROM4_AGAIN0             0x00FF  /* Antenna 0 */
 #define  SSB_SPROM4_AGAIN0_SHIFT       0
 #define  SSB_SPROM4_AGAIN1             0xFF00  /* Antenna 1 */
 #define  SSB_SPROM4_AGAIN1_SHIFT       8
-#define SSB_SPROM4_AGAIN23             0x1060
+#define SSB_SPROM4_AGAIN23             0x0060
 #define  SSB_SPROM4_AGAIN2             0x00FF  /* Antenna 2 */
 #define  SSB_SPROM4_AGAIN2_SHIFT       0
 #define  SSB_SPROM4_AGAIN3             0xFF00  /* Antenna 3 */
 #define  SSB_SPROM4_AGAIN3_SHIFT       8
-#define SSB_SPROM4_BFLHI               0x1046  /* Board Flags Hi */
-#define SSB_SPROM4_MAXP_BG             0x1080  /* Max Power BG in path 1 */
+#define SSB_SPROM4_MAXP_BG             0x0080  /* Max Power BG in path 1 */
 #define  SSB_SPROM4_MAXP_BG_MASK       0x00FF  /* Mask for Max Power BG */
 #define  SSB_SPROM4_ITSSI_BG           0xFF00  /* Mask for path 1 itssi_bg */
 #define  SSB_SPROM4_ITSSI_BG_SHIFT     8
-#define SSB_SPROM4_MAXP_A              0x108A  /* Max Power A in path 1 */
+#define SSB_SPROM4_MAXP_A              0x008A  /* Max Power A in path 1 */
 #define  SSB_SPROM4_MAXP_A_MASK                0x00FF  /* Mask for Max Power A */
 #define  SSB_SPROM4_ITSSI_A            0xFF00  /* Mask for path 1 itssi_a */
 #define  SSB_SPROM4_ITSSI_A_SHIFT      8
-#define SSB_SPROM4_GPIOA               0x1056  /* Gen. Purpose IO # 0 and 1 */
-#define  SSB_SPROM4_GPIOA_P0           0x00FF  /* Pin 0 */
-#define  SSB_SPROM4_GPIOA_P1           0xFF00  /* Pin 1 */
-#define  SSB_SPROM4_GPIOA_P1_SHIFT     8
-#define SSB_SPROM4_GPIOB               0x1058  /* Gen. Purpose IO # 2 and 3 */
-#define  SSB_SPROM4_GPIOB_P2           0x00FF  /* Pin 2 */
-#define  SSB_SPROM4_GPIOB_P3           0xFF00  /* Pin 3 */
-#define  SSB_SPROM4_GPIOB_P3_SHIFT     8
-#define SSB_SPROM4_PA0B0               0x1082  /* The paXbY locations are */
-#define SSB_SPROM4_PA0B1               0x1084  /*   only guesses */
-#define SSB_SPROM4_PA0B2               0x1086
-#define SSB_SPROM4_PA1B0               0x108E
-#define SSB_SPROM4_PA1B1               0x1090
-#define SSB_SPROM4_PA1B2               0x1092
+#define SSB_SPROM4_PA0B0               0x0082  /* The paXbY locations are */
+#define SSB_SPROM4_PA0B1               0x0084  /*   only guesses */
+#define SSB_SPROM4_PA0B2               0x0086
+#define SSB_SPROM4_PA1B0               0x008E
+#define SSB_SPROM4_PA1B1               0x0090
+#define SSB_SPROM4_PA1B2               0x0092
 
 /* SPROM Revision 5 (inherits most data from rev 4) */
-#define SSB_SPROM5_BFLLO               0x104A  /* Boardflags (low 16 bits) */
-#define SSB_SPROM5_BFLHI               0x104C  /* Board Flags Hi */
-#define SSB_SPROM5_IL0MAC              0x1052  /* 6 byte MAC address for a/b/g/n */
-#define SSB_SPROM5_CCODE               0x1044  /* Country Code (2 bytes) */
-#define SSB_SPROM5_GPIOA               0x1076  /* Gen. Purpose IO # 0 and 1 */
+#define SSB_SPROM5_CCODE               0x0044  /* Country Code (2 bytes) */
+#define SSB_SPROM5_BFLLO               0x004A  /* Boardflags (low 16 bits) */
+#define SSB_SPROM5_BFLHI               0x004C  /* Board Flags Hi */
+#define SSB_SPROM5_IL0MAC              0x0052  /* 6 byte MAC address for a/b/g/n */
+#define SSB_SPROM5_GPIOA               0x0076  /* Gen. Purpose IO # 0 and 1 */
 #define  SSB_SPROM5_GPIOA_P0           0x00FF  /* Pin 0 */
 #define  SSB_SPROM5_GPIOA_P1           0xFF00  /* Pin 1 */
 #define  SSB_SPROM5_GPIOA_P1_SHIFT     8
-#define SSB_SPROM5_GPIOB               0x1078  /* Gen. Purpose IO # 2 and 3 */
+#define SSB_SPROM5_GPIOB               0x0078  /* Gen. Purpose IO # 2 and 3 */
 #define  SSB_SPROM5_GPIOB_P2           0x00FF  /* Pin 2 */
 #define  SSB_SPROM5_GPIOB_P3           0xFF00  /* Pin 3 */
 #define  SSB_SPROM5_GPIOB_P3_SHIFT     8
 
 /* SPROM Revision 8 */
-#define SSB_SPROM8_BOARDREV            0x1082  /* Board revision */
-#define SSB_SPROM8_BFLLO               0x1084  /* Board flags (bits 0-15) */
-#define SSB_SPROM8_BFLHI               0x1086  /* Board flags (bits 16-31) */
-#define SSB_SPROM8_BFL2LO              0x1088  /* Board flags (bits 32-47) */
-#define SSB_SPROM8_BFL2HI              0x108A  /* Board flags (bits 48-63) */
-#define SSB_SPROM8_IL0MAC              0x108C  /* 6 byte MAC address */
-#define SSB_SPROM8_CCODE               0x1092  /* 2 byte country code */
-#define SSB_SPROM8_ANTAVAIL            0x109C  /* Antenna available bitfields*/
-#define SSB_SPROM8_ANTAVAIL_A          0xFF00  /* A-PHY bitfield */
-#define SSB_SPROM8_ANTAVAIL_A_SHIFT    8
-#define SSB_SPROM8_ANTAVAIL_BG         0x00FF  /* B-PHY and G-PHY bitfield */
-#define SSB_SPROM8_ANTAVAIL_BG_SHIFT   0
-#define SSB_SPROM8_AGAIN01             0x109E  /* Antenna Gain (in dBm Q5.2) */
+#define SSB_SPROM8_BOARDREV            0x0082  /* Board revision */
+#define SSB_SPROM8_BFLLO               0x0084  /* Board flags (bits 0-15) */
+#define SSB_SPROM8_BFLHI               0x0086  /* Board flags (bits 16-31) */
+#define SSB_SPROM8_BFL2LO              0x0088  /* Board flags (bits 32-47) */
+#define SSB_SPROM8_BFL2HI              0x008A  /* Board flags (bits 48-63) */
+#define SSB_SPROM8_IL0MAC              0x008C  /* 6 byte MAC address */
+#define SSB_SPROM8_CCODE               0x0092  /* 2 byte country code */
+#define SSB_SPROM8_GPIOA               0x0096  /*Gen. Purpose IO # 0 and 1 */
+#define  SSB_SPROM8_GPIOA_P0           0x00FF  /* Pin 0 */
+#define  SSB_SPROM8_GPIOA_P1           0xFF00  /* Pin 1 */
+#define  SSB_SPROM8_GPIOA_P1_SHIFT     8
+#define SSB_SPROM8_GPIOB               0x0098  /* Gen. Purpose IO # 2 and 3 */
+#define  SSB_SPROM8_GPIOB_P2           0x00FF  /* Pin 2 */
+#define  SSB_SPROM8_GPIOB_P3           0xFF00  /* Pin 3 */
+#define  SSB_SPROM8_GPIOB_P3_SHIFT     8
+#define SSB_SPROM8_ANTAVAIL            0x009C  /* Antenna available bitfields*/
+#define  SSB_SPROM8_ANTAVAIL_A         0xFF00  /* A-PHY bitfield */
+#define  SSB_SPROM8_ANTAVAIL_A_SHIFT   8
+#define  SSB_SPROM8_ANTAVAIL_BG                0x00FF  /* B-PHY and G-PHY bitfield */
+#define  SSB_SPROM8_ANTAVAIL_BG_SHIFT  0
+#define SSB_SPROM8_AGAIN01             0x009E  /* Antenna Gain (in dBm Q5.2) */
 #define  SSB_SPROM8_AGAIN0             0x00FF  /* Antenna 0 */
 #define  SSB_SPROM8_AGAIN0_SHIFT       0
 #define  SSB_SPROM8_AGAIN1             0xFF00  /* Antenna 1 */
 #define  SSB_SPROM8_AGAIN1_SHIFT       8
-#define SSB_SPROM8_AGAIN23             0x10A0
+#define SSB_SPROM8_AGAIN23             0x00A0
 #define  SSB_SPROM8_AGAIN2             0x00FF  /* Antenna 2 */
 #define  SSB_SPROM8_AGAIN2_SHIFT       0
 #define  SSB_SPROM8_AGAIN3             0xFF00  /* Antenna 3 */
 #define  SSB_SPROM8_AGAIN3_SHIFT       8
-#define SSB_SPROM8_GPIOA               0x1096  /*Gen. Purpose IO # 0 and 1 */
-#define  SSB_SPROM8_GPIOA_P0           0x00FF  /* Pin 0 */
-#define  SSB_SPROM8_GPIOA_P1           0xFF00  /* Pin 1 */
-#define  SSB_SPROM8_GPIOA_P1_SHIFT     8
-#define SSB_SPROM8_GPIOB               0x1098  /* Gen. Purpose IO # 2 and 3 */
-#define  SSB_SPROM8_GPIOB_P2           0x00FF  /* Pin 2 */
-#define  SSB_SPROM8_GPIOB_P3           0xFF00  /* Pin 3 */
-#define  SSB_SPROM8_GPIOB_P3_SHIFT     8
-#define SSB_SPROM8_RSSIPARM2G          0x10A4  /* RSSI params for 2GHz */
+#define SSB_SPROM8_RSSIPARM2G          0x00A4  /* RSSI params for 2GHz */
 #define  SSB_SPROM8_RSSISMF2G          0x000F
 #define  SSB_SPROM8_RSSISMC2G          0x00F0
 #define  SSB_SPROM8_RSSISMC2G_SHIFT    4
 #define  SSB_SPROM8_RSSISAV2G_SHIFT    8
 #define  SSB_SPROM8_BXA2G              0x1800
 #define  SSB_SPROM8_BXA2G_SHIFT                11
-#define SSB_SPROM8_RSSIPARM5G          0x10A6  /* RSSI params for 5GHz */
+#define SSB_SPROM8_RSSIPARM5G          0x00A6  /* RSSI params for 5GHz */
 #define  SSB_SPROM8_RSSISMF5G          0x000F
 #define  SSB_SPROM8_RSSISMC5G          0x00F0
 #define  SSB_SPROM8_RSSISMC5G_SHIFT    4
 #define  SSB_SPROM8_RSSISAV5G_SHIFT    8
 #define  SSB_SPROM8_BXA5G              0x1800
 #define  SSB_SPROM8_BXA5G_SHIFT                11
-#define SSB_SPROM8_TRI25G              0x10A8  /* TX isolation 2.4&5.3GHz */
+#define SSB_SPROM8_TRI25G              0x00A8  /* TX isolation 2.4&5.3GHz */
 #define  SSB_SPROM8_TRI2G              0x00FF  /* TX isolation 2.4GHz */
 #define  SSB_SPROM8_TRI5G              0xFF00  /* TX isolation 5.3GHz */
 #define  SSB_SPROM8_TRI5G_SHIFT                8
-#define SSB_SPROM8_TRI5GHL             0x10AA  /* TX isolation 5.2/5.8GHz */
+#define SSB_SPROM8_TRI5GHL             0x00AA  /* TX isolation 5.2/5.8GHz */
 #define  SSB_SPROM8_TRI5GL             0x00FF  /* TX isolation 5.2GHz */
 #define  SSB_SPROM8_TRI5GH             0xFF00  /* TX isolation 5.8GHz */
 #define  SSB_SPROM8_TRI5GH_SHIFT       8
-#define SSB_SPROM8_RXPO                        0x10AC  /* RX power offsets */
+#define SSB_SPROM8_RXPO                        0x00AC  /* RX power offsets */
 #define  SSB_SPROM8_RXPO2G             0x00FF  /* 2GHz RX power offset */
 #define  SSB_SPROM8_RXPO5G             0xFF00  /* 5GHz RX power offset */
 #define  SSB_SPROM8_RXPO5G_SHIFT       8
-#define SSB_SPROM8_MAXP_BG             0x10C0  /* Max Power 2GHz in path 1 */
+#define SSB_SPROM8_MAXP_BG             0x00C0  /* Max Power 2GHz in path 1 */
 #define  SSB_SPROM8_MAXP_BG_MASK       0x00FF  /* Mask for Max Power 2GHz */
 #define  SSB_SPROM8_ITSSI_BG           0xFF00  /* Mask for path 1 itssi_bg */
 #define  SSB_SPROM8_ITSSI_BG_SHIFT     8
-#define SSB_SPROM8_PA0B0               0x10C2  /* 2GHz power amp settings */
-#define SSB_SPROM8_PA0B1               0x10C4
-#define SSB_SPROM8_PA0B2               0x10C6
-#define SSB_SPROM8_MAXP_A              0x10C8  /* Max Power 5.3GHz */
+#define SSB_SPROM8_PA0B0               0x00C2  /* 2GHz power amp settings */
+#define SSB_SPROM8_PA0B1               0x00C4
+#define SSB_SPROM8_PA0B2               0x00C6
+#define SSB_SPROM8_MAXP_A              0x00C8  /* Max Power 5.3GHz */
 #define  SSB_SPROM8_MAXP_A_MASK                0x00FF  /* Mask for Max Power 5.3GHz */
 #define  SSB_SPROM8_ITSSI_A            0xFF00  /* Mask for path 1 itssi_a */
 #define  SSB_SPROM8_ITSSI_A_SHIFT      8
-#define SSB_SPROM8_MAXP_AHL            0x10CA  /* Max Power 5.2/5.8GHz */
+#define SSB_SPROM8_MAXP_AHL            0x00CA  /* Max Power 5.2/5.8GHz */
 #define  SSB_SPROM8_MAXP_AH_MASK       0x00FF  /* Mask for Max Power 5.8GHz */
 #define  SSB_SPROM8_MAXP_AL_MASK       0xFF00  /* Mask for Max Power 5.2GHz */
 #define  SSB_SPROM8_MAXP_AL_SHIFT      8
-#define SSB_SPROM8_PA1B0               0x10CC  /* 5.3GHz power amp settings */
-#define SSB_SPROM8_PA1B1               0x10CE
-#define SSB_SPROM8_PA1B2               0x10D0
-#define SSB_SPROM8_PA1LOB0             0x10D2  /* 5.2GHz power amp settings */
-#define SSB_SPROM8_PA1LOB1             0x10D4
-#define SSB_SPROM8_PA1LOB2             0x10D6
-#define SSB_SPROM8_PA1HIB0             0x10D8  /* 5.8GHz power amp settings */
-#define SSB_SPROM8_PA1HIB1             0x10DA
-#define SSB_SPROM8_PA1HIB2             0x10DC
-#define SSB_SPROM8_CCK2GPO             0x1140  /* CCK power offset */
-#define SSB_SPROM8_OFDM2GPO            0x1142  /* 2.4GHz OFDM power offset */
-#define SSB_SPROM8_OFDM5GPO            0x1146  /* 5.3GHz OFDM power offset */
-#define SSB_SPROM8_OFDM5GLPO           0x114A  /* 5.2GHz OFDM power offset */
-#define SSB_SPROM8_OFDM5GHPO           0x114E  /* 5.8GHz OFDM power offset */
+#define SSB_SPROM8_PA1B0               0x00CC  /* 5.3GHz power amp settings */
+#define SSB_SPROM8_PA1B1               0x00CE
+#define SSB_SPROM8_PA1B2               0x00D0
+#define SSB_SPROM8_PA1LOB0             0x00D2  /* 5.2GHz power amp settings */
+#define SSB_SPROM8_PA1LOB1             0x00D4
+#define SSB_SPROM8_PA1LOB2             0x00D6
+#define SSB_SPROM8_PA1HIB0             0x00D8  /* 5.8GHz power amp settings */
+#define SSB_SPROM8_PA1HIB1             0x00DA
+#define SSB_SPROM8_PA1HIB2             0x00DC
+#define SSB_SPROM8_CCK2GPO             0x0140  /* CCK power offset */
+#define SSB_SPROM8_OFDM2GPO            0x0142  /* 2.4GHz OFDM power offset */
+#define SSB_SPROM8_OFDM5GPO            0x0146  /* 5.3GHz OFDM power offset */
+#define SSB_SPROM8_OFDM5GLPO           0x014A  /* 5.2GHz OFDM power offset */
+#define SSB_SPROM8_OFDM5GHPO           0x014E  /* 5.8GHz OFDM power offset */
 
 /* Values for SSB_SPROM1_BINF_CCODE */
 enum {
index 32bfd1a8a48d3b7d5da83b425f4e6416603c33c6..632ff7c0328040f4f3ceb5dd8f06655bf05e84b5 100644 (file)
@@ -33,6 +33,7 @@ struct plat_stmmacenet_data {
        int bus_id;
        int pbl;
        int has_gmac;
+       int enh_desc;
        void (*fix_mac_speed)(void *priv, unsigned int speed);
        void (*bus_setup)(unsigned long ioaddr);
 #ifdef CONFIG_STM_DRIVERS
index f66014c90c9fe8b8aecc528072151550130ecb41..7bb5cb64f3b84798db8023be585755d94af785a0 100644 (file)
@@ -980,6 +980,8 @@ extern int proc_doulongvec_minmax(struct ctl_table *, int,
                                  void __user *, size_t *, loff_t *);
 extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int,
                                      void __user *, size_t *, loff_t *);
+extern int proc_do_large_bitmap(struct ctl_table *, int,
+                               void __user *, size_t *, loff_t *);
 
 /*
  * Register a set of sysctl names by calling register_sysctl_table
index 3d92396639de9a6f542357d4276075c97dedc758..181c8d0e6f739fbfd091876c0726206491b8b1cd 100644 (file)
@@ -107,7 +107,7 @@ static inline unsigned int tipc_node(__u32 addr)
  * Message importance levels
  */
 
-#define TIPC_LOW_IMPORTANCE            0  /* default */
+#define TIPC_LOW_IMPORTANCE            0
 #define TIPC_MEDIUM_IMPORTANCE         1
 #define TIPC_HIGH_IMPORTANCE           2
 #define TIPC_CRITICAL_IMPORTANCE       3
@@ -127,23 +127,17 @@ static inline unsigned int tipc_node(__u32 addr)
  * TIPC topology subscription service definitions
  */
 
-#define TIPC_SUB_PORTS         0x01    /* filter for port availability */
-#define TIPC_SUB_SERVICE       0x02    /* filter for service availability */
-#define TIPC_SUB_CANCEL         0x04    /* cancel a subscription */
-#if 0
-/* The following filter options are not currently implemented */
-#define TIPC_SUB_NO_BIND_EVTS  0x04    /* filter out "publish" events */
-#define TIPC_SUB_NO_UNBIND_EVTS        0x08    /* filter out "withdraw" events */
-#define TIPC_SUB_SINGLE_EVT    0x10    /* expire after first event */
-#endif
+#define TIPC_SUB_SERVICE       0x00    /* Filter for service availability    */
+#define TIPC_SUB_PORTS         0x01    /* Filter for port availability  */
+#define TIPC_SUB_CANCEL         0x04    /* Cancel a subscription         */
 
 #define TIPC_WAIT_FOREVER      ~0      /* timeout for permanent subscription */
 
 struct tipc_subscr {
-       struct tipc_name_seq seq;       /* name sequence of interest */
-       __u32 timeout;                  /* subscription duration (in ms) */
-        __u32 filter;                  /* bitmask of filter options */
-       char usr_handle[8];             /* available for subscriber use */
+       struct tipc_name_seq seq;       /* NBO. Name sequence of interest */
+       __u32 timeout;                  /* NBO. Subscription duration (in ms) */
+        __u32 filter;                  /* NBO. Bitmask of filter options */
+       char usr_handle[8];             /* Opaque. Available for subscriber use */
 };
 
 #define TIPC_PUBLISHED         1       /* publication event */
@@ -151,11 +145,11 @@ struct tipc_subscr {
 #define TIPC_SUBSCR_TIMEOUT    3       /* subscription timeout event */
 
 struct tipc_event {
-       __u32 event;                    /* event type */
-       __u32 found_lower;              /* matching name seq instances */
-       __u32 found_upper;              /*    "      "    "     "      */
-       struct tipc_portid port;        /* associated port */
-       struct tipc_subscr s;           /* associated subscription */
+       __u32 event;                    /* NBO. Event type, as defined above */
+       __u32 found_lower;              /* NBO. Matching name seq instances  */
+       __u32 found_upper;              /*  "      "       "   "    "        */
+       struct tipc_portid port;        /* NBO. Associated port              */
+       struct tipc_subscr s;           /* Original, associated subscription */
 };
 
 /*
@@ -188,7 +182,7 @@ struct sockaddr_tipc {
                struct tipc_name_seq nameseq;
                struct {
                        struct tipc_name name;
-                       __u32 domain; /* 0: own zone */
+                       __u32 domain;
                } name;
        } addr;
 };
@@ -206,7 +200,7 @@ struct sockaddr_tipc {
  */
 
 #define TIPC_IMPORTANCE                127     /* Default: TIPC_LOW_IMPORTANCE */
-#define TIPC_SRC_DROPPABLE     128     /* Default: 0 (resend congested msg) */
+#define TIPC_SRC_DROPPABLE     128     /* Default: based on socket type */
 #define TIPC_DEST_DROPPABLE    129     /* Default: based on socket type */
 #define TIPC_CONN_TIMEOUT      130     /* Default: 8000 (ms)  */
 #define TIPC_NODE_RECVQ_DEPTH  131     /* Default: none (read only) */
index 2bc6fa4adeb5e2d2076b456ad4cfd6943952cef9..9cde86c324122389228ae880c1794a68ee08c0e0 100644 (file)
@@ -74,6 +74,7 @@
 #define  TIPC_CMD_SHOW_NAME_TABLE   0x0005    /* tx name_tbl_query, rx ultra_string */
 #define  TIPC_CMD_SHOW_PORTS        0x0006    /* tx none, rx ultra_string */
 #define  TIPC_CMD_SHOW_LINK_STATS   0x000B    /* tx link_name, rx ultra_string */
+#define  TIPC_CMD_SHOW_STATS        0x000F    /* tx unsigned, rx ultra_string */
 
 #if 0
 #define  TIPC_CMD_SHOW_PORT_STATS   0x0008    /* tx port_ref, rx ultra_string */
index 4409967db0c45e8e0a5568b5596e4b42bffe659c..bb44fa9ae135a030a9cc7173db61b3f48c4c392f 100644 (file)
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT  4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX      (1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS              20
+#define NR_LDISCS              21
 
 /* line disciplines */
 #define N_TTY          0
@@ -46,8 +46,8 @@
 #define N_GIGASET_M101 16      /* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN                17      /* Serial / USB serial CAN Adaptors */
 #define N_PPS          18      /* Pulse per Second */
-
 #define N_V253         19      /* Codec control over voice modem */
+#define N_CAIF         20      /* CAIF protocol for talking to modems */
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
index 5b4c6c772a9b1ac53926d27250d0d11cb033f560..e6827eedf18bc4934f0f6b47e7b7a7c4de76f0df 100644 (file)
 #define SIOCIWFIRST    0x8B00
 #define SIOCIWLAST     SIOCIWLASTPRIV          /* 0x8BFF */
 #define IW_IOCTL_IDX(cmd)      ((cmd) - SIOCIWFIRST)
+#define IW_HANDLER(id, func)                   \
+       [IW_IOCTL_IDX(id)] = func
 
 /* Odd : get (world access), even : set (root access) */
 #define IW_IS_SET(cmd) (!((cmd) & 0x1))
  * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
 #define IW_EVENT_CAPA_BASE(cmd)                ((cmd >= SIOCIWFIRSTPRIV) ? \
                                         (cmd - SIOCIWFIRSTPRIV + 0x60) : \
-                                        (cmd - SIOCSIWCOMMIT))
+                                        (cmd - SIOCIWFIRST))
 #define IW_EVENT_CAPA_INDEX(cmd)       (IW_EVENT_CAPA_BASE(cmd) >> 5)
 #define IW_EVENT_CAPA_MASK(cmd)                (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
 /* Event capability constants - event autogenerated by the kernel
index 1614d78c60ed2c4b616b530b89f8247addbcc17f..20725e213aeec4b5363388080a8f5fe61129226b 100644 (file)
@@ -30,7 +30,7 @@ struct unix_skb_parms {
 #endif
 };
 
-#define UNIXCB(skb)    (*(struct unix_skb_parms*)&((skb)->cb))
+#define UNIXCB(skb)    (*(struct unix_skb_parms *)&((skb)->cb))
 #define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
 #define UNIXSID(skb)   (&UNIXCB((skb)).secid)
 
@@ -45,21 +45,23 @@ struct unix_skb_parms {
 struct unix_sock {
        /* WARNING: sk has to be the first member */
        struct sock             sk;
-        struct unix_address     *addr;
-        struct dentry          *dentry;
-        struct vfsmount                *mnt;
+       struct unix_address     *addr;
+       struct dentry           *dentry;
+       struct vfsmount         *mnt;
        struct mutex            readlock;
-        struct sock            *peer;
-        struct sock            *other;
+       struct sock             *peer;
+       struct sock             *other;
        struct list_head        link;
-        atomic_long_t           inflight;
-        spinlock_t             lock;
+       atomic_long_t           inflight;
+       spinlock_t              lock;
        unsigned int            gc_candidate : 1;
        unsigned int            gc_maybe_cycle : 1;
-        wait_queue_head_t       peer_wait;
+       struct socket_wq        peer_wq;
 };
 #define unix_sk(__sk) ((struct unix_sock *)__sk)
 
+#define peer_wait peer_wq.wait
+
 #ifdef CONFIG_SYSCTL
 extern int unix_sysctl_register(struct net *net);
 extern void unix_sysctl_unregister(struct net *net);
index ce3c99e5fa25d984a9be0ef2b30adb5b9262c008..e42f6ed5421cabd05f653ba24f1acc09c1a66844 100644 (file)
@@ -107,6 +107,8 @@ struct hci_dev {
        unsigned long   acl_last_tx;
        unsigned long   sco_last_tx;
 
+       struct workqueue_struct *workqueue;
+
        struct tasklet_struct   cmd_task;
        struct tasklet_struct   rx_task;
        struct tasklet_struct   tx_task;
@@ -636,8 +638,8 @@ int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
-int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
-int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
+void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
 
index 17a689f27a6a397be082509e4f818f10566968cc..7c695bfd853cb44108b83d24ebf2afe56c875f93 100644 (file)
 #define L2CAP_DEFAULT_MIN_MTU          48
 #define L2CAP_DEFAULT_FLUSH_TO         0xffff
 #define L2CAP_DEFAULT_TX_WINDOW                63
-#define L2CAP_DEFAULT_NUM_TO_ACK        (L2CAP_DEFAULT_TX_WINDOW/5)
 #define L2CAP_DEFAULT_MAX_TX           3
 #define L2CAP_DEFAULT_RETRANS_TO       1000    /* 1 second */
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     672
+#define L2CAP_DEFAULT_ACK_TO           200
+#define L2CAP_LOCAL_BUSY_TRIES         12
 
 #define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
 #define L2CAP_INFO_TIMEOUT     (4000)  /*  4 seconds */
@@ -55,6 +56,8 @@ struct l2cap_options {
        __u16 flush_to;
        __u8  mode;
        __u8  fcs;
+       __u8  max_tx;
+       __u16 txwin_size;
 };
 
 #define L2CAP_CONNINFO 0x02
@@ -292,6 +295,7 @@ struct l2cap_conn {
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
 #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue)
 #define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue)
+#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue)
 #define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list)
 
 struct srej_list {
@@ -320,7 +324,7 @@ struct l2cap_pinfo {
        __u8            conf_req[64];
        __u8            conf_len;
        __u8            conf_state;
-       __u           conn_state;
+       __u16           conn_state;
 
        __u8            next_tx_seq;
        __u8            expected_ack_seq;
@@ -328,27 +332,35 @@ struct l2cap_pinfo {
        __u8            buffer_seq;
        __u8            buffer_seq_srej;
        __u8            srej_save_reqseq;
+       __u8            frames_sent;
        __u8            unacked_frames;
        __u8            retry_count;
-       __u8            num_to_ack;
+       __u8            num_acked;
        __u16           sdu_len;
        __u16           partial_sdu_len;
        struct sk_buff  *sdu;
 
        __u8            ident;
 
+       __u8            tx_win;
+       __u8            max_tx;
        __u8            remote_tx_win;
        __u8            remote_max_tx;
        __u16           retrans_timeout;
        __u16           monitor_timeout;
-       __u16           max_pdu_size;
+       __u16           remote_mps;
+       __u16           mps;
 
        __le16          sport;
 
+       spinlock_t              send_lock;
        struct timer_list       retrans_timer;
        struct timer_list       monitor_timer;
+       struct timer_list       ack_timer;
        struct sk_buff_head     tx_queue;
        struct sk_buff_head     srej_queue;
+       struct sk_buff_head     busy_queue;
+       struct work_struct      busy_work;
        struct srej_list        srej_l;
        struct l2cap_conn       *conn;
        struct sock             *next_c;
@@ -367,19 +379,24 @@ struct l2cap_pinfo {
 #define L2CAP_CONF_MAX_CONF_REQ 2
 #define L2CAP_CONF_MAX_CONF_RSP 2
 
-#define L2CAP_CONN_SAR_SDU         0x01
-#define L2CAP_CONN_SREJ_SENT       0x02
-#define L2CAP_CONN_WAIT_F          0x04
-#define L2CAP_CONN_SREJ_ACT        0x08
-#define L2CAP_CONN_SEND_PBIT       0x10
-#define L2CAP_CONN_REMOTE_BUSY     0x20
-#define L2CAP_CONN_LOCAL_BUSY      0x40
-#define L2CAP_CONN_REJ_ACT         0x80
+#define L2CAP_CONN_SAR_SDU         0x0001
+#define L2CAP_CONN_SREJ_SENT       0x0002
+#define L2CAP_CONN_WAIT_F          0x0004
+#define L2CAP_CONN_SREJ_ACT        0x0008
+#define L2CAP_CONN_SEND_PBIT       0x0010
+#define L2CAP_CONN_REMOTE_BUSY     0x0020
+#define L2CAP_CONN_LOCAL_BUSY      0x0040
+#define L2CAP_CONN_REJ_ACT         0x0080
+#define L2CAP_CONN_SEND_FBIT       0x0100
+#define L2CAP_CONN_RNR_SENT        0x0200
+#define L2CAP_CONN_SAR_RETRY       0x0400
 
 #define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \
                jiffies +  msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
 #define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \
                jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
+#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \
+               jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
 
 static inline int l2cap_tx_window_full(struct sock *sk)
 {
diff --git a/include/net/caif/caif_dev.h b/include/net/caif/caif_dev.h
new file mode 100644 (file)
index 0000000..318ab94
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_DEV_H_
+#define CAIF_DEV_H_
+
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfcnfg.h>
+#include <linux/caif/caif_socket.h>
+#include <linux/if.h>
+
+/**
+ * struct caif_param - CAIF parameters.
+ * @size:      Length of data
+ * @data:      Binary Data Blob
+ */
+struct caif_param {
+       u16  size;
+       u8   data[256];
+};
+
+/**
+ * struct caif_connect_request - Request data for CAIF channel setup.
+ * @protocol:          Type of CAIF protocol to use (at, datagram etc)
+ * @sockaddr:          Socket address to connect.
+ * @priority:          Priority of the connection.
+ * @link_selector:     Link selector (high bandwidth or low latency)
+ * @link_name:         Name of the CAIF Link Layer to use.
+ * @param:             Connect Request parameters (CAIF_SO_REQ_PARAM).
+ *
+ * This struct is used when connecting a CAIF channel.
+ * It contains all CAIF channel configuration options.
+ */
+struct caif_connect_request {
+       enum caif_protocol_type protocol;
+       struct sockaddr_caif sockaddr;
+       enum caif_channel_priority priority;
+       enum caif_link_selector link_selector;
+       char link_name[16];
+       struct caif_param param;
+};
+
+/**
+ * caif_connect_client - Connect a client to CAIF Core Stack.
+ * @config:            Channel setup parameters, specifying what address
+ *                     to connect on the Modem.
+ * @client_layer:      User implementation of client layer. This layer
+ *                     MUST have receive and control callback functions
+ *                     implemented.
+ *
+ * This function connects a CAIF channel. The Client must implement
+ * the struct cflayer. This layer represents the Client layer and holds
+ * receive functions and control callback functions. Control callback
+ * function will receive information about connect/disconnect responses,
+ * flow control etc (see enum caif_control).
+ * E.g. CAIF Socket will call this function for each socket it connects
+ * and have one client_layer instance for each socket.
+ */
+int caif_connect_client(struct caif_connect_request *config,
+                          struct cflayer *client_layer);
+
+/**
+ * caif_disconnect_client - Disconnects a client from the CAIF stack.
+ *
+ * @client_layer: Client layer to be removed.
+ */
+int caif_disconnect_client(struct cflayer *client_layer);
+
+/**
+ * caif_release_client - Release adaptation layer reference to client.
+ *
+ * @client_layer: Client layer.
+ *
+ * Releases a client/adaptation layer use of the caif stack.
+ * This function must be used after caif_disconnect_client to
+ * decrease the reference count of the service layer.
+ */
+void caif_release_client(struct cflayer *client_layer);
+
+/**
+ * connect_req_to_link_param - Translate configuration parameters
+ *                             from socket format to internal format.
+ * @cnfg:      Pointer to configuration handler
+ * @con_req:   Configuration parameters supplied in function
+ *             caif_connect_client
+ * @channel_setup_param: Parameters supplied to the CAIF Core stack for
+ *                      setting up channels.
+ *
+ */
+int connect_req_to_link_param(struct cfcnfg *cnfg,
+                               struct caif_connect_request *con_req,
+                               struct cfctrl_link_param *channel_setup_param);
+
+/**
+ * get_caif_conf() - Get the configuration handler.
+ */
+struct cfcnfg *get_caif_conf(void);
+
+
+#endif /* CAIF_DEV_H_ */
diff --git a/include/net/caif/caif_device.h b/include/net/caif/caif_device.h
new file mode 100644 (file)
index 0000000..d02f044
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/ sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_DEVICE_H_
+#define CAIF_DEVICE_H_
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/caif/caif_socket.h>
+#include <net/caif/caif_device.h>
+
+/**
+ * struct caif_dev_common - data shared between CAIF drivers and stack.
+ * @flowctrl:          Flow Control callback function. This function is
+ *                      supplied by CAIF Core Stack and is used by CAIF
+ *                      Link Layer to send flow-stop to CAIF Core.
+ *                      The flow information will be distributed to all
+ *                      clients of CAIF.
+ *
+ * @link_select:       Profile of device, either high-bandwidth or
+ *                     low-latency. This member is set by CAIF Link
+ *                     Layer Device in order to indicate if this device
+ *                     is a high bandwidth or low latency device.
+ *
+ * @use_frag:          CAIF Frames may be fragmented.
+ *                     Is set by CAIF Link Layer in order to indicate if the
+ *                     interface receives fragmented frames that must be
+ *                     assembled by CAIF Core Layer.
+ *
+ * @use_fcs:           Indicate if Frame CheckSum (fcs) is used.
+ *                     Is set if the physical interface is
+ *                     using Frame Checksum on the CAIF Frames.
+ *
+ * @use_stx:           Indicate STart of frame eXtension (stx) in use.
+ *                     Is set if the CAIF Link Layer expects
+ *                     CAIF Frames to start with the STX byte.
+ *
+ * This structure is shared between the CAIF drivers and the CAIF stack.
+ * It is used by the device to register its behavior.
+ * CAIF Core layer must set the member flowctrl in order to supply
+ * CAIF Link Layer with the flow control function.
+ *
+ */
+ struct caif_dev_common {
+       void (*flowctrl)(struct net_device *net, int on);
+       enum caif_link_selector link_select;
+       int use_frag;
+       int use_fcs;
+       int use_stx;
+};
+
+#endif /* CAIF_DEVICE_H_ */
diff --git a/include/net/caif/caif_layer.h b/include/net/caif/caif_layer.h
new file mode 100644 (file)
index 0000000..25c472f
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland / sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_LAYER_H_
+#define CAIF_LAYER_H_
+
+#include <linux/list.h>
+
+struct cflayer;
+struct cfpkt;
+struct cfpktq;
+struct caif_payload_info;
+struct caif_packet_funcs;
+
+#define CAIF_MAX_FRAMESIZE 4096
+#define CAIF_MAX_PAYLOAD_SIZE (4096 - 64)
+#define CAIF_NEEDED_HEADROOM (10)
+#define CAIF_NEEDED_TAILROOM (2)
+
+#define CAIF_LAYER_NAME_SZ 16
+#define CAIF_SUCCESS   1
+#define CAIF_FAILURE   0
+
+/**
+ * caif_assert() - Assert function for CAIF.
+ * @assert: expression to evaluate.
+ *
+ * This function will print a error message and a do WARN_ON if the
+ * assertion failes. Normally this will do a stack up at the current location.
+ */
+#define caif_assert(assert)                                    \
+do {                                                           \
+       if (!(assert)) {                                        \
+               pr_err("caif:Assert detected:'%s'\n", #assert); \
+               WARN_ON(!(assert));                             \
+       }                                                       \
+} while (0)
+
+
+/**
+ * enum caif_ctrlcmd - CAIF Stack Control Signaling sent in layer.ctrlcmd().
+ *
+ * @CAIF_CTRLCMD_FLOW_OFF_IND:         Flow Control is OFF, transmit function
+ *                                     should stop sending data
+ *
+ * @CAIF_CTRLCMD_FLOW_ON_IND:          Flow Control is ON, transmit function
+ *                                     can start sending data
+ *
+ * @CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:  Remote end modem has decided to close
+ *                                     down channel
+ *
+ * @CAIF_CTRLCMD_INIT_RSP:             Called initially when the layer below
+ *                                     has finished initialization
+ *
+ * @CAIF_CTRLCMD_DEINIT_RSP:           Called when de-initialization is
+ *                                     complete
+ *
+ * @CAIF_CTRLCMD_INIT_FAIL_RSP:                Called if initialization fails
+ *
+ * @_CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:  CAIF Link layer temporarily cannot
+ *                                     send more packets.
+ * @_CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:   Called if CAIF Link layer is able
+ *                                     to send packets again.
+ * @_CAIF_CTRLCMD_PHYIF_DOWN_IND:      Called if CAIF Link layer is going
+ *                                     down.
+ *
+ * These commands are sent upwards in the CAIF stack to the CAIF Client.
+ * They are used for signaling originating from the modem or CAIF Link Layer.
+ * These are either responses (*_RSP) or events (*_IND).
+ */
+enum caif_ctrlcmd {
+       CAIF_CTRLCMD_FLOW_OFF_IND,
+       CAIF_CTRLCMD_FLOW_ON_IND,
+       CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND,
+       CAIF_CTRLCMD_INIT_RSP,
+       CAIF_CTRLCMD_DEINIT_RSP,
+       CAIF_CTRLCMD_INIT_FAIL_RSP,
+       _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
+       _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND,
+       _CAIF_CTRLCMD_PHYIF_DOWN_IND,
+};
+
+/**
+ * enum caif_modemcmd -         Modem Control Signaling, sent from CAIF Client
+ *                      to the CAIF Link Layer or modem.
+ *
+ * @CAIF_MODEMCMD_FLOW_ON_REQ:         Flow Control is ON, transmit function
+ *                                     can start sending data.
+ *
+ * @CAIF_MODEMCMD_FLOW_OFF_REQ:                Flow Control is OFF, transmit function
+ *                                     should stop sending data.
+ *
+ * @_CAIF_MODEMCMD_PHYIF_USEFULL:      Notify physical layer that it is in use
+ *
+ * @_CAIF_MODEMCMD_PHYIF_USELESS:      Notify physical layer that it is
+ *                                     no longer in use.
+ *
+ * These are requests sent 'downwards' in the stack.
+ * Flow ON, OFF can be indicated to the modem.
+ */
+enum caif_modemcmd {
+       CAIF_MODEMCMD_FLOW_ON_REQ = 0,
+       CAIF_MODEMCMD_FLOW_OFF_REQ = 1,
+       _CAIF_MODEMCMD_PHYIF_USEFULL = 3,
+       _CAIF_MODEMCMD_PHYIF_USELESS = 4
+};
+
+/**
+ * enum caif_direction - CAIF Packet Direction.
+ * Indicate if a packet is to be sent out or to be received in.
+ * @CAIF_DIR_IN:               Incoming packet received.
+ * @CAIF_DIR_OUT:              Outgoing packet to be transmitted.
+ */
+enum caif_direction {
+       CAIF_DIR_IN = 0,
+       CAIF_DIR_OUT = 1
+};
+
+/**
+ * struct cflayer - CAIF Stack layer.
+ * Defines the framework for the CAIF Core Stack.
+ * @up:                Pointer up to the layer above.
+ * @dn:                Pointer down to the layer below.
+ * @node:      List node used when layer participate in a list.
+ * @receive:   Packet receive function.
+ * @transmit:  Packet transmit funciton.
+ * @ctrlcmd:   Used for control signalling upwards in the stack.
+ * @modemcmd:  Used for control signaling downwards in the stack.
+ * @prio:      Priority of this layer.
+ * @id:                The identity of this layer
+ * @type:      The type of this layer
+ * @name:      Name of the layer.
+ *
+ *  This structure defines the layered structure in CAIF.
+ *
+ *  It defines CAIF layering structure, used by all CAIF Layers and the
+ *  layers interfacing CAIF.
+ *
+ *  In order to integrate with CAIF an adaptation layer on top of the CAIF stack
+ *  and PHY layer below the CAIF stack
+ *  must be implemented. These layer must follow the design principles below.
+ *
+ *  Principles for layering of protocol layers:
+ *    - All layers must use this structure. If embedding it, then place this
+ *     structure first in the layer specific structure.
+ *
+ *    - Each layer should not depend on any others layer private data.
+ *
+ *    - In order to send data upwards do
+ *     layer->up->receive(layer->up, packet);
+ *
+ *    - In order to send data downwards do
+ *     layer->dn->transmit(layer->dn, info, packet);
+ */
+struct cflayer {
+       struct cflayer *up;
+       struct cflayer *dn;
+       struct list_head node;
+
+       /*
+        *  receive() - Receive Function.
+        *  Contract: Each layer must implement a receive function passing the
+        *  CAIF packets upwards in the stack.
+        *      Packet handling rules:
+        *            - The CAIF packet (cfpkt) cannot be accessed after
+        *                   passing it to the next layer using up->receive().
+        *            - If parsing of the packet fails, the packet must be
+        *                   destroyed and -1 returned from the function.
+        *            - If parsing succeeds (and above layers return OK) then
+        *                    the function must return a value > 0.
+        *
+        *  Returns result < 0 indicates an error, 0 or positive value
+        *           indicates success.
+        *
+        *  @layr: Pointer to the current layer the receive function is
+        *              implemented for (this pointer).
+        *  @cfpkt: Pointer to CaifPacket to be handled.
+        */
+       int (*receive)(struct cflayer *layr, struct cfpkt *cfpkt);
+
+       /*
+        *  transmit() - Transmit Function.
+        *  Contract: Each layer must implement a transmit function passing the
+        *      CAIF packet downwards in the stack.
+        *      Packet handling rules:
+        *            - The CAIF packet (cfpkt) ownership is passed to the
+        *              transmit function. This means that the the packet
+        *              cannot be accessed after passing it to the below
+        *              layer using dn->transmit().
+        *
+        *            - If transmit fails, however, the ownership is returned
+        *              to thecaller. The caller of "dn->transmit()" must
+        *              destroy or resend packet.
+        *
+        *            - Return value less than zero means error, zero or
+        *              greater than zero means OK.
+        *
+        *       result < 0 indicates an error, 0 or positive value
+        *       indicate success.
+        *
+        *  @layr:      Pointer to the current layer the receive function
+        *              isimplemented for (this pointer).
+        *  @cfpkt:      Pointer to CaifPacket to be handled.
+        */
+       int (*transmit) (struct cflayer *layr, struct cfpkt *cfpkt);
+
+       /*
+        *  cttrlcmd() - Control Function upwards in CAIF Stack.
+        *  Used for signaling responses (CAIF_CTRLCMD_*_RSP)
+        *  and asynchronous events from the modem  (CAIF_CTRLCMD_*_IND)
+        *
+        *  @layr:      Pointer to the current layer the receive function
+        *              is implemented for (this pointer).
+        *  @ctrl:      Control Command.
+        */
+       void (*ctrlcmd) (struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                        int phyid);
+
+       /*
+        *  modemctrl() - Control Function used for controlling the modem.
+        *  Used to signal down-wards in the CAIF stack.
+        *  Returns 0 on success, < 0 upon failure.
+        *
+        *  @layr:      Pointer to the current layer the receive function
+        *              is implemented for (this pointer).
+        *  @ctrl:  Control Command.
+        */
+       int (*modemcmd) (struct cflayer *layr, enum caif_modemcmd ctrl);
+
+       unsigned short prio;
+       unsigned int id;
+       unsigned int type;
+       char name[CAIF_LAYER_NAME_SZ];
+};
+
+/**
+ * layer_set_up() - Set the up pointer for a specified layer.
+ *  @layr: Layer where up pointer shall be set.
+ *  @above: Layer above.
+ */
+#define layer_set_up(layr, above) ((layr)->up = (struct cflayer *)(above))
+
+/**
+ *  layer_set_dn() - Set the down pointer for a specified layer.
+ *  @layr:  Layer where down pointer shall be set.
+ *  @below: Layer below.
+ */
+#define layer_set_dn(layr, below) ((layr)->dn = (struct cflayer *)(below))
+
+/**
+ * struct dev_info - Physical Device info information about physical layer.
+ * @dev:       Pointer to native physical device.
+ * @id:                Physical ID of the physical connection used by the
+ *             logical CAIF connection. Used by service layers to
+ *             identify their physical id to Caif MUX (CFMUXL)so
+ *             that the MUX can add the correct physical ID to the
+ *             packet.
+ */
+struct dev_info {
+       void *dev;
+       unsigned int id;
+};
+
+/**
+ * struct caif_payload_info - Payload information embedded in packet (sk_buff).
+ *
+ * @dev_info:  Information about the receiving device.
+ *
+ * @hdr_len:   Header length, used to align pay load on 32bit boundary.
+ *
+ * @channel_id: Channel ID of the logical CAIF connection.
+ *             Used by mux to insert channel id into the caif packet.
+ */
+struct caif_payload_info {
+       struct dev_info *dev_info;
+       unsigned short hdr_len;
+       unsigned short channel_id;
+};
+
+#endif /* CAIF_LAYER_H_ */
diff --git a/include/net/caif/cfcnfg.h b/include/net/caif/cfcnfg.h
new file mode 100644 (file)
index 0000000..9fc2fc2
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFCNFG_H_
+#define CFCNFG_H_
+#include <linux/spinlock.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfctrl.h>
+
+struct cfcnfg;
+
+/**
+ * enum cfcnfg_phy_type -  Types of physical layers defined in CAIF Stack
+ *
+ * @CFPHYTYPE_FRAG:    Fragmented frames physical interface.
+ * @CFPHYTYPE_CAIF:    Generic CAIF physical interface
+ */
+enum cfcnfg_phy_type {
+       CFPHYTYPE_FRAG = 1,
+       CFPHYTYPE_CAIF,
+       CFPHYTYPE_MAX
+};
+
+/**
+ * enum cfcnfg_phy_preference - Physical preference HW Abstraction
+ *
+ * @CFPHYPREF_UNSPECIFIED:     Default physical interface
+ *
+ * @CFPHYPREF_LOW_LAT:         Default physical interface for low-latency
+ *                             traffic
+ * @CFPHYPREF_HIGH_BW:         Default physical interface for high-bandwidth
+ *                             traffic
+ * @CFPHYPREF_LOOP:            TEST only Loopback interface simulating modem
+ *                             responses.
+ *
+ */
+enum cfcnfg_phy_preference {
+       CFPHYPREF_UNSPECIFIED,
+       CFPHYPREF_LOW_LAT,
+       CFPHYPREF_HIGH_BW,
+       CFPHYPREF_LOOP
+};
+
+/**
+ * cfcnfg_create() - Create the CAIF configuration object.
+ */
+struct cfcnfg *cfcnfg_create(void);
+
+/**
+ * cfcnfg_remove() -  Remove the CFCNFG object
+ * @cfg: config object
+ */
+void cfcnfg_remove(struct cfcnfg *cfg);
+
+/**
+ * cfcnfg_add_phy_layer() - Adds a physical layer to the CAIF stack.
+ * @cnfg:      Pointer to a CAIF configuration object, created by
+ *             cfcnfg_create().
+ * @phy_type:  Specifies the type of physical interface, e.g.
+ *                     CFPHYTYPE_FRAG.
+ * @dev:       Pointer to link layer device
+ * @phy_layer: Specify the physical layer. The transmit function
+ *             MUST be set in the structure.
+ * @phyid:     The assigned physical ID for this layer, used in
+ *             cfcnfg_add_adapt_layer to specify PHY for the link.
+ * @pref:      The phy (link layer) preference.
+ * @fcs:       Specify if checksum is used in CAIF Framing Layer.
+ * @stx:       Specify if Start Of Frame eXtention is used.
+ */
+
+void
+cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
+                    void *dev, struct cflayer *phy_layer, u16 *phyid,
+                    enum cfcnfg_phy_preference pref,
+                    bool fcs, bool stx);
+
+/**
+ * cfcnfg_del_phy_layer - Deletes an phy layer from the CAIF stack.
+ *
+ * @cnfg:      Pointer to a CAIF configuration object, created by
+ *             cfcnfg_create().
+ * @phy_layer: Adaptation layer to be removed.
+ */
+int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer);
+
+/**
+ * cfcnfg_disconn_adapt_layer - Disconnects an adaptation layer.
+ *
+ * @cnfg:      Pointer to a CAIF configuration object, created by
+ *             cfcnfg_create().
+ * @adap_layer: Adaptation layer to be removed.
+ */
+int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg,
+                       struct cflayer *adap_layer);
+
+/**
+ * cfcnfg_release_adap_layer - Used by client to release the adaptation layer.
+ *
+ * @adap_layer: Adaptation layer.
+ */
+void cfcnfg_release_adap_layer(struct cflayer *adap_layer);
+
+/**
+ * cfcnfg_add_adaptation_layer - Add an adaptation layer to the CAIF stack.
+ *
+ * The adaptation Layer is where the interface to application or higher-level
+ * driver functionality is implemented.
+ *
+ * @cnfg:              Pointer to a CAIF configuration object, created by
+ *                     cfcnfg_create().
+ * @param:             Link setup parameters.
+ * @adap_layer:                Specify the adaptation layer; the receive and
+ *                     flow-control functions MUST be set in the structure.
+ *
+ */
+int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
+                           struct cfctrl_link_param *param,
+                           struct cflayer *adap_layer);
+
+/**
+ * cfcnfg_get_phyid() - Get physical ID, given type.
+ * Returns one of the physical interfaces matching the given type.
+ * Zero if no match is found.
+ * @cnfg:      Configuration object
+ * @phy_pref:  Caif Link Layer preference
+ */
+struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
+                    enum cfcnfg_phy_preference phy_pref);
+
+/**
+ * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer
+ * @cnfg:      Configuration object
+ * @name:      Name of the Physical Layer (Caif Link Layer)
+ */
+int cfcnfg_get_named(struct cfcnfg *cnfg, char *name);
+
+#endif                         /* CFCNFG_H_ */
diff --git a/include/net/caif/cfctrl.h b/include/net/caif/cfctrl.h
new file mode 100644 (file)
index 0000000..997603f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFCTRL_H_
+#define CFCTRL_H_
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+
+/* CAIF Control packet commands */
+enum cfctrl_cmd {
+       CFCTRL_CMD_LINK_SETUP = 0,
+       CFCTRL_CMD_LINK_DESTROY = 1,
+       CFCTRL_CMD_LINK_ERR = 2,
+       CFCTRL_CMD_ENUM = 3,
+       CFCTRL_CMD_SLEEP = 4,
+       CFCTRL_CMD_WAKE = 5,
+       CFCTRL_CMD_LINK_RECONF = 6,
+       CFCTRL_CMD_START_REASON = 7,
+       CFCTRL_CMD_RADIO_SET = 8,
+       CFCTRL_CMD_MODEM_SET = 9,
+       CFCTRL_CMD_MASK = 0xf
+};
+
+/* Channel types */
+enum cfctrl_srv {
+       CFCTRL_SRV_DECM = 0,
+       CFCTRL_SRV_VEI = 1,
+       CFCTRL_SRV_VIDEO = 2,
+       CFCTRL_SRV_DBG = 3,
+       CFCTRL_SRV_DATAGRAM = 4,
+       CFCTRL_SRV_RFM = 5,
+       CFCTRL_SRV_UTIL = 6,
+       CFCTRL_SRV_MASK = 0xf
+};
+
+#define CFCTRL_RSP_BIT 0x20
+#define CFCTRL_ERR_BIT 0x10
+
+struct cfctrl_rsp {
+       void (*linksetup_rsp)(struct cflayer *layer, u8 linkid,
+                             enum cfctrl_srv serv, u8 phyid,
+                             struct cflayer *adapt_layer);
+       void (*linkdestroy_rsp)(struct cflayer *layer, u8 linkid);
+       void (*linkerror_ind)(void);
+       void (*enum_rsp)(void);
+       void (*sleep_rsp)(void);
+       void (*wake_rsp)(void);
+       void (*restart_rsp)(void);
+       void (*radioset_rsp)(void);
+       void (*reject_rsp)(struct cflayer *layer, u8 linkid,
+                               struct cflayer *client_layer);;
+};
+
+/* Link Setup Parameters for CAIF-Links. */
+struct cfctrl_link_param {
+       enum cfctrl_srv linktype;/* (T3,T0) Type of Channel */
+       u8 priority;              /* (P4,P0) Priority of the channel */
+       u8 phyid;                 /* (U2-U0) Physical interface to connect */
+       u8 endpoint;              /* (E1,E0) Endpoint for data channels */
+       u8 chtype;                /* (H1,H0) Channel-Type, applies to
+                                  *            VEI, DEBUG */
+       union {
+               struct {
+                       u8 connid;      /*  (D7,D0) Video LinkId */
+               } video;
+
+               struct {
+                       u32 connid;     /* (N31,Ngit0) Connection ID used
+                                        *  for Datagram */
+               } datagram;
+
+               struct {
+                       u32 connid;     /* Connection ID used for RFM */
+                       char volume[20];        /* Volume to mount for RFM */
+               } rfm;          /* Configuration for RFM */
+
+               struct {
+                       u16 fifosize_kb;        /* Psock FIFO size in KB */
+                       u16 fifosize_bufs;      /* Psock # signal buffers */
+                       char name[16];  /* Name of the PSOCK service */
+                       u8 params[255]; /* Link setup Parameters> */
+                       u16 paramlen;   /* Length of Link Setup
+                                                *   Parameters */
+               } utility;      /* Configuration for Utility Links (Psock) */
+       } u;
+};
+
+/* This structure is used internally in CFCTRL */
+struct cfctrl_request_info {
+       int sequence_no;
+       enum cfctrl_cmd cmd;
+       u8 channel_id;
+       struct cfctrl_link_param param;
+       struct cfctrl_request_info *next;
+       struct cflayer *client_layer;
+};
+
+struct cfctrl {
+       struct cfsrvl serv;
+       struct cfctrl_rsp res;
+       atomic_t req_seq_no;
+       atomic_t rsp_seq_no;
+       struct cfctrl_request_info *first_req;
+       /* Protects from simultaneous access to first_req list */
+       spinlock_t info_list_lock;
+#ifndef CAIF_NO_LOOP
+       u8 loop_linkid;
+       int loop_linkused[256];
+       /* Protects simultaneous access to loop_linkid and loop_linkused */
+       spinlock_t loop_linkid_lock;
+#endif
+
+};
+
+void cfctrl_enum_req(struct cflayer *cfctrl, u8 physlinkid);
+int cfctrl_linkup_request(struct cflayer *cfctrl,
+                          struct cfctrl_link_param *param,
+                          struct cflayer *user_layer);
+int  cfctrl_linkdown_req(struct cflayer *cfctrl, u8 linkid,
+                        struct cflayer *client);
+void cfctrl_sleep_req(struct cflayer *cfctrl);
+void cfctrl_wake_req(struct cflayer *cfctrl);
+void cfctrl_getstartreason_req(struct cflayer *cfctrl);
+struct cflayer *cfctrl_create(void);
+void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn);
+void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up);
+struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer);
+bool cfctrl_req_eq(struct cfctrl_request_info *r1,
+                  struct cfctrl_request_info *r2);
+void cfctrl_insert_req(struct cfctrl *ctrl,
+                             struct cfctrl_request_info *req);
+struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
+                                             struct cfctrl_request_info *req);
+void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer);
+
+#endif                         /* CFCTRL_H_ */
diff --git a/include/net/caif/cffrml.h b/include/net/caif/cffrml.h
new file mode 100644 (file)
index 0000000..3f14d2e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFFRML_H_
+#define CFFRML_H_
+#include <net/caif/caif_layer.h>
+
+struct cffrml;
+struct cflayer *cffrml_create(u16 phyid, bool DoFCS);
+void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up);
+void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn);
+
+#endif /* CFFRML_H_ */
diff --git a/include/net/caif/cfmuxl.h b/include/net/caif/cfmuxl.h
new file mode 100644 (file)
index 0000000..4e1b4f3
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFMUXL_H_
+#define CFMUXL_H_
+#include <net/caif/caif_layer.h>
+
+struct cfsrvl;
+struct cffrml;
+
+struct cflayer *cfmuxl_create(void);
+int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid);
+struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid);
+int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *up, u8 phyid);
+struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 linkid);
+bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid);
+u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id);
+
+#endif                         /* CFMUXL_H_ */
diff --git a/include/net/caif/cfpkt.h b/include/net/caif/cfpkt.h
new file mode 100644 (file)
index 0000000..fbc681b
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFPKT_H_
+#define CFPKT_H_
+#include <net/caif/caif_layer.h>
+#include <linux/types.h>
+struct cfpkt;
+
+/* Create a CAIF packet.
+ * len: Length of packet to be created
+ * @return New packet.
+ */
+struct cfpkt *cfpkt_create(u16 len);
+
+/* Create a CAIF packet.
+ * data Data to copy.
+ * len Length of packet to be created
+ * @return New packet.
+ */
+struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len);
+/*
+ * Destroy a CAIF Packet.
+ * pkt Packet to be destoyed.
+ */
+void cfpkt_destroy(struct cfpkt *pkt);
+
+/*
+ * Extract header from packet.
+ *
+ * pkt Packet to extract header data from.
+ * data Pointer to copy the header data into.
+ * len Length of head data to copy.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len);
+
+/*
+ * Peek header from packet.
+ * Reads data from packet without changing packet.
+ *
+ * pkt Packet to extract header data from.
+ * data Pointer to copy the header data into.
+ * len Length of head data to copy.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len);
+
+/*
+ * Extract header from trailer (end of packet).
+ *
+ * pkt Packet to extract header data from.
+ * data Pointer to copy the trailer data into.
+ * len Length of header data to copy.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_extr_trail(struct cfpkt *pkt, void *data, u16 len);
+
+/*
+ * Add header to packet.
+ *
+ *
+ * pkt Packet to add header data to.
+ * data Pointer to data to copy into the header.
+ * len Length of header data to copy.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_add_head(struct cfpkt *pkt, const void *data, u16 len);
+
+/*
+ * Add trailer to packet.
+ *
+ *
+ * pkt Packet to add trailer data to.
+ * data Pointer to data to copy into the trailer.
+ * len Length of trailer data to copy.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len);
+
+/*
+ * Pad trailer on packet.
+ * Moves data pointer in packet, no content copied.
+ *
+ * pkt Packet in which to pad trailer.
+ * len Length of padding to add.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_pad_trail(struct cfpkt *pkt, u16 len);
+
+/*
+ * Add a single byte to packet body (tail).
+ *
+ * pkt Packet in which to add byte.
+ * data Byte to add.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_addbdy(struct cfpkt *pkt, const u8 data);
+
+/*
+ * Add a data to packet body (tail).
+ *
+ * pkt Packet in which to add data.
+ * data Pointer to data to copy into the packet body.
+ * len Length of data to add.
+ * @return zero on success and error code upon failure
+ */
+int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len);
+
+/*
+ * Checks whether there are more data to process in packet.
+ * pkt Packet to check.
+ * @return true if more data are available in packet false otherwise
+ */
+bool cfpkt_more(struct cfpkt *pkt);
+
+/*
+ * Checks whether the packet is erroneous,
+ * i.e. if it has been attempted to extract more data than available in packet
+ * or writing more data than has been allocated in cfpkt_create().
+ * pkt Packet to check.
+ * @return true on error false otherwise
+ */
+bool cfpkt_erroneous(struct cfpkt *pkt);
+
+/*
+ * Get the packet length.
+ * pkt Packet to get length from.
+ * @return Number of bytes in packet.
+ */
+u16 cfpkt_getlen(struct cfpkt *pkt);
+
+/*
+ * Set the packet length, by adjusting the trailer pointer according to length.
+ * pkt Packet to set length.
+ * len Packet length.
+ * @return Number of bytes in packet.
+ */
+int cfpkt_setlen(struct cfpkt *pkt, u16 len);
+
+/*
+ * cfpkt_append - Appends a packet's data to another packet.
+ * dstpkt:    Packet to append data into, WILL BE FREED BY THIS FUNCTION
+ * addpkt:    Packet to be appended and automatically released,
+ *            WILL BE FREED BY THIS FUNCTION.
+ * expectlen: Packet's expected total length. This should be considered
+ *            as a hint.
+ * NB: Input packets will be destroyed after appending and cannot be used
+ * after calling this function.
+ * @return    The new appended packet.
+ */
+struct cfpkt *cfpkt_append(struct cfpkt *dstpkt, struct cfpkt *addpkt,
+                     u16 expectlen);
+
+/*
+ * cfpkt_split - Split a packet into two packets at the specified split point.
+ * pkt: Packet to be split (will contain the first part of the data on exit)
+ * pos: Position to split packet in two parts.
+ * @return The new packet, containing the second part of the data.
+ */
+struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos);
+
+/*
+ * Iteration function, iterates the packet buffers from start to end.
+ *
+ * Checksum iteration function used to iterate buffers
+ * (we may have packets consisting of a chain of buffers)
+ * pkt:       Packet to calculate checksum for
+ * iter_func: Function pointer to iteration function
+ * chks:      Checksum calculated so far.
+ * buf:       Pointer to the buffer to checksum
+ * len:       Length of buf.
+ * data:      Initial checksum value.
+ * @return    Checksum of buffer.
+ */
+
+u16 cfpkt_iterate(struct cfpkt *pkt,
+               u16 (*iter_func)(u16 chks, void *buf, u16 len),
+               u16 data);
+
+/* Append by giving user access to packet buffer
+ * cfpkt Packet to append to
+ * buf Buffer inside pkt that user shall copy data into
+ * buflen Length of buffer and number of bytes added to packet
+ * @return 0 on error, 1 on success
+ */
+int cfpkt_raw_append(struct cfpkt *cfpkt, void **buf, unsigned int buflen);
+
+/* Extract by giving user access to packet buffer
+ * cfpkt Packet to extract from
+ * buf Buffer inside pkt that user shall copy data from
+ * buflen Length of buffer and number of bytes removed from packet
+ * @return 0 on error, 1 on success
+ */
+int cfpkt_raw_extract(struct cfpkt *cfpkt, void **buf, unsigned int buflen);
+
+/* Map from a "native" packet (e.g. Linux Socket Buffer) to a CAIF packet.
+ *  dir - Direction indicating whether this packet is to be sent or received.
+ *  nativepkt  - The native packet to be transformed to a CAIF packet
+ *  @return The mapped CAIF Packet CFPKT.
+ */
+struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt);
+
+/* Map from a CAIF packet to a "native" packet (e.g. Linux Socket Buffer).
+ *  pkt  - The CAIF packet to be transformed into a "native" packet.
+ *  @return The native packet transformed from a CAIF packet.
+ */
+void *cfpkt_tonative(struct cfpkt *pkt);
+
+/*
+ * Insert a packet in the packet queue.
+ * pktq Packet queue to insert into
+ * pkt Packet to be inserted in queue
+ * prio Priority of packet
+ */
+void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt,
+                unsigned short prio);
+
+/*
+ * Remove a packet from the packet queue.
+ * pktq Packet queue to fetch packets from.
+ * @return Dequeued packet.
+ */
+struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq);
+
+/*
+ * Peek into a packet from the packet queue.
+ * pktq Packet queue to fetch packets from.
+ * @return Peeked packet.
+ */
+struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq);
+
+/*
+ * Initiates the packet queue.
+ * @return Pointer to new packet queue.
+ */
+struct cfpktq *cfpktq_create(void);
+
+/*
+ * Get the number of packets in the queue.
+ * pktq Packet queue to fetch count from.
+ * @return Number of packets in queue.
+ */
+int cfpkt_qcount(struct cfpktq *pktq);
+
+/*
+ * Put content of packet into buffer for debuging purposes.
+ * pkt Packet to copy data from
+ * buf Buffer to copy data into
+ * buflen Length of data to copy
+ * @return Pointer to copied data
+ */
+char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen);
+
+/*
+ * Clones a packet and releases the original packet.
+ * This is used for taking ownership of a packet e.g queueing.
+ * pkt Packet to clone and release.
+ * @return Cloned packet.
+ */
+struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt);
+
+
+/*
+ * Returns packet information for a packet.
+ * pkt Packet to get info from;
+ * @return Packet information
+ */
+struct caif_payload_info *cfpkt_info(struct cfpkt *pkt);
+/*! @} */
+#endif                         /* CFPKT_H_ */
diff --git a/include/net/caif/cfserl.h b/include/net/caif/cfserl.h
new file mode 100644 (file)
index 0000000..b837432
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFSERL_H_
+#define CFSERL_H_
+#include <net/caif/caif_layer.h>
+
+struct cflayer *cfserl_create(int type, int instance, bool use_stx);
+#endif                         /* CFSERL_H_ */
diff --git a/include/net/caif/cfsrvl.h b/include/net/caif/cfsrvl.h
new file mode 100644 (file)
index 0000000..2dc9eb1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CFSRVL_H_
+#define CFSRVL_H_
+#include <linux/list.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/kref.h>
+
+struct cfsrvl {
+       struct cflayer layer;
+       bool open;
+       bool phy_flow_on;
+       bool modem_flow_on;
+       struct dev_info dev_info;
+       struct kref ref;
+};
+
+void cfsrvl_release(struct kref *kref);
+struct cflayer *cfvei_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfdgml_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfutill_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfvidl_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfrfml_create(u8 linkid, struct dev_info *dev_info);
+struct cflayer *cfdbgl_create(u8 linkid, struct dev_info *dev_info);
+bool cfsrvl_phyid_match(struct cflayer *layer, int phyid);
+void cfservl_destroy(struct cflayer *layer);
+void cfsrvl_init(struct cfsrvl *service,
+                u8 channel_id,
+                struct dev_info *dev_info);
+bool cfsrvl_ready(struct cfsrvl *service, int *err);
+u8 cfsrvl_getphyid(struct cflayer *layer);
+
+static inline void cfsrvl_get(struct cflayer *layr)
+{
+       struct cfsrvl *s;
+       if (layr == NULL)
+               return;
+       s = container_of(layr, struct cfsrvl, layer);
+       kref_get(&s->ref);
+}
+
+static inline void cfsrvl_put(struct cflayer *layr)
+{
+       struct cfsrvl *s;
+       if (layr == NULL)
+               return;
+       s = container_of(layr, struct cfsrvl, layer);
+       kref_put(&s->ref, cfsrvl_release);
+}
+
+#endif                         /* CFSRVL_H_ */
index 3d134a1fb96bd734c5b1224d79703ecf33cb1600..b44a2e5321a365468312d56ac7285c8ff09129ed 100644 (file)
@@ -511,6 +511,7 @@ struct mpath_info {
  * @basic_rates: basic rates in IEEE 802.11 format
  *     (or NULL for no change)
  * @basic_rates_len: number of basic rates
+ * @ap_isolate: do not forward packets between connected stations
  */
 struct bss_parameters {
        int use_cts_prot;
@@ -518,6 +519,7 @@ struct bss_parameters {
        int use_short_slot_time;
        u8 *basic_rates;
        u8 basic_rates_len;
+       int ap_isolate;
 };
 
 struct mesh_config {
@@ -704,6 +706,10 @@ struct cfg80211_crypto_settings {
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
  * @key: WEP key for shared key authentication
+ * @local_state_change: This is a request for a local state only, i.e., no
+ *     Authentication frame is to be transmitted and authentication state is
+ *     to be changed without having to wait for a response from the peer STA
+ *     (AP).
  */
 struct cfg80211_auth_request {
        struct cfg80211_bss *bss;
@@ -712,6 +718,7 @@ struct cfg80211_auth_request {
        enum nl80211_auth_type auth_type;
        const u8 *key;
        u8 key_len, key_idx;
+       bool local_state_change;
 };
 
 /**
@@ -744,12 +751,15 @@ struct cfg80211_assoc_request {
  * @ie: Extra IEs to add to Deauthentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @reason_code: The reason code for the deauthentication
+ * @local_state_change: This is a request for a local state only, i.e., no
+ *     Deauthentication frame is to be transmitted.
  */
 struct cfg80211_deauth_request {
        struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
        u16 reason_code;
+       bool local_state_change;
 };
 
 /**
@@ -762,12 +772,15 @@ struct cfg80211_deauth_request {
  * @ie: Extra IEs to add to Disassociation frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @reason_code: The reason code for the disassociation
+ * @local_state_change: This is a request for a local state only, i.e., no
+ *     Disassociation frame is to be transmitted.
  */
 struct cfg80211_disassoc_request {
        struct cfg80211_bss *bss;
        const u8 *ie;
        size_t ie_len;
        u16 reason_code;
+       bool local_state_change;
 };
 
 /**
@@ -953,7 +966,11 @@ struct cfg80211_pmksa {
  *
  * @set_txq_params: Set TX queue parameters
  *
- * @set_channel: Set channel
+ * @set_channel: Set channel for a given wireless interface. Some devices
+ *     may support multi-channel operation (by channel hopping) so cfg80211
+ *     doesn't verify much. Note, however, that the passed netdev may be
+ *     %NULL as well if the user requested changing the channel for the
+ *     device itself, or for a monitor interface.
  *
  * @scan: Request to do a scan. If returning zero, the scan request is given
  *     the driver, and will be valid until passed to cfg80211_scan_done().
@@ -1007,6 +1024,9 @@ struct cfg80211_pmksa {
  *     RSN IE. It allows for faster roaming between WPA2 BSSIDs.
  * @del_pmksa: Delete a cached PMKID.
  * @flush_pmksa: Flush all cached PMKIDs.
+ * @set_power_mgmt: Configure WLAN power management. A timeout value of -1
+ *     allows the driver to adjust the dynamic ps timeout value.
+ * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
  *
  */
 struct cfg80211_ops {
@@ -1079,7 +1099,7 @@ struct cfg80211_ops {
        int     (*set_txq_params)(struct wiphy *wiphy,
                                  struct ieee80211_txq_params *params);
 
-       int     (*set_channel)(struct wiphy *wiphy,
+       int     (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
                               struct ieee80211_channel *chan,
                               enum nl80211_channel_type channel_type);
 
@@ -1152,6 +1172,10 @@ struct cfg80211_ops {
 
        int     (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
                                  bool enabled, int timeout);
+
+       int     (*set_cqm_rssi_config)(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      s32 rssi_thold, u32 rssi_hyst);
 };
 
 /*
@@ -1441,6 +1465,8 @@ struct cfg80211_cached_keys;
  * @list: (private) Used to collect the interfaces
  * @netdev: (private) Used to reference back to the netdev
  * @current_bss: (private) Used by the internal configuration code
+ * @channel: (private) Used by the internal configuration code to track
+ *     user-set AP, monitor and WDS channels for wireless extensions
  * @bssid: (private) Used by the internal configuration code
  * @ssid: (private) Used by the internal configuration code
  * @ssid_len: (private) Used by the internal configuration code
@@ -1487,6 +1513,7 @@ struct wireless_dev {
        struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES];
        struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
        struct cfg80211_internal_bss *current_bss; /* associated / joined */
+       struct ieee80211_channel *channel;
 
        bool ps;
        int ps_timeout;
@@ -1627,7 +1654,7 @@ struct ieee80211_radiotap_iterator {
        const struct ieee80211_radiotap_namespace *current_namespace;
 
        unsigned char *_arg, *_next_ns_data;
-       uint32_t *_next_bitmap;
+       __le32 *_next_bitmap;
 
        unsigned char *this_arg;
        int this_arg_index;
@@ -2337,4 +2364,18 @@ bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
 void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
                               const u8 *buf, size_t len, bool ack, gfp_t gfp);
 
+
+/**
+ * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
+ * @dev: network device
+ * @rssi_event: the triggered RSSI event
+ * @gfp: context flags
+ *
+ * This function is called when a configured connection quality monitoring
+ * rssi threshold reached event occurs.
+ */
+void cfg80211_cqm_rssi_notify(struct net_device *dev,
+                             enum nl80211_cqm_rssi_threshold_event rssi_event,
+                             gfp_t gfp);
+
 #endif /* __NET_CFG80211_H */
index 52da6c3dd50df6a1dd016546f679b5991bf006f6..bbcde3238e580b1d1a906c6fbc31afad0d518759 100644 (file)
@@ -50,10 +50,6 @@ struct dn_fib_info {
        __le16                  fib_prefsrc;
        __u32                   fib_priority;
        __u32                   fib_metrics[RTAX_MAX];
-#define dn_fib_mtu  fib_metrics[RTAX_MTU-1]
-#define dn_fib_window fib_metrics[RTAX_WINDOW-1]
-#define dn_fib_rtt fib_metrics[RTAX_RTT-1]
-#define dn_fib_advmss fib_metrics[RTAX_ADVMSS-1]
        int                     fib_nhs;
        int                     fib_power;
        struct dn_fib_nh        fib_nh[0];
index ce078cda6b748a61eadfcf16315b84e8893aeded..612069beda733676b1e106ce8f24ee19e66b8910 100644 (file)
@@ -168,6 +168,12 @@ static inline void dst_use(struct dst_entry *dst, unsigned long time)
        dst->lastuse = time;
 }
 
+static inline void dst_use_noref(struct dst_entry *dst, unsigned long time)
+{
+       dst->__use++;
+       dst->lastuse = time;
+}
+
 static inline
 struct dst_entry * dst_clone(struct dst_entry * dst)
 {
@@ -177,11 +183,67 @@ struct dst_entry * dst_clone(struct dst_entry * dst)
 }
 
 extern void dst_release(struct dst_entry *dst);
+
+static inline void refdst_drop(unsigned long refdst)
+{
+       if (!(refdst & SKB_DST_NOREF))
+               dst_release((struct dst_entry *)(refdst & SKB_DST_PTRMASK));
+}
+
+/**
+ * skb_dst_drop - drops skb dst
+ * @skb: buffer
+ *
+ * Drops dst reference count if a reference was taken.
+ */
 static inline void skb_dst_drop(struct sk_buff *skb)
 {
-       if (skb->_skb_dst)
-               dst_release(skb_dst(skb));
-       skb->_skb_dst = 0UL;
+       if (skb->_skb_refdst) {
+               refdst_drop(skb->_skb_refdst);
+               skb->_skb_refdst = 0UL;
+       }
+}
+
+static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb)
+{
+       nskb->_skb_refdst = oskb->_skb_refdst;
+       if (!(nskb->_skb_refdst & SKB_DST_NOREF))
+               dst_clone(skb_dst(nskb));
+}
+
+/**
+ * skb_dst_force - makes sure skb dst is refcounted
+ * @skb: buffer
+ *
+ * If dst is not yet refcounted, let's do it
+ */
+static inline void skb_dst_force(struct sk_buff *skb)
+{
+       if (skb_dst_is_noref(skb)) {
+               WARN_ON(!rcu_read_lock_held());
+               skb->_skb_refdst &= ~SKB_DST_NOREF;
+               dst_clone(skb_dst(skb));
+       }
+}
+
+
+/**
+ *     skb_tunnel_rx - prepare skb for rx reinsert
+ *     @skb: buffer
+ *     @dev: tunnel device
+ *
+ *     After decapsulation, packet is going to re-enter (netif_rx()) our stack,
+ *     so make some cleanups, and perform accounting.
+ */
+static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev)
+{
+       skb->dev = dev;
+       /* TODO : stats should be SMP safe */
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+       skb->rxhash = 0;
+       skb_dst_drop(skb);
+       nf_reset(skb);
 }
 
 /* Children define the path of the packet through the
@@ -225,21 +287,6 @@ static inline void dst_confirm(struct dst_entry *dst)
                neigh_confirm(dst->neighbour);
 }
 
-static inline void dst_negative_advice(struct dst_entry **dst_p,
-                                      struct sock *sk)
-{
-       struct dst_entry * dst = *dst_p;
-       if (dst && dst->ops->negative_advice) {
-               *dst_p = dst->ops->negative_advice(dst);
-
-               if (dst != *dst_p) {
-                       extern void sk_reset_txq(struct sock *sk);
-
-                       sk_reset_txq(sk);
-               }
-       }
-}
-
 static inline void dst_link_failure(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
index c49086d2bc7da380c9ef18873e88bc6a709ce9e6..e8923bc20f9ff8f28b586af3b795bcf6230df92f 100644 (file)
@@ -104,7 +104,7 @@ static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
        return frh->table;
 }
 
-extern struct fib_rules_ops *fib_rules_register(struct fib_rules_ops *, struct net *);
+extern struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *, struct net *);
 extern void fib_rules_unregister(struct fib_rules_ops *);
 extern void                     fib_rules_cleanup_ops(struct fib_rules_ops *);
 
@@ -114,4 +114,5 @@ extern int                  fib_rules_lookup(struct fib_rules_ops *,
 extern int                     fib_default_rule_add(struct fib_rules_ops *,
                                                     u32 pref, u32 table,
                                                     u32 flags);
+extern u32                     fib_default_rule_pref(struct fib_rules_ops *ops);
 #endif
index 809970b7dfee71670ac9a8c1bf753923a96a264e..bb08692a20b08841ead94acce78c9ead82293d94 100644 (file)
@@ -86,11 +86,26 @@ struct flowi {
 
 struct net;
 struct sock;
-typedef int (*flow_resolve_t)(struct net *net, struct flowi *key, u16 family,
-                             u8 dir, void **objp, atomic_t **obj_refp);
+struct flow_cache_ops;
+
+struct flow_cache_object {
+       const struct flow_cache_ops *ops;
+};
+
+struct flow_cache_ops {
+       struct flow_cache_object *(*get)(struct flow_cache_object *);
+       int (*check)(struct flow_cache_object *);
+       void (*delete)(struct flow_cache_object *);
+};
+
+typedef struct flow_cache_object *(*flow_resolve_t)(
+               struct net *net, struct flowi *key, u16 family,
+               u8 dir, struct flow_cache_object *oldobj, void *ctx);
+
+extern struct flow_cache_object *flow_cache_lookup(
+               struct net *net, struct flowi *key, u16 family,
+               u8 dir, flow_resolve_t resolver, void *ctx);
 
-extern void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family,
-                              u8 dir, flow_resolve_t resolver);
 extern void flow_cache_flush(void);
 extern atomic_t flow_cache_genid;
 
index 15b3dfe9fce8334611ba4549e3d32353585e036d..6e991e0d0d6fef8763a1d58693c373a7105c9ddc 100644 (file)
@@ -48,15 +48,4 @@ extern void  icmp_out_count(struct net *net, unsigned char type);
 /* Move into dst.h ? */
 extern int     xrlim_allow(struct dst_entry *dst, int timeout);
 
-struct raw_sock {
-       /* inet_sock has to be the first member */
-       struct inet_sock   inet;
-       struct icmp_filter filter;
-};
-
-static inline struct raw_sock *raw_sk(const struct sock *sk)
-{
-       return (struct raw_sock *)sk;
-}
-
 #endif /* _ICMP_H */
index 545d8b059bef227b5e97cb8060982ee7363e8a91..f95ff8d9aa474a42f0810f92e830886e1a5fb160 100644 (file)
 
 #ifdef __KERNEL__
 
+enum {
+       INET6_IFADDR_STATE_DAD,
+       INET6_IFADDR_STATE_POSTDAD,
+       INET6_IFADDR_STATE_UP,
+       INET6_IFADDR_STATE_DEAD,
+};
+
 struct inet6_ifaddr {
        struct in6_addr         addr;
        __u32                   prefix_len;
@@ -40,6 +47,9 @@ struct inet6_ifaddr {
        __u32                   prefered_lft;
        atomic_t                refcnt;
        spinlock_t              lock;
+       spinlock_t              state_lock;
+
+       int                     state;
 
        __u8                    probes;
        __u8                    flags;
@@ -54,16 +64,15 @@ struct inet6_ifaddr {
        struct inet6_dev        *idev;
        struct rt6_info         *rt;
 
-       struct inet6_ifaddr     *lst_next;      /* next addr in addr_lst */
-       struct inet6_ifaddr     *if_next;       /* next addr in inet6_dev */
+       struct hlist_node       addr_lst;
+       struct list_head        if_list;
 
 #ifdef CONFIG_IPV6_PRIVACY
-       struct inet6_ifaddr     *tmp_next;      /* next addr in tempaddr_lst */
+       struct list_head        tmp_list;
        struct inet6_ifaddr     *ifpub;
        int                     regen_count;
 #endif
-
-       int                     dead;
+       struct rcu_head         rcu;
 };
 
 struct ip6_sf_socklist {
@@ -151,9 +160,9 @@ struct ipv6_devstat {
 };
 
 struct inet6_dev {
-       struct net_device               *dev;
+       struct net_device       *dev;
 
-       struct inet6_ifaddr     *addr_list;
+       struct list_head        addr_list;
 
        struct ifmcaddr6        *mc_list;
        struct ifmcaddr6        *mc_tomb;
@@ -175,7 +184,7 @@ struct inet6_dev {
 #ifdef CONFIG_IPV6_PRIVACY
        u8                      rndid[8];
        struct timer_list       regen_timer;
-       struct inet6_ifaddr     *tempaddr_list;
+       struct list_head        tempaddr_list;
 #endif
 
        struct neigh_parms      *nd_parms;
index f13ddc2543b1fcb07a10aee710a7e43b0f894d17..aae08f6866331eb5de5454e4724911aefd067fd0 100644 (file)
@@ -38,5 +38,5 @@ extern void inet6_csk_reqsk_queue_hash_add(struct sock *sk,
 
 extern void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr);
 
-extern int inet6_csk_xmit(struct sk_buff *skb, int ipfragok);
+extern int inet6_csk_xmit(struct sk_buff *skb);
 #endif /* _INET6_CONNECTION_SOCK_H */
index 696d6e4ce68a0e72b857b1d569c1bb98c5ceeca0..b6d3b55da19b49e71d5cc7e0206090240cca0346 100644 (file)
@@ -36,9 +36,8 @@ struct tcp_congestion_ops;
  * (i.e. things that depend on the address family)
  */
 struct inet_connection_sock_af_ops {
-       int         (*queue_xmit)(struct sk_buff *skb, int ipfragok);
-       void        (*send_check)(struct sock *sk, int len,
-                                 struct sk_buff *skb);
+       int         (*queue_xmit)(struct sk_buff *skb);
+       void        (*send_check)(struct sock *sk, struct sk_buff *skb);
        int         (*rebuild_header)(struct sock *sk);
        int         (*conn_request)(struct sock *sk, struct sk_buff *skb);
        struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
index 83fd34437cf1f3eb7509a35856573c3ede5b171c..1653de515ceec95c8e9017edfdda532d4a851547 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/jhash.h>
+#include <linux/netdevice.h>
 
 #include <net/flow.h>
 #include <net/sock.h>
index 79f67eae8a7e212f30e5b89e09ede8b4d21a245b..a066fdd50da6c5041a12bb4983eeb4b9c8b9eee1 100644 (file)
@@ -224,7 +224,9 @@ static inline
 struct net *twsk_net(const struct inet_timewait_sock *twsk)
 {
 #ifdef CONFIG_NET_NS
-       return rcu_dereference(twsk->tw_net);
+       return rcu_dereference_raw(twsk->tw_net); /* protected by locking, */
+                                                 /* reference counting, */
+                                                 /* initialization, or RCU. */
 #else
        return &init_net;
 #endif
index 503994a38ed11a2cbaa97f2ef2e15417b08390ce..63548f0a44b17e933fa37cbe8283fdb93bbb179a 100644 (file)
@@ -101,7 +101,7 @@ extern int          ip_do_nat(struct sk_buff *skb);
 extern void            ip_send_check(struct iphdr *ip);
 extern int             __ip_local_out(struct sk_buff *skb);
 extern int             ip_local_out(struct sk_buff *skb);
-extern int             ip_queue_xmit(struct sk_buff *skb, int ipfragok);
+extern int             ip_queue_xmit(struct sk_buff *skb);
 extern void            ip_init(void);
 extern int             ip_append_data(struct sock *sk,
                                       int getfrag(void *from, char *to, int offset, int len,
@@ -184,6 +184,12 @@ extern struct local_ports {
 } sysctl_local_ports;
 extern void inet_get_local_port_range(int *low, int *high);
 
+extern unsigned long *sysctl_local_reserved_ports;
+static inline int inet_is_reserved_local_port(int port)
+{
+       return test_bit(port, sysctl_local_reserved_ports);
+}
+
 extern int sysctl_ip_default_ttl;
 extern int sysctl_ip_nonlocal_bind;
 
@@ -393,6 +399,7 @@ extern int ip_options_rcv_srr(struct sk_buff *skb);
  *     Functions provided by ip_sockglue.c
  */
 
+extern int     ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
 extern void    ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
 extern int     ip_cmsg_send(struct net *net,
                             struct msghdr *msg, struct ipcm_cookie *ipc);
index 86f46c49e3183da8484d436a8aa2cf7dbe2418e7..4b1dc1161c37ca162eb3d69e82737192ebf8d220 100644 (file)
@@ -88,34 +88,37 @@ struct rt6_info {
                struct dst_entry        dst;
        } u;
 
-       struct inet6_dev                *rt6i_idev;
-
 #define rt6i_dev                       u.dst.dev
 #define rt6i_nexthop                   u.dst.neighbour
 #define rt6i_expires                   u.dst.expires
 
+       /*
+        * Tail elements of dst_entry (__refcnt etc.)
+        * and these elements (rarely used in hot path) are in
+        * the same cache line.
+        */
+       struct fib6_table               *rt6i_table;
        struct fib6_node                *rt6i_node;
 
        struct in6_addr                 rt6i_gateway;
-       
-       u32                             rt6i_flags;
-       u32                             rt6i_metric;
-       atomic_t                        rt6i_ref;
 
-       /* more non-fragment space at head required */
-       unsigned short                  rt6i_nfheader_len;
-
-       u8                              rt6i_protocol;
+       atomic_t                        rt6i_ref;
 
-       struct fib6_table               *rt6i_table;
+       /* These are in a separate cache line. */
+       struct rt6key                   rt6i_dst ____cacheline_aligned_in_smp;
+       u32                             rt6i_flags;
+       struct rt6key                   rt6i_src;
+       u32                             rt6i_metric;
 
-       struct rt6key                   rt6i_dst;
+       struct inet6_dev                *rt6i_idev;
 
 #ifdef CONFIG_XFRM
        u32                             rt6i_flow_cache_genid;
 #endif
+       /* more non-fragment space at head required */
+       unsigned short                  rt6i_nfheader_len;
 
-       struct rt6key                   rt6i_src;
+       u8                              rt6i_protocol;
 };
 
 static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
index 68f67836e1464599c64d3743649b25b82b2688f6..278312c95f9600bd863fa0dc76c52a7c048a9d19 100644 (file)
@@ -152,9 +152,9 @@ static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst,
 static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
                                 struct in6_addr *daddr, struct in6_addr *saddr)
 {
-       write_lock(&sk->sk_dst_lock);
+       spin_lock(&sk->sk_dst_lock);
        __ip6_dst_store(sk, dst, daddr, saddr);
-       write_unlock(&sk->sk_dst_lock);
+       spin_unlock(&sk->sk_dst_lock);
 }
 
 static inline int ipv6_unicast_destination(struct sk_buff *skb)
index e72fb10ce57348e82fcfd0bb36a1e641bde56cc5..eba5cc00325aff321d81366b3e47c2895c265a9c 100644 (file)
@@ -422,7 +422,7 @@ static inline int __ipv6_addr_diff(const void *token1, const void *token2, int a
        for (i = 0; i < addrlen; i++) {
                __be32 xb = a1[i] ^ a2[i];
                if (xb)
-                       return i * 32 + 32 - fls(ntohl(xb));
+                       return i * 32 + 31 - __fls(ntohl(xb));
        }
 
        /*
@@ -482,8 +482,7 @@ extern int                  ip6_rcv_finish(struct sk_buff *skb);
 extern int                     ip6_xmit(struct sock *sk,
                                         struct sk_buff *skb,
                                         struct flowi *fl,
-                                        struct ipv6_txoptions *opt,
-                                        int ipfragok);
+                                        struct ipv6_txoptions *opt);
 
 extern int                     ip6_nd_hdr(struct sock *sk,
                                           struct sk_buff *skb,
@@ -504,7 +503,8 @@ extern int                  ip6_append_data(struct sock *sk,
                                                struct ipv6_txoptions *opt,
                                                struct flowi *fl,
                                                struct rt6_info *rt,
-                                               unsigned int flags);
+                                               unsigned int flags,
+                                               int dontfrag);
 
 extern int                     ip6_push_pending_frames(struct sock *sk);
 
@@ -578,9 +578,11 @@ extern int                 ip6_datagram_connect(struct sock *sk,
                                                     struct sockaddr *addr, int addr_len);
 
 extern int                     ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len);
+extern int                     ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len);
 extern void                    ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port,
                                                u32 info, u8 *payload);
 extern void                    ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info);
+extern void                    ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu);
 
 extern int inet6_release(struct socket *sock);
 extern int inet6_bind(struct socket *sock, struct sockaddr *uaddr, 
index b2b98f3fa2650e2411a9cf15272836ab93126d3b..3afdb21cc31d263e8e53a7de7e9ca46cde4b4b6f 100644 (file)
@@ -323,7 +323,7 @@ typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
 struct iw_handler_def {
 
        /* Array of handlers for standard ioctls
-        * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWCOMMIT]
+        * We will call dev->wireless_handlers->standard[ioctl - SIOCIWFIRST]
         */
        const iw_handler *      standard;
        /* Number of handlers defined (more precisely, index of the
index 45d7d44d7cbe401ff92050f31531c2526a774b30..5be900d19660543adfbd040bc9abfe42f1e78fdb 100644 (file)
@@ -144,6 +144,8 @@ struct ieee80211_low_level_stats {
  *     new beacon (beaconing modes)
  * @BSS_CHANGED_BEACON_ENABLED: Beaconing should be
  *     enabled/disabled (beaconing modes)
+ * @BSS_CHANGED_CQM: Connection quality monitor config changed
+ * @BSS_CHANGED_IBSS: IBSS join status changed
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -156,6 +158,10 @@ enum ieee80211_bss_change {
        BSS_CHANGED_BSSID               = 1<<7,
        BSS_CHANGED_BEACON              = 1<<8,
        BSS_CHANGED_BEACON_ENABLED      = 1<<9,
+       BSS_CHANGED_CQM                 = 1<<10,
+       BSS_CHANGED_IBSS                = 1<<11,
+
+       /* when adding here, make sure to change ieee80211_reconfig */
 };
 
 /**
@@ -165,6 +171,8 @@ enum ieee80211_bss_change {
  * to that BSS) that can change during the lifetime of the BSS.
  *
  * @assoc: association status
+ * @ibss_joined: indicates whether this station is part of an IBSS
+ *     or not
  * @aid: association ID number, valid only when @assoc is true
  * @use_cts_prot: use CTS protection
  * @use_short_preamble: use 802.11b short preamble;
@@ -183,13 +191,19 @@ enum ieee80211_bss_change {
  *     the current band.
  * @bssid: The BSSID for this BSS
  * @enable_beacon: whether beaconing should be enabled or not
+ * @channel_type: Channel type for this BSS -- the hardware might be
+ *     configured for HT40+ while this BSS only uses no-HT, for
+ *     example.
  * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info).
  *     This field is only valid when the channel type is one of the HT types.
+ * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
+ *     implies disabled
+ * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
  */
 struct ieee80211_bss_conf {
        const u8 *bssid;
        /* association related data */
-       bool assoc;
+       bool assoc, ibss_joined;
        u16 aid;
        /* erp related data */
        bool use_cts_prot;
@@ -202,6 +216,9 @@ struct ieee80211_bss_conf {
        u64 timestamp;
        u32 basic_rates;
        u16 ht_operation_mode;
+       s32 cqm_rssi_thold;
+       u32 cqm_rssi_hyst;
+       enum nl80211_channel_type channel_type;
 };
 
 /**
@@ -267,6 +284,9 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_INTFL_NL80211_FRAME_TX: Frame was requested through nl80211
  *     MLME command (internal to mac80211 to figure out whether to send TX
  *     status to user space)
+ * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame
+ * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this
+ *     frame and selects the maximum number of streams that it can use.
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
@@ -290,6 +310,9 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_INTFL_RETRANSMISSION       = BIT(19),
        IEEE80211_TX_INTFL_HAS_RADIOTAP         = BIT(20),
        IEEE80211_TX_INTFL_NL80211_FRAME_TX     = BIT(21),
+       IEEE80211_TX_CTL_LDPC                   = BIT(22),
+       IEEE80211_TX_CTL_STBC                   = BIT(23) | BIT(24),
+#define IEEE80211_TX_CTL_STBC_SHIFT            23
 };
 
 /**
@@ -388,11 +411,11 @@ struct ieee80211_tx_rate {
  * @status: union for status data
  * @driver_data: array of driver_data pointers
  * @ampdu_ack_len: number of acked aggregated frames.
- *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ *     relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ampdu_ack_map: block ack bit map for the aggregation.
- *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ *     relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ampdu_len: number of aggregated frames.
- *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
+ *     relevant only if IEEE80211_TX_STAT_AMPDU was set.
  * @ack_signal: signal strength of the ACK frame
  */
 struct ieee80211_tx_info {
@@ -543,7 +566,6 @@ enum mac80211_rx_flags {
  * @signal: signal strength when receiving this frame, either in dBm, in dB or
  *     unspecified depending on the hardware capabilities flags
  *     @IEEE80211_HW_SIGNAL_*
- * @noise: noise when receiving this frame, in dBm.
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates or MCS index if
  *     HT rates are use (RX_FLAG_HT)
@@ -554,7 +576,6 @@ struct ieee80211_rx_status {
        enum ieee80211_band band;
        int freq;
        int signal;
-       int noise;
        int antenna;
        int rate_idx;
        int flag;
@@ -580,11 +601,15 @@ struct ieee80211_rx_status {
  *     may turn the device off as much as possible. Typically, this flag will
  *     be set when an interface is set UP but not associated or scanning, but
  *     it can also be unset in that case when monitor interfaces are active.
+ * @IEEE80211_CONF_QOS: Enable 802.11e QoS also know as WMM (Wireless
+ *      Multimedia). On some drivers (iwlwifi is one of know) we have
+ *      to enable/disable QoS explicitly.
  */
 enum ieee80211_conf_flags {
        IEEE80211_CONF_MONITOR          = (1<<0),
        IEEE80211_CONF_PS               = (1<<1),
        IEEE80211_CONF_IDLE             = (1<<2),
+       IEEE80211_CONF_QOS              = (1<<3),
 };
 
 
@@ -599,6 +624,7 @@ enum ieee80211_conf_flags {
  * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed
  * @IEEE80211_CONF_CHANGE_IDLE: Idle flag changed
  * @IEEE80211_CONF_CHANGE_SMPS: Spatial multiplexing powersave mode changed
+ * @IEEE80211_CONF_CHANGE_QOS: Quality of service was enabled or disabled
  */
 enum ieee80211_conf_changed {
        IEEE80211_CONF_CHANGE_SMPS              = BIT(1),
@@ -609,6 +635,7 @@ enum ieee80211_conf_changed {
        IEEE80211_CONF_CHANGE_CHANNEL           = BIT(6),
        IEEE80211_CONF_CHANGE_RETRY_LIMITS      = BIT(7),
        IEEE80211_CONF_CHANGE_IDLE              = BIT(8),
+       IEEE80211_CONF_CHANGE_QOS               = BIT(9),
 };
 
 /**
@@ -649,6 +676,9 @@ enum ieee80211_smps_mode {
  * @dynamic_ps_timeout: The dynamic powersave timeout (in ms), see the
  *     powersave documentation below. This variable is valid only when
  *     the CONF_PS flag is set.
+ * @dynamic_ps_forced_timeout: The dynamic powersave timeout (in ms) configured
+ *     by cfg80211 (essentially, wext) If set, this value overrules the value
+ *     chosen by mac80211 based on ps qos network latency.
  *
  * @power_level: requested transmit power (in dBm)
  *
@@ -668,7 +698,7 @@ enum ieee80211_smps_mode {
  */
 struct ieee80211_conf {
        u32 flags;
-       int power_level, dynamic_ps_timeout;
+       int power_level, dynamic_ps_timeout, dynamic_ps_forced_timeout;
        int max_sleep_period;
 
        u16 listen_interval;
@@ -681,6 +711,28 @@ struct ieee80211_conf {
        enum ieee80211_smps_mode smps_mode;
 };
 
+/**
+ * struct ieee80211_channel_switch - holds the channel switch data
+ *
+ * The information provided in this structure is required for channel switch
+ * operation.
+ *
+ * @timestamp: value in microseconds of the 64-bit Time Synchronization
+ *     Function (TSF) timer when the frame containing the channel switch
+ *     announcement was received. This is simply the rx.mactime parameter
+ *     the driver passed into mac80211.
+ * @block_tx: Indicates whether transmission must be blocked before the
+ *     scheduled channel switch, as indicated by the AP.
+ * @channel: the new channel to switch to
+ * @count: the number of TBTT's until the channel switch event
+ */
+struct ieee80211_channel_switch {
+       u64 timestamp;
+       bool block_tx;
+       struct ieee80211_channel *channel;
+       u8 count;
+};
+
 /**
  * struct ieee80211_vif - per-interface data
  *
@@ -779,6 +831,7 @@ struct ieee80211_key_conf {
        u8 iv_len;
        u8 hw_key_idx;
        u8 flags;
+       u8 *ap_addr;
        s8 keyidx;
        u8 keylen;
        u8 key[0];
@@ -907,10 +960,6 @@ enum ieee80211_tkip_key_type {
  *     one milliwatt. This is the preferred method since it is standardized
  *     between different devices. @max_signal does not need to be set.
  *
- * @IEEE80211_HW_NOISE_DBM:
- *     Hardware can provide noise (radio interference) values in units dBm,
- *      decibel difference from one milliwatt.
- *
  * @IEEE80211_HW_SPECTRUM_MGMT:
  *     Hardware supports spectrum management defined in 802.11h
  *     Measurement, Channel Switch, Quieting, TPC
@@ -954,6 +1003,17 @@ enum ieee80211_tkip_key_type {
  *     Hardware can provide ack status reports of Tx frames to
  *     the stack.
  *
+ * @IEEE80211_HW_CONNECTION_MONITOR:
+ *      The hardware performs its own connection monitoring, including
+ *      periodic keep-alives to the AP and probing the AP on beacon loss.
+ *      When this flag is set, signaling beacon-loss will cause an immediate
+ *      change to disassociated state.
+ *
+ * @IEEE80211_HW_SUPPORTS_CQM_RSSI:
+ *     Hardware can do connection quality monitoring - i.e. it can monitor
+ *     connection quality related parameters, such as the RSSI level and
+ *     provide notifications if configured trigger levels are reached.
+ *
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
@@ -963,7 +1023,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE      = 1<<4,
        IEEE80211_HW_SIGNAL_UNSPEC                      = 1<<5,
        IEEE80211_HW_SIGNAL_DBM                         = 1<<6,
-       IEEE80211_HW_NOISE_DBM                          = 1<<7,
+       /* use this hole */
        IEEE80211_HW_SPECTRUM_MGMT                      = 1<<8,
        IEEE80211_HW_AMPDU_AGGREGATION                  = 1<<9,
        IEEE80211_HW_SUPPORTS_PS                        = 1<<10,
@@ -975,6 +1035,8 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS              = 1<<16,
        IEEE80211_HW_SUPPORTS_UAPSD                     = 1<<17,
        IEEE80211_HW_REPORTS_TX_ACK_STATUS              = 1<<18,
+       IEEE80211_HW_CONNECTION_MONITOR                 = 1<<19,
+       IEEE80211_HW_SUPPORTS_CQM_RSSI                  = 1<<20,
 };
 
 /**
@@ -1591,6 +1653,11 @@ enum ieee80211_ampdu_mlme_action {
  * @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.
+ *
+ * @channel_switch: Drivers that need (or want) to offload the channel
+ *     switch operation for CSAs received from the AP may implement this
+ *     callback. They must then call ieee80211_chswitch_done() to indicate
+ *     completion of the channel switch.
  */
 struct ieee80211_ops {
        int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1606,7 +1673,7 @@ struct ieee80211_ops {
                                 struct ieee80211_bss_conf *info,
                                 u32 changed);
        u64 (*prepare_multicast)(struct ieee80211_hw *hw,
-                                int mc_count, struct dev_addr_list *mc_list);
+                                struct netdev_hw_addr_list *mc_list);
        void (*configure_filter)(struct ieee80211_hw *hw,
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
@@ -1621,7 +1688,7 @@ struct ieee80211_ops {
                                struct ieee80211_key_conf *conf,
                                struct ieee80211_sta *sta,
                                u32 iv32, u16 *phase1key);
-       int (*hw_scan)(struct ieee80211_hw *hw,
+       int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct cfg80211_scan_request *req);
        void (*sw_scan_start)(struct ieee80211_hw *hw);
        void (*sw_scan_complete)(struct ieee80211_hw *hw);
@@ -1646,13 +1713,16 @@ struct ieee80211_ops {
                            struct ieee80211_vif *vif,
                            enum ieee80211_ampdu_mlme_action action,
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn);
-
+       int (*get_survey)(struct ieee80211_hw *hw, int idx,
+               struct survey_info *survey);
        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);
+       void (*channel_switch)(struct ieee80211_hw *hw,
+                              struct ieee80211_channel_switch *ch_switch);
 };
 
 /**
@@ -1802,7 +1872,10 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
  * ieee80211_rx - receive frame
  *
  * Use this function to hand received frames to mac80211. The receive
- * buffer in @skb must start with an IEEE 802.11 header.
+ * buffer in @skb must start with an IEEE 802.11 header. In case of a
+ * paged @skb is used, the driver is recommended to put the ieee80211
+ * header of the frame on the linear part of the @skb to avoid memory
+ * allocation and/or memcpy by the stack.
  *
  * This function may not be called in IRQ context. Calls to this function
  * for a single hardware must be synchronized against each other. Calls to
@@ -2364,12 +2437,52 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  *
- * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and
- * IEEE80211_CONF_PS is set, the driver needs to inform whenever the
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING and
+ * %IEEE80211_CONF_PS is set, the driver needs to inform whenever the
  * hardware is not receiving beacons with this function.
  */
 void ieee80211_beacon_loss(struct ieee80211_vif *vif);
 
+/**
+ * ieee80211_connection_loss - inform hardware has lost connection to the AP
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * When beacon filtering is enabled with %IEEE80211_HW_BEACON_FILTERING, and
+ * %IEEE80211_CONF_PS and %IEEE80211_HW_CONNECTION_MONITOR are set, the driver
+ * needs to inform if the connection to the AP has been lost.
+ *
+ * This function will cause immediate change to disassociated state,
+ * without connection recovery attempts.
+ */
+void ieee80211_connection_loss(struct ieee80211_vif *vif);
+
+/**
+ * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
+ *     rssi threshold triggered
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @rssi_event: the RSSI trigger event type
+ * @gfp: context flags
+ *
+ * When the %IEEE80211_HW_SUPPORTS_CQM_RSSI is set, and a connection quality
+ * monitoring is configured with an rssi threshold, the driver will inform
+ * whenever the rssi level reaches the threshold.
+ */
+void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
+                              enum nl80211_cqm_rssi_threshold_event rssi_event,
+                              gfp_t gfp);
+
+/**
+ * ieee80211_chswitch_done - Complete channel switch process
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @success: make the channel switch successful or not
+ *
+ * Complete the channel switch post-process: set the new operational channel
+ * and wake up the suspended queues.
+ */
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success);
+
 /* Rate control API */
 
 /**
diff --git a/include/net/mld.h b/include/net/mld.h
new file mode 100644 (file)
index 0000000..467143c
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef LINUX_MLD_H
+#define LINUX_MLD_H
+
+#include <linux/in6.h>
+#include <linux/icmpv6.h>
+
+/* MLDv1 Query/Report/Done */
+struct mld_msg {
+       struct icmp6hdr         mld_hdr;
+       struct in6_addr         mld_mca;
+};
+
+#define mld_type               mld_hdr.icmp6_type
+#define mld_code               mld_hdr.icmp6_code
+#define mld_cksum              mld_hdr.icmp6_cksum
+#define mld_maxdelay           mld_hdr.icmp6_maxdelay
+#define mld_reserved           mld_hdr.icmp6_dataun.un_data16[1]
+
+/* Multicast Listener Discovery version 2 headers */
+/* MLDv2 Report */
+struct mld2_grec {
+       __u8            grec_type;
+       __u8            grec_auxwords;
+       __be16          grec_nsrcs;
+       struct in6_addr grec_mca;
+       struct in6_addr grec_src[0];
+};
+
+struct mld2_report {
+       struct icmp6hdr         mld2r_hdr;
+       struct mld2_grec        mld2r_grec[0];
+};
+
+#define mld2r_type             mld2r_hdr.icmp6_type
+#define mld2r_resv1            mld2r_hdr.icmp6_code
+#define mld2r_cksum            mld2r_hdr.icmp6_cksum
+#define mld2r_resv2            mld2r_hdr.icmp6_dataun.un_data16[0]
+#define mld2r_ngrec            mld2r_hdr.icmp6_dataun.un_data16[1]
+
+/* MLDv2 Query */
+struct mld2_query {
+       struct icmp6hdr         mld2q_hdr;
+       struct in6_addr         mld2q_mca;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8                    mld2q_qrv:3,
+                               mld2q_suppress:1,
+                               mld2q_resv2:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       __u8                    mld2q_resv2:4,
+                               mld2q_suppress:1,
+                               mld2q_qrv:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+       __u8                    mld2q_qqic;
+       __be16                  mld2q_nsrcs;
+       struct in6_addr         mld2q_srcs[0];
+};
+
+#define mld2q_type             mld2q_hdr.icmp6_type
+#define mld2q_code             mld2q_hdr.icmp6_code
+#define mld2q_cksum            mld2q_hdr.icmp6_cksum
+#define mld2q_mrc              mld2q_hdr.icmp6_maxdelay
+#define mld2q_resv1            mld2q_hdr.icmp6_dataun.un_data16[1]
+
+/* Max Response Code */
+#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
+#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
+       ((value) < (thresh) ? (value) : \
+       ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
+       (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
+
+#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
+
+#endif
index da1d58be31b7a4a3e9d8c43e2d11ef62f7b0be84..eb21340a573b4906d267a18bf69bbf37bdebb8b4 100644 (file)
@@ -299,6 +299,20 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
        return 0;
 }
 
+#ifdef CONFIG_BRIDGE_NETFILTER
+static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
+{
+       unsigned seq, hh_alen;
+
+       do {
+               seq = read_seqbegin(&hh->hh_lock);
+               hh_alen = HH_DATA_ALIGN(ETH_HLEN);
+               memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN);
+       } while (read_seqretry(&hh->hh_lock, seq));
+       return 0;
+}
+#endif
+
 static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
 {
        unsigned seq;
index ff4982ab84b60ecfbcc764d460a15f7bbb87a4da..81a31c0db3e71d96018b76191de64940fced1869 100644 (file)
  * The rules are simple:
  * 1. set pernet_operations->id.  After register_pernet_device you
  *    will have the id of your private pointer.
- * 2. Either set pernet_operations->size (to have the code allocate and
- *    free a private structure pointed to from struct net ) or 
- *    call net_assign_generic() to put the private data on the struct
- *    net (most preferably this should be done in the ->init callback
- *    of the ops registered);
+ * 2. set pernet_operations->size to have the code allocate and free
+ *    a private structure pointed to from struct net.
  * 3. do not change this pointer while the net is alive;
  * 4. do not try to have any private reference on the net_generic object.
  *
@@ -46,6 +43,4 @@ static inline void *net_generic(struct net *net, int id)
 
        return ptr;
 }
-
-extern int net_assign_generic(struct net *net, int id, void *data);
 #endif
index 2764994c9136a83b0e7194023e15ed21a6e87323..d68c3f12177484f7150cec7a8dd0ae7e91538d7d 100644 (file)
@@ -55,19 +55,14 @@ struct netns_ipv4 {
        int sysctl_rt_cache_rebuild_count;
        int current_rt_cache_rebuild_count;
 
-       struct timer_list rt_secret_timer;
        atomic_t rt_genid;
 
 #ifdef CONFIG_IP_MROUTE
-       struct sock             *mroute_sk;
-       struct mfc_cache        **mfc_cache_array;
-       struct vif_device       *vif_table;
-       int                     maxvif;
-       atomic_t                cache_resolve_queue_len;
-       int                     mroute_do_assert;
-       int                     mroute_do_pim;
-#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
-       int                     mroute_reg_vif_num;
+#ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES
+       struct mr_table         *mrt;
+#else
+       struct list_head        mr_tables;
+       struct fib_rules_ops    *mr_rules_ops;
 #endif
 #endif
 };
index 1f11ebc221517058a10c3eae7a04918e03e2fefd..81abfcb2eb4e7d8394dbf9ec5da60a361cbb34c3 100644 (file)
@@ -59,15 +59,11 @@ struct netns_ipv6 {
        struct sock             *tcp_sk;
        struct sock             *igmp_sk;
 #ifdef CONFIG_IPV6_MROUTE
-       struct sock             *mroute6_sk;
-       struct mfc6_cache       **mfc6_cache_array;
-       struct mif_device       *vif6_table;
-       int                     maxvif;
-       atomic_t                cache_resolve_queue_len;
-       int                     mroute_do_assert;
-       int                     mroute_do_pim;
-#ifdef CONFIG_IPV6_PIMSM_V2
-       int                     mroute_reg_vif_num;
+#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+       struct mr6_table        *mrt6;
+#else
+       struct list_head        mr6_tables;
+       struct fib_rules_ops    *mr6_rules_ops;
 #endif
 #endif
 };
index b6cdc33b39c1597a8b1059e0652d4cb5ae7bf889..9d4d87cc970e3b487c5c0879008bb0588a0e87dd 100644 (file)
@@ -12,7 +12,7 @@ struct qdisc_walker {
        int     (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *);
 };
 
-#define QDISC_ALIGNTO          32
+#define QDISC_ALIGNTO          64
 #define QDISC_ALIGN(len)       (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1))
 
 static inline void *qdisc_priv(struct Qdisc *q)
index 6c14a656357a8449dc79269ce992ee16fe6c6d89..43c57502659b230c637d9c8d1e21aa986bde3de9 100644 (file)
@@ -19,6 +19,7 @@
 
 
 #include <net/protocol.h>
+#include <linux/icmp.h>
 
 extern struct proto raw_prot;
 
@@ -56,4 +57,16 @@ int raw_seq_open(struct inode *ino, struct file *file,
 void raw_hash_sk(struct sock *sk);
 void raw_unhash_sk(struct sock *sk);
 
+struct raw_sock {
+       /* inet_sock has to be the first member */
+       struct inet_sock   inet;
+       struct icmp_filter filter;
+       u32                ipmr_table;
+};
+
+static inline struct raw_sock *raw_sk(const struct sock *sk)
+{
+       return (struct raw_sock *)sk;
+}
+
 #endif /* _RAW_H */
index 2c9fba7f77319214d87b09d7be87857a46fc4808..af6cf4b4c9dc53aef5d8d1a21abb2cf71a29045a 100644 (file)
@@ -112,7 +112,22 @@ extern void                rt_cache_flush_batch(void);
 extern int             __ip_route_output_key(struct net *, struct rtable **, const struct flowi *flp);
 extern int             ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
 extern int             ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
-extern int             ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
+
+extern int ip_route_input_common(struct sk_buff *skb, __be32 dst, __be32 src,
+                                u8 tos, struct net_device *devin, bool noref);
+
+static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src,
+                                u8 tos, struct net_device *devin)
+{
+       return ip_route_input_common(skb, dst, src, tos, devin, false);
+}
+
+static inline int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src,
+                                      u8 tos, struct net_device *devin)
+{
+       return ip_route_input_common(skb, dst, src, tos, devin, true);
+}
+
 extern unsigned short  ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
 extern void            ip_rt_send_redirect(struct sk_buff *skb);
 
index 67dc08eaaa457cf18d079a7e04807b96f774ebd5..03ca5d826757bb0459b3e612b5fdf5ae03757e9b 100644 (file)
@@ -73,6 +73,7 @@ struct Qdisc {
        struct sk_buff_head     q;
        struct gnet_stats_basic_packed bstats;
        struct gnet_stats_queue qstats;
+       struct rcu_head     rcu_head;
 };
 
 struct Qdisc_class_ops {
index fa6cde578a1d122a43a0f63e07969a36cf3e27ff..65946bc43d00876e4c90165627cb46ee68f4d8e0 100644 (file)
@@ -269,7 +269,7 @@ enum {
 #define SCTP_MIB_MAX    __SCTP_MIB_MAX
 struct sctp_mib {
         unsigned long   mibs[SCTP_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 
 /* Print debugging messages.  */
@@ -547,7 +547,7 @@ for (pos = chunk->subh.fwdtsn_hdr->skip;\
 #define WORD_ROUND(s) (((s)+3)&~3)
 
 /* Make a new instance of type.  */
-#define t_new(type, flags)     (type *)kmalloc(sizeof(type), flags)
+#define t_new(type, flags)     (type *)kzalloc(sizeof(type), flags)
 
 /* Compare two timevals.  */
 #define tv_lt(s, t) \
index 61d73e37d5436138d743372a48aecad3191526fe..4088c89a9055ee5b0a33bc72690f431fa701a1b8 100644 (file)
@@ -438,7 +438,7 @@ sctp_vtag_verify_either(const struct sctp_chunk *chunk,
         */
         if ((!sctp_test_T_bit(chunk) &&
              (ntohl(chunk->sctp_hdr->vtag) == asoc->c.my_vtag)) ||
-           (sctp_test_T_bit(chunk) &&
+           (sctp_test_T_bit(chunk) && asoc->c.peer_vtag &&
             (ntohl(chunk->sctp_hdr->vtag) == asoc->c.peer_vtag))) {
                 return 1;
        }
index 219043a67bf7ab6073eba985e80ebb8ca206f2c1..6173c619913ae51b5bdb2c010f544ce451fe99c7 100644 (file)
@@ -643,17 +643,15 @@ struct sctp_pf {
 struct sctp_datamsg {
        /* Chunks waiting to be submitted to lower layer. */
        struct list_head chunks;
-       /* Chunks that have been transmitted. */
-       size_t msg_size;
        /* Reference counting. */
        atomic_t refcnt;
        /* When is this message no longer interesting to the peer? */
        unsigned long expires_at;
        /* Did the messenge fail to send? */
        int send_error;
-       char send_failed;
-       /* Control whether chunks from this message can be abandoned. */
-       char can_abandon;
+       u8 send_failed:1,
+          can_abandon:1,   /* can chunks from this message can be abandoned. */
+          can_delay;       /* should this message be Nagle delayed */
 };
 
 struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
@@ -757,7 +755,6 @@ struct sctp_chunk {
 #define SCTP_NEED_FRTX 0x1
 #define SCTP_DONT_FRTX 0x2
        __u16   rtt_in_progress:1,      /* This chunk used for RTT calc? */
-               resent:1,               /* Has this chunk ever been resent. */
                has_tsn:1,              /* Does this chunk have a TSN yet? */
                has_ssn:1,              /* Does this chunk have a SSN yet? */
                singleton:1,            /* Only chunk in the packet? */
@@ -879,7 +876,30 @@ struct sctp_transport {
 
        /* Reference counting. */
        atomic_t refcnt;
-       int      dead;
+       int      dead:1,
+               /* RTO-Pending : A flag used to track if one of the DATA
+                *              chunks sent to this address is currently being
+                *              used to compute a RTT. If this flag is 0,
+                *              the next DATA chunk sent to this destination
+                *              should be used to compute a RTT and this flag
+                *              should be set. Every time the RTT
+                *              calculation completes (i.e. the DATA chunk
+                *              is SACK'd) clear this flag.
+                */
+                rto_pending:1,
+
+               /*
+                * hb_sent : a flag that signals that we have a pending
+                * heartbeat.
+                */
+               hb_sent:1,
+
+               /* Is the Path MTU update pending on this tranport */
+               pmtu_pending:1,
+
+               /* Is this structure kfree()able? */
+               malloced:1;
+
 
        /* This is the peer's IP address and port. */
        union sctp_addr ipaddr;
@@ -909,22 +929,6 @@ struct sctp_transport {
        /* SRTT        : The current smoothed round trip time.  */
        __u32 srtt;
 
-       /* RTO-Pending : A flag used to track if one of the DATA
-        *              chunks sent to this address is currently being
-        *              used to compute a RTT. If this flag is 0,
-        *              the next DATA chunk sent to this destination
-        *              should be used to compute a RTT and this flag
-        *              should be set. Every time the RTT
-        *              calculation completes (i.e. the DATA chunk
-        *              is SACK'd) clear this flag.
-        * hb_sent : a flag that signals that we have a pending heartbeat.
-        */
-       __u8 rto_pending;
-       __u8 hb_sent;
-
-       /* Flag to track the current fast recovery state */
-       __u8 fast_recovery;
-
        /*
         * These are the congestion stats.
         */
@@ -944,9 +948,6 @@ struct sctp_transport {
 
        __u32 burst_limited;    /* Holds old cwnd when max.burst is applied */
 
-       /* TSN marking the fast recovery exit point */
-       __u32 fast_recovery_exit;
-
        /* Destination */
        struct dst_entry *dst;
        /* Source address. */
@@ -977,9 +978,6 @@ struct sctp_transport {
         */
        __u16 pathmaxrxt;
 
-       /* is the Path MTU update pending on this tranport */
-       __u8 pmtu_pending;
-
        /* PMTU       : The current known path MTU.  */
        __u32 pathmtu;
 
@@ -1026,8 +1024,6 @@ struct sctp_transport {
        /* This is the list of transports that have chunks to send.  */
        struct list_head send_ready;
 
-       int malloced; /* Is this structure kfree()able? */
-
        /* State information saved for SFR_CACC algorithm. The key
         * idea in SFR_CACC is to maintain state at the sender on a
         * per-destination basis when a changeover happens.
@@ -1069,7 +1065,7 @@ void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
                          struct sctp_sock *);
 void sctp_transport_pmtu(struct sctp_transport *);
 void sctp_transport_free(struct sctp_transport *);
-void sctp_transport_reset_timers(struct sctp_transport *, int);
+void sctp_transport_reset_timers(struct sctp_transport *);
 void sctp_transport_hold(struct sctp_transport *);
 void sctp_transport_put(struct sctp_transport *);
 void sctp_transport_update_rto(struct sctp_transport *, __u32);
@@ -1723,6 +1719,12 @@ struct sctp_association {
        /* Highest TSN that is acknowledged by incoming SACKs. */
        __u32 highest_sacked;
 
+       /* TSN marking the fast recovery exit point */
+       __u32 fast_recovery_exit;
+
+       /* Flag to track the current fast recovery state */
+       __u8 fast_recovery;
+
        /* The number of unacknowledged data chunks.  Reported through
         * the SCTP_STATUS sockopt.
         */
index 692ee0061dc40b09335b44398aa638cdadef3a14..92456f1035f52bd6e1a6c8e7733c7737d58d15e1 100644 (file)
@@ -52,26 +52,11 @@ struct snmp_mib {
  * count on the 20Gb/s + networks people expect in a few years time!
  */
 
-/* 
- * The rule for padding: 
- * Best is power of two because then the right structure can be found by a 
- * simple shift. The structure should be always cache line aligned.
- * gcc needs n=alignto(cachelinesize, popcnt(sizeof(bla_mib))) shift/add 
- * instructions to emulate multiply in case it is not power-of-two. 
- * Currently n is always <=3 for all sizes so simple cache line alignment 
- * is enough. 
- * 
- * The best solution would be a global CPU local area , especially on 64 
- * and 128byte cacheline machine it makes a *lot* of sense -AK
- */ 
-
-#define __SNMP_MIB_ALIGN__     ____cacheline_aligned
-
 /* IPstats */
 #define IPSTATS_MIB_MAX        __IPSTATS_MIB_MAX
 struct ipstats_mib {
        unsigned long   mibs[IPSTATS_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 /* ICMP */
 #define ICMP_MIB_DUMMY __ICMP_MIB_MAX
@@ -79,36 +64,36 @@ struct ipstats_mib {
 
 struct icmp_mib {
        unsigned long   mibs[ICMP_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 #define ICMPMSG_MIB_MAX        __ICMPMSG_MIB_MAX
 struct icmpmsg_mib {
        unsigned long   mibs[ICMPMSG_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 /* ICMP6 (IPv6-ICMP) */
 #define ICMP6_MIB_MAX  __ICMP6_MIB_MAX
 struct icmpv6_mib {
        unsigned long   mibs[ICMP6_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 #define ICMP6MSG_MIB_MAX  __ICMP6MSG_MIB_MAX
 struct icmpv6msg_mib {
        unsigned long   mibs[ICMP6MSG_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 
 /* TCP */
 #define TCP_MIB_MAX    __TCP_MIB_MAX
 struct tcp_mib {
        unsigned long   mibs[TCP_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 /* UDP */
 #define UDP_MIB_MAX    __UDP_MIB_MAX
 struct udp_mib {
        unsigned long   mibs[UDP_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 /* Linux */
 #define LINUX_MIB_MAX  __LINUX_MIB_MAX
@@ -148,6 +133,8 @@ struct linux_xfrm_mib {
                        __this_cpu_add(mib[0]->mibs[field], addend)
 #define SNMP_ADD_STATS_USER(mib, field, addend)        \
                        this_cpu_add(mib[1]->mibs[field], addend)
+#define SNMP_ADD_STATS(mib, field, addend)     \
+                       this_cpu_add(mib[0]->mibs[field], addend)
 /*
  * Use "__typeof__(*mib[0]) *ptr" instead of "__typeof__(mib[0]) ptr"
  * to make @ptr a non-percpu pointer.
index 1ad6435f252eda64b17e6b4568c58f42a0eed6d0..5697caf8cc76044efb9fc61dc9b7c931d74d95fa 100644 (file)
@@ -159,7 +159,7 @@ struct sock_common {
   *    @sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings
   *    @sk_lock:       synchronizer
   *    @sk_rcvbuf: size of receive buffer in bytes
-  *    @sk_sleep: sock wait queue
+  *    @sk_wq: sock wait queue and async head
   *    @sk_dst_cache: destination cache
   *    @sk_dst_lock: destination cache lock
   *    @sk_policy: flow policy
@@ -177,6 +177,7 @@ struct sock_common {
   *               %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
   *    @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
   *    @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
+  *    @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
   *    @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
   *    @sk_gso_max_size: Maximum GSO segment size to build
   *    @sk_lingertime: %SO_LINGER l_linger setting
@@ -198,6 +199,7 @@ struct sock_common {
   *    @sk_rcvlowat: %SO_RCVLOWAT setting
   *    @sk_rcvtimeo: %SO_RCVTIMEO setting
   *    @sk_sndtimeo: %SO_SNDTIMEO setting
+  *    @sk_rxhash: flow hash received from netif layer
   *    @sk_filter: socket filtering instructions
   *    @sk_protinfo: private area, net family specific, when not using slab
   *    @sk_timer: sock cleanup timer
@@ -255,14 +257,13 @@ struct sock {
                struct sk_buff *head;
                struct sk_buff *tail;
                int len;
-               int limit;
        } sk_backlog;
-       wait_queue_head_t       *sk_sleep;
+       struct socket_wq        *sk_wq;
        struct dst_entry        *sk_dst_cache;
 #ifdef CONFIG_XFRM
        struct xfrm_policy      *sk_policy[2];
 #endif
-       rwlock_t                sk_dst_lock;
+       spinlock_t              sk_dst_lock;
        atomic_t                sk_rmem_alloc;
        atomic_t                sk_wmem_alloc;
        atomic_t                sk_omem_alloc;
@@ -276,9 +277,13 @@ struct sock {
        int                     sk_forward_alloc;
        gfp_t                   sk_allocation;
        int                     sk_route_caps;
+       int                     sk_route_nocaps;
        int                     sk_gso_type;
        unsigned int            sk_gso_max_size;
        int                     sk_rcvlowat;
+#ifdef CONFIG_RPS
+       __u32                   sk_rxhash;
+#endif
        unsigned long           sk_flags;
        unsigned long           sk_lingertime;
        struct sk_buff_head     sk_error_queue;
@@ -595,19 +600,32 @@ static inline int sk_stream_memory_free(struct sock *sk)
 /* OOB backlog add */
 static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
-       if (!sk->sk_backlog.tail) {
-               sk->sk_backlog.head = sk->sk_backlog.tail = skb;
-       } else {
+       /* dont let skb dst not refcounted, we are going to leave rcu lock */
+       skb_dst_force(skb);
+
+       if (!sk->sk_backlog.tail)
+               sk->sk_backlog.head = skb;
+       else
                sk->sk_backlog.tail->next = skb;
-               sk->sk_backlog.tail = skb;
-       }
+
+       sk->sk_backlog.tail = skb;
        skb->next = NULL;
 }
 
+/*
+ * Take into account size of receive queue and backlog queue
+ */
+static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb)
+{
+       unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc);
+
+       return qsize + skb->truesize > sk->sk_rcvbuf;
+}
+
 /* The per-socket spinlock must be held here. */
 static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *skb)
 {
-       if (sk->sk_backlog.len >= max(sk->sk_backlog.limit, sk->sk_rcvbuf << 1))
+       if (sk_rcvqueues_full(sk, skb))
                return -ENOBUFS;
 
        __sk_add_backlog(sk, skb);
@@ -620,6 +638,40 @@ static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
        return sk->sk_backlog_rcv(sk, skb);
 }
 
+static inline void sock_rps_record_flow(const struct sock *sk)
+{
+#ifdef CONFIG_RPS
+       struct rps_sock_flow_table *sock_flow_table;
+
+       rcu_read_lock();
+       sock_flow_table = rcu_dereference(rps_sock_flow_table);
+       rps_record_sock_flow(sock_flow_table, sk->sk_rxhash);
+       rcu_read_unlock();
+#endif
+}
+
+static inline void sock_rps_reset_flow(const struct sock *sk)
+{
+#ifdef CONFIG_RPS
+       struct rps_sock_flow_table *sock_flow_table;
+
+       rcu_read_lock();
+       sock_flow_table = rcu_dereference(rps_sock_flow_table);
+       rps_reset_sock_flow(sock_flow_table, sk->sk_rxhash);
+       rcu_read_unlock();
+#endif
+}
+
+static inline void sock_rps_save_rxhash(struct sock *sk, u32 rxhash)
+{
+#ifdef CONFIG_RPS
+       if (unlikely(sk->sk_rxhash != rxhash)) {
+               sock_rps_reset_flow(sk);
+               sk->sk_rxhash = rxhash;
+       }
+#endif
+}
+
 #define sk_wait_event(__sk, __timeo, __condition)                      \
        ({      int __rc;                                               \
                release_sock(__sk);                                     \
@@ -974,6 +1026,16 @@ extern void release_sock(struct sock *sk);
                                SINGLE_DEPTH_NESTING)
 #define bh_unlock_sock(__sk)   spin_unlock(&((__sk)->sk_lock.slock))
 
+static inline void lock_sock_bh(struct sock *sk)
+{
+       spin_lock_bh(&sk->sk_lock.slock);
+}
+
+static inline void unlock_sock_bh(struct sock *sk)
+{
+       spin_unlock_bh(&sk->sk_lock.slock);
+}
+
 extern struct sock             *sk_alloc(struct net *net, int family,
                                          gfp_t priority,
                                          struct proto *prot);
@@ -1160,6 +1222,10 @@ static inline void sk_set_socket(struct sock *sk, struct socket *sock)
        sk->sk_socket = sock;
 }
 
+static inline wait_queue_head_t *sk_sleep(struct sock *sk)
+{
+       return &sk->sk_wq->wait;
+}
 /* Detach socket from process context.
  * Announce socket dead, detach it from wait queue and inode.
  * Note that parent inode held reference count on this struct sock,
@@ -1172,14 +1238,14 @@ static inline void sock_orphan(struct sock *sk)
        write_lock_bh(&sk->sk_callback_lock);
        sock_set_flag(sk, SOCK_DEAD);
        sk_set_socket(sk, NULL);
-       sk->sk_sleep  = NULL;
+       sk->sk_wq  = NULL;
        write_unlock_bh(&sk->sk_callback_lock);
 }
 
 static inline void sock_graft(struct sock *sk, struct socket *parent)
 {
        write_lock_bh(&sk->sk_callback_lock);
-       sk->sk_sleep = &parent->wait;
+       rcu_assign_pointer(sk->sk_wq, parent->wq);
        parent->sk = sk;
        sk_set_socket(sk, parent);
        security_sock_graft(sk, parent);
@@ -1192,7 +1258,9 @@ extern unsigned long sock_i_ino(struct sock *sk);
 static inline struct dst_entry *
 __sk_dst_get(struct sock *sk)
 {
-       return sk->sk_dst_cache;
+       return rcu_dereference_check(sk->sk_dst_cache, rcu_read_lock_held() ||
+                                                      sock_owned_by_user(sk) ||
+                                                      lockdep_is_held(&sk->sk_lock.slock));
 }
 
 static inline struct dst_entry *
@@ -1200,50 +1268,65 @@ sk_dst_get(struct sock *sk)
 {
        struct dst_entry *dst;
 
-       read_lock(&sk->sk_dst_lock);
-       dst = sk->sk_dst_cache;
+       rcu_read_lock();
+       dst = rcu_dereference(sk->sk_dst_cache);
        if (dst)
                dst_hold(dst);
-       read_unlock(&sk->sk_dst_lock);
+       rcu_read_unlock();
        return dst;
 }
 
+extern void sk_reset_txq(struct sock *sk);
+
+static inline void dst_negative_advice(struct sock *sk)
+{
+       struct dst_entry *ndst, *dst = __sk_dst_get(sk);
+
+       if (dst && dst->ops->negative_advice) {
+               ndst = dst->ops->negative_advice(dst);
+
+               if (ndst != dst) {
+                       rcu_assign_pointer(sk->sk_dst_cache, ndst);
+                       sk_reset_txq(sk);
+               }
+       }
+}
+
 static inline void
 __sk_dst_set(struct sock *sk, struct dst_entry *dst)
 {
        struct dst_entry *old_dst;
 
        sk_tx_queue_clear(sk);
-       old_dst = sk->sk_dst_cache;
-       sk->sk_dst_cache = dst;
+       /*
+        * This can be called while sk is owned by the caller only,
+        * with no state that can be checked in a rcu_dereference_check() cond
+        */
+       old_dst = rcu_dereference_raw(sk->sk_dst_cache);
+       rcu_assign_pointer(sk->sk_dst_cache, dst);
        dst_release(old_dst);
 }
 
 static inline void
 sk_dst_set(struct sock *sk, struct dst_entry *dst)
 {
-       write_lock(&sk->sk_dst_lock);
+       spin_lock(&sk->sk_dst_lock);
        __sk_dst_set(sk, dst);
-       write_unlock(&sk->sk_dst_lock);
+       spin_unlock(&sk->sk_dst_lock);
 }
 
 static inline void
 __sk_dst_reset(struct sock *sk)
 {
-       struct dst_entry *old_dst;
-
-       sk_tx_queue_clear(sk);
-       old_dst = sk->sk_dst_cache;
-       sk->sk_dst_cache = NULL;
-       dst_release(old_dst);
+       __sk_dst_set(sk, NULL);
 }
 
 static inline void
 sk_dst_reset(struct sock *sk)
 {
-       write_lock(&sk->sk_dst_lock);
+       spin_lock(&sk->sk_dst_lock);
        __sk_dst_reset(sk);
-       write_unlock(&sk->sk_dst_lock);
+       spin_unlock(&sk->sk_dst_lock);
 }
 
 extern struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie);
@@ -1257,6 +1340,12 @@ static inline int sk_can_gso(const struct sock *sk)
 
 extern void sk_setup_caps(struct sock *sk, struct dst_entry *dst);
 
+static inline void sk_nocaps_add(struct sock *sk, int flags)
+{
+       sk->sk_route_nocaps |= flags;
+       sk->sk_route_caps &= ~flags;
+}
+
 static inline int skb_copy_to_page(struct sock *sk, char __user *from,
                                   struct sk_buff *skb, struct page *page,
                                   int off, int copy)
@@ -1314,12 +1403,12 @@ static inline int sk_has_allocations(const struct sock *sk)
 }
 
 /**
- * sk_has_sleeper - check if there are any waiting processes
- * @sk: socket
+ * wq_has_sleeper - check if there are any waiting processes
+ * @sk: struct socket_wq
  *
- * Returns true if socket has waiting processes
+ * Returns true if socket_wq has waiting processes
  *
- * The purpose of the sk_has_sleeper and sock_poll_wait is to wrap the memory
+ * The purpose of the wq_has_sleeper and sock_poll_wait is to wrap the memory
  * barrier call. They were added due to the race found within the tcp code.
  *
  * Consider following tcp code paths:
@@ -1332,9 +1421,10 @@ static inline int sk_has_allocations(const struct sock *sk)
  *   ...                 ...
  *   tp->rcv_nxt check   sock_def_readable
  *   ...                 {
- *   schedule               ...
- *                          if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
- *                              wake_up_interruptible(sk->sk_sleep)
+ *   schedule               rcu_read_lock();
+ *                          wq = rcu_dereference(sk->sk_wq);
+ *                          if (wq && waitqueue_active(&wq->wait))
+ *                              wake_up_interruptible(&wq->wait)
  *                          ...
  *                       }
  *
@@ -1343,19 +1433,18 @@ static inline int sk_has_allocations(const struct sock *sk)
  * could then endup calling schedule and sleep forever if there are no more
  * data on the socket.
  *
- * The sk_has_sleeper is always called right after a call to read_lock, so we
- * can use smp_mb__after_lock barrier.
  */
-static inline int sk_has_sleeper(struct sock *sk)
+static inline bool wq_has_sleeper(struct socket_wq *wq)
 {
+
        /*
         * We need to be sure we are in sync with the
         * add_wait_queue modifications to the wait queue.
         *
         * This memory barrier is paired in the sock_poll_wait.
         */
-       smp_mb__after_lock();
-       return sk->sk_sleep && waitqueue_active(sk->sk_sleep);
+       smp_mb();
+       return wq && waitqueue_active(&wq->wait);
 }
 
 /**
@@ -1364,7 +1453,7 @@ static inline int sk_has_sleeper(struct sock *sk)
  * @wait_address:   socket wait queue
  * @p:              poll_table
  *
- * See the comments in the sk_has_sleeper function.
+ * See the comments in the wq_has_sleeper function.
  */
 static inline void sock_poll_wait(struct file *filp,
                wait_queue_head_t *wait_address, poll_table *p)
@@ -1375,7 +1464,7 @@ static inline void sock_poll_wait(struct file *filp,
                 * We need to be sure we are in sync with the
                 * socket flags modification.
                 *
-                * This memory barrier is paired in the sk_has_sleeper.
+                * This memory barrier is paired in the wq_has_sleeper.
                */
                smp_mb();
        }
@@ -1557,7 +1646,24 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
                sk->sk_stamp = kt;
 }
 
-extern void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb);
+extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+                                    struct sk_buff *skb);
+
+static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+                                         struct sk_buff *skb)
+{
+#define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL)                      | \
+                          (1UL << SOCK_RCVTSTAMP)                      | \
+                          (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)       | \
+                          (1UL << SOCK_TIMESTAMPING_SOFTWARE)          | \
+                          (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)      | \
+                          (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE))
+
+       if (sk->sk_flags & FLAGS_TS_OR_DROPS)
+               __sock_recv_ts_and_drops(msg, sk, skb);
+       else
+               sk->sk_stamp = skb->tstamp;
+}
 
 /**
  * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped
index aa04b9a5093b2ceed25c672cf5abaefa9b75b7fb..a1449144848aad1e09a0de356df96f898cd651e8 100644 (file)
@@ -294,6 +294,7 @@ extern struct proto tcp_prot;
 #define TCP_INC_STATS_BH(net, field)   SNMP_INC_STATS_BH((net)->mib.tcp_statistics, field)
 #define TCP_DEC_STATS(net, field)      SNMP_DEC_STATS((net)->mib.tcp_statistics, field)
 #define TCP_ADD_STATS_USER(net, field, val) SNMP_ADD_STATS_USER((net)->mib.tcp_statistics, field, val)
+#define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val)
 
 extern void                    tcp_v4_err(struct sk_buff *skb, u32);
 
@@ -423,7 +424,7 @@ extern u8                   *tcp_parse_md5sig_option(struct tcphdr *th);
  *     TCP v4 functions exported for the inet6 API
  */
 
-extern void                    tcp_v4_send_check(struct sock *sk, int len,
+extern void                    tcp_v4_send_check(struct sock *sk,
                                                  struct sk_buff *skb);
 
 extern int                     tcp_v4_conn_request(struct sock *sk,
@@ -939,7 +940,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb)
 
                tp->ucopy.memory = 0;
        } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
-               wake_up_interruptible_sync_poll(sk->sk_sleep,
+               wake_up_interruptible_sync_poll(sk_sleep(sk),
                                           POLLIN | POLLRDNORM | POLLRDBAND);
                if (!inet_csk_ack_scheduled(sk))
                        inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
@@ -1032,6 +1033,14 @@ static inline int keepalive_probes(const struct tcp_sock *tp)
        return tp->keepalive_probes ? : sysctl_tcp_keepalive_probes;
 }
 
+static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp)
+{
+       const struct inet_connection_sock *icsk = &tp->inet_conn;
+
+       return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime,
+                         tcp_time_stamp - tp->rcv_tstamp);
+}
+
 static inline int tcp_fin_time(const struct sock *sk)
 {
        int fin_timeout = tcp_sk(sk)->linger2 ? : sysctl_tcp_fin_timeout;
index 9566608c88cf88878ea742dfa9451d1e7a146ae4..15af6dca0b493f982f6de117402a19f04c7b03a1 100644 (file)
@@ -2,7 +2,7 @@
  * include/net/tipc/tipc.h: Main include file for TIPC users
  * 
  * Copyright (c) 2003-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005,2010 Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@ int tipc_createport(unsigned int tipc_user,
                    tipc_msg_event message_cb, 
                    tipc_named_msg_event named_message_cb, 
                    tipc_conn_msg_event conn_message_cb, 
-                   tipc_continue_event continue_event_cb,/* May be zero */
+                   tipc_continue_event continue_event_cb,
                    u32 *portref);
 
 int tipc_deleteport(u32 portref);
@@ -145,13 +145,13 @@ int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable);
 int tipc_publish(u32 portref, unsigned int scope, 
                 struct tipc_name_seq const *name_seq);
 int tipc_withdraw(u32 portref, unsigned int scope,
-                 struct tipc_name_seq const *name_seq); /* 0: all */
+                 struct tipc_name_seq const *name_seq);
 
 int tipc_connect2port(u32 portref, struct tipc_portid const *port);
 
 int tipc_disconnect(u32 portref);
 
-int tipc_shutdown(u32 ref); /* Sends SHUTDOWN msg */
+int tipc_shutdown(u32 ref);
 
 int tipc_isconnected(u32 portref, int *isconnected);
 
@@ -176,7 +176,7 @@ int tipc_send_buf(u32 portref,
 
 int tipc_send2name(u32 portref, 
                   struct tipc_name const *name, 
-                  u32 domain,  /* 0:own zone */
+                  u32 domain,
                   unsigned int num_sect,
                   struct iovec const *msg_sect);
 
@@ -188,7 +188,7 @@ int tipc_send_buf2name(u32 portref,
 
 int tipc_forward2name(u32 portref, 
                      struct tipc_name const *name, 
-                     u32 domain,   /*0: own zone */
+                     u32 domain,
                      unsigned int section_count,
                      struct iovec const *msg_sect,
                      struct tipc_portid const *origin,
@@ -228,14 +228,14 @@ int tipc_forward_buf2port(u32 portref,
 
 int tipc_multicast(u32 portref, 
                   struct tipc_name_seq const *seq, 
-                  u32 domain,  /* 0:own zone */
+                  u32 domain,  /* currently unused */
                   unsigned int section_count,
                   struct iovec const *msg);
 
 #if 0
 int tipc_multicast_buf(u32 portref, 
                       struct tipc_name_seq const *seq, 
-                      u32 domain,      /* 0:own zone */
+                      u32 domain,
                       void *buf,
                       unsigned int size);
 #endif
index d65381cad0fcc5298bbb1a879afb6afc3b7e3345..42a0eb68b7b6a4706b9a62bde44621b256a764b4 100644 (file)
@@ -44,7 +44,8 @@ extern int                    datagram_send_ctl(struct net *net,
                                                  struct msghdr *msg,
                                                  struct flowi *fl,
                                                  struct ipv6_txoptions *opt,
-                                                 int *hlimit, int *tclass);
+                                                 int *hlimit, int *tclass,
+                                                 int *dontfrag);
 
 #define                LOOPBACK4_IPV6          cpu_to_be32(0x7f000006)
 
index 468551ea4f1d4248a10a5b7e19c43647c4f013d9..1479cb4a41fc988fba91183c512c950f07db71d2 100644 (file)
@@ -80,8 +80,6 @@ enum {
 #define        X25_DEFAULT_PACKET_SIZE X25_PS128               /* Default Packet Size */
 #define        X25_DEFAULT_THROUGHPUT  0x0A                    /* Deafult Throughput */
 #define        X25_DEFAULT_REVERSE     0x00                    /* Default Reverse Charging */
-#define X25_DENY_ACCPT_APPRV   0x01                    /* Default value */
-#define X25_ALLOW_ACCPT_APPRV  0x00                    /* Control enabled */
 
 #define X25_SMODULUS           8
 #define        X25_EMODULUS            128
@@ -113,6 +111,11 @@ enum {
 #define X25_MAX_AE_LEN                 40                      /* Max num of semi-octets in AE - OSI Nw */
 #define X25_MAX_DTE_FACIL_LEN  21                      /* Max length of DTE facility params */
 
+/* Bitset in x25_sock->flags for misc flags */
+#define X25_Q_BIT_FLAG         0
+#define X25_INTERRUPT_FLAG     1
+#define X25_ACCPT_APPRV_FLAG   2
+
 /**
  *     struct x25_route - x25 routing entry
  *     @node - entry in x25_list_lock
@@ -146,10 +149,11 @@ struct x25_sock {
        struct x25_address      source_addr, dest_addr;
        struct x25_neigh        *neighbour;
        unsigned int            lci, cudmatchlength;
-       unsigned char           state, condition, qbitincl, intflag, accptapprv;
+       unsigned char           state, condition;
        unsigned short          vs, vr, va, vl;
        unsigned long           t2, t21, t22, t23;
        unsigned short          fraglen;
+       unsigned long           flags;
        struct sk_buff_head     ack_queue;
        struct sk_buff_head     fragment_queue;
        struct sk_buff_head     interrupt_in_queue;
index 1415bcf93980f9c06aca48ee41de41065d72cedb..1fa08b49f1c25d1a3b9a1c930e238b45db52535a 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
+#include <linux/if_x25.h>
 #include <linux/skbuff.h>
 
 static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev)
index ac52f33f3e4af06113dc060fd4a8282e6f837c94..1913af67c43d8ef976f08dcaef307499b59e4e0b 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/route.h>
 #include <net/ipv6.h>
 #include <net/ip6_fib.h>
+#include <net/flow.h>
 
 #include <linux/interrupt.h>
 
@@ -267,7 +268,6 @@ struct xfrm_policy_afinfo {
                                               xfrm_address_t *saddr,
                                               xfrm_address_t *daddr);
        int                     (*get_saddr)(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr);
-       struct dst_entry        *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
        void                    (*decode_session)(struct sk_buff *skb,
                                                  struct flowi *fl,
                                                  int reverse);
@@ -482,13 +482,14 @@ struct xfrm_policy {
        atomic_t                refcnt;
        struct timer_list       timer;
 
+       struct flow_cache_object flo;
+       atomic_t                genid;
        u32                     priority;
        u32                     index;
        struct xfrm_mark        mark;
        struct xfrm_selector    selector;
        struct xfrm_lifetime_cfg lft;
        struct xfrm_lifetime_cur curlft;
-       struct dst_entry       *bundles;
        struct xfrm_policy_walk_entry walk;
        u8                      type;
        u8                      action;
@@ -735,19 +736,12 @@ static inline void xfrm_pol_put(struct xfrm_policy *policy)
                xfrm_policy_destroy(policy);
 }
 
-#ifdef CONFIG_XFRM_SUB_POLICY
 static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
 {
        int i;
        for (i = npols - 1; i >= 0; --i)
                xfrm_pol_put(pols[i]);
 }
-#else
-static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols)
-{
-       xfrm_pol_put(pols[0]);
-}
-#endif
 
 extern void __xfrm_state_destroy(struct xfrm_state *);
 
@@ -878,11 +872,15 @@ struct xfrm_dst {
                struct rt6_info         rt6;
        } u;
        struct dst_entry *route;
+       struct flow_cache_object flo;
+       struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
+       int num_pols, num_xfrms;
 #ifdef CONFIG_XFRM_SUB_POLICY
        struct flowi *origin;
        struct xfrm_selector *partner;
 #endif
-       u32 genid;
+       u32 xfrm_genid;
+       u32 policy_genid;
        u32 route_mtu_cached;
        u32 child_mtu_cached;
        u32 route_cookie;
@@ -892,6 +890,7 @@ struct xfrm_dst {
 #ifdef CONFIG_XFRM
 static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
 {
+       xfrm_pols_put(xdst->pols, xdst->num_pols);
        dst_release(xdst->route);
        if (likely(xdst->u.dst.xfrm))
                xfrm_state_put(xdst->u.dst.xfrm);
index 509e6ba5df2059e1ce6d5d3d968b21ac01e780fb..b1258304775796ec0946fbdc749dc84bc43c675a 100644 (file)
@@ -2062,8 +2062,132 @@ int proc_dostring(struct ctl_table *table, int write,
                               buffer, lenp, ppos);
 }
 
+static size_t proc_skip_spaces(char **buf)
+{
+       size_t ret;
+       char *tmp = skip_spaces(*buf);
+       ret = tmp - *buf;
+       *buf = tmp;
+       return ret;
+}
+
+static void proc_skip_char(char **buf, size_t *size, const char v)
+{
+       while (*size) {
+               if (**buf != v)
+                       break;
+               (*size)--;
+               (*buf)++;
+       }
+}
+
+#define TMPBUFLEN 22
+/**
+ * proc_get_long - reads an ASCII formated integer from a user buffer
+ *
+ * @buf - a kernel buffer
+ * @size - size of the kernel buffer
+ * @val - this is where the number will be stored
+ * @neg - set to %TRUE if number is negative
+ * @perm_tr - a vector which contains the allowed trailers
+ * @perm_tr_len - size of the perm_tr vector
+ * @tr - pointer to store the trailer character
+ *
+ * In case of success 0 is returned and buf and size are updated with
+ * the amount of bytes read. If tr is non NULL and a trailing
+ * character exist (size is non zero after returning from this
+ * function) tr is updated with the trailing character.
+ */
+static int proc_get_long(char **buf, size_t *size,
+                         unsigned long *val, bool *neg,
+                         const char *perm_tr, unsigned perm_tr_len, char *tr)
+{
+       int len;
+       char *p, tmp[TMPBUFLEN];
+
+       if (!*size)
+               return -EINVAL;
+
+       len = *size;
+       if (len > TMPBUFLEN - 1)
+               len = TMPBUFLEN - 1;
+
+       memcpy(tmp, *buf, len);
+
+       tmp[len] = 0;
+       p = tmp;
+       if (*p == '-' && *size > 1) {
+               *neg = true;
+               p++;
+       } else
+               *neg = false;
+       if (!isdigit(*p))
+               return -EINVAL;
+
+       *val = simple_strtoul(p, &p, 0);
+
+       len = p - tmp;
+
+       /* We don't know if the next char is whitespace thus we may accept
+        * invalid integers (e.g. 1234...a) or two integers instead of one
+        * (e.g. 123...1). So lets not allow such large numbers. */
+       if (len == TMPBUFLEN - 1)
+               return -EINVAL;
+
+       if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len))
+               return -EINVAL;
+
+       if (tr && (len < *size))
+               *tr = *p;
+
+       *buf += len;
+       *size -= len;
+
+       return 0;
+}
+
+/**
+ * proc_put_long - coverts an integer to a decimal ASCII formated string
+ *
+ * @buf - the user buffer
+ * @size - the size of the user buffer
+ * @val - the integer to be converted
+ * @neg - sign of the number, %TRUE for negative
+ *
+ * In case of success 0 is returned and buf and size are updated with
+ * the amount of bytes read.
+ */
+static int proc_put_long(void __user **buf, size_t *size, unsigned long val,
+                         bool neg)
+{
+       int len;
+       char tmp[TMPBUFLEN], *p = tmp;
+
+       sprintf(p, "%s%lu", neg ? "-" : "", val);
+       len = strlen(tmp);
+       if (len > *size)
+               len = *size;
+       if (copy_to_user(*buf, tmp, len))
+               return -EFAULT;
+       *size -= len;
+       *buf += len;
+       return 0;
+}
+#undef TMPBUFLEN
+
+static int proc_put_char(void __user **buf, size_t *size, char c)
+{
+       if (*size) {
+               char __user **buffer = (char __user **)buf;
+               if (put_user(c, *buffer))
+                       return -EFAULT;
+               (*size)--, (*buffer)++;
+               *buf = *buffer;
+       }
+       return 0;
+}
 
-static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
+static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
                                 int *valp,
                                 int write, void *data)
 {
@@ -2072,33 +2196,31 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
        } else {
                int val = *valp;
                if (val < 0) {
-                       *negp = -1;
+                       *negp = true;
                        *lvalp = (unsigned long)-val;
                } else {
-                       *negp = 0;
+                       *negp = false;
                        *lvalp = (unsigned long)val;
                }
        }
        return 0;
 }
 
+static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
+
 static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                  int write, void __user *buffer,
                  size_t *lenp, loff_t *ppos,
-                 int (*conv)(int *negp, unsigned long *lvalp, int *valp,
+                 int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
                              int write, void *data),
                  void *data)
 {
-#define TMPBUFLEN 21
-       int *i, vleft, first = 1, neg;
-       unsigned long lval;
-       size_t left, len;
+       int *i, vleft, first = 1, err = 0;
+       unsigned long page = 0;
+       size_t left;
+       char *kbuf;
        
-       char buf[TMPBUFLEN], *p;
-       char __user *s = buffer;
-       
-       if (!tbl_data || !table->maxlen || !*lenp ||
-           (*ppos && !write)) {
+       if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }
@@ -2110,89 +2232,69 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
        if (!conv)
                conv = do_proc_dointvec_conv;
 
+       if (write) {
+               if (left > PAGE_SIZE - 1)
+                       left = PAGE_SIZE - 1;
+               page = __get_free_page(GFP_TEMPORARY);
+               kbuf = (char *) page;
+               if (!kbuf)
+                       return -ENOMEM;
+               if (copy_from_user(kbuf, buffer, left)) {
+                       err = -EFAULT;
+                       goto free;
+               }
+               kbuf[left] = 0;
+       }
+
        for (; left && vleft--; i++, first=0) {
-               if (write) {
-                       while (left) {
-                               char c;
-                               if (get_user(c, s))
-                                       return -EFAULT;
-                               if (!isspace(c))
-                                       break;
-                               left--;
-                               s++;
-                       }
-                       if (!left)
-                               break;
-                       neg = 0;
-                       len = left;
-                       if (len > sizeof(buf) - 1)
-                               len = sizeof(buf) - 1;
-                       if (copy_from_user(buf, s, len))
-                               return -EFAULT;
-                       buf[len] = 0;
-                       p = buf;
-                       if (*p == '-' && left > 1) {
-                               neg = 1;
-                               p++;
-                       }
-                       if (*p < '0' || *p > '9')
-                               break;
+               unsigned long lval;
+               bool neg;
 
-                       lval = simple_strtoul(p, &p, 0);
+               if (write) {
+                       left -= proc_skip_spaces(&kbuf);
 
-                       len = p-buf;
-                       if ((len < left) && *p && !isspace(*p))
+                       err = proc_get_long(&kbuf, &left, &lval, &neg,
+                                            proc_wspace_sep,
+                                            sizeof(proc_wspace_sep), NULL);
+                       if (err)
                                break;
-                       s += len;
-                       left -= len;
-
-                       if (conv(&neg, &lval, i, 1, data))
+                       if (conv(&neg, &lval, i, 1, data)) {
+                               err = -EINVAL;
                                break;
+                       }
                } else {
-                       p = buf;
+                       if (conv(&neg, &lval, i, 0, data)) {
+                               err = -EINVAL;
+                               break;
+                       }
                        if (!first)
-                               *p++ = '\t';
-       
-                       if (conv(&neg, &lval, i, 0, data))
+                               err = proc_put_char(&buffer, &left, '\t');
+                       if (err)
+                               break;
+                       err = proc_put_long(&buffer, &left, lval, neg);
+                       if (err)
                                break;
-
-                       sprintf(p, "%s%lu", neg ? "-" : "", lval);
-                       len = strlen(buf);
-                       if (len > left)
-                               len = left;
-                       if(copy_to_user(s, buf, len))
-                               return -EFAULT;
-                       left -= len;
-                       s += len;
                }
        }
 
-       if (!write && !first && left) {
-               if(put_user('\n', s))
-                       return -EFAULT;
-               left--, s++;
-       }
+       if (!write && !first && left && !err)
+               err = proc_put_char(&buffer, &left, '\n');
+       if (write && !err)
+               left -= proc_skip_spaces(&kbuf);
+free:
        if (write) {
-               while (left) {
-                       char c;
-                       if (get_user(c, s++))
-                               return -EFAULT;
-                       if (!isspace(c))
-                               break;
-                       left--;
-               }
+               free_page(page);
+               if (first)
+                       return err ? : -EINVAL;
        }
-       if (write && first)
-               return -EINVAL;
        *lenp -= left;
        *ppos += *lenp;
-       return 0;
-#undef TMPBUFLEN
+       return err;
 }
 
 static int do_proc_dointvec(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos,
-                 int (*conv)(int *negp, unsigned long *lvalp, int *valp,
+                 int (*conv)(bool *negp, unsigned long *lvalp, int *valp,
                              int write, void *data),
                  void *data)
 {
@@ -2260,8 +2362,8 @@ struct do_proc_dointvec_minmax_conv_param {
        int *max;
 };
 
-static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp, 
-                                       int *valp, 
+static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
+                                       int *valp,
                                        int write, void *data)
 {
        struct do_proc_dointvec_minmax_conv_param *param = data;
@@ -2274,10 +2376,10 @@ static int do_proc_dointvec_minmax_conv(int *negp, unsigned long *lvalp,
        } else {
                int val = *valp;
                if (val < 0) {
-                       *negp = -1;
+                       *negp = true;
                        *lvalp = (unsigned long)-val;
                } else {
-                       *negp = 0;
+                       *negp = false;
                        *lvalp = (unsigned long)val;
                }
        }
@@ -2317,102 +2419,78 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
                                     unsigned long convmul,
                                     unsigned long convdiv)
 {
-#define TMPBUFLEN 21
-       unsigned long *i, *min, *max, val;
-       int vleft, first=1, neg;
-       size_t len, left;
-       char buf[TMPBUFLEN], *p;
-       char __user *s = buffer;
-       
-       if (!data || !table->maxlen || !*lenp ||
-           (*ppos && !write)) {
+       unsigned long *i, *min, *max;
+       int vleft, first = 1, err = 0;
+       unsigned long page = 0;
+       size_t left;
+       char *kbuf;
+
+       if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }
-       
+
        i = (unsigned long *) data;
        min = (unsigned long *) table->extra1;
        max = (unsigned long *) table->extra2;
        vleft = table->maxlen / sizeof(unsigned long);
        left = *lenp;
-       
+
+       if (write) {
+               if (left > PAGE_SIZE - 1)
+                       left = PAGE_SIZE - 1;
+               page = __get_free_page(GFP_TEMPORARY);
+               kbuf = (char *) page;
+               if (!kbuf)
+                       return -ENOMEM;
+               if (copy_from_user(kbuf, buffer, left)) {
+                       err = -EFAULT;
+                       goto free;
+               }
+               kbuf[left] = 0;
+       }
+
        for (; left && vleft--; i++, min++, max++, first=0) {
+               unsigned long val;
+
                if (write) {
-                       while (left) {
-                               char c;
-                               if (get_user(c, s))
-                                       return -EFAULT;
-                               if (!isspace(c))
-                                       break;
-                               left--;
-                               s++;
-                       }
-                       if (!left)
-                               break;
-                       neg = 0;
-                       len = left;
-                       if (len > TMPBUFLEN-1)
-                               len = TMPBUFLEN-1;
-                       if (copy_from_user(buf, s, len))
-                               return -EFAULT;
-                       buf[len] = 0;
-                       p = buf;
-                       if (*p == '-' && left > 1) {
-                               neg = 1;
-                               p++;
-                       }
-                       if (*p < '0' || *p > '9')
-                               break;
-                       val = simple_strtoul(p, &p, 0) * convmul / convdiv ;
-                       len = p-buf;
-                       if ((len < left) && *p && !isspace(*p))
+                       bool neg;
+
+                       left -= proc_skip_spaces(&kbuf);
+
+                       err = proc_get_long(&kbuf, &left, &val, &neg,
+                                            proc_wspace_sep,
+                                            sizeof(proc_wspace_sep), NULL);
+                       if (err)
                                break;
                        if (neg)
-                               val = -val;
-                       s += len;
-                       left -= len;
-
-                       if(neg)
                                continue;
                        if ((min && val < *min) || (max && val > *max))
                                continue;
                        *i = val;
                } else {
-                       p = buf;
+                       val = convdiv * (*i) / convmul;
                        if (!first)
-                               *p++ = '\t';
-                       sprintf(p, "%lu", convdiv * (*i) / convmul);
-                       len = strlen(buf);
-                       if (len > left)
-                               len = left;
-                       if(copy_to_user(s, buf, len))
-                               return -EFAULT;
-                       left -= len;
-                       s += len;
+                               err = proc_put_char(&buffer, &left, '\t');
+                       err = proc_put_long(&buffer, &left, val, false);
+                       if (err)
+                               break;
                }
        }
 
-       if (!write && !first && left) {
-               if(put_user('\n', s))
-                       return -EFAULT;
-               left--, s++;
-       }
+       if (!write && !first && left && !err)
+               err = proc_put_char(&buffer, &left, '\n');
+       if (write && !err)
+               left -= proc_skip_spaces(&kbuf);
+free:
        if (write) {
-               while (left) {
-                       char c;
-                       if (get_user(c, s++))
-                               return -EFAULT;
-                       if (!isspace(c))
-                               break;
-                       left--;
-               }
+               free_page(page);
+               if (first)
+                       return err ? : -EINVAL;
        }
-       if (write && first)
-               return -EINVAL;
        *lenp -= left;
        *ppos += *lenp;
-       return 0;
-#undef TMPBUFLEN
+       return err;
 }
 
 static int do_proc_doulongvec_minmax(struct ctl_table *table, int write,
@@ -2473,7 +2551,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
 }
 
 
-static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
+static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,
                                         int *valp,
                                         int write, void *data)
 {
@@ -2485,10 +2563,10 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
                int val = *valp;
                unsigned long lval;
                if (val < 0) {
-                       *negp = -1;
+                       *negp = true;
                        lval = (unsigned long)-val;
                } else {
-                       *negp = 0;
+                       *negp = false;
                        lval = (unsigned long)val;
                }
                *lvalp = lval / HZ;
@@ -2496,7 +2574,7 @@ static int do_proc_dointvec_jiffies_conv(int *negp, unsigned long *lvalp,
        return 0;
 }
 
-static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
+static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp,
                                                int *valp,
                                                int write, void *data)
 {
@@ -2508,10 +2586,10 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
                int val = *valp;
                unsigned long lval;
                if (val < 0) {
-                       *negp = -1;
+                       *negp = true;
                        lval = (unsigned long)-val;
                } else {
-                       *negp = 0;
+                       *negp = false;
                        lval = (unsigned long)val;
                }
                *lvalp = jiffies_to_clock_t(lval);
@@ -2519,7 +2597,7 @@ static int do_proc_dointvec_userhz_jiffies_conv(int *negp, unsigned long *lvalp,
        return 0;
 }
 
-static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp,
+static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
                                            int *valp,
                                            int write, void *data)
 {
@@ -2529,10 +2607,10 @@ static int do_proc_dointvec_ms_jiffies_conv(int *negp, unsigned long *lvalp,
                int val = *valp;
                unsigned long lval;
                if (val < 0) {
-                       *negp = -1;
+                       *negp = true;
                        lval = (unsigned long)-val;
                } else {
-                       *negp = 0;
+                       *negp = false;
                        lval = (unsigned long)val;
                }
                *lvalp = jiffies_to_msecs(lval);
@@ -2629,6 +2707,157 @@ static int proc_do_cad_pid(struct ctl_table *table, int write,
        return 0;
 }
 
+/**
+ * proc_do_large_bitmap - read/write from/to a large bitmap
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * The bitmap is stored at table->data and the bitmap length (in bits)
+ * in table->maxlen.
+ *
+ * We use a range comma separated format (e.g. 1,3-4,10-10) so that
+ * large bitmaps may be represented in a compact manner. Writing into
+ * the file will clear the bitmap then update it with the given input.
+ *
+ * Returns 0 on success.
+ */
+int proc_do_large_bitmap(struct ctl_table *table, int write,
+                        void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       int err = 0;
+       bool first = 1;
+       size_t left = *lenp;
+       unsigned long bitmap_len = table->maxlen;
+       unsigned long *bitmap = (unsigned long *) table->data;
+       unsigned long *tmp_bitmap = NULL;
+       char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
+
+       if (!bitmap_len || !left || (*ppos && !write)) {
+               *lenp = 0;
+               return 0;
+       }
+
+       if (write) {
+               unsigned long page = 0;
+               char *kbuf;
+
+               if (left > PAGE_SIZE - 1)
+                       left = PAGE_SIZE - 1;
+
+               page = __get_free_page(GFP_TEMPORARY);
+               kbuf = (char *) page;
+               if (!kbuf)
+                       return -ENOMEM;
+               if (copy_from_user(kbuf, buffer, left)) {
+                       free_page(page);
+                       return -EFAULT;
+                }
+               kbuf[left] = 0;
+
+               tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),
+                                    GFP_KERNEL);
+               if (!tmp_bitmap) {
+                       free_page(page);
+                       return -ENOMEM;
+               }
+               proc_skip_char(&kbuf, &left, '\n');
+               while (!err && left) {
+                       unsigned long val_a, val_b;
+                       bool neg;
+
+                       err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a,
+                                            sizeof(tr_a), &c);
+                       if (err)
+                               break;
+                       if (val_a >= bitmap_len || neg) {
+                               err = -EINVAL;
+                               break;
+                       }
+
+                       val_b = val_a;
+                       if (left) {
+                               kbuf++;
+                               left--;
+                       }
+
+                       if (c == '-') {
+                               err = proc_get_long(&kbuf, &left, &val_b,
+                                                    &neg, tr_b, sizeof(tr_b),
+                                                    &c);
+                               if (err)
+                                       break;
+                               if (val_b >= bitmap_len || neg ||
+                                   val_a > val_b) {
+                                       err = -EINVAL;
+                                       break;
+                               }
+                               if (left) {
+                                       kbuf++;
+                                       left--;
+                               }
+                       }
+
+                       while (val_a <= val_b)
+                               set_bit(val_a++, tmp_bitmap);
+
+                       first = 0;
+                       proc_skip_char(&kbuf, &left, '\n');
+               }
+               free_page(page);
+       } else {
+               unsigned long bit_a, bit_b = 0;
+
+               while (left) {
+                       bit_a = find_next_bit(bitmap, bitmap_len, bit_b);
+                       if (bit_a >= bitmap_len)
+                               break;
+                       bit_b = find_next_zero_bit(bitmap, bitmap_len,
+                                                  bit_a + 1) - 1;
+
+                       if (!first) {
+                               err = proc_put_char(&buffer, &left, ',');
+                               if (err)
+                                       break;
+                       }
+                       err = proc_put_long(&buffer, &left, bit_a, false);
+                       if (err)
+                               break;
+                       if (bit_a != bit_b) {
+                               err = proc_put_char(&buffer, &left, '-');
+                               if (err)
+                                       break;
+                               err = proc_put_long(&buffer, &left, bit_b, false);
+                               if (err)
+                                       break;
+                       }
+
+                       first = 0; bit_b++;
+               }
+               if (!err)
+                       err = proc_put_char(&buffer, &left, '\n');
+       }
+
+       if (!err) {
+               if (write) {
+                       if (*ppos)
+                               bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len);
+                       else
+                               memcpy(bitmap, tmp_bitmap,
+                                       BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long));
+               }
+               kfree(tmp_bitmap);
+               *lenp -= left;
+               *ppos += *lenp;
+               return 0;
+       } else {
+               kfree(tmp_bitmap);
+               return err;
+       }
+}
+
 #else /* CONFIG_PROC_FS */
 
 int proc_dostring(struct ctl_table *table, int write,
index 59030570f5ca4970283d24aea52f4e06fa849b4f..937d31dc8566e1208dd0e14e8618403daa536057 100644 (file)
@@ -224,7 +224,6 @@ static const struct bin_table bin_net_ipv4_route_table[] = {
        { CTL_INT,      NET_IPV4_ROUTE_MTU_EXPIRES,             "mtu_expires" },
        { CTL_INT,      NET_IPV4_ROUTE_MIN_PMTU,                "min_pmtu" },
        { CTL_INT,      NET_IPV4_ROUTE_MIN_ADVMSS,              "min_adv_mss" },
-       { CTL_INT,      NET_IPV4_ROUTE_SECRET_INTERVAL,         "secret_interval" },
        {}
 };
 
index 9ed7c0e7dc1759972f6c323085a0f10f1d38d31d..941f2a324d3aed7ef68bb2173eb3f562d49a104a 100644 (file)
@@ -576,7 +576,7 @@ int garp_init_applicant(struct net_device *dev, struct garp_application *appl)
        if (!app)
                goto err2;
 
-       err = dev_mc_add(dev, appl->proto.group_address, ETH_ALEN, 0);
+       err = dev_mc_add(dev, appl->proto.group_address);
        if (err < 0)
                goto err3;
 
@@ -616,7 +616,7 @@ void garp_uninit_applicant(struct net_device *dev, struct garp_application *appl
        garp_pdu_queue(app);
        garp_queue_xmit(app);
 
-       dev_mc_delete(dev, appl->proto.group_address, ETH_ALEN, 0);
+       dev_mc_del(dev, appl->proto.group_address);
        kfree(app);
        garp_release_port(dev);
 }
index 97da977c2a23338e57fb8b8a11db3f2a4d47965d..3c1c8c14e929d689104035727a462d5d6f9f18d8 100644 (file)
@@ -357,13 +357,13 @@ static void vlan_sync_address(struct net_device *dev,
         * the new address */
        if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_delete(dev, vlandev->dev_addr);
+               dev_uc_del(dev, vlandev->dev_addr);
 
        /* vlan address was equal to the old address and is different from
         * the new address */
        if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
            compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
-               dev_unicast_add(dev, vlandev->dev_addr);
+               dev_uc_add(dev, vlandev->dev_addr);
 
        memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
 }
@@ -533,6 +533,10 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                }
                unregister_netdevice_many(&list);
                break;
+
+       case NETDEV_PRE_TYPE_CHANGE:
+               /* Forbid underlaying device to change its type. */
+               return NOTIFY_BAD;
        }
 
 out:
index c584a0af77d3efaf436a1cc07413fcfa31f442e1..bd537fc10254c9fbb6cf3872e8488bba1809781b 100644 (file)
@@ -61,7 +61,7 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb)
                                        dev->dev_addr))
                        skb->pkt_type = PACKET_HOST;
                break;
-       };
+       }
        return 0;
 }
 
index 29b6348c8d4d6f280c3e349a6518c6b5ce3d75c1..55be90826f5fd1317f961b9fbabb3f3b989f380e 100644 (file)
@@ -327,7 +327,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
        len = skb->len;
        ret = dev_queue_xmit(skb);
 
-       if (likely(ret == NET_XMIT_SUCCESS)) {
+       if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
                txq->tx_packets++;
                txq->tx_bytes += len;
        } else
@@ -353,7 +353,7 @@ static netdev_tx_t vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb,
        len = skb->len;
        ret = dev_queue_xmit(skb);
 
-       if (likely(ret == NET_XMIT_SUCCESS)) {
+       if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
                txq->tx_packets++;
                txq->tx_bytes += len;
        } else
@@ -470,7 +470,7 @@ static int vlan_dev_open(struct net_device *dev)
                return -ENETDOWN;
 
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
-               err = dev_unicast_add(real_dev, dev->dev_addr);
+               err = dev_uc_add(real_dev, dev->dev_addr);
                if (err < 0)
                        goto out;
        }
@@ -499,7 +499,7 @@ clear_allmulti:
                dev_set_allmulti(real_dev, -1);
 del_unicast:
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
-               dev_unicast_delete(real_dev, dev->dev_addr);
+               dev_uc_del(real_dev, dev->dev_addr);
 out:
        netif_carrier_off(dev);
        return err;
@@ -514,14 +514,14 @@ static int vlan_dev_stop(struct net_device *dev)
                vlan_gvrp_request_leave(dev);
 
        dev_mc_unsync(real_dev, dev);
-       dev_unicast_unsync(real_dev, dev);
+       dev_uc_unsync(real_dev, dev);
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(real_dev, -1);
        if (dev->flags & IFF_PROMISC)
                dev_set_promiscuity(real_dev, -1);
 
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
-               dev_unicast_delete(real_dev, dev->dev_addr);
+               dev_uc_del(real_dev, dev->dev_addr);
 
        netif_carrier_off(dev);
        return 0;
@@ -540,13 +540,13 @@ static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
                goto out;
 
        if (compare_ether_addr(addr->sa_data, real_dev->dev_addr)) {
-               err = dev_unicast_add(real_dev, addr->sa_data);
+               err = dev_uc_add(real_dev, addr->sa_data);
                if (err < 0)
                        return err;
        }
 
        if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
-               dev_unicast_delete(real_dev, dev->dev_addr);
+               dev_uc_del(real_dev, dev->dev_addr);
 
 out:
        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
@@ -663,7 +663,7 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change)
 static void vlan_dev_set_rx_mode(struct net_device *vlan_dev)
 {
        dev_mc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
-       dev_unicast_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
+       dev_uc_sync(vlan_dev_info(vlan_dev)->real_dev, vlan_dev);
 }
 
 /*
index 041101ab4aa55b6ceec057e40c007ae57ff409ba..0ea20c30466c7b5758e419fd51c3cba70c9797d7 100644 (file)
@@ -308,7 +308,6 @@ handle_recv(struct p9_client *client, struct p9_trans_rdma *rdma,
                   req, err, status);
        rdma->state = P9_RDMA_FLUSHING;
        client->status = Disconnected;
-       return;
 }
 
 static void
index 041c35edb763dd96b266f89b8080cb694a87bbf4..0d68b40fc0e625d79aece260f08952c1ac374987 100644 (file)
@@ -186,6 +186,7 @@ source "net/sctp/Kconfig"
 source "net/rds/Kconfig"
 source "net/tipc/Kconfig"
 source "net/atm/Kconfig"
+source "net/l2tp/Kconfig"
 source "net/802/Kconfig"
 source "net/bridge/Kconfig"
 source "net/dsa/Kconfig"
@@ -203,6 +204,11 @@ source "net/ieee802154/Kconfig"
 source "net/sched/Kconfig"
 source "net/dcb/Kconfig"
 
+config RPS
+       boolean
+       depends on SMP && SYSFS
+       default y
+
 menu "Network testing"
 
 config NET_PKTGEN
@@ -275,5 +281,7 @@ source "net/wimax/Kconfig"
 
 source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
+source "net/caif/Kconfig"
+
 
 endif   # if NET
index 1542e7268a7baa01ee4a6cb6d620a849057e795c..cb7bdc1210cbeec5be41916d8fb052b2929cf054 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_BT)              += bluetooth/
 obj-$(CONFIG_SUNRPC)           += sunrpc/
 obj-$(CONFIG_AF_RXRPC)         += rxrpc/
 obj-$(CONFIG_ATM)              += atm/
+obj-$(CONFIG_L2TP)             += l2tp/
 obj-$(CONFIG_DECNET)           += decnet/
 obj-$(CONFIG_ECONET)           += econet/
 obj-$(CONFIG_PHONET)           += phonet/
@@ -56,6 +57,7 @@ obj-$(CONFIG_NETLABEL)                += netlabel/
 obj-$(CONFIG_IUCV)             += iucv/
 obj-$(CONFIG_RFKILL)           += rfkill/
 obj-$(CONFIG_NET_9P)           += 9p/
+obj-$(CONFIG_CAIF)             += caif/
 ifneq ($(CONFIG_DCB),)
 obj-y                          += dcb/
 endif
index 7b02967fbbe7dcf0a2138059b44967c4f0cc9375..c410b93fda2ecde367bf1815dda21ccbbff36823 100644 (file)
@@ -782,7 +782,7 @@ static int atif_ioctl(int cmd, void __user *arg)
                                                atrtr_create(&rtdef, dev);
                                        }
                        }
-                       dev_mc_add(dev, aarp_mcast, 6, 1);
+                       dev_mc_add_global(dev, aarp_mcast);
                        return 0;
 
                case SIOCGIFADDR:
index d6c7ceaf13e969171eb96fb54e5a7ea2ed03844e..6719af6a59fada591a8bc9e912cab196de5a6c81 100644 (file)
@@ -446,7 +446,6 @@ error:
        net_dev->stats.rx_errors++;
 free_skb:
        dev_kfree_skb(skb);
-       return;
 }
 
 /*
index 97ed94aa0cbceb3623b91e918fd886f353793aab..b43feb1a3995f77a75d0c445859ab70030c2f477 100644 (file)
@@ -90,10 +90,13 @@ static void vcc_sock_destruct(struct sock *sk)
 
 static void vcc_def_wakeup(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
-       if (sk_has_sleeper(sk))
-               wake_up(sk->sk_sleep);
-       read_unlock(&sk->sk_callback_lock);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up(&wq->wait);
+       rcu_read_unlock();
 }
 
 static inline int vcc_writable(struct sock *sk)
@@ -106,16 +109,19 @@ static inline int vcc_writable(struct sock *sk)
 
 static void vcc_write_space(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
 
        if (vcc_writable(sk)) {
-               if (sk_has_sleeper(sk))
-                       wake_up_interruptible(sk->sk_sleep);
+               wq = rcu_dereference(sk->sk_wq);
+               if (wq_has_sleeper(wq))
+                       wake_up_interruptible(&wq->wait);
 
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
 
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 static struct proto vcc_proto = {
@@ -549,7 +555,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);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        error = 0;
        while (!(skb = alloc_tx(vcc, eff))) {
                if (m->msg_flags & MSG_DONTWAIT) {
@@ -568,9 +574,9 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                        send_sig(SIGPIPE, current, 0);
                        break;
                }
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (error)
                goto out;
        skb->dev = NULL; /* for paths shared with net_device interfaces */
@@ -595,7 +601,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct atm_vcc *vcc;
        unsigned int mask;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        vcc = ATM_SD(sock);
index feeaf5718472ec076bfd01c866f04f0e9e3b83ea..d98bde1a0ac8ffafb95ef961382a51e2d2c179cb 100644 (file)
@@ -161,8 +161,6 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
                skb_queue_tail(&sk->sk_receive_queue, skb2);
                sk->sk_data_ready(sk, skb2->len);
        }
-
-       return;
 }
 #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
 
@@ -640,7 +638,6 @@ static void lec_set_multicast_list(struct net_device *dev)
         * by default, all multicast frames arrive over the bus.
         * eventually support selective multicast service
         */
-       return;
 }
 
 static const struct net_device_ops lec_netdev_ops = {
@@ -1199,8 +1196,6 @@ static void __exit lane_module_cleanup(void)
                        dev_lec[i] = NULL;
                }
        }
-
-       return;
 }
 
 module_init(lane_module_init);
@@ -1334,7 +1329,6 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr,
                priv->lane2_ops->associate_indicator(dev, mac_addr,
                                                     tlvs, sizeoftlvs);
        }
-       return;
 }
 
 /*
index 436f2e177657e7b184c7afe5c467f97cbcc420cd..622b471e14e03dbc3752697851022a59aebffbe0 100644 (file)
@@ -455,7 +455,6 @@ static void lane2_assoc_ind(struct net_device *dev, const u8 *mac_addr,
        if (end_of_tlvs - tlvs != 0)
                pr_info("(%s) ignoring %Zd bytes of trailing TLV garbage\n",
                        dev->name, end_of_tlvs - tlvs);
-       return;
 }
 
 /*
@@ -684,8 +683,6 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev)
 
        if (in_entry == NULL && eg_entry == NULL)
                dprintk("(%s) unused vcc closed\n", dev->name);
-
-       return;
 }
 
 static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
@@ -783,8 +780,6 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)
 
        memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
        netif_rx(new_skb);
-
-       return;
 }
 
 static struct atmdev_ops mpc_ops = { /* only send is required */
@@ -873,8 +868,6 @@ static void send_set_mps_ctrl_addr(const char *addr, struct mpoa_client *mpc)
        mesg.type = SET_MPS_CTRL_ADDR;
        memcpy(mesg.MPS_ctrl, addr, ATM_ESA_LEN);
        msg_to_mpoad(&mesg, mpc);
-
-       return;
 }
 
 static void mpoad_close(struct atm_vcc *vcc)
@@ -911,8 +904,6 @@ static void mpoad_close(struct atm_vcc *vcc)
        pr_info("(%s) going down\n",
                (mpc->dev) ? mpc->dev->name : "<unknown>");
        module_put(THIS_MODULE);
-
-       return;
 }
 
 /*
@@ -1122,7 +1113,6 @@ static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        pr_info("(%s) entry already in resolving state\n",
                (mpc->dev) ? mpc->dev->name : "<unknown>");
        mpc->in_ops->put(entry);
-       return;
 }
 
 /*
@@ -1166,7 +1156,6 @@ static void check_qos_and_open_shortcut(struct k_message *msg,
        } else
                memset(&msg->qos, 0, sizeof(struct atm_qos));
        msg_to_mpoad(msg, client);
-       return;
 }
 
 static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc)
@@ -1240,8 +1229,6 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
                mpc->in_ops->put(entry);
                entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
        } while (entry != NULL);
-
-       return;
 }
 
 static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
@@ -1260,8 +1247,6 @@ static void egress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
        write_unlock_irq(&mpc->egress_lock);
 
        mpc->eg_ops->put(entry);
-
-       return;
 }
 
 static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
@@ -1295,8 +1280,6 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)
        skb_queue_tail(&sk->sk_receive_queue, skb);
        sk->sk_data_ready(sk, skb->len);
        dprintk("exiting\n");
-
-       return;
 }
 
 /*
@@ -1325,8 +1308,6 @@ static void mps_death(struct k_message *msg, struct mpoa_client *mpc)
 
        mpc->in_ops->destroy_cache(mpc);
        mpc->eg_ops->destroy_cache(mpc);
-
-       return;
 }
 
 static void MPOA_cache_impos_rcvd(struct k_message *msg,
@@ -1353,8 +1334,6 @@ static void MPOA_cache_impos_rcvd(struct k_message *msg,
        write_unlock_irq(&mpc->egress_lock);
 
        mpc->eg_ops->put(entry);
-
-       return;
 }
 
 static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg,
@@ -1392,8 +1371,6 @@ static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg,
                        pr_info("(%s) targetless LE_ARP request failed\n",
                                mpc->dev->name);
        }
-
-       return;
 }
 
 static void set_mps_mac_addr_rcvd(struct k_message *msg,
@@ -1409,8 +1386,6 @@ static void set_mps_mac_addr_rcvd(struct k_message *msg,
                return;
        }
        client->number_of_mps_macs = 1;
-
-       return;
 }
 
 /*
@@ -1436,7 +1411,6 @@ static void clean_up(struct k_message *msg, struct mpoa_client *mpc, int action)
 
        msg->type = action;
        msg_to_mpoad(msg, mpc);
-       return;
 }
 
 static void mpc_timer_refresh(void)
@@ -1445,8 +1419,6 @@ static void mpc_timer_refresh(void)
        mpc_timer.data = mpc_timer.expires;
        mpc_timer.function = mpc_cache_check;
        add_timer(&mpc_timer);
-
-       return;
 }
 
 static void mpc_cache_check(unsigned long checking_time)
@@ -1471,8 +1443,6 @@ static void mpc_cache_check(unsigned long checking_time)
                mpc = mpc->next;
        }
        mpc_timer_refresh();
-
-       return;
 }
 
 static int atm_mpoa_ioctl(struct socket *sock, unsigned int cmd,
@@ -1561,8 +1531,6 @@ static void __exit atm_mpoa_cleanup(void)
                kfree(qos);
                qos = nextqos;
        }
-
-       return;
 }
 
 module_init(atm_mpoa_init);
index e773d8336918b021eeeea82e409fba657f564ab1..d1b2d9a0314412570f770ce4630ee08e8f5b229c 100644 (file)
@@ -182,8 +182,6 @@ static void in_cache_put(in_cache_entry *entry)
                memset(entry, 0, sizeof(in_cache_entry));
                kfree(entry);
        }
-
-       return;
 }
 
 /*
@@ -221,8 +219,6 @@ static void in_cache_remove_entry(in_cache_entry *entry,
                }
                vcc_release_async(vcc, -EPIPE);
        }
-
-       return;
 }
 
 /* Call this every MPC-p2 seconds... Not exactly correct solution,
@@ -248,8 +244,6 @@ static void clear_count_and_expired(struct mpoa_client *client)
                entry = next_entry;
        }
        write_unlock_bh(&client->ingress_lock);
-
-       return;
 }
 
 /* Call this every MPC-p4 seconds. */
@@ -334,8 +328,6 @@ static void in_destroy_cache(struct mpoa_client *mpc)
        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,
@@ -427,8 +419,6 @@ static void eg_cache_put(eg_cache_entry *entry)
                memset(entry, 0, sizeof(eg_cache_entry));
                kfree(entry);
        }
-
-       return;
 }
 
 /*
@@ -463,8 +453,6 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
                }
                vcc_release_async(vcc, -EPIPE);
        }
-
-       return;
 }
 
 static eg_cache_entry *eg_cache_add_entry(struct k_message *msg,
@@ -509,8 +497,6 @@ static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time)
        do_gettimeofday(&(entry->tv));
        entry->entry_state = EGRESS_RESOLVED;
        entry->ctrl_info.holding_time = holding_time;
-
-       return;
 }
 
 static void clear_expired(struct mpoa_client *client)
@@ -537,8 +523,6 @@ static void clear_expired(struct mpoa_client *client)
                entry = next_entry;
        }
        write_unlock_irq(&client->egress_lock);
-
-       return;
 }
 
 static void eg_destroy_cache(struct mpoa_client *mpc)
@@ -547,8 +531,6 @@ static void eg_destroy_cache(struct mpoa_client *mpc)
        while (mpc->eg_cache != NULL)
                mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
        write_unlock_irq(&mpc->egress_lock);
-
-       return;
 }
 
 
@@ -584,6 +566,4 @@ void atm_mpoa_init_cache(struct mpoa_client *mpc)
 {
        mpc->in_ops = &ingress_ops;
        mpc->eg_ops = &egress_ops;
-
-       return;
 }
index 696e218436e5ec3de66b9bb63e06d70c31ab427d..6262aeae398e8a242eae84f70287b7f07f5768c3 100644 (file)
@@ -407,7 +407,6 @@ EXPORT_SYMBOL(atm_proc_root);
 
 int atm_proc_dev_register(struct atm_dev *dev)
 {
-       int digits, num;
        int error;
 
        /* No proc info */
@@ -415,16 +414,9 @@ int atm_proc_dev_register(struct atm_dev *dev)
                return 0;
 
        error = -ENOMEM;
-       digits = 0;
-       for (num = dev->number; num; num /= 10)
-               digits++;
-       if (!digits)
-               digits++;
-
-       dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_KERNEL);
+       dev->proc_name = kasprintf(GFP_KERNEL, "%s:%d", dev->type, dev->number);
        if (!dev->proc_name)
                goto err_out;
-       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);
index 6ba6e466ee545af605264c45eea340cb9b27e1cd..509c8ac02b63cdb91677049d6c304ee4c9f10399 100644 (file)
@@ -131,7 +131,7 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
                }
                sk->sk_ack_backlog++;
                skb_queue_tail(&sk->sk_receive_queue, skb);
-               pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
+               pr_debug("waking sk_sleep(sk) 0x%p\n", sk_sleep(sk));
                sk->sk_state_change(sk);
 as_indicate_complete:
                release_sock(sk);
index 3ba9a45a51acaffd9b26ddb9f2c5115429de6fc4..754ee4791d966d46843798be0f5b5865ed0f519d 100644 (file)
@@ -49,14 +49,14 @@ static void svc_disconnect(struct atm_vcc *vcc)
 
        pr_debug("%p\n", vcc);
        if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
                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,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_UNINTERRUPTIBLE);
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
        }
        /* beware - socket is still in use by atmsigd until the last
           as_indicate has been answered */
@@ -125,13 +125,13 @@ static int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
        }
        vcc->local = *addr;
        set_bit(ATM_VF_WAITING, &vcc->flags);
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
        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);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
        if (!sigd) {
                error = -EUNATCH;
@@ -201,10 +201,10 @@ 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);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
                if (flags & O_NONBLOCK) {
-                       finish_wait(sk->sk_sleep, &wait);
+                       finish_wait(sk_sleep(sk), &wait);
                        sock->state = SS_CONNECTING;
                        error = -EINPROGRESS;
                        goto out;
@@ -213,7 +213,7 @@ 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,
+                               prepare_to_wait(sk_sleep(sk), &wait,
                                                TASK_INTERRUPTIBLE);
                                continue;
                        }
@@ -232,14 +232,14 @@ static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
                         */
                        sigd_enq(vcc, as_close, NULL, NULL, NULL);
                        while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
-                               prepare_to_wait(sk->sk_sleep, &wait,
+                               prepare_to_wait(sk_sleep(sk), &wait,
                                                TASK_INTERRUPTIBLE);
                                schedule();
                        }
                        if (!sk->sk_err)
                                while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
                                       sigd) {
-                                       prepare_to_wait(sk->sk_sleep, &wait,
+                                       prepare_to_wait(sk_sleep(sk), &wait,
                                                        TASK_INTERRUPTIBLE);
                                        schedule();
                                }
@@ -250,7 +250,7 @@ static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
                        error = -EINTR;
                        break;
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
                if (error)
                        goto out;
                if (!sigd) {
@@ -302,13 +302,13 @@ static int svc_listen(struct socket *sock, int backlog)
                goto out;
        }
        set_bit(ATM_VF_WAITING, &vcc->flags);
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
        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);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (!sigd) {
                error = -EUNATCH;
                goto out;
@@ -343,7 +343,7 @@ static int svc_accept(struct socket *sock, struct socket *newsock, int flags)
        while (1) {
                DEFINE_WAIT(wait);
 
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
                       sigd) {
                        if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
@@ -363,10 +363,10 @@ static int svc_accept(struct socket *sock, struct socket *newsock, int flags)
                                error = -ERESTARTSYS;
                                break;
                        }
-                       prepare_to_wait(sk->sk_sleep, &wait,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_INTERRUPTIBLE);
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
                if (error)
                        goto out;
                if (!skb) {
@@ -392,17 +392,17 @@ static int svc_accept(struct socket *sock, struct socket *newsock, int flags)
                }
                /* 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,
+               prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &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,
+                       prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
                                        TASK_UNINTERRUPTIBLE);
                }
-               finish_wait(sk_atm(new_vcc)->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk_atm(new_vcc)), &wait);
                if (!sigd) {
                        error = -EUNATCH;
                        goto out;
@@ -438,14 +438,14 @@ int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
        DEFINE_WAIT(wait);
 
        set_bit(ATM_VF_WAITING, &vcc->flags);
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
        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);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (!sigd)
                return -EUNATCH;
        return -sk->sk_err;
@@ -534,20 +534,20 @@ static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
 
        lock_sock(sk);
        set_bit(ATM_VF_WAITING, &vcc->flags);
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        sigd_enq(vcc, as_addparty, NULL, NULL,
                 (struct sockaddr_atmsvc *) sockaddr);
        if (flags & O_NONBLOCK) {
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
                error = -EINPROGRESS;
                goto out;
        }
        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);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        error = xchg(&sk->sk_err_soft, 0);
 out:
        release_sock(sk);
@@ -563,13 +563,13 @@ static int svc_dropparty(struct socket *sock, int ep_ref)
 
        lock_sock(sk);
        set_bit(ATM_VF_WAITING, &vcc->flags);
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
        while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
                schedule();
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (!sigd) {
                error = -EUNATCH;
                goto out;
index 65c5801261f949b206d242e65f0c36ff7265cb54..cfdfd7e2a1726b1399633bdcb6625a6a5731a310 100644 (file)
@@ -1281,7 +1281,7 @@ static int __must_check ax25_connect(struct socket *sock,
                DEFINE_WAIT(wait);
 
                for (;;) {
-                       prepare_to_wait(sk->sk_sleep, &wait,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
@@ -1294,7 +1294,7 @@ static int __must_check ax25_connect(struct socket *sock,
                        err = -ERESTARTSYS;
                        break;
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
 
                if (err)
                        goto out_release;
@@ -1346,7 +1346,7 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
         *      hooked into the SABM we saved
         */
        for (;;) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                skb = skb_dequeue(&sk->sk_receive_queue);
                if (skb)
                        break;
@@ -1364,7 +1364,7 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
                err = -ERESTARTSYS;
                break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
 
        if (err)
                goto out;
index ed371684c133d184e9d68f87b85ea171f6107a13..ee3b3049d385839297d7a87e53fde0d6b5ec8456 100644 (file)
@@ -43,6 +43,19 @@ config BT_L2CAP
          Say Y here to compile L2CAP support into the kernel or say M to
          compile it as module (l2cap).
 
+config BT_L2CAP_EXT_FEATURES
+       bool "L2CAP Extended Features support (EXPERIMENTAL)"
+       depends on BT_L2CAP && EXPERIMENTAL
+       help
+         This option enables the L2CAP Extended Features support. These
+         new features include the Enhanced Retransmission and Streaming
+         Modes, the Frame Check Sequence (FCS), and Segmentation and
+         Reassembly (SAR) for L2CAP packets. They are a required for the
+         new Alternate MAC/PHY and the Bluetooth Medical Profile.
+
+         You should say N unless you know what you are doing. Note that
+         this is in an experimental state yet.
+
 config BT_SCO
        tristate "SCO links support"
        depends on BT
index 404a8500fd031b254b0049a6c97b8ff6f7805675..421c45bd1b95232e0a4ac7a282fdaeabd18fb21d 100644 (file)
@@ -288,7 +288,7 @@ unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *w
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
-       poll_wait(file, sk->sk_sleep, wait);
+       poll_wait(file, sk_sleep(sk), wait);
 
        if (sk->sk_state == BT_LISTEN)
                return bt_accept_poll(sk);
@@ -378,7 +378,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
 
        BT_DBG("sk %p", sk);
 
-       add_wait_queue(sk->sk_sleep, &wait);
+       add_wait_queue(sk_sleep(sk), &wait);
        while (sk->sk_state != state) {
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -401,7 +401,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
                        break;
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
        return err;
 }
 EXPORT_SYMBOL(bt_sock_wait_state);
index 8062dad6d10d0c83afd345d1f4c0ea8532d41b9a..f10b41fb05a0e1cd51ebae02320f755c249ef0a3 100644 (file)
@@ -474,7 +474,7 @@ static int bnep_session(void *arg)
        set_user_nice(current, -15);
 
        init_waitqueue_entry(&wait, current);
-       add_wait_queue(sk->sk_sleep, &wait);
+       add_wait_queue(sk_sleep(sk), &wait);
        while (!atomic_read(&s->killed)) {
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -496,7 +496,7 @@ static int bnep_session(void *arg)
                schedule();
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        /* Cleanup session */
        down_write(&bnep_session_sem);
@@ -507,7 +507,7 @@ static int bnep_session(void *arg)
        /* Wakeup user-space polling for socket errors */
        s->sock->sk->sk_err = EUNATCH;
 
-       wake_up_interruptible(s->sock->sk->sk_sleep);
+       wake_up_interruptible(sk_sleep(s->sock->sk));
 
        /* Release the socket */
        fput(s->sock->file);
@@ -638,7 +638,7 @@ int bnep_del_connection(struct bnep_conndel_req *req)
 
                /* Kill session thread */
                atomic_inc(&s->killed);
-               wake_up_interruptible(s->sock->sk->sk_sleep);
+               wake_up_interruptible(sk_sleep(s->sock->sk));
        } else
                err = -ENOENT;
 
index 5643a2391e76979e6de26e589debb2580555612f..0faad5ce6dc480efe1928c1c60728e14b4093b92 100644 (file)
@@ -88,7 +88,7 @@ static void bnep_net_set_mc_list(struct net_device *dev)
                memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
                r->len = htons(ETH_ALEN * 2);
        } else {
-               struct dev_mc_list *dmi = dev->mc_list;
+               struct netdev_hw_addr *ha;
                int i, len = skb->len;
 
                if (dev->flags & IFF_BROADCAST) {
@@ -98,18 +98,18 @@ static void bnep_net_set_mc_list(struct net_device *dev)
 
                /* FIXME: We should group addresses here. */
 
-               for (i = 0;
-                    i < netdev_mc_count(dev) && i < BNEP_MAX_MULTICAST_FILTERS;
-                    i++) {
-                       memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-                       memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
-                       dmi = dmi->next;
+               i = 0;
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (i == BNEP_MAX_MULTICAST_FILTERS)
+                               break;
+                       memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
+                       memcpy(__skb_put(skb, ETH_ALEN), ha->addr, ETH_ALEN);
                }
                r->len = htons(skb->len - len);
        }
 
        skb_queue_tail(&sk->sk_write_queue, skb);
-       wake_up_interruptible(sk->sk_sleep);
+       wake_up_interruptible(sk_sleep(sk));
 #endif
 }
 
@@ -193,11 +193,11 @@ static netdev_tx_t bnep_net_xmit(struct sk_buff *skb,
        /*
         * We cannot send L2CAP packets from here as we are potentially in a bh.
         * So we have to queue them and wake up session thread which is sleeping
-        * on the sk->sk_sleep.
+        * on the sk_sleep(sk).
         */
        dev->trans_start = jiffies;
        skb_queue_tail(&sk->sk_write_queue, skb);
-       wake_up_interruptible(sk->sk_sleep);
+       wake_up_interruptible(sk_sleep(sk));
 
        if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) {
                BT_DBG("tx queue is full");
index e4663aa14d264830d528c8fdc109ff3381da5e59..785e79e953c5852a309739b878bfe7445ad530eb 100644 (file)
@@ -125,7 +125,7 @@ static inline void cmtp_schedule(struct cmtp_session *session)
 {
        struct sock *sk = session->sock->sk;
 
-       wake_up_interruptible(sk->sk_sleep);
+       wake_up_interruptible(sk_sleep(sk));
 }
 
 /* CMTP init defines */
index 0073ec8495da2e1ff04ad1266a1f2a815a3cc10d..d4c6af082d488f025ff22664fe7274370a2bb061 100644 (file)
@@ -284,7 +284,7 @@ static int cmtp_session(void *arg)
        set_user_nice(current, -15);
 
        init_waitqueue_entry(&wait, current);
-       add_wait_queue(sk->sk_sleep, &wait);
+       add_wait_queue(sk_sleep(sk), &wait);
        while (!atomic_read(&session->terminate)) {
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -301,7 +301,7 @@ static int cmtp_session(void *arg)
                schedule();
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        down_write(&cmtp_session_sem);
 
index 4ad23192c7a52dfd5ce76734c12d6541b8295c5d..2f768de8701178091008cca90346647790fe6706 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/fcntl.h>
 #include <linux/init.h>
 #include <linux/skbuff.h>
+#include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/rfkill.h>
@@ -928,6 +929,10 @@ int hci_register_dev(struct hci_dev *hdev)
 
        write_unlock_bh(&hci_dev_list_lock);
 
+       hdev->workqueue = create_singlethread_workqueue(hdev->name);
+       if (!hdev->workqueue)
+               goto nomem;
+
        hci_register_sysfs(hdev);
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
@@ -942,6 +947,13 @@ int hci_register_dev(struct hci_dev *hdev)
        hci_notify(hdev, HCI_DEV_REG);
 
        return id;
+
+nomem:
+       write_lock_bh(&hci_dev_list_lock);
+       list_del(&hdev->list);
+       write_unlock_bh(&hci_dev_list_lock);
+
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(hci_register_dev);
 
@@ -970,6 +982,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
 
        hci_unregister_sysfs(hdev);
 
+       destroy_workqueue(hdev->workqueue);
+
        __hci_dev_put(hdev);
 
        return 0;
@@ -1260,7 +1274,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
@@ -1302,24 +1316,17 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
        }
 
        tasklet_schedule(&hdev->tx_task);
-
-       return 0;
 }
 EXPORT_SYMBOL(hci_send_acl);
 
 /* Send SCO data */
-int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
+void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_sco_hdr hdr;
 
        BT_DBG("%s len %d", hdev->name, skb->len);
 
-       if (skb->len > hdev->sco_mtu) {
-               kfree_skb(skb);
-               return -EINVAL;
-       }
-
        hdr.handle = cpu_to_le16(conn->handle);
        hdr.dlen   = skb->len;
 
@@ -1332,8 +1339,6 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
 
        skb_queue_tail(&conn->data_q, skb);
        tasklet_schedule(&hdev->tx_task);
-
-       return 0;
 }
 EXPORT_SYMBOL(hci_send_sco);
 
index 0e8e1a59856c40ffe5b1cde05d6bd6321febc24a..463ffa4fe042dee7539205ee4fb7e713fa145f1c 100644 (file)
@@ -14,8 +14,6 @@ static struct class *bt_class;
 struct dentry *bt_debugfs = NULL;
 EXPORT_SYMBOL_GPL(bt_debugfs);
 
-static struct workqueue_struct *bt_workq;
-
 static inline char *link_typetostr(int type)
 {
        switch (type) {
@@ -161,14 +159,14 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
 {
        BT_DBG("conn %p", conn);
 
-       queue_work(bt_workq, &conn->work_add);
+       queue_work(conn->hdev->workqueue, &conn->work_add);
 }
 
 void hci_conn_del_sysfs(struct hci_conn *conn)
 {
        BT_DBG("conn %p", conn);
 
-       queue_work(bt_workq, &conn->work_del);
+       queue_work(conn->hdev->workqueue, &conn->work_del);
 }
 
 static inline char *host_bustostr(int bus)
@@ -283,11 +281,9 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at
 static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
-       char *ptr;
-       __u32 val;
+       unsigned long val;
 
-       val = simple_strtoul(buf, &ptr, 10);
-       if (ptr == buf)
+       if (strict_strtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        if (val != 0 && (val < 500 || val > 3600000))
@@ -307,11 +303,9 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu
 static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
-       char *ptr;
-       __u16 val;
+       unsigned long val;
 
-       val = simple_strtoul(buf, &ptr, 10);
-       if (ptr == buf)
+       if (strict_strtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        if (val < 0x0002 || val > 0xFFFE || val % 2)
@@ -334,11 +328,9 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu
 static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct hci_dev *hdev = dev_get_drvdata(dev);
-       char *ptr;
-       __u16 val;
+       unsigned long val;
 
-       val = simple_strtoul(buf, &ptr, 10);
-       if (ptr == buf)
+       if (strict_strtoul(buf, 0, &val) < 0)
                return -EINVAL;
 
        if (val < 0x0002 || val > 0xFFFE || val % 2)
@@ -487,17 +479,11 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
 
 int __init bt_sysfs_init(void)
 {
-       bt_workq = create_singlethread_workqueue("bluetooth");
-       if (!bt_workq)
-               return -ENOMEM;
-
        bt_debugfs = debugfs_create_dir("bluetooth", NULL);
 
        bt_class = class_create(THIS_MODULE, "bluetooth");
-       if (IS_ERR(bt_class)) {
-               destroy_workqueue(bt_workq);
+       if (IS_ERR(bt_class))
                return PTR_ERR(bt_class);
-       }
 
        return 0;
 }
@@ -507,6 +493,4 @@ void bt_sysfs_cleanup(void)
        class_destroy(bt_class);
 
        debugfs_remove_recursive(bt_debugfs);
-
-       destroy_workqueue(bt_workq);
 }
index 280529ad9274afe107dc4b566f25768c4c044d73..bfe641b7dfaf0e0ba70fa604ebffec7155cbaec8 100644 (file)
@@ -561,8 +561,8 @@ static int hidp_session(void *arg)
 
        init_waitqueue_entry(&ctrl_wait, current);
        init_waitqueue_entry(&intr_wait, current);
-       add_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
-       add_wait_queue(intr_sk->sk_sleep, &intr_wait);
+       add_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
+       add_wait_queue(sk_sleep(intr_sk), &intr_wait);
        while (!atomic_read(&session->terminate)) {
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -584,8 +584,8 @@ static int hidp_session(void *arg)
                schedule();
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(intr_sk->sk_sleep, &intr_wait);
-       remove_wait_queue(ctrl_sk->sk_sleep, &ctrl_wait);
+       remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
+       remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
 
        down_write(&hidp_session_sem);
 
@@ -609,7 +609,7 @@ static int hidp_session(void *arg)
 
        fput(session->intr_sock->file);
 
-       wait_event_timeout(*(ctrl_sk->sk_sleep),
+       wait_event_timeout(*(sk_sleep(ctrl_sk)),
                (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
 
        fput(session->ctrl_sock->file);
index a4e215d50c10ba23190c402f9b3d66a27d454bcb..8d934a19da0a422c395ca93d400e53203a4c8627 100644 (file)
@@ -164,8 +164,8 @@ static inline void hidp_schedule(struct hidp_session *session)
        struct sock *ctrl_sk = session->ctrl_sock->sk;
        struct sock *intr_sk = session->intr_sock->sk;
 
-       wake_up_interruptible(ctrl_sk->sk_sleep);
-       wake_up_interruptible(intr_sk->sk_sleep);
+       wake_up_interruptible(sk_sleep(ctrl_sk));
+       wake_up_interruptible(sk_sleep(intr_sk));
 }
 
 /* HIDP init defines */
index 9753b690a8b356b9bd24e88efb45d8d6e2b5ca56..1b682a5aa0616911c2861b5d836c015230922faf 100644 (file)
 
 #define VERSION "2.14"
 
+#ifdef CONFIG_BT_L2CAP_EXT_FEATURES
+static int enable_ertm = 1;
+#else
 static int enable_ertm = 0;
+#endif
 static int max_transmit = L2CAP_DEFAULT_MAX_TX;
+static int tx_window = L2CAP_DEFAULT_TX_WINDOW;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static const struct proto_ops l2cap_sock_ops;
 
+static struct workqueue_struct *_busy_wq;
+
 static struct bt_sock_list l2cap_sk_list = {
        .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
 };
 
+static void l2cap_busy_work(struct work_struct *work);
+
 static void __l2cap_sock_close(struct sock *sk, int reason);
 static void l2cap_sock_close(struct sock *sk);
 static void l2cap_sock_kill(struct sock *sk);
@@ -219,7 +228,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 
        l2cap_pi(sk)->conn = conn;
 
-       if (sk->sk_type == SOCK_SEQPACKET) {
+       if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
                /* Alloc CID for connection-oriented socket */
                l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
        } else if (sk->sk_type == SOCK_DGRAM) {
@@ -325,19 +334,19 @@ static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
        return id;
 }
 
-static inline int l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+static inline void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
 {
        struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
 
        BT_DBG("code 0x%2.2x", code);
 
        if (!skb)
-               return -ENOMEM;
+               return;
 
-       return hci_send_acl(conn->hcon, skb, 0);
+       hci_send_acl(conn->hcon, skb, 0);
 }
 
-static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
+static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
 {
        struct sk_buff *skb;
        struct l2cap_hdr *lh;
@@ -352,9 +361,19 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
        count = min_t(unsigned int, conn->mtu, hlen);
        control |= L2CAP_CTRL_FRAME_TYPE;
 
+       if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+               control |= L2CAP_CTRL_FINAL;
+               pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+       }
+
+       if (pi->conn_state & L2CAP_CONN_SEND_PBIT) {
+               control |= L2CAP_CTRL_POLL;
+               pi->conn_state &= ~L2CAP_CONN_SEND_PBIT;
+       }
+
        skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
-               return -ENOMEM;
+               return;
 
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
@@ -366,19 +385,20 @@ static inline int l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control)
                put_unaligned_le16(fcs, skb_put(skb, 2));
        }
 
-       return hci_send_acl(pi->conn->hcon, skb, 0);
+       hci_send_acl(pi->conn->hcon, skb, 0);
 }
 
-static inline int l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
+static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control)
 {
-       if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY)
+       if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
                control |= L2CAP_SUPER_RCV_NOT_READY;
-       else
+               pi->conn_state |= L2CAP_CONN_RNR_SENT;
+       } else
                control |= L2CAP_SUPER_RCV_READY;
 
        control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
 
-       return l2cap_send_sframe(pi, control);
+       l2cap_send_sframe(pi, control);
 }
 
 static void l2cap_do_start(struct sock *sk)
@@ -437,7 +457,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
 
-               if (sk->sk_type != SOCK_SEQPACKET) {
+               if (sk->sk_type != SOCK_SEQPACKET &&
+                               sk->sk_type != SOCK_STREAM) {
                        bh_unlock_sock(sk);
                        continue;
                }
@@ -497,7 +518,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
                bh_lock_sock(sk);
 
-               if (sk->sk_type != SOCK_SEQPACKET) {
+               if (sk->sk_type != SOCK_SEQPACKET &&
+                               sk->sk_type != SOCK_STREAM) {
                        l2cap_sock_clear_timer(sk);
                        sk->sk_state = BT_CONNECTED;
                        sk->sk_state_change(sk);
@@ -706,7 +728,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
 
        case BT_CONNECTED:
        case BT_CONFIG:
-               if (sk->sk_type == SOCK_SEQPACKET) {
+               if (sk->sk_type == SOCK_SEQPACKET ||
+                               sk->sk_type == SOCK_STREAM) {
                        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 
                        sk->sk_state = BT_DISCONN;
@@ -717,7 +740,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
                break;
 
        case BT_CONNECT2:
-               if (sk->sk_type == SOCK_SEQPACKET) {
+               if (sk->sk_type == SOCK_SEQPACKET ||
+                               sk->sk_type == SOCK_STREAM) {
                        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
                        struct l2cap_conn_rsp rsp;
                        __u16 result;
@@ -772,14 +796,21 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                pi->omtu = l2cap_pi(parent)->omtu;
                pi->mode = l2cap_pi(parent)->mode;
                pi->fcs  = l2cap_pi(parent)->fcs;
+               pi->max_tx = l2cap_pi(parent)->max_tx;
+               pi->tx_win = l2cap_pi(parent)->tx_win;
                pi->sec_level = l2cap_pi(parent)->sec_level;
                pi->role_switch = l2cap_pi(parent)->role_switch;
                pi->force_reliable = l2cap_pi(parent)->force_reliable;
        } else {
                pi->imtu = L2CAP_DEFAULT_MTU;
                pi->omtu = 0;
-               pi->mode = L2CAP_MODE_BASIC;
+               if (enable_ertm && sk->sk_type == SOCK_STREAM)
+                       pi->mode = L2CAP_MODE_ERTM;
+               else
+                       pi->mode = L2CAP_MODE_BASIC;
+               pi->max_tx = max_transmit;
                pi->fcs  = L2CAP_FCS_CRC16;
+               pi->tx_win = tx_window;
                pi->sec_level = BT_SECURITY_LOW;
                pi->role_switch = 0;
                pi->force_reliable = 0;
@@ -790,6 +821,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
        pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
        skb_queue_head_init(TX_QUEUE(sk));
        skb_queue_head_init(SREJ_QUEUE(sk));
+       skb_queue_head_init(BUSY_QUEUE(sk));
        INIT_LIST_HEAD(SREJ_LIST(sk));
 }
 
@@ -833,7 +865,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
 
        sock->state = SS_UNCONNECTED;
 
-       if (sock->type != SOCK_SEQPACKET &&
+       if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
                        sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
                return -ESOCKTNOSUPPORT;
 
@@ -981,7 +1013,8 @@ static int l2cap_do_connect(struct sock *sk)
        l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
 
        if (hcon->state == BT_CONNECTED) {
-               if (sk->sk_type != SOCK_SEQPACKET) {
+               if (sk->sk_type != SOCK_SEQPACKET &&
+                               sk->sk_type != SOCK_STREAM) {
                        l2cap_sock_clear_timer(sk);
                        sk->sk_state = BT_CONNECTED;
                } else
@@ -1015,7 +1048,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
 
        lock_sock(sk);
 
-       if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
+       if ((sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM)
+                       && !la.l2_psm) {
                err = -EINVAL;
                goto done;
        }
@@ -1079,7 +1113,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
 
        lock_sock(sk);
 
-       if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+       if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
+                       || sk->sk_state != BT_BOUND) {
                err = -EBADFD;
                goto done;
        }
@@ -1147,7 +1182,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
        BT_DBG("sk %p timeo %ld", sk, timeo);
 
        /* Wait for an incoming connection. (wake-one). */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(nsk = bt_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -1170,7 +1205,7 @@ static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int fl
                }
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -1207,10 +1242,40 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        return 0;
 }
 
+static int __l2cap_wait_ack(struct sock *sk)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int err = 0;
+       int timeo = HZ/5;
+
+       add_wait_queue(sk_sleep(sk), &wait);
+       while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (!timeo)
+                       timeo = HZ/5;
+
+               if (signal_pending(current)) {
+                       err = sock_intr_errno(timeo);
+                       break;
+               }
+
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock(sk);
+
+               err = sock_error(sk);
+               if (err)
+                       break;
+       }
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(sk_sleep(sk), &wait);
+       return err;
+}
+
 static void l2cap_monitor_timeout(unsigned long arg)
 {
        struct sock *sk = (void *) arg;
-       u16 control;
 
        bh_lock_sock(sk);
        if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) {
@@ -1222,15 +1287,13 @@ static void l2cap_monitor_timeout(unsigned long arg)
        l2cap_pi(sk)->retry_count++;
        __mod_monitor_timer();
 
-       control = L2CAP_CTRL_POLL;
-       l2cap_send_rr_or_rnr(l2cap_pi(sk), control);
+       l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
        bh_unlock_sock(sk);
 }
 
 static void l2cap_retrans_timeout(unsigned long arg)
 {
        struct sock *sk = (void *) arg;
-       u16 control;
 
        bh_lock_sock(sk);
        l2cap_pi(sk)->retry_count = 1;
@@ -1238,8 +1301,7 @@ static void l2cap_retrans_timeout(unsigned long arg)
 
        l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
 
-       control = L2CAP_CTRL_POLL;
-       l2cap_send_rr_or_rnr(l2cap_pi(sk), control);
+       l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL);
        bh_unlock_sock(sk);
 }
 
@@ -1247,7 +1309,8 @@ static void l2cap_drop_acked_frames(struct sock *sk)
 {
        struct sk_buff *skb;
 
-       while ((skb = skb_peek(TX_QUEUE(sk)))) {
+       while ((skb = skb_peek(TX_QUEUE(sk))) &&
+                       l2cap_pi(sk)->unacked_frames) {
                if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq)
                        break;
 
@@ -1259,22 +1322,15 @@ static void l2cap_drop_acked_frames(struct sock *sk)
 
        if (!l2cap_pi(sk)->unacked_frames)
                del_timer(&l2cap_pi(sk)->retrans_timer);
-
-       return;
 }
 
-static inline int l2cap_do_send(struct sock *sk, struct sk_buff *skb)
+static inline void l2cap_do_send(struct sock *sk, struct sk_buff *skb)
 {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
-       int err;
 
        BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len);
 
-       err = hci_send_acl(pi->conn->hcon, skb, 0);
-       if (err < 0)
-               kfree_skb(skb);
-
-       return err;
+       hci_send_acl(pi->conn->hcon, skb, 0);
 }
 
 static int l2cap_streaming_send(struct sock *sk)
@@ -1282,7 +1338,6 @@ static int l2cap_streaming_send(struct sock *sk)
        struct sk_buff *skb, *tx_skb;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        u16 control, fcs;
-       int err;
 
        while ((skb = sk->sk_send_head)) {
                tx_skb = skb_clone(skb, GFP_ATOMIC);
@@ -1291,16 +1346,12 @@ static int l2cap_streaming_send(struct sock *sk)
                control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
-               if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
+               if (pi->fcs == L2CAP_FCS_CRC16) {
                        fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
                        put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
                }
 
-               err = l2cap_do_send(sk, tx_skb);
-               if (err < 0) {
-                       l2cap_send_disconn_req(pi->conn, sk);
-                       return err;
-               }
+               l2cap_do_send(sk, tx_skb);
 
                pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
 
@@ -1315,48 +1366,44 @@ static int l2cap_streaming_send(struct sock *sk)
        return 0;
 }
 
-static int l2cap_retransmit_frame(struct sock *sk, u8 tx_seq)
+static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq)
 {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct sk_buff *skb, *tx_skb;
        u16 control, fcs;
-       int err;
 
        skb = skb_peek(TX_QUEUE(sk));
-       do {
-               if (bt_cb(skb)->tx_seq != tx_seq) {
-                       if (skb_queue_is_last(TX_QUEUE(sk), skb))
-                               break;
-                       skb = skb_queue_next(TX_QUEUE(sk), skb);
-                       continue;
-               }
+       if (!skb)
+               return;
 
-               if (pi->remote_max_tx &&
-                               bt_cb(skb)->retries == pi->remote_max_tx) {
-                       l2cap_send_disconn_req(pi->conn, sk);
+       do {
+               if (bt_cb(skb)->tx_seq == tx_seq)
                        break;
-               }
 
-               tx_skb = skb_clone(skb, GFP_ATOMIC);
-               bt_cb(skb)->retries++;
-               control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-               control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                               | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
-               put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+               if (skb_queue_is_last(TX_QUEUE(sk), skb))
+                       return;
 
-               if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
-                       put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
-               }
+       } while ((skb = skb_queue_next(TX_QUEUE(sk), skb)));
 
-               err = l2cap_do_send(sk, tx_skb);
-               if (err < 0) {
-                       l2cap_send_disconn_req(pi->conn, sk);
-                       return err;
-               }
-               break;
-       } while(1);
-       return 0;
+       if (pi->remote_max_tx &&
+                       bt_cb(skb)->retries == pi->remote_max_tx) {
+               l2cap_send_disconn_req(pi->conn, sk);
+               return;
+       }
+
+       tx_skb = skb_clone(skb, GFP_ATOMIC);
+       bt_cb(skb)->retries++;
+       control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+       control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
+                       | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+       put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+
+       if (pi->fcs == L2CAP_FCS_CRC16) {
+               fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
+               put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+       }
+
+       l2cap_do_send(sk, tx_skb);
 }
 
 static int l2cap_ertm_send(struct sock *sk)
@@ -1364,13 +1411,13 @@ static int l2cap_ertm_send(struct sock *sk)
        struct sk_buff *skb, *tx_skb;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        u16 control, fcs;
-       int err;
+       int nsent = 0;
 
        if (pi->conn_state & L2CAP_CONN_WAIT_F)
                return 0;
 
        while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk)) &&
-              !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
+                       !(pi->conn_state & L2CAP_CONN_REMOTE_BUSY)) {
 
                if (pi->remote_max_tx &&
                                bt_cb(skb)->retries == pi->remote_max_tx) {
@@ -1383,35 +1430,97 @@ static int l2cap_ertm_send(struct sock *sk)
                bt_cb(skb)->retries++;
 
                control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
+               if (pi->conn_state & L2CAP_CONN_SEND_FBIT) {
+                       control |= L2CAP_CTRL_FINAL;
+                       pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+               }
                control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
                                | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
                put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
 
 
-               if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
+               if (pi->fcs == L2CAP_FCS_CRC16) {
                        fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
                        put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
                }
 
-               err = l2cap_do_send(sk, tx_skb);
-               if (err < 0) {
-                       l2cap_send_disconn_req(pi->conn, sk);
-                       return err;
-               }
+               l2cap_do_send(sk, tx_skb);
+
                __mod_retrans_timer();
 
                bt_cb(skb)->tx_seq = pi->next_tx_seq;
                pi->next_tx_seq = (pi->next_tx_seq + 1) % 64;
 
                pi->unacked_frames++;
+               pi->frames_sent++;
 
                if (skb_queue_is_last(TX_QUEUE(sk), skb))
                        sk->sk_send_head = NULL;
                else
                        sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb);
+
+               nsent++;
        }
 
-       return 0;
+       return nsent;
+}
+
+static int l2cap_retransmit_frames(struct sock *sk)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       int ret;
+
+       spin_lock_bh(&pi->send_lock);
+
+       if (!skb_queue_empty(TX_QUEUE(sk)))
+               sk->sk_send_head = TX_QUEUE(sk)->next;
+
+       pi->next_tx_seq = pi->expected_ack_seq;
+       ret = l2cap_ertm_send(sk);
+
+       spin_unlock_bh(&pi->send_lock);
+
+       return ret;
+}
+
+static void l2cap_send_ack(struct l2cap_pinfo *pi)
+{
+       struct sock *sk = (struct sock *)pi;
+       u16 control = 0;
+       int nframes;
+
+       control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+       if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+               control |= L2CAP_SUPER_RCV_NOT_READY;
+               pi->conn_state |= L2CAP_CONN_RNR_SENT;
+               l2cap_send_sframe(pi, control);
+               return;
+       }
+
+       spin_lock_bh(&pi->send_lock);
+       nframes = l2cap_ertm_send(sk);
+       spin_unlock_bh(&pi->send_lock);
+
+       if (nframes > 0)
+               return;
+
+       control |= L2CAP_SUPER_RCV_READY;
+       l2cap_send_sframe(pi, control);
+}
+
+static void l2cap_send_srejtail(struct sock *sk)
+{
+       struct srej_list *tail;
+       u16 control;
+
+       control = L2CAP_SUPER_SELECT_REJECT;
+       control |= L2CAP_CTRL_FINAL;
+
+       tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list);
+       control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+       l2cap_send_sframe(l2cap_pi(sk), control);
 }
 
 static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
@@ -1420,9 +1529,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
        struct sk_buff **frag;
        int err, sent = 0;
 
-       if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+       if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
                return -EFAULT;
-       }
 
        sent += count;
        len  -= count;
@@ -1513,6 +1621,9 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m
 
        BT_DBG("sk %p len %d", sk, (int)len);
 
+       if (!conn)
+               return ERR_PTR(-ENOTCONN);
+
        if (sdulen)
                hlen += 2;
 
@@ -1554,25 +1665,24 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz
        u16 control;
        size_t size = 0;
 
-       __skb_queue_head_init(&sar_queue);
+       skb_queue_head_init(&sar_queue);
        control = L2CAP_SDU_START;
-       skb = l2cap_create_iframe_pdu(sk, msg, pi->max_pdu_size, control, len);
+       skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len);
        if (IS_ERR(skb))
                return PTR_ERR(skb);
 
        __skb_queue_tail(&sar_queue, skb);
-       len -= pi->max_pdu_size;
-       size +=pi->max_pdu_size;
-       control = 0;
+       len -= pi->remote_mps;
+       size += pi->remote_mps;
 
        while (len > 0) {
                size_t buflen;
 
-               if (len > pi->max_pdu_size) {
-                       control |= L2CAP_SDU_CONTINUE;
-                       buflen = pi->max_pdu_size;
+               if (len > pi->remote_mps) {
+                       control = L2CAP_SDU_CONTINUE;
+                       buflen = pi->remote_mps;
                } else {
-                       control |= L2CAP_SDU_END;
+                       control = L2CAP_SDU_END;
                        buflen = len;
                }
 
@@ -1585,11 +1695,12 @@ static inline int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, siz
                __skb_queue_tail(&sar_queue, skb);
                len -= buflen;
                size += buflen;
-               control = 0;
        }
        skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk));
+       spin_lock_bh(&pi->send_lock);
        if (sk->sk_send_head == NULL)
                sk->sk_send_head = sar_queue.next;
+       spin_unlock_bh(&pi->send_lock);
 
        return size;
 }
@@ -1611,11 +1722,6 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
 
-       /* Check outgoing MTU */
-       if (sk->sk_type == SOCK_SEQPACKET && pi->mode == L2CAP_MODE_BASIC &&
-           len > pi->omtu)
-               return -EINVAL;
-
        lock_sock(sk);
 
        if (sk->sk_state != BT_CONNECTED) {
@@ -1626,15 +1732,23 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        /* Connectionless channel */
        if (sk->sk_type == SOCK_DGRAM) {
                skb = l2cap_create_connless_pdu(sk, msg, len);
-               if (IS_ERR(skb))
+               if (IS_ERR(skb)) {
                        err = PTR_ERR(skb);
-               else
-                       err = l2cap_do_send(sk, skb);
+               } else {
+                       l2cap_do_send(sk, skb);
+                       err = len;
+               }
                goto done;
        }
 
        switch (pi->mode) {
        case L2CAP_MODE_BASIC:
+               /* Check outgoing MTU */
+               if (len > pi->omtu) {
+                       err = -EINVAL;
+                       goto done;
+               }
+
                /* Create a basic PDU */
                skb = l2cap_create_basic_pdu(sk, msg, len);
                if (IS_ERR(skb)) {
@@ -1642,15 +1756,14 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                        goto done;
                }
 
-               err = l2cap_do_send(sk, skb);
-               if (!err)
-                       err = len;
+               l2cap_do_send(sk, skb);
+               err = len;
                break;
 
        case L2CAP_MODE_ERTM:
        case L2CAP_MODE_STREAMING:
                /* Entire SDU fits into one PDU */
-               if (len <= pi->max_pdu_size) {
+               if (len <= pi->remote_mps) {
                        control = L2CAP_SDU_UNSEGMENTED;
                        skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0);
                        if (IS_ERR(skb)) {
@@ -1658,8 +1771,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                                goto done;
                        }
                        __skb_queue_tail(TX_QUEUE(sk), skb);
+
+                       if (pi->mode == L2CAP_MODE_ERTM)
+                               spin_lock_bh(&pi->send_lock);
+
                        if (sk->sk_send_head == NULL)
                                sk->sk_send_head = skb;
+
+                       if (pi->mode == L2CAP_MODE_ERTM)
+                               spin_unlock_bh(&pi->send_lock);
                } else {
                /* Segment SDU into multiples PDUs */
                        err = l2cap_sar_segment_sdu(sk, msg, len);
@@ -1667,12 +1787,15 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                                goto done;
                }
 
-               if (pi->mode == L2CAP_MODE_STREAMING)
+               if (pi->mode == L2CAP_MODE_STREAMING) {
                        err = l2cap_streaming_send(sk);
-               else
+               } else {
+                       spin_lock_bh(&pi->send_lock);
                        err = l2cap_ertm_send(sk);
+                       spin_unlock_bh(&pi->send_lock);
+               }
 
-               if (!err)
+               if (err >= 0)
                        err = len;
                break;
 
@@ -1731,6 +1854,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                opts.flush_to = l2cap_pi(sk)->flush_to;
                opts.mode     = l2cap_pi(sk)->mode;
                opts.fcs      = l2cap_pi(sk)->fcs;
+               opts.max_tx   = l2cap_pi(sk)->max_tx;
+               opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
 
                len = min_t(unsigned int, sizeof(opts), optlen);
                if (copy_from_user((char *) &opts, optval, len)) {
@@ -1738,10 +1863,25 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
+               l2cap_pi(sk)->mode = opts.mode;
+               switch (l2cap_pi(sk)->mode) {
+               case L2CAP_MODE_BASIC:
+                       break;
+               case L2CAP_MODE_ERTM:
+               case L2CAP_MODE_STREAMING:
+                       if (enable_ertm)
+                               break;
+                       /* fall through */
+               default:
+                       err = -EINVAL;
+                       break;
+               }
+
                l2cap_pi(sk)->imtu = opts.imtu;
                l2cap_pi(sk)->omtu = opts.omtu;
-               l2cap_pi(sk)->mode = opts.mode;
                l2cap_pi(sk)->fcs  = opts.fcs;
+               l2cap_pi(sk)->max_tx = opts.max_tx;
+               l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
                break;
 
        case L2CAP_LM:
@@ -1789,7 +1929,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
        switch (optname) {
        case BT_SECURITY:
-               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
+                               && sk->sk_type != SOCK_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -1856,6 +1997,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                opts.flush_to = l2cap_pi(sk)->flush_to;
                opts.mode     = l2cap_pi(sk)->mode;
                opts.fcs      = l2cap_pi(sk)->fcs;
+               opts.max_tx   = l2cap_pi(sk)->max_tx;
+               opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
 
                len = min_t(unsigned int, len, sizeof(opts));
                if (copy_to_user(optval, (char *) &opts, len))
@@ -1937,7 +2080,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
        switch (optname) {
        case BT_SECURITY:
-               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
+                               && sk->sk_type != SOCK_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -1982,6 +2126,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 
        lock_sock(sk);
        if (!sk->sk_shutdown) {
+               if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM)
+                       err = __l2cap_wait_ack(sk);
+
                sk->sk_shutdown = SHUTDOWN_MASK;
                l2cap_sock_clear_timer(sk);
                __l2cap_sock_close(sk, 0);
@@ -2184,19 +2331,35 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
        *ptr += L2CAP_CONF_OPT_SIZE + len;
 }
 
+static void l2cap_ack_timeout(unsigned long arg)
+{
+       struct sock *sk = (void *) arg;
+
+       bh_lock_sock(sk);
+       l2cap_send_ack(l2cap_pi(sk));
+       bh_unlock_sock(sk);
+}
+
 static inline void l2cap_ertm_init(struct sock *sk)
 {
        l2cap_pi(sk)->expected_ack_seq = 0;
        l2cap_pi(sk)->unacked_frames = 0;
        l2cap_pi(sk)->buffer_seq = 0;
-       l2cap_pi(sk)->num_to_ack = 0;
+       l2cap_pi(sk)->num_acked = 0;
+       l2cap_pi(sk)->frames_sent = 0;
 
        setup_timer(&l2cap_pi(sk)->retrans_timer,
                        l2cap_retrans_timeout, (unsigned long) sk);
        setup_timer(&l2cap_pi(sk)->monitor_timer,
                        l2cap_monitor_timeout, (unsigned long) sk);
+       setup_timer(&l2cap_pi(sk)->ack_timer,
+                       l2cap_ack_timeout, (unsigned long) sk);
 
        __skb_queue_head_init(SREJ_QUEUE(sk));
+       __skb_queue_head_init(BUSY_QUEUE(sk));
+       spin_lock_init(&l2cap_pi(sk)->send_lock);
+
+       INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work);
 }
 
 static int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
@@ -2232,7 +2395,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data)
 {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct l2cap_conf_req *req = data;
-       struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       struct l2cap_conf_rfc rfc = { .mode = pi->mode };
        void *ptr = req->data;
 
        BT_DBG("sk %p", sk);
@@ -2261,11 +2424,13 @@ done:
 
        case L2CAP_MODE_ERTM:
                rfc.mode            = L2CAP_MODE_ERTM;
-               rfc.txwin_size      = L2CAP_DEFAULT_TX_WINDOW;
-               rfc.max_transmit    = max_transmit;
+               rfc.txwin_size      = pi->tx_win;
+               rfc.max_transmit    = pi->max_tx;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
                rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+               if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
+                       rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
@@ -2287,6 +2452,8 @@ done:
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
                rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
+               if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
+                       rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
@@ -2415,10 +2582,15 @@ done:
                case L2CAP_MODE_ERTM:
                        pi->remote_tx_win = rfc.txwin_size;
                        pi->remote_max_tx = rfc.max_transmit;
-                       pi->max_pdu_size = rfc.max_pdu_size;
+                       if (rfc.max_pdu_size > pi->conn->mtu - 10)
+                               rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10);
 
-                       rfc.retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
-                       rfc.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
+                       pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+
+                       rfc.retrans_timeout =
+                               le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
+                       rfc.monitor_timeout =
+                               le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
 
                        pi->conf_state |= L2CAP_CONF_MODE_DONE;
 
@@ -2428,8 +2600,10 @@ done:
                        break;
 
                case L2CAP_MODE_STREAMING:
-                       pi->remote_tx_win = rfc.txwin_size;
-                       pi->max_pdu_size = rfc.max_pdu_size;
+                       if (rfc.max_pdu_size > pi->conn->mtu - 10)
+                               rfc.max_pdu_size = le16_to_cpu(pi->conn->mtu - 10);
+
+                       pi->remote_mps = le16_to_cpu(rfc.max_pdu_size);
 
                        pi->conf_state |= L2CAP_CONF_MODE_DONE;
 
@@ -2506,13 +2680,12 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
                switch (rfc.mode) {
                case L2CAP_MODE_ERTM:
                        pi->remote_tx_win   = rfc.txwin_size;
-                       pi->retrans_timeout = rfc.retrans_timeout;
-                       pi->monitor_timeout = rfc.monitor_timeout;
-                       pi->max_pdu_size    = le16_to_cpu(rfc.max_pdu_size);
+                       pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
+                       pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
+                       pi->mps    = le16_to_cpu(rfc.max_pdu_size);
                        break;
                case L2CAP_MODE_STREAMING:
-                       pi->max_pdu_size    = le16_to_cpu(rfc.max_pdu_size);
-                       break;
+                       pi->mps    = le16_to_cpu(rfc.max_pdu_size);
                }
        }
 
@@ -2536,6 +2709,42 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla
        return ptr - data;
 }
 
+static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       int type, olen;
+       unsigned long val;
+       struct l2cap_conf_rfc rfc;
+
+       BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len);
+
+       if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING))
+               return;
+
+       while (len >= L2CAP_CONF_OPT_SIZE) {
+               len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
+
+               switch (type) {
+               case L2CAP_CONF_RFC:
+                       if (olen == sizeof(rfc))
+                               memcpy(&rfc, (void *)val, olen);
+                       goto done;
+               }
+       }
+
+done:
+       switch (rfc.mode) {
+       case L2CAP_MODE_ERTM:
+               pi->remote_tx_win   = rfc.txwin_size;
+               pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
+               pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
+               pi->mps    = le16_to_cpu(rfc.max_pdu_size);
+               break;
+       case L2CAP_MODE_STREAMING:
+               pi->mps    = le16_to_cpu(rfc.max_pdu_size);
+       }
+}
+
 static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
@@ -2815,6 +3024,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
        struct sock *sk;
+       int len = cmd->len - sizeof(*rsp);
 
        scid   = __le16_to_cpu(rsp->scid);
        flags  = __le16_to_cpu(rsp->flags);
@@ -2829,11 +3039,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        switch (result) {
        case L2CAP_CONF_SUCCESS:
+               l2cap_conf_rfc_get(sk, rsp->data, len);
                break;
 
        case L2CAP_CONF_UNACCEPT:
                if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
-                       int len = cmd->len - sizeof(*rsp);
                        char req[64];
 
                        if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
@@ -2917,8 +3127,10 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
                skb_queue_purge(SREJ_QUEUE(sk));
+               skb_queue_purge(BUSY_QUEUE(sk));
                del_timer(&l2cap_pi(sk)->retrans_timer);
                del_timer(&l2cap_pi(sk)->monitor_timer);
+               del_timer(&l2cap_pi(sk)->ack_timer);
        }
 
        l2cap_chan_del(sk, ECONNRESET);
@@ -2947,8 +3159,10 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
 
        if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) {
                skb_queue_purge(SREJ_QUEUE(sk));
+               skb_queue_purge(BUSY_QUEUE(sk));
                del_timer(&l2cap_pi(sk)->retrans_timer);
                del_timer(&l2cap_pi(sk)->monitor_timer);
+               del_timer(&l2cap_pi(sk)->ack_timer);
        }
 
        l2cap_chan_del(sk, 0);
@@ -3143,7 +3357,40 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi,  struct sk_buff *skb)
        return 0;
 }
 
-static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
+static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       u16 control = 0;
+
+       pi->frames_sent = 0;
+       pi->conn_state |= L2CAP_CONN_SEND_FBIT;
+
+       control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+
+       if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+               control |= L2CAP_SUPER_RCV_NOT_READY | L2CAP_CTRL_FINAL;
+               l2cap_send_sframe(pi, control);
+               pi->conn_state |= L2CAP_CONN_RNR_SENT;
+               pi->conn_state &= ~L2CAP_CONN_SEND_FBIT;
+       }
+
+       if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY && pi->unacked_frames > 0)
+               __mod_retrans_timer();
+
+       pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+
+       spin_lock_bh(&pi->send_lock);
+       l2cap_ertm_send(sk);
+       spin_unlock_bh(&pi->send_lock);
+
+       if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
+                       pi->frames_sent == 0) {
+               control |= L2CAP_SUPER_RCV_READY;
+               l2cap_send_sframe(pi, control);
+       }
+}
+
+static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar)
 {
        struct sk_buff *next_skb;
 
@@ -3153,77 +3400,309 @@ static void l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_
        next_skb = skb_peek(SREJ_QUEUE(sk));
        if (!next_skb) {
                __skb_queue_tail(SREJ_QUEUE(sk), skb);
-               return;
+               return 0;
        }
 
        do {
+               if (bt_cb(next_skb)->tx_seq == tx_seq)
+                       return -EINVAL;
+
                if (bt_cb(next_skb)->tx_seq > tx_seq) {
                        __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb);
-                       return;
+                       return 0;
                }
 
                if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb))
                        break;
 
-       } while((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb)));
+       } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb)));
 
        __skb_queue_tail(SREJ_QUEUE(sk), skb);
+
+       return 0;
 }
 
-static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
+static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
 {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        struct sk_buff *_skb;
-       int err = -EINVAL;
+       int err;
 
        switch (control & L2CAP_CTRL_SAR) {
        case L2CAP_SDU_UNSEGMENTED:
-               if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
-                       kfree_skb(pi->sdu);
-                       break;
-               }
+               if (pi->conn_state & L2CAP_CONN_SAR_SDU)
+                       goto drop;
 
                err = sock_queue_rcv_skb(sk, skb);
                if (!err)
-                       return 0;
+                       return err;
 
                break;
 
        case L2CAP_SDU_START:
-               if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
-                       kfree_skb(pi->sdu);
-                       break;
-               }
+               if (pi->conn_state & L2CAP_CONN_SAR_SDU)
+                       goto drop;
 
                pi->sdu_len = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+
+               if (pi->sdu_len > pi->imtu)
+                       goto disconnect;
 
                pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
-               if (!pi->sdu) {
-                       err = -ENOMEM;
-                       break;
-               }
+               if (!pi->sdu)
+                       return -ENOMEM;
+
+               /* pull sdu_len bytes only after alloc, because of Local Busy
+                * condition we have to be sure that this will be executed
+                * only once, i.e., when alloc does not fail */
+               skb_pull(skb, 2);
 
                memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
 
                pi->conn_state |= L2CAP_CONN_SAR_SDU;
                pi->partial_sdu_len = skb->len;
-               err = 0;
                break;
 
        case L2CAP_SDU_CONTINUE:
                if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
-                       break;
+                       goto disconnect;
 
-               memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+               if (!pi->sdu)
+                       goto disconnect;
 
                pi->partial_sdu_len += skb->len;
                if (pi->partial_sdu_len > pi->sdu_len)
-                       kfree_skb(pi->sdu);
-               else
-                       err = 0;
+                       goto drop;
 
-               break;
+               memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+
+               break;
+
+       case L2CAP_SDU_END:
+               if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+                       goto disconnect;
+
+               if (!pi->sdu)
+                       goto disconnect;
+
+               if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) {
+                       pi->partial_sdu_len += skb->len;
+
+                       if (pi->partial_sdu_len > pi->imtu)
+                               goto drop;
+
+                       if (pi->partial_sdu_len != pi->sdu_len)
+                               goto drop;
+
+                       memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+               }
+
+               _skb = skb_clone(pi->sdu, GFP_ATOMIC);
+               if (!_skb) {
+                       pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+                       return -ENOMEM;
+               }
+
+               err = sock_queue_rcv_skb(sk, _skb);
+               if (err < 0) {
+                       kfree_skb(_skb);
+                       pi->conn_state |= L2CAP_CONN_SAR_RETRY;
+                       return err;
+               }
+
+               pi->conn_state &= ~L2CAP_CONN_SAR_RETRY;
+               pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
+
+               kfree_skb(pi->sdu);
+               break;
+       }
+
+       kfree_skb(skb);
+       return 0;
+
+drop:
+       kfree_skb(pi->sdu);
+       pi->sdu = NULL;
+
+disconnect:
+       l2cap_send_disconn_req(pi->conn, sk);
+       kfree_skb(skb);
+       return 0;
+}
+
+static void l2cap_busy_work(struct work_struct *work)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       struct l2cap_pinfo *pi =
+               container_of(work, struct l2cap_pinfo, busy_work);
+       struct sock *sk = (struct sock *)pi;
+       int n_tries = 0, timeo = HZ/5, err;
+       struct sk_buff *skb;
+       u16 control;
+
+       lock_sock(sk);
+
+       add_wait_queue(sk_sleep(sk), &wait);
+       while ((skb = skb_peek(BUSY_QUEUE(sk)))) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
+                       err = -EBUSY;
+                       l2cap_send_disconn_req(pi->conn, sk);
+                       goto done;
+               }
+
+               if (!timeo)
+                       timeo = HZ/5;
+
+               if (signal_pending(current)) {
+                       err = sock_intr_errno(timeo);
+                       goto done;
+               }
+
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock(sk);
+
+               err = sock_error(sk);
+               if (err)
+                       goto done;
+
+               while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) {
+                       control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+                       err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+                       if (err < 0) {
+                               skb_queue_head(BUSY_QUEUE(sk), skb);
+                               break;
+                       }
+
+                       pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+               }
+
+               if (!skb)
+                       break;
+       }
+
+       if (!(pi->conn_state & L2CAP_CONN_RNR_SENT))
+               goto done;
+
+       control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+       l2cap_send_sframe(pi, control);
+       l2cap_pi(sk)->retry_count = 1;
+
+       del_timer(&pi->retrans_timer);
+       __mod_monitor_timer();
+
+       l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F;
+
+done:
+       pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
+       pi->conn_state &= ~L2CAP_CONN_RNR_SENT;
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(sk_sleep(sk), &wait);
+
+       release_sock(sk);
+}
+
+static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       int sctrl, err;
+
+       if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) {
+               bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
+               __skb_queue_tail(BUSY_QUEUE(sk), skb);
+               return -EBUSY;
+       }
+
+       err = l2cap_ertm_reassembly_sdu(sk, skb, control);
+       if (err >= 0) {
+               pi->buffer_seq = (pi->buffer_seq + 1) % 64;
+               return err;
+       }
+
+       /* Busy Condition */
+       pi->conn_state |= L2CAP_CONN_LOCAL_BUSY;
+       bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
+       __skb_queue_tail(BUSY_QUEUE(sk), skb);
+
+       sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       sctrl |= L2CAP_SUPER_RCV_NOT_READY;
+       l2cap_send_sframe(pi, sctrl);
+
+       pi->conn_state |= L2CAP_CONN_RNR_SENT;
+
+       queue_work(_busy_wq, &pi->busy_work);
+
+       return err;
+}
+
+static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       struct sk_buff *_skb;
+       int err = -EINVAL;
+
+       /*
+        * TODO: We have to notify the userland if some data is lost with the
+        * Streaming Mode.
+        */
+
+       switch (control & L2CAP_CTRL_SAR) {
+       case L2CAP_SDU_UNSEGMENTED:
+               if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
+                       kfree_skb(pi->sdu);
+                       break;
+               }
+
+               err = sock_queue_rcv_skb(sk, skb);
+               if (!err)
+                       return 0;
+
+               break;
+
+       case L2CAP_SDU_START:
+               if (pi->conn_state & L2CAP_CONN_SAR_SDU) {
+                       kfree_skb(pi->sdu);
+                       break;
+               }
+
+               pi->sdu_len = get_unaligned_le16(skb->data);
+               skb_pull(skb, 2);
+
+               if (pi->sdu_len > pi->imtu) {
+                       err = -EMSGSIZE;
+                       break;
+               }
+
+               pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC);
+               if (!pi->sdu) {
+                       err = -ENOMEM;
+                       break;
+               }
+
+               memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+
+               pi->conn_state |= L2CAP_CONN_SAR_SDU;
+               pi->partial_sdu_len = skb->len;
+               err = 0;
+               break;
+
+       case L2CAP_SDU_CONTINUE:
+               if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
+                       break;
+
+               memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len);
+
+               pi->partial_sdu_len += skb->len;
+               if (pi->partial_sdu_len > pi->sdu_len)
+                       kfree_skb(pi->sdu);
+               else
+                       err = 0;
+
+               break;
 
        case L2CAP_SDU_END:
                if (!(pi->conn_state & L2CAP_CONN_SAR_SDU))
@@ -3234,15 +3713,19 @@ static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 co
                pi->conn_state &= ~L2CAP_CONN_SAR_SDU;
                pi->partial_sdu_len += skb->len;
 
+               if (pi->partial_sdu_len > pi->imtu)
+                       goto drop;
+
                if (pi->partial_sdu_len == pi->sdu_len) {
                        _skb = skb_clone(pi->sdu, GFP_ATOMIC);
                        err = sock_queue_rcv_skb(sk, _skb);
                        if (err < 0)
                                kfree_skb(_skb);
                }
-               kfree_skb(pi->sdu);
                err = 0;
 
+drop:
+               kfree_skb(pi->sdu);
                break;
        }
 
@@ -3253,15 +3736,15 @@ static int l2cap_sar_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 co
 static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq)
 {
        struct sk_buff *skb;
-       u16 control = 0;
+       u16 control;
 
-       while((skb = skb_peek(SREJ_QUEUE(sk)))) {
+       while ((skb = skb_peek(SREJ_QUEUE(sk)))) {
                if (bt_cb(skb)->tx_seq != tx_seq)
                        break;
 
                skb = skb_dequeue(SREJ_QUEUE(sk));
-               control |= bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
-               l2cap_sar_reassembly_sdu(sk, skb, control);
+               control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+               l2cap_ertm_reassembly_sdu(sk, skb, control);
                l2cap_pi(sk)->buffer_seq_srej =
                        (l2cap_pi(sk)->buffer_seq_srej + 1) % 64;
                tx_seq++;
@@ -3274,7 +3757,7 @@ static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq)
        struct srej_list *l, *tmp;
        u16 control;
 
-       list_for_each_entry_safe(l,tmp, SREJ_LIST(sk), list) {
+       list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
                if (l->tx_seq == tx_seq) {
                        list_del(&l->list);
                        kfree(l);
@@ -3297,10 +3780,6 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq)
        while (tx_seq != pi->expected_tx_seq) {
                control = L2CAP_SUPER_SELECT_REJECT;
                control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-               if (pi->conn_state & L2CAP_CONN_SEND_PBIT) {
-                       control |= L2CAP_CTRL_POLL;
-                       pi->conn_state &= ~L2CAP_CONN_SEND_PBIT;
-               }
                l2cap_send_sframe(pi, control);
 
                new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
@@ -3315,18 +3794,40 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
        struct l2cap_pinfo *pi = l2cap_pi(sk);
        u8 tx_seq = __get_txseq(rx_control);
        u8 req_seq = __get_reqseq(rx_control);
-       u16 tx_control = 0;
        u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
+       u8 tx_seq_offset, expected_tx_seq_offset;
+       int num_to_ack = (pi->tx_win/6) + 1;
        int err = 0;
 
        BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
 
+       if (L2CAP_CTRL_FINAL & rx_control &&
+                       l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
+               del_timer(&pi->monitor_timer);
+               if (pi->unacked_frames > 0)
+                       __mod_retrans_timer();
+               pi->conn_state &= ~L2CAP_CONN_WAIT_F;
+       }
+
        pi->expected_ack_seq = req_seq;
        l2cap_drop_acked_frames(sk);
 
        if (tx_seq == pi->expected_tx_seq)
                goto expected;
 
+       tx_seq_offset = (tx_seq - pi->buffer_seq) % 64;
+       if (tx_seq_offset < 0)
+               tx_seq_offset += 64;
+
+       /* invalid tx_seq */
+       if (tx_seq_offset >= pi->tx_win) {
+               l2cap_send_disconn_req(pi->conn, sk);
+               goto drop;
+       }
+
+       if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY)
+               goto drop;
+
        if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
                struct srej_list *first;
 
@@ -3342,10 +3843,14 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
                        if (list_empty(SREJ_LIST(sk))) {
                                pi->buffer_seq = pi->buffer_seq_srej;
                                pi->conn_state &= ~L2CAP_CONN_SREJ_SENT;
+                               l2cap_send_ack(pi);
                        }
                } else {
                        struct srej_list *l;
-                       l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
+
+                       /* duplicated tx_seq */
+                       if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0)
+                               goto drop;
 
                        list_for_each_entry(l, SREJ_LIST(sk), list) {
                                if (l->tx_seq == tx_seq) {
@@ -3356,12 +3861,22 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str
                        l2cap_send_srejframe(sk, tx_seq);
                }
        } else {
+               expected_tx_seq_offset =
+                       (pi->expected_tx_seq - pi->buffer_seq) % 64;
+               if (expected_tx_seq_offset < 0)
+                       expected_tx_seq_offset += 64;
+
+               /* duplicated tx_seq */
+               if (tx_seq_offset < expected_tx_seq_offset)
+                       goto drop;
+
                pi->conn_state |= L2CAP_CONN_SREJ_SENT;
 
                INIT_LIST_HEAD(SREJ_LIST(sk));
                pi->buffer_seq_srej = pi->buffer_seq;
 
                __skb_queue_head_init(SREJ_QUEUE(sk));
+               __skb_queue_head_init(BUSY_QUEUE(sk));
                l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
 
                pi->conn_state |= L2CAP_CONN_SEND_PBIT;
@@ -3374,153 +3889,189 @@ expected:
        pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
 
        if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
-               l2cap_add_to_srej_queue(sk, skb, tx_seq, sar);
+               bt_cb(skb)->tx_seq = tx_seq;
+               bt_cb(skb)->sar = sar;
+               __skb_queue_tail(SREJ_QUEUE(sk), skb);
                return 0;
        }
 
        if (rx_control & L2CAP_CTRL_FINAL) {
                if (pi->conn_state & L2CAP_CONN_REJ_ACT)
                        pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
-               else {
-                       sk->sk_send_head = TX_QUEUE(sk)->next;
-                       pi->next_tx_seq = pi->expected_ack_seq;
-                       l2cap_ertm_send(sk);
-               }
+               else
+                       l2cap_retransmit_frames(sk);
        }
 
-       pi->buffer_seq = (pi->buffer_seq + 1) % 64;
-
-       err = l2cap_sar_reassembly_sdu(sk, skb, rx_control);
+       err = l2cap_push_rx_skb(sk, skb, rx_control);
        if (err < 0)
-               return err;
+               return 0;
+
+       __mod_ack_timer();
+
+       pi->num_acked = (pi->num_acked + 1) % num_to_ack;
+       if (pi->num_acked == num_to_ack - 1)
+               l2cap_send_ack(pi);
 
-       pi->num_to_ack = (pi->num_to_ack + 1) % L2CAP_DEFAULT_NUM_TO_ACK;
-       if (pi->num_to_ack == L2CAP_DEFAULT_NUM_TO_ACK - 1) {
-               tx_control |= L2CAP_SUPER_RCV_READY;
-               tx_control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-               l2cap_send_sframe(pi, tx_control);
-       }
+       return 0;
+
+drop:
+       kfree_skb(skb);
        return 0;
 }
 
-static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
+static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
 {
        struct l2cap_pinfo *pi = l2cap_pi(sk);
-       u8 tx_seq = __get_reqseq(rx_control);
 
-       BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
+       pi->expected_ack_seq = __get_reqseq(rx_control);
+       l2cap_drop_acked_frames(sk);
 
-       switch (rx_control & L2CAP_CTRL_SUPERVISE) {
-       case L2CAP_SUPER_RCV_READY:
-               if (rx_control & L2CAP_CTRL_POLL) {
-                       u16 control = L2CAP_CTRL_FINAL;
-                       control |= L2CAP_SUPER_RCV_READY |
-                               (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT);
-                       l2cap_send_sframe(l2cap_pi(sk), control);
-                       pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+       if (rx_control & L2CAP_CTRL_POLL) {
+               if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
+                       if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+                                       (pi->unacked_frames > 0))
+                               __mod_retrans_timer();
 
-               } else if (rx_control & L2CAP_CTRL_FINAL) {
                        pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
-                       pi->expected_ack_seq = tx_seq;
-                       l2cap_drop_acked_frames(sk);
-
-                       if (pi->conn_state & L2CAP_CONN_REJ_ACT)
-                               pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
-                       else {
-                               sk->sk_send_head = TX_QUEUE(sk)->next;
-                               pi->next_tx_seq = pi->expected_ack_seq;
-                               l2cap_ertm_send(sk);
-                       }
-
-                       if (!(pi->conn_state & L2CAP_CONN_WAIT_F))
-                               break;
+                       l2cap_send_srejtail(sk);
+               } else {
+                       l2cap_send_i_or_rr_or_rnr(sk);
+               }
 
-                       pi->conn_state &= ~L2CAP_CONN_WAIT_F;
-                       del_timer(&pi->monitor_timer);
+       } else if (rx_control & L2CAP_CTRL_FINAL) {
+               pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
 
-                       if (pi->unacked_frames > 0)
-                               __mod_retrans_timer();
-               } else {
-                       pi->expected_ack_seq = tx_seq;
-                       l2cap_drop_acked_frames(sk);
+               if (pi->conn_state & L2CAP_CONN_REJ_ACT)
+                       pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+               else
+                       l2cap_retransmit_frames(sk);
 
-                       if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
-                           (pi->unacked_frames > 0))
-                               __mod_retrans_timer();
+       } else {
+               if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
+                               (pi->unacked_frames > 0))
+                       __mod_retrans_timer();
 
-                       pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+               pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+               if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
+                       l2cap_send_ack(pi);
+               } else {
+                       spin_lock_bh(&pi->send_lock);
                        l2cap_ertm_send(sk);
+                       spin_unlock_bh(&pi->send_lock);
                }
-               break;
+       }
+}
 
-       case L2CAP_SUPER_REJECT:
-               pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       u8 tx_seq = __get_reqseq(rx_control);
+
+       pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+
+       pi->expected_ack_seq = tx_seq;
+       l2cap_drop_acked_frames(sk);
+
+       if (rx_control & L2CAP_CTRL_FINAL) {
+               if (pi->conn_state & L2CAP_CONN_REJ_ACT)
+                       pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
+               else
+                       l2cap_retransmit_frames(sk);
+       } else {
+               l2cap_retransmit_frames(sk);
+
+               if (pi->conn_state & L2CAP_CONN_WAIT_F)
+                       pi->conn_state |= L2CAP_CONN_REJ_ACT;
+       }
+}
+static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       u8 tx_seq = __get_reqseq(rx_control);
 
-               pi->expected_ack_seq = __get_reqseq(rx_control);
+       pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+
+       if (rx_control & L2CAP_CTRL_POLL) {
+               pi->expected_ack_seq = tx_seq;
                l2cap_drop_acked_frames(sk);
+               l2cap_retransmit_one_frame(sk, tx_seq);
 
-               if (rx_control & L2CAP_CTRL_FINAL) {
-                       if (pi->conn_state & L2CAP_CONN_REJ_ACT)
-                               pi->conn_state &= ~L2CAP_CONN_REJ_ACT;
-                       else {
-                               sk->sk_send_head = TX_QUEUE(sk)->next;
-                               pi->next_tx_seq = pi->expected_ack_seq;
-                               l2cap_ertm_send(sk);
-                       }
-               } else {
-                       sk->sk_send_head = TX_QUEUE(sk)->next;
-                       pi->next_tx_seq = pi->expected_ack_seq;
-                       l2cap_ertm_send(sk);
+               spin_lock_bh(&pi->send_lock);
+               l2cap_ertm_send(sk);
+               spin_unlock_bh(&pi->send_lock);
 
-                       if (pi->conn_state & L2CAP_CONN_WAIT_F) {
-                               pi->srej_save_reqseq = tx_seq;
-                               pi->conn_state |= L2CAP_CONN_REJ_ACT;
-                       }
+               if (pi->conn_state & L2CAP_CONN_WAIT_F) {
+                       pi->srej_save_reqseq = tx_seq;
+                       pi->conn_state |= L2CAP_CONN_SREJ_ACT;
+               }
+       } else if (rx_control & L2CAP_CTRL_FINAL) {
+               if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) &&
+                               pi->srej_save_reqseq == tx_seq)
+                       pi->conn_state &= ~L2CAP_CONN_SREJ_ACT;
+               else
+                       l2cap_retransmit_one_frame(sk, tx_seq);
+       } else {
+               l2cap_retransmit_one_frame(sk, tx_seq);
+               if (pi->conn_state & L2CAP_CONN_WAIT_F) {
+                       pi->srej_save_reqseq = tx_seq;
+                       pi->conn_state |= L2CAP_CONN_SREJ_ACT;
                }
+       }
+}
 
+static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control)
+{
+       struct l2cap_pinfo *pi = l2cap_pi(sk);
+       u8 tx_seq = __get_reqseq(rx_control);
+
+       pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
+       pi->expected_ack_seq = tx_seq;
+       l2cap_drop_acked_frames(sk);
+
+       if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) {
+               del_timer(&pi->retrans_timer);
+               if (rx_control & L2CAP_CTRL_POLL)
+                       l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL);
+               return;
+       }
+
+       if (rx_control & L2CAP_CTRL_POLL)
+               l2cap_send_srejtail(sk);
+       else
+               l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY);
+}
+
+static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb)
+{
+       BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len);
+
+       if (L2CAP_CTRL_FINAL & rx_control &&
+                       l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) {
+               del_timer(&l2cap_pi(sk)->monitor_timer);
+               if (l2cap_pi(sk)->unacked_frames > 0)
+                       __mod_retrans_timer();
+               l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F;
+       }
+
+       switch (rx_control & L2CAP_CTRL_SUPERVISE) {
+       case L2CAP_SUPER_RCV_READY:
+               l2cap_data_channel_rrframe(sk, rx_control);
                break;
 
-       case L2CAP_SUPER_SELECT_REJECT:
-               pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
+       case L2CAP_SUPER_REJECT:
+               l2cap_data_channel_rejframe(sk, rx_control);
+               break;
 
-               if (rx_control & L2CAP_CTRL_POLL) {
-                       pi->expected_ack_seq = tx_seq;
-                       l2cap_drop_acked_frames(sk);
-                       l2cap_retransmit_frame(sk, tx_seq);
-                       l2cap_ertm_send(sk);
-                       if (pi->conn_state & L2CAP_CONN_WAIT_F) {
-                               pi->srej_save_reqseq = tx_seq;
-                               pi->conn_state |= L2CAP_CONN_SREJ_ACT;
-                       }
-               } else if (rx_control & L2CAP_CTRL_FINAL) {
-                       if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) &&
-                                       pi->srej_save_reqseq == tx_seq)
-                               pi->conn_state &= ~L2CAP_CONN_SREJ_ACT;
-                       else
-                               l2cap_retransmit_frame(sk, tx_seq);
-               }
-               else {
-                       l2cap_retransmit_frame(sk, tx_seq);
-                       if (pi->conn_state & L2CAP_CONN_WAIT_F) {
-                               pi->srej_save_reqseq = tx_seq;
-                               pi->conn_state |= L2CAP_CONN_SREJ_ACT;
-                       }
-               }
+       case L2CAP_SUPER_SELECT_REJECT:
+               l2cap_data_channel_srejframe(sk, rx_control);
                break;
 
        case L2CAP_SUPER_RCV_NOT_READY:
-               pi->conn_state |= L2CAP_CONN_REMOTE_BUSY;
-               pi->expected_ack_seq = tx_seq;
-               l2cap_drop_acked_frames(sk);
-
-               del_timer(&l2cap_pi(sk)->retrans_timer);
-               if (rx_control & L2CAP_CTRL_POLL) {
-                       u16 control = L2CAP_CTRL_FINAL;
-                       l2cap_send_rr_or_rnr(l2cap_pi(sk), control);
-               }
+               l2cap_data_channel_rnrframe(sk, rx_control);
                break;
        }
 
+       kfree_skb(skb);
        return 0;
 }
 
@@ -3529,7 +4080,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
        struct sock *sk;
        struct l2cap_pinfo *pi;
        u16 control, len;
-       u8 tx_seq;
+       u8 tx_seq, req_seq, next_tx_seq_offset, req_seq_offset;
 
        sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
        if (!sk) {
@@ -3574,16 +4125,45 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                 * Receiver will miss it and start proper recovery
                 * procedures and ask retransmission.
                 */
-               if (len > L2CAP_DEFAULT_MAX_PDU_SIZE)
+               if (len > pi->mps) {
+                       l2cap_send_disconn_req(pi->conn, sk);
                        goto drop;
+               }
 
                if (l2cap_check_fcs(pi, skb))
                        goto drop;
 
-               if (__is_iframe(control))
+               req_seq = __get_reqseq(control);
+               req_seq_offset = (req_seq - pi->expected_ack_seq) % 64;
+               if (req_seq_offset < 0)
+                       req_seq_offset += 64;
+
+               next_tx_seq_offset =
+                       (pi->next_tx_seq - pi->expected_ack_seq) % 64;
+               if (next_tx_seq_offset < 0)
+                       next_tx_seq_offset += 64;
+
+               /* check for invalid req-seq */
+               if (req_seq_offset > next_tx_seq_offset) {
+                       l2cap_send_disconn_req(pi->conn, sk);
+                       goto drop;
+               }
+
+               if (__is_iframe(control)) {
+                       if (len < 4) {
+                               l2cap_send_disconn_req(pi->conn, sk);
+                               goto drop;
+                       }
+
                        l2cap_data_channel_iframe(sk, control, skb);
-               else
+               } else {
+                       if (len != 0) {
+                               l2cap_send_disconn_req(pi->conn, sk);
+                               goto drop;
+                       }
+
                        l2cap_data_channel_sframe(sk, control, skb);
+               }
 
                goto done;
 
@@ -3598,7 +4178,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                if (pi->fcs == L2CAP_FCS_CRC16)
                        len -= 2;
 
-               if (len > L2CAP_DEFAULT_MAX_PDU_SIZE || __is_sframe(control))
+               if (len > pi->mps || len < 4 || __is_sframe(control))
                        goto drop;
 
                if (l2cap_check_fcs(pi, skb))
@@ -3609,14 +4189,14 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                if (pi->expected_tx_seq == tx_seq)
                        pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64;
                else
-                       pi->expected_tx_seq = tx_seq + 1;
+                       pi->expected_tx_seq = (tx_seq + 1) % 64;
 
-               l2cap_sar_reassembly_sdu(sk, skb, control);
+               l2cap_streaming_reassembly_sdu(sk, skb, control);
 
                goto done;
 
        default:
-               BT_DBG("sk %p: bad mode 0x%2.2x", sk, l2cap_pi(sk)->mode);
+               BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode);
                break;
        }
 
@@ -3772,7 +4352,7 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 
 static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
 {
-       if (sk->sk_type != SOCK_SEQPACKET)
+       if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM)
                return;
 
        if (encrypt == 0x00) {
@@ -4030,6 +4610,10 @@ static int __init l2cap_init(void)
        if (err < 0)
                return err;
 
+       _busy_wq = create_singlethread_workqueue("l2cap");
+       if (!_busy_wq)
+               goto error;
+
        err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
        if (err < 0) {
                BT_ERR("L2CAP socket registration failed");
@@ -4064,6 +4648,9 @@ static void __exit l2cap_exit(void)
 {
        debugfs_remove(l2cap_debugfs);
 
+       flush_workqueue(_busy_wq);
+       destroy_workqueue(_busy_wq);
+
        if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
                BT_ERR("L2CAP socket unregistration failed");
 
@@ -4078,7 +4665,6 @@ void l2cap_load(void)
        /* Dummy function to trigger automatic L2CAP module loading by
         * other modules that use L2CAP sockets but don't use any other
         * symbols from it. */
-       return;
 }
 EXPORT_SYMBOL(l2cap_load);
 
@@ -4091,6 +4677,9 @@ MODULE_PARM_DESC(enable_ertm, "Enable enhanced retransmission mode");
 module_param(max_transmit, uint, 0644);
 MODULE_PARM_DESC(max_transmit, "Max transmit value (default = 3)");
 
+module_param(tx_window, uint, 0644);
+MODULE_PARM_DESC(tx_window, "Transmission window size value (default = 63)");
+
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
 MODULE_VERSION(VERSION);
index 8ed3c37684fa345326366239d719a1b1a100458b..43fbf6b4b4bfcefdcf9ddcd64c0549959bfb50d6 100644 (file)
@@ -503,7 +503,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
        BT_DBG("sk %p timeo %ld", sk, timeo);
 
        /* Wait for an incoming connection. (wake-one). */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(nsk = bt_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -526,7 +526,7 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f
                }
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -621,7 +621,7 @@ static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
 {
        DECLARE_WAITQUEUE(wait, current);
 
-       add_wait_queue(sk->sk_sleep, &wait);
+       add_wait_queue(sk_sleep(sk), &wait);
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
 
@@ -640,7 +640,7 @@ static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
        }
 
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
        return timeo;
 }
 
index cab71ea2796d472f740a88277d75805081873748..309b6c261b258e985c256674b1df7cba480f82aa 100644 (file)
@@ -1014,8 +1014,6 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
                rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud,
                                data_bits, stop_bits, parity,
                                RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);
-
-       return;
 }
 
 static void rfcomm_tty_throttle(struct tty_struct *tty)
index ca6b2ad1c3fc02a6bcbf16a034aa253e05b1a456..d0927d1fdadaba4887dbac40064c4328541b9b00 100644 (file)
@@ -165,11 +165,11 @@ static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct so
        int err = 0;
 
        sco_conn_lock(conn);
-       if (conn->sk) {
+       if (conn->sk)
                err = -EBUSY;
-       } else {
+       else
                __sco_chan_add(conn, sk, parent);
-       }
+
        sco_conn_unlock(conn);
        return err;
 }
@@ -241,22 +241,19 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
        BT_DBG("sk %p len %d", sk, len);
 
        count = min_t(unsigned int, conn->mtu, len);
-       if (!(skb = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+       skb = bt_skb_send_alloc(sk, count,
+                       msg->msg_flags & MSG_DONTWAIT, &err);
+       if (!skb)
                return err;
 
        if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
-               err = -EFAULT;
-               goto fail;
+               kfree_skb(skb);
+               return -EFAULT;
        }
 
-       if ((err = hci_send_sco(conn->hcon, skb)) < 0)
-               return err;
+       hci_send_sco(conn->hcon, skb);
 
        return count;
-
-fail:
-       kfree_skb(skb);
-       return err;
 }
 
 static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
@@ -276,7 +273,6 @@ static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
 
 drop:
        kfree_skb(skb);
-       return;
 }
 
 /* -------- Socket interface ---------- */
@@ -567,7 +563,7 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
        BT_DBG("sk %p timeo %ld", sk, timeo);
 
        /* Wait for an incoming connection. (wake-one). */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(ch = bt_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -590,7 +586,7 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag
                }
        }
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -626,7 +622,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                            struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
-       int err = 0;
+       int err;
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
@@ -851,7 +847,8 @@ static void sco_conn_ready(struct sco_conn *conn)
 
                bh_lock_sock(parent);
 
-               sk = sco_sock_alloc(sock_net(parent), NULL, BTPROTO_SCO, GFP_ATOMIC);
+               sk = sco_sock_alloc(sock_net(parent), NULL,
+                               BTPROTO_SCO, GFP_ATOMIC);
                if (!sk) {
                        bh_unlock_sock(parent);
                        goto done;
index d115d5cea5b6b63421769ccfc2b12bd922ac5918..9190ae462cb4215db167eaeb08164b11a052e63f 100644 (file)
@@ -33,14 +33,14 @@ config BRIDGE
          If unsure, say N.
 
 config BRIDGE_IGMP_SNOOPING
-       bool "IGMP snooping"
+       bool "IGMP/MLD snooping"
        depends on BRIDGE
        depends on INET
        default y
        ---help---
          If you say Y here, then the Ethernet bridge will be able selectively
-         forward multicast traffic based on IGMP traffic received from each
-         port.
+         forward multicast traffic based on IGMP/MLD traffic received from
+         each port.
 
          Say N to exclude this support and reduce the binary size.
 
index e1241c76239a96fb3e4d027ba071b640c2904ceb..76357b547752327d2ff4a7ce310effc5f4142b79 100644 (file)
@@ -38,7 +38,7 @@ static int __init br_init(void)
 
        err = stp_proto_register(&br_stp_proto);
        if (err < 0) {
-               printk(KERN_ERR "bridge: can't register sap for STP\n");
+               pr_err("bridge: can't register sap for STP\n");
                return err;
        }
 
index 90a9024e5c1eaf30713258c4d32151a89cc87c06..eedf2c94820e26150d8823c2aa1652626c5f281d 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/netpoll.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/list.h>
+#include <linux/netfilter_bridge.h>
 
 #include <asm/uaccess.h>
 #include "br_private.h"
@@ -26,16 +29,24 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        const unsigned char *dest = skb->data;
        struct net_bridge_fdb_entry *dst;
        struct net_bridge_mdb_entry *mdst;
+       struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-       BR_INPUT_SKB_CB(skb)->brdev = dev;
+#ifdef CONFIG_BRIDGE_NETFILTER
+       if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
+               br_nf_pre_routing_finish_bridge_slow(skb);
+               return NETDEV_TX_OK;
+       }
+#endif
 
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
+       brstats->tx_packets++;
+       brstats->tx_bytes += skb->len;
+
+       BR_INPUT_SKB_CB(skb)->brdev = dev;
 
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
 
-       if (dest[0] & 1) {
+       if (is_multicast_ether_addr(dest)) {
                if (br_multicast_rcv(br, NULL, skb))
                        goto out;
 
@@ -81,6 +92,31 @@ static int br_dev_stop(struct net_device *dev)
        return 0;
 }
 
+static struct net_device_stats *br_get_stats(struct net_device *dev)
+{
+       struct net_bridge *br = netdev_priv(dev);
+       struct net_device_stats *stats = &dev->stats;
+       struct br_cpu_netstats sum = { 0 };
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu) {
+               const struct br_cpu_netstats *bstats
+                       = per_cpu_ptr(br->stats, cpu);
+
+               sum.tx_bytes   += bstats->tx_bytes;
+               sum.tx_packets += bstats->tx_packets;
+               sum.rx_bytes   += bstats->rx_bytes;
+               sum.rx_packets += bstats->rx_packets;
+       }
+
+       stats->tx_bytes   = sum.tx_bytes;
+       stats->tx_packets = sum.tx_packets;
+       stats->rx_bytes   = sum.rx_bytes;
+       stats->rx_packets = sum.rx_packets;
+
+       return stats;
+}
+
 static int br_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct net_bridge *br = netdev_priv(dev);
@@ -162,6 +198,78 @@ static int br_set_tx_csum(struct net_device *dev, u32 data)
        return 0;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static bool br_devices_support_netpoll(struct net_bridge *br)
+{
+       struct net_bridge_port *p;
+       bool ret = true;
+       int count = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&br->lock, flags);
+       list_for_each_entry(p, &br->port_list, list) {
+               count++;
+               if ((p->dev->priv_flags & IFF_DISABLE_NETPOLL) ||
+                   !p->dev->netdev_ops->ndo_poll_controller)
+                       ret = false;
+       }
+       spin_unlock_irqrestore(&br->lock, flags);
+       return count != 0 && ret;
+}
+
+static void br_poll_controller(struct net_device *br_dev)
+{
+       struct netpoll *np = br_dev->npinfo->netpoll;
+
+       if (np->real_dev != br_dev)
+               netpoll_poll_dev(np->real_dev);
+}
+
+void br_netpoll_cleanup(struct net_device *dev)
+{
+       struct net_bridge *br = netdev_priv(dev);
+       struct net_bridge_port *p, *n;
+       const struct net_device_ops *ops;
+
+       br->dev->npinfo = NULL;
+       list_for_each_entry_safe(p, n, &br->port_list, list) {
+               if (p->dev) {
+                       ops = p->dev->netdev_ops;
+                       if (ops->ndo_netpoll_cleanup)
+                               ops->ndo_netpoll_cleanup(p->dev);
+                       else
+                               p->dev->npinfo = NULL;
+               }
+       }
+}
+
+void br_netpoll_disable(struct net_bridge *br,
+                       struct net_device *dev)
+{
+       if (br_devices_support_netpoll(br))
+               br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+       if (dev->netdev_ops->ndo_netpoll_cleanup)
+               dev->netdev_ops->ndo_netpoll_cleanup(dev);
+       else
+               dev->npinfo = NULL;
+}
+
+void br_netpoll_enable(struct net_bridge *br,
+                      struct net_device *dev)
+{
+       if (br_devices_support_netpoll(br)) {
+               br->dev->priv_flags &= ~IFF_DISABLE_NETPOLL;
+               if (br->dev->npinfo)
+                       dev->npinfo = br->dev->npinfo;
+       } else if (!(br->dev->priv_flags & IFF_DISABLE_NETPOLL)) {
+               br->dev->priv_flags |= IFF_DISABLE_NETPOLL;
+               br_info(br,"new device %s does not support netpoll (disabling)",
+                       dev->name);
+       }
+}
+
+#endif
+
 static const struct ethtool_ops br_ethtool_ops = {
        .get_drvinfo    = br_getinfo,
        .get_link       = ethtool_op_get_link,
@@ -180,19 +288,32 @@ static const struct net_device_ops br_netdev_ops = {
        .ndo_open                = br_dev_open,
        .ndo_stop                = br_dev_stop,
        .ndo_start_xmit          = br_dev_xmit,
+       .ndo_get_stats           = br_get_stats,
        .ndo_set_mac_address     = br_set_mac_address,
        .ndo_set_multicast_list  = br_dev_set_multicast_list,
        .ndo_change_mtu          = br_change_mtu,
        .ndo_do_ioctl            = br_dev_ioctl,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_netpoll_cleanup     = br_netpoll_cleanup,
+       .ndo_poll_controller     = br_poll_controller,
+#endif
 };
 
+static void br_dev_free(struct net_device *dev)
+{
+       struct net_bridge *br = netdev_priv(dev);
+
+       free_percpu(br->stats);
+       free_netdev(dev);
+}
+
 void br_dev_setup(struct net_device *dev)
 {
        random_ether_addr(dev->dev_addr);
        ether_setup(dev);
 
        dev->netdev_ops = &br_netdev_ops;
-       dev->destructor = free_netdev;
+       dev->destructor = br_dev_free;
        SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
        dev->tx_queue_len = 0;
        dev->priv_flags = IFF_EBRIDGE;
index 9101a4e5620129fa4d29df1a7e2cbde264cf88f2..26637439965bef745542f7baa4242d5249a33d9d 100644 (file)
@@ -353,8 +353,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
                 */
                if (fdb->is_local)
                        return 0;
-
-               printk(KERN_WARNING "%s adding interface with same address "
+               br_warn(br, "adding interface %s with same address "
                       "as a received packet\n",
                       source->dev->name);
                fdb_delete(fdb);
@@ -397,9 +396,9 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
                /* attempt to update an entry for a local interface */
                if (unlikely(fdb->is_local)) {
                        if (net_ratelimit())
-                               printk(KERN_WARNING "%s: received packet with "
-                                      "own address as source address\n",
-                                      source->dev->name);
+                               br_warn(br, "received packet on %s with "
+                                       "own address as source address\n",
+                                       source->dev->name);
                } else {
                        /* fastpath: update of existing entry */
                        fdb->dst = source;
index 7a241c396981eebb9ee1357daf88e7d18f3f8db8..a98ef13930979a129a8d0195e5a94dee3ec7bd2a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/netpoll.h>
 #include <linux/skbuff.h>
 #include <linux/if_vlan.h>
 #include <linux/netfilter_bridge.h>
@@ -44,13 +45,19 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
        if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
                kfree_skb(skb);
        else {
-               /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
+               /* ip_fragment doesn't copy the MAC header */
                if (nf_bridge_maybe_copy_header(skb))
                        kfree_skb(skb);
                else {
                        skb_push(skb, ETH_HLEN);
 
-                       dev_queue_xmit(skb);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+                       if (unlikely(skb->dev->priv_flags & IFF_IN_NETPOLL)) {
+                               netpoll_send_skb(skb->dev->npinfo->netpoll, skb);
+                               skb->dev->priv_flags &= ~IFF_IN_NETPOLL;
+                       } else
+#endif
+                               dev_queue_xmit(skb);
                }
        }
 
@@ -59,16 +66,30 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
 
 int br_forward_finish(struct sk_buff *skb)
 {
-       return NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
+       return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
                       br_dev_queue_push_xmit);
 
 }
 
 static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 {
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       struct net_bridge *br = to->br;
+       if (unlikely(br->dev->priv_flags & IFF_IN_NETPOLL)) {
+               struct netpoll *np;
+               to->dev->npinfo = skb->dev->npinfo;
+               np = skb->dev->npinfo->netpoll;
+               np->real_dev = np->dev = to->dev;
+               to->dev->priv_flags |= IFF_IN_NETPOLL;
+       }
+#endif
        skb->dev = to->dev;
-       NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
-                       br_forward_finish);
+       NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+               br_forward_finish);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       if (skb->dev->npinfo)
+               skb->dev->npinfo->netpoll->dev = br->dev;
+#endif
 }
 
 static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
@@ -84,8 +105,8 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
        skb->dev = to->dev;
        skb_forward_csum(skb);
 
-       NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
-                       br_forward_finish);
+       NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
+               br_forward_finish);
 }
 
 /* called with rcu_read_lock */
@@ -208,17 +229,15 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
 {
        struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
        struct net_bridge *br = netdev_priv(dev);
-       struct net_bridge_port *port;
-       struct net_bridge_port *lport, *rport;
-       struct net_bridge_port *prev;
+       struct net_bridge_port *prev = NULL;
        struct net_bridge_port_group *p;
        struct hlist_node *rp;
 
-       prev = NULL;
-
-       rp = br->router_list.first;
-       p = mdst ? mdst->ports : NULL;
+       rp = rcu_dereference(br->router_list.first);
+       p = mdst ? rcu_dereference(mdst->ports) : NULL;
        while (p || rp) {
+               struct net_bridge_port *port, *lport, *rport;
+
                lport = p ? p->port : NULL;
                rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
                             NULL;
@@ -231,9 +250,9 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
                        goto out;
 
                if ((unsigned long)lport >= (unsigned long)port)
-                       p = p->next;
+                       p = rcu_dereference(p->next);
                if ((unsigned long)rport >= (unsigned long)port)
-                       rp = rp->next;
+                       rp = rcu_dereference(rp->next);
        }
 
        if (!prev)
index 0b6b1f2ff7acb4000892dd08e1e9834844d188e7..18b245e2c00edb642ef59c1aa2f5e03324a38790 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
+#include <linux/netpoll.h>
 #include <linux/ethtool.h>
 #include <linux/if_arp.h>
 #include <linux/module.h>
@@ -132,7 +133,7 @@ static void del_nbp(struct net_bridge_port *p)
        struct net_bridge *br = p->br;
        struct net_device *dev = p->dev;
 
-       sysfs_remove_link(br->ifobj, dev->name);
+       sysfs_remove_link(br->ifobj, p->dev->name);
 
        dev_set_promiscuity(dev, -1);
 
@@ -153,6 +154,7 @@ static void del_nbp(struct net_bridge_port *p)
        kobject_uevent(&p->kobj, KOBJ_REMOVE);
        kobject_del(&p->kobj);
 
+       br_netpoll_disable(br, dev);
        call_rcu(&p->rcu, destroy_nbp_rcu);
 }
 
@@ -165,6 +167,8 @@ static void del_br(struct net_bridge *br, struct list_head *head)
                del_nbp(p);
        }
 
+       br_netpoll_cleanup(br->dev);
+
        del_timer_sync(&br->gc_timer);
 
        br_sysfs_delbr(br->dev);
@@ -186,6 +190,12 @@ static struct net_device *new_bridge_dev(struct net *net, const char *name)
        br = netdev_priv(dev);
        br->dev = dev;
 
+       br->stats = alloc_percpu(struct br_cpu_netstats);
+       if (!br->stats) {
+               free_netdev(dev);
+               return NULL;
+       }
+
        spin_lock_init(&br->lock);
        INIT_LIST_HEAD(&br->port_list);
        spin_lock_init(&br->hash_lock);
@@ -438,6 +448,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        kobject_uevent(&p->kobj, KOBJ_ADD);
 
+       br_netpoll_enable(br, dev);
+
        return 0;
 err2:
        br_fdb_delete_by_port(br, p, 1);
index a82dde2d2ead34d32af8ecd3829ee5563d8cf710..d36e700f7a26505b4828a08302b5bfec27b06483 100644 (file)
@@ -24,14 +24,16 @@ const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 static int br_pass_frame_up(struct sk_buff *skb)
 {
        struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
+       struct net_bridge *br = netdev_priv(brdev);
+       struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-       brdev->stats.rx_packets++;
-       brdev->stats.rx_bytes += skb->len;
+       brstats->rx_packets++;
+       brstats->rx_bytes += skb->len;
 
        indev = skb->dev;
        skb->dev = brdev;
 
-       return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
+       return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
                       netif_receive_skb);
 }
 
@@ -154,7 +156,7 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
                if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
                        goto forward;
 
-               if (NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
+               if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
                            NULL, br_handle_local_finish))
                        return NULL;    /* frame consumed by filter */
                else
@@ -175,7 +177,7 @@ forward:
                if (!compare_ether_addr(p->br->dev->dev_addr, dest))
                        skb->pkt_type = PACKET_HOST;
 
-               NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+               NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
                        br_handle_frame_finish);
                break;
        default:
index 995afc4b04dc58bf46d0ca4b5b7d650247b37282..cb43312b846ee8f33be636e7ca69df3dd2eeb455 100644 (file)
@@ -412,6 +412,6 @@ int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
        }
 
-       pr_debug("Bridge does not support ioctl 0x%x\n", cmd);
+       br_debug(br, "Bridge does not support ioctl 0x%x\n", cmd);
        return -EOPNOTSUPP;
 }
index eaa0e1bae49bcf28dff4f10e648dbd5ee418554f..9d21d98ae5fa98cc5d187bc6ae9b6ceb85f294cc 100644 (file)
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <net/ip.h>
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <net/ipv6.h>
+#include <net/mld.h>
+#include <net/addrconf.h>
+#include <net/ip6_checksum.h>
+#endif
 
 #include "br_private.h"
 
-static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb, __be32 ip)
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline int ipv6_is_local_multicast(const struct in6_addr *addr)
 {
-       return jhash_1word(mdb->secret, (u32)ip) & (mdb->max - 1);
+       if (ipv6_addr_is_multicast(addr) &&
+           IPV6_ADDR_MC_SCOPE(addr) <= IPV6_ADDR_SCOPE_LINKLOCAL)
+               return 1;
+       return 0;
+}
+#endif
+
+static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
+{
+       if (a->proto != b->proto)
+               return 0;
+       switch (a->proto) {
+       case htons(ETH_P_IP):
+               return a->u.ip4 == b->u.ip4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case htons(ETH_P_IPV6):
+               return ipv6_addr_equal(&a->u.ip6, &b->u.ip6);
+#endif
+       }
+       return 0;
+}
+
+static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip)
+{
+       return jhash_1word(mdb->secret, (__force u32)ip) & (mdb->max - 1);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb,
+                               const struct in6_addr *ip)
+{
+       return jhash2((__force u32 *)ip->s6_addr32, 4, mdb->secret) & (mdb->max - 1);
+}
+#endif
+
+static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
+                            struct br_ip *ip)
+{
+       switch (ip->proto) {
+       case htons(ETH_P_IP):
+               return __br_ip4_hash(mdb, ip->u.ip4);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case htons(ETH_P_IPV6):
+               return __br_ip6_hash(mdb, &ip->u.ip6);
+#endif
+       }
+       return 0;
 }
 
 static struct net_bridge_mdb_entry *__br_mdb_ip_get(
-       struct net_bridge_mdb_htable *mdb, __be32 dst, int hash)
+       struct net_bridge_mdb_htable *mdb, struct br_ip *dst, int hash)
 {
        struct net_bridge_mdb_entry *mp;
        struct hlist_node *p;
 
        hlist_for_each_entry_rcu(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {
-               if (dst == mp->addr)
+               if (br_ip_equal(&mp->addr, dst))
                        return mp;
        }
 
        return NULL;
 }
 
-static struct net_bridge_mdb_entry *br_mdb_ip_get(
+static struct net_bridge_mdb_entry *br_mdb_ip4_get(
        struct net_bridge_mdb_htable *mdb, __be32 dst)
 {
-       if (!mdb)
-               return NULL;
+       struct br_ip br_dst;
+
+       br_dst.u.ip4 = dst;
+       br_dst.proto = htons(ETH_P_IP);
+
+       return __br_mdb_ip_get(mdb, &br_dst, __br_ip4_hash(mdb, dst));
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct net_bridge_mdb_entry *br_mdb_ip6_get(
+       struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst)
+{
+       struct br_ip br_dst;
+
+       ipv6_addr_copy(&br_dst.u.ip6, dst);
+       br_dst.proto = htons(ETH_P_IPV6);
 
+       return __br_mdb_ip_get(mdb, &br_dst, __br_ip6_hash(mdb, dst));
+}
+#endif
+
+static struct net_bridge_mdb_entry *br_mdb_ip_get(
+       struct net_bridge_mdb_htable *mdb, struct br_ip *dst)
+{
        return __br_mdb_ip_get(mdb, dst, br_ip_hash(mdb, dst));
 }
 
 struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
                                        struct sk_buff *skb)
 {
-       if (br->multicast_disabled)
+       struct net_bridge_mdb_htable *mdb = br->mdb;
+       struct br_ip ip;
+
+       if (!mdb || br->multicast_disabled)
                return NULL;
 
+       if (BR_INPUT_SKB_CB(skb)->igmp)
+               return NULL;
+
+       ip.proto = skb->protocol;
+
        switch (skb->protocol) {
        case htons(ETH_P_IP):
-               if (BR_INPUT_SKB_CB(skb)->igmp)
-                       break;
-               return br_mdb_ip_get(br->mdb, ip_hdr(skb)->daddr);
+               ip.u.ip4 = ip_hdr(skb)->daddr;
+               break;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case htons(ETH_P_IPV6):
+               ipv6_addr_copy(&ip.u.ip6, &ipv6_hdr(skb)->daddr);
+               break;
+#endif
+       default:
+               return NULL;
        }
 
-       return NULL;
+       return br_mdb_ip_get(mdb, &ip);
 }
 
 static void br_mdb_free(struct rcu_head *head)
@@ -95,7 +183,7 @@ static int br_mdb_copy(struct net_bridge_mdb_htable *new,
        for (i = 0; i < old->max; i++)
                hlist_for_each_entry(mp, p, &old->mhash[i], hlist[old->ver])
                        hlist_add_head(&mp->hlist[new->ver],
-                                      &new->mhash[br_ip_hash(new, mp->addr)]);
+                                      &new->mhash[br_ip_hash(new, &mp->addr)]);
 
        if (!elasticity)
                return 0;
@@ -163,7 +251,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
        struct net_bridge_port_group *p;
        struct net_bridge_port_group **pp;
 
-       mp = br_mdb_ip_get(mdb, pg->addr);
+       mp = br_mdb_ip_get(mdb, &pg->addr);
        if (WARN_ON(!mp))
                return;
 
@@ -171,7 +259,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
                if (p != pg)
                        continue;
 
-               *pp = p->next;
+               rcu_assign_pointer(*pp, p->next);
                hlist_del_init(&p->mglist);
                del_timer(&p->timer);
                del_timer(&p->query_timer);
@@ -249,8 +337,8 @@ out:
        return 0;
 }
 
-static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
-                                               __be32 group)
+static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
+                                                   __be32 group)
 {
        struct sk_buff *skb;
        struct igmphdr *ih;
@@ -314,12 +402,104 @@ out:
        return skb;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
+                                                   struct in6_addr *group)
+{
+       struct sk_buff *skb;
+       struct ipv6hdr *ip6h;
+       struct mld_msg *mldq;
+       struct ethhdr *eth;
+       u8 *hopopt;
+       unsigned long interval;
+
+       skb = netdev_alloc_skb_ip_align(br->dev, sizeof(*eth) + sizeof(*ip6h) +
+                                                8 + sizeof(*mldq));
+       if (!skb)
+               goto out;
+
+       skb->protocol = htons(ETH_P_IPV6);
+
+       /* Ethernet header */
+       skb_reset_mac_header(skb);
+       eth = eth_hdr(skb);
+
+       memcpy(eth->h_source, br->dev->dev_addr, 6);
+       ipv6_eth_mc_map(group, eth->h_dest);
+       eth->h_proto = htons(ETH_P_IPV6);
+       skb_put(skb, sizeof(*eth));
+
+       /* IPv6 header + HbH option */
+       skb_set_network_header(skb, skb->len);
+       ip6h = ipv6_hdr(skb);
+
+       *(__force __be32 *)ip6h = htonl(0x60000000);
+       ip6h->payload_len = 8 + sizeof(*mldq);
+       ip6h->nexthdr = IPPROTO_HOPOPTS;
+       ip6h->hop_limit = 1;
+       ipv6_addr_set(&ip6h->saddr, 0, 0, 0, 0);
+       ipv6_addr_set(&ip6h->daddr, htonl(0xff020000), 0, 0, htonl(1));
+
+       hopopt = (u8 *)(ip6h + 1);
+       hopopt[0] = IPPROTO_ICMPV6;             /* next hdr */
+       hopopt[1] = 0;                          /* length of HbH */
+       hopopt[2] = IPV6_TLV_ROUTERALERT;       /* Router Alert */
+       hopopt[3] = 2;                          /* Length of RA Option */
+       hopopt[4] = 0;                          /* Type = 0x0000 (MLD) */
+       hopopt[5] = 0;
+       hopopt[6] = IPV6_TLV_PAD0;              /* Pad0 */
+       hopopt[7] = IPV6_TLV_PAD0;              /* Pad0 */
+
+       skb_put(skb, sizeof(*ip6h) + 8);
+
+       /* ICMPv6 */
+       skb_set_transport_header(skb, skb->len);
+       mldq = (struct mld_msg *) icmp6_hdr(skb);
+
+       interval = ipv6_addr_any(group) ? br->multicast_last_member_interval :
+                                         br->multicast_query_response_interval;
+
+       mldq->mld_type = ICMPV6_MGM_QUERY;
+       mldq->mld_code = 0;
+       mldq->mld_cksum = 0;
+       mldq->mld_maxdelay = htons((u16)jiffies_to_msecs(interval));
+       mldq->mld_reserved = 0;
+       ipv6_addr_copy(&mldq->mld_mca, group);
+
+       /* checksum */
+       mldq->mld_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
+                                         sizeof(*mldq), IPPROTO_ICMPV6,
+                                         csum_partial(mldq,
+                                                      sizeof(*mldq), 0));
+       skb_put(skb, sizeof(*mldq));
+
+       __skb_pull(skb, sizeof(*eth));
+
+out:
+       return skb;
+}
+#endif
+
+static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br,
+                                               struct br_ip *addr)
+{
+       switch (addr->proto) {
+       case htons(ETH_P_IP):
+               return br_ip4_multicast_alloc_query(br, addr->u.ip4);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case htons(ETH_P_IPV6):
+               return br_ip6_multicast_alloc_query(br, &addr->u.ip6);
+#endif
+       }
+       return NULL;
+}
+
 static void br_multicast_send_group_query(struct net_bridge_mdb_entry *mp)
 {
        struct net_bridge *br = mp->br;
        struct sk_buff *skb;
 
-       skb = br_multicast_alloc_query(br, mp->addr);
+       skb = br_multicast_alloc_query(br, &mp->addr);
        if (!skb)
                goto timer;
 
@@ -353,7 +533,7 @@ static void br_multicast_send_port_group_query(struct net_bridge_port_group *pg)
        struct net_bridge *br = port->br;
        struct sk_buff *skb;
 
-       skb = br_multicast_alloc_query(br, pg->addr);
+       skb = br_multicast_alloc_query(br, &pg->addr);
        if (!skb)
                goto timer;
 
@@ -383,8 +563,8 @@ out:
 }
 
 static struct net_bridge_mdb_entry *br_multicast_get_group(
-       struct net_bridge *br, struct net_bridge_port *port, __be32 group,
-       int hash)
+       struct net_bridge *br, struct net_bridge_port *port,
+       struct br_ip *group, int hash)
 {
        struct net_bridge_mdb_htable *mdb = br->mdb;
        struct net_bridge_mdb_entry *mp;
@@ -396,9 +576,8 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
 
        hlist_for_each_entry(mp, p, &mdb->mhash[hash], hlist[mdb->ver]) {
                count++;
-               if (unlikely(group == mp->addr)) {
+               if (unlikely(br_ip_equal(group, &mp->addr)))
                        return mp;
-               }
        }
 
        elasticity = 0;
@@ -406,10 +585,9 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
 
        if (unlikely(count > br->hash_elasticity && count)) {
                if (net_ratelimit())
-                       printk(KERN_INFO "%s: Multicast hash table "
-                              "chain limit reached: %s\n",
-                              br->dev->name, port ? port->dev->name :
-                                                    br->dev->name);
+                       br_info(br, "Multicast hash table "
+                               "chain limit reached: %s\n",
+                               port ? port->dev->name : br->dev->name);
 
                elasticity = br->hash_elasticity;
        }
@@ -417,11 +595,9 @@ static struct net_bridge_mdb_entry *br_multicast_get_group(
        if (mdb->size >= max) {
                max *= 2;
                if (unlikely(max >= br->hash_max)) {
-                       printk(KERN_WARNING "%s: Multicast hash table maximum "
-                              "reached, disabling snooping: %s, %d\n",
-                              br->dev->name, port ? port->dev->name :
-                                                    br->dev->name,
-                              max);
+                       br_warn(br, "Multicast hash table maximum "
+                               "reached, disabling snooping: %s, %d\n",
+                               port ? port->dev->name : br->dev->name, max);
                        err = -E2BIG;
 disable:
                        br->multicast_disabled = 1;
@@ -432,22 +608,19 @@ disable:
        if (max > mdb->max || elasticity) {
                if (mdb->old) {
                        if (net_ratelimit())
-                               printk(KERN_INFO "%s: Multicast hash table "
-                                      "on fire: %s\n",
-                                      br->dev->name, port ? port->dev->name :
-                                                            br->dev->name);
+                               br_info(br, "Multicast hash table "
+                                       "on fire: %s\n",
+                                       port ? port->dev->name : br->dev->name);
                        err = -EEXIST;
                        goto err;
                }
 
                err = br_mdb_rehash(&br->mdb, max, elasticity);
                if (err) {
-                       printk(KERN_WARNING "%s: Cannot rehash multicast "
-                              "hash table, disabling snooping: "
-                              "%s, %d, %d\n",
-                              br->dev->name, port ? port->dev->name :
-                                                    br->dev->name,
-                              mdb->size, err);
+                       br_warn(br, "Cannot rehash multicast "
+                               "hash table, disabling snooping: %s, %d, %d\n",
+                               port ? port->dev->name : br->dev->name,
+                               mdb->size, err);
                        goto disable;
                }
 
@@ -463,7 +636,8 @@ err:
 }
 
 static struct net_bridge_mdb_entry *br_multicast_new_group(
-       struct net_bridge *br, struct net_bridge_port *port, __be32 group)
+       struct net_bridge *br, struct net_bridge_port *port,
+       struct br_ip *group)
 {
        struct net_bridge_mdb_htable *mdb = br->mdb;
        struct net_bridge_mdb_entry *mp;
@@ -496,7 +670,7 @@ rehash:
                goto out;
 
        mp->br = br;
-       mp->addr = group;
+       mp->addr = *group;
        setup_timer(&mp->timer, br_multicast_group_expired,
                    (unsigned long)mp);
        setup_timer(&mp->query_timer, br_multicast_group_query_expired,
@@ -510,7 +684,8 @@ out:
 }
 
 static int br_multicast_add_group(struct net_bridge *br,
-                                 struct net_bridge_port *port, __be32 group)
+                                 struct net_bridge_port *port,
+                                 struct br_ip *group)
 {
        struct net_bridge_mdb_entry *mp;
        struct net_bridge_port_group *p;
@@ -518,9 +693,6 @@ static int br_multicast_add_group(struct net_bridge *br,
        unsigned long now = jiffies;
        int err;
 
-       if (ipv4_is_local_multicast(group))
-               return 0;
-
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) ||
            (port && port->state == BR_STATE_DISABLED))
@@ -549,7 +721,7 @@ static int br_multicast_add_group(struct net_bridge *br,
        if (unlikely(!p))
                goto err;
 
-       p->addr = group;
+       p->addr = *group;
        p->port = port;
        p->next = *pp;
        hlist_add_head(&p->mglist, &port->mglist);
@@ -570,6 +742,38 @@ err:
        return err;
 }
 
+static int br_ip4_multicast_add_group(struct net_bridge *br,
+                                     struct net_bridge_port *port,
+                                     __be32 group)
+{
+       struct br_ip br_group;
+
+       if (ipv4_is_local_multicast(group))
+               return 0;
+
+       br_group.u.ip4 = group;
+       br_group.proto = htons(ETH_P_IP);
+
+       return br_multicast_add_group(br, port, &br_group);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_ip6_multicast_add_group(struct net_bridge *br,
+                                     struct net_bridge_port *port,
+                                     const struct in6_addr *group)
+{
+       struct br_ip br_group;
+
+       if (ipv6_is_local_multicast(group))
+               return 0;
+
+       ipv6_addr_copy(&br_group.u.ip6, group);
+       br_group.proto = htons(ETH_P_IP);
+
+       return br_multicast_add_group(br, port, &br_group);
+}
+#endif
+
 static void br_multicast_router_expired(unsigned long data)
 {
        struct net_bridge_port *port = (void *)data;
@@ -591,29 +795,45 @@ static void br_multicast_local_router_expired(unsigned long data)
 {
 }
 
-static void br_multicast_send_query(struct net_bridge *br,
-                                   struct net_bridge_port *port, u32 sent)
+static void __br_multicast_send_query(struct net_bridge *br,
+                                     struct net_bridge_port *port,
+                                     struct br_ip *ip)
 {
-       unsigned long time;
        struct sk_buff *skb;
 
-       if (!netif_running(br->dev) || br->multicast_disabled ||
-           timer_pending(&br->multicast_querier_timer))
-               return;
-
-       skb = br_multicast_alloc_query(br, 0);
+       skb = br_multicast_alloc_query(br, ip);
        if (!skb)
-               goto timer;
+               return;
 
        if (port) {
                __skb_push(skb, sizeof(struct ethhdr));
                skb->dev = port->dev;
-               NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+               NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
                        dev_queue_xmit);
        } else
                netif_rx(skb);
+}
+
+static void br_multicast_send_query(struct net_bridge *br,
+                                   struct net_bridge_port *port, u32 sent)
+{
+       unsigned long time;
+       struct br_ip br_group;
+
+       if (!netif_running(br->dev) || br->multicast_disabled ||
+           timer_pending(&br->multicast_querier_timer))
+               return;
+
+       memset(&br_group.u, 0, sizeof(br_group.u));
+
+       br_group.proto = htons(ETH_P_IP);
+       __br_multicast_send_query(br, port, &br_group);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       br_group.proto = htons(ETH_P_IPV6);
+       __br_multicast_send_query(br, port, &br_group);
+#endif
 
-timer:
        time = jiffies;
        time += sent < br->multicast_startup_query_count ?
                br->multicast_startup_query_interval :
@@ -698,9 +918,9 @@ void br_multicast_disable_port(struct net_bridge_port *port)
        spin_unlock(&br->multicast_lock);
 }
 
-static int br_multicast_igmp3_report(struct net_bridge *br,
-                                    struct net_bridge_port *port,
-                                    struct sk_buff *skb)
+static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        struct sk_buff *skb)
 {
        struct igmpv3_report *ih;
        struct igmpv3_grec *grec;
@@ -745,7 +965,7 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
                        continue;
                }
 
-               err = br_multicast_add_group(br, port, group);
+               err = br_ip4_multicast_add_group(br, port, group);
                if (err)
                        break;
        }
@@ -753,24 +973,87 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
        return err;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_ip6_multicast_mld2_report(struct net_bridge *br,
+                                       struct net_bridge_port *port,
+                                       struct sk_buff *skb)
+{
+       struct icmp6hdr *icmp6h;
+       struct mld2_grec *grec;
+       int i;
+       int len;
+       int num;
+       int err = 0;
+
+       if (!pskb_may_pull(skb, sizeof(*icmp6h)))
+               return -EINVAL;
+
+       icmp6h = icmp6_hdr(skb);
+       num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
+       len = sizeof(*icmp6h);
+
+       for (i = 0; i < num; i++) {
+               __be16 *nsrcs, _nsrcs;
+
+               nsrcs = skb_header_pointer(skb,
+                                          len + offsetof(struct mld2_grec,
+                                                         grec_mca),
+                                          sizeof(_nsrcs), &_nsrcs);
+               if (!nsrcs)
+                       return -EINVAL;
+
+               if (!pskb_may_pull(skb,
+                                  len + sizeof(*grec) +
+                                  sizeof(struct in6_addr) * (*nsrcs)))
+                       return -EINVAL;
+
+               grec = (struct mld2_grec *)(skb->data + len);
+               len += sizeof(*grec) + sizeof(struct in6_addr) * (*nsrcs);
+
+               /* We treat these as MLDv1 reports for now. */
+               switch (grec->grec_type) {
+               case MLD2_MODE_IS_INCLUDE:
+               case MLD2_MODE_IS_EXCLUDE:
+               case MLD2_CHANGE_TO_INCLUDE:
+               case MLD2_CHANGE_TO_EXCLUDE:
+               case MLD2_ALLOW_NEW_SOURCES:
+               case MLD2_BLOCK_OLD_SOURCES:
+                       break;
+
+               default:
+                       continue;
+               }
+
+               err = br_ip6_multicast_add_group(br, port, &grec->grec_mca);
+               if (!err)
+                       break;
+       }
+
+       return err;
+}
+#endif
+
+/*
+ * Add port to rotuer_list
+ *  list is maintained ordered by pointer value
+ *  and locked by br->multicast_lock and RCU
+ */
 static void br_multicast_add_router(struct net_bridge *br,
                                    struct net_bridge_port *port)
 {
-       struct hlist_node *p;
-       struct hlist_node **h;
-
-       for (h = &br->router_list.first;
-            (p = *h) &&
-            (unsigned long)container_of(p, struct net_bridge_port, rlist) >
-            (unsigned long)port;
-            h = &p->next)
-               ;
-
-       port->rlist.pprev = h;
-       port->rlist.next = p;
-       rcu_assign_pointer(*h, &port->rlist);
-       if (p)
-               p->pprev = &port->rlist.next;
+       struct net_bridge_port *p;
+       struct hlist_node *n, *slot = NULL;
+
+       hlist_for_each_entry(p, n, &br->router_list, rlist) {
+               if ((unsigned long) port >= (unsigned long) p)
+                       break;
+               slot = n;
+       }
+
+       if (slot)
+               hlist_add_after_rcu(slot, &port->rlist);
+       else
+               hlist_add_head_rcu(&port->rlist, &br->router_list);
 }
 
 static void br_multicast_mark_router(struct net_bridge *br,
@@ -800,7 +1083,7 @@ timer:
 
 static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
-                                       __be32 saddr)
+                                       int saddr)
 {
        if (saddr)
                mod_timer(&br->multicast_querier_timer,
@@ -811,9 +1094,9 @@ static void br_multicast_query_received(struct net_bridge *br,
        br_multicast_mark_router(br, port);
 }
 
-static int br_multicast_query(struct net_bridge *br,
-                             struct net_bridge_port *port,
-                             struct sk_buff *skb)
+static int br_ip4_multicast_query(struct net_bridge *br,
+                                 struct net_bridge_port *port,
+                                 struct sk_buff *skb)
 {
        struct iphdr *iph = ip_hdr(skb);
        struct igmphdr *ih = igmp_hdr(skb);
@@ -831,7 +1114,7 @@ static int br_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, iph->saddr);
+       br_multicast_query_received(br, port, !!iph->saddr);
 
        group = ih->group;
 
@@ -859,7 +1142,7 @@ static int br_multicast_query(struct net_bridge *br,
        if (!group)
                goto out;
 
-       mp = br_mdb_ip_get(br->mdb, group);
+       mp = br_mdb_ip4_get(br->mdb, group);
        if (!mp)
                goto out;
 
@@ -883,9 +1166,78 @@ out:
        return err;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_ip6_multicast_query(struct net_bridge *br,
+                                 struct net_bridge_port *port,
+                                 struct sk_buff *skb)
+{
+       struct ipv6hdr *ip6h = ipv6_hdr(skb);
+       struct mld_msg *mld = (struct mld_msg *) icmp6_hdr(skb);
+       struct net_bridge_mdb_entry *mp;
+       struct mld2_query *mld2q;
+       struct net_bridge_port_group *p, **pp;
+       unsigned long max_delay;
+       unsigned long now = jiffies;
+       struct in6_addr *group = NULL;
+       int err = 0;
+
+       spin_lock(&br->multicast_lock);
+       if (!netif_running(br->dev) ||
+           (port && port->state == BR_STATE_DISABLED))
+               goto out;
+
+       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
+
+       if (skb->len == sizeof(*mld)) {
+               if (!pskb_may_pull(skb, sizeof(*mld))) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               mld = (struct mld_msg *) icmp6_hdr(skb);
+               max_delay = msecs_to_jiffies(htons(mld->mld_maxdelay));
+               if (max_delay)
+                       group = &mld->mld_mca;
+       } else if (skb->len >= sizeof(*mld2q)) {
+               if (!pskb_may_pull(skb, sizeof(*mld2q))) {
+                       err = -EINVAL;
+                       goto out;
+               }
+               mld2q = (struct mld2_query *)icmp6_hdr(skb);
+               if (!mld2q->mld2q_nsrcs)
+                       group = &mld2q->mld2q_mca;
+               max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(mld2q->mld2q_mrc) : 1;
+       }
+
+       if (!group)
+               goto out;
+
+       mp = br_mdb_ip6_get(br->mdb, group);
+       if (!mp)
+               goto out;
+
+       max_delay *= br->multicast_last_member_count;
+       if (!hlist_unhashed(&mp->mglist) &&
+           (timer_pending(&mp->timer) ?
+            time_after(mp->timer.expires, now + max_delay) :
+            try_to_del_timer_sync(&mp->timer) >= 0))
+               mod_timer(&mp->timer, now + max_delay);
+
+       for (pp = &mp->ports; (p = *pp); pp = &p->next) {
+               if (timer_pending(&p->timer) ?
+                   time_after(p->timer.expires, now + max_delay) :
+                   try_to_del_timer_sync(&p->timer) >= 0)
+                       mod_timer(&mp->timer, now + max_delay);
+       }
+
+out:
+       spin_unlock(&br->multicast_lock);
+       return err;
+}
+#endif
+
 static void br_multicast_leave_group(struct net_bridge *br,
                                     struct net_bridge_port *port,
-                                    __be32 group)
+                                    struct br_ip *group)
 {
        struct net_bridge_mdb_htable *mdb;
        struct net_bridge_mdb_entry *mp;
@@ -893,9 +1245,6 @@ static void br_multicast_leave_group(struct net_bridge *br,
        unsigned long now;
        unsigned long time;
 
-       if (ipv4_is_local_multicast(group))
-               return;
-
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) ||
            (port && port->state == BR_STATE_DISABLED) ||
@@ -946,6 +1295,38 @@ out:
        spin_unlock(&br->multicast_lock);
 }
 
+static void br_ip4_multicast_leave_group(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        __be32 group)
+{
+       struct br_ip br_group;
+
+       if (ipv4_is_local_multicast(group))
+               return;
+
+       br_group.u.ip4 = group;
+       br_group.proto = htons(ETH_P_IP);
+
+       br_multicast_leave_group(br, port, &br_group);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static void br_ip6_multicast_leave_group(struct net_bridge *br,
+                                        struct net_bridge_port *port,
+                                        const struct in6_addr *group)
+{
+       struct br_ip br_group;
+
+       if (ipv6_is_local_multicast(group))
+               return;
+
+       ipv6_addr_copy(&br_group.u.ip6, group);
+       br_group.proto = htons(ETH_P_IPV6);
+
+       br_multicast_leave_group(br, port, &br_group);
+}
+#endif
+
 static int br_multicast_ipv4_rcv(struct net_bridge *br,
                                 struct net_bridge_port *port,
                                 struct sk_buff *skb)
@@ -1000,8 +1381,6 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
        if (!pskb_may_pull(skb2, sizeof(*ih)))
                goto out;
 
-       iph = ip_hdr(skb2);
-
        switch (skb2->ip_summed) {
        case CHECKSUM_COMPLETE:
                if (!csum_fold(skb2->csum))
@@ -1022,16 +1401,16 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
        case IGMP_HOST_MEMBERSHIP_REPORT:
        case IGMPV2_HOST_MEMBERSHIP_REPORT:
                BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
-               err = br_multicast_add_group(br, port, ih->group);
+               err = br_ip4_multicast_add_group(br, port, ih->group);
                break;
        case IGMPV3_HOST_MEMBERSHIP_REPORT:
-               err = br_multicast_igmp3_report(br, port, skb2);
+               err = br_ip4_multicast_igmp3_report(br, port, skb2);
                break;
        case IGMP_HOST_MEMBERSHIP_QUERY:
-               err = br_multicast_query(br, port, skb2);
+               err = br_ip4_multicast_query(br, port, skb2);
                break;
        case IGMP_HOST_LEAVE_MESSAGE:
-               br_multicast_leave_group(br, port, ih->group);
+               br_ip4_multicast_leave_group(br, port, ih->group);
                break;
        }
 
@@ -1043,6 +1422,123 @@ err_out:
        return err;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int br_multicast_ipv6_rcv(struct net_bridge *br,
+                                struct net_bridge_port *port,
+                                struct sk_buff *skb)
+{
+       struct sk_buff *skb2 = skb;
+       struct ipv6hdr *ip6h;
+       struct icmp6hdr *icmp6h;
+       u8 nexthdr;
+       unsigned len;
+       unsigned offset;
+       int err;
+
+       if (!pskb_may_pull(skb, sizeof(*ip6h)))
+               return -EINVAL;
+
+       ip6h = ipv6_hdr(skb);
+
+       /*
+        * We're interested in MLD messages only.
+        *  - Version is 6
+        *  - MLD has always Router Alert hop-by-hop option
+        *  - But we do not support jumbrograms.
+        */
+       if (ip6h->version != 6 ||
+           ip6h->nexthdr != IPPROTO_HOPOPTS ||
+           ip6h->payload_len == 0)
+               return 0;
+
+       len = ntohs(ip6h->payload_len);
+       if (skb->len < len)
+               return -EINVAL;
+
+       nexthdr = ip6h->nexthdr;
+       offset = ipv6_skip_exthdr(skb, sizeof(*ip6h), &nexthdr);
+
+       if (offset < 0 || nexthdr != IPPROTO_ICMPV6)
+               return 0;
+
+       /* Okay, we found ICMPv6 header */
+       skb2 = skb_clone(skb, GFP_ATOMIC);
+       if (!skb2)
+               return -ENOMEM;
+
+       len -= offset - skb_network_offset(skb2);
+
+       __skb_pull(skb2, offset);
+       skb_reset_transport_header(skb2);
+
+       err = -EINVAL;
+       if (!pskb_may_pull(skb2, sizeof(*icmp6h)))
+               goto out;
+
+       icmp6h = icmp6_hdr(skb2);
+
+       switch (icmp6h->icmp6_type) {
+       case ICMPV6_MGM_QUERY:
+       case ICMPV6_MGM_REPORT:
+       case ICMPV6_MGM_REDUCTION:
+       case ICMPV6_MLD2_REPORT:
+               break;
+       default:
+               err = 0;
+               goto out;
+       }
+
+       /* Okay, we found MLD message. Check further. */
+       if (skb2->len > len) {
+               err = pskb_trim_rcsum(skb2, len);
+               if (err)
+                       goto out;
+       }
+
+       switch (skb2->ip_summed) {
+       case CHECKSUM_COMPLETE:
+               if (!csum_fold(skb2->csum))
+                       break;
+               /*FALLTHROUGH*/
+       case CHECKSUM_NONE:
+               skb2->csum = 0;
+               if (skb_checksum_complete(skb2))
+                       goto out;
+       }
+
+       err = 0;
+
+       BR_INPUT_SKB_CB(skb)->igmp = 1;
+
+       switch (icmp6h->icmp6_type) {
+       case ICMPV6_MGM_REPORT:
+           {
+               struct mld_msg *mld = (struct mld_msg *)icmp6h;
+               BR_INPUT_SKB_CB(skb2)->mrouters_only = 1;
+               err = br_ip6_multicast_add_group(br, port, &mld->mld_mca);
+               break;
+           }
+       case ICMPV6_MLD2_REPORT:
+               err = br_ip6_multicast_mld2_report(br, port, skb2);
+               break;
+       case ICMPV6_MGM_QUERY:
+               err = br_ip6_multicast_query(br, port, skb2);
+               break;
+       case ICMPV6_MGM_REDUCTION:
+           {
+               struct mld_msg *mld = (struct mld_msg *)icmp6h;
+               br_ip6_multicast_leave_group(br, port, &mld->mld_mca);
+           }
+       }
+
+out:
+       __skb_push(skb2, offset);
+       if (skb2 != skb)
+               kfree_skb(skb2);
+       return err;
+}
+#endif
+
 int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
                     struct sk_buff *skb)
 {
@@ -1055,6 +1551,10 @@ int br_multicast_rcv(struct net_bridge *br, struct net_bridge_port *port,
        switch (skb->protocol) {
        case htons(ETH_P_IP):
                return br_multicast_ipv4_rcv(br, port, skb);
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       case htons(ETH_P_IPV6):
+               return br_multicast_ipv6_rcv(br, port, skb);
+#endif
        }
 
        return 0;
index 4c4977d12fd64d81a0c0281cd166346b81e65da1..44420992f72f17cc61f9e854ff511c8ec2bb270b 100644 (file)
@@ -3,15 +3,8 @@
  *     Linux ethernet bridge
  *
  *     Authors:
- *     Lennert Buytenhek               <buytenh@gnu.org>
- *     Bart De Schuymer (maintainer)   <bdschuym@pandora.be>
- *
- *     Changes:
- *     Apr 29 2003: physdev module support (bdschuym)
- *     Jun 19 2003: let arptables see bridged ARP traffic (bdschuym)
- *     Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge
- *                  (bdschuym)
- *     Sep 01 2004: add IPv6 filtering (bdschuym)
+ *     Lennert Buytenhek               <buytenh@gnu.org>
+ *     Bart De Schuymer                <bdschuym@pandora.be>
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -204,15 +197,24 @@ static inline void nf_bridge_save_header(struct sk_buff *skb)
                                         skb->nf_bridge->data, header_size);
 }
 
-/*
- * When forwarding bridge frames, we save a copy of the original
- * header before processing.
+static inline void nf_bridge_update_protocol(struct sk_buff *skb)
+{
+       if (skb->nf_bridge->mask & BRNF_8021Q)
+               skb->protocol = htons(ETH_P_8021Q);
+       else if (skb->nf_bridge->mask & BRNF_PPPoE)
+               skb->protocol = htons(ETH_P_PPP_SES);
+}
+
+/* Fill in the header for fragmented IP packets handled by
+ * the IPv4 connection tracking code.
  */
 int nf_bridge_copy_header(struct sk_buff *skb)
 {
        int err;
-       int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
+       unsigned int header_size;
 
+       nf_bridge_update_protocol(skb);
+       header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
        err = skb_cow_head(skb, header_size);
        if (err)
                return err;
@@ -246,27 +248,48 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
        skb_dst_set(skb, &rt->u.dst);
 
        skb->dev = nf_bridge->physindev;
+       nf_bridge_update_protocol(skb);
        nf_bridge_push_encap_header(skb);
-       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+       NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
                       br_handle_frame_finish, 1);
 
        return 0;
 }
 
-static void __br_dnat_complain(void)
+/* Obtain the correct destination MAC address, while preserving the original
+ * source MAC address. If we already know this address, we just copy it. If we
+ * don't, we use the neighbour framework to find out. In both cases, we make
+ * sure that br_handle_frame_finish() is called afterwards.
+ */
+static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
 {
-       static unsigned long last_complaint;
+       struct nf_bridge_info *nf_bridge = skb->nf_bridge;
+       struct dst_entry *dst;
 
-       if (jiffies - last_complaint >= 5 * HZ) {
-               printk(KERN_WARNING "Performing cross-bridge DNAT requires IP "
-                      "forwarding to be enabled\n");
-               last_complaint = jiffies;
+       skb->dev = bridge_parent(skb->dev);
+       if (!skb->dev)
+               goto free_skb;
+       dst = skb_dst(skb);
+       if (dst->hh) {
+               neigh_hh_bridge(dst->hh, skb);
+               skb->dev = nf_bridge->physindev;
+               return br_handle_frame_finish(skb);
+       } else if (dst->neighbour) {
+               /* the neighbour function below overwrites the complete
+                * MAC header, so we save the Ethernet source address and
+                * protocol number. */
+               skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN);
+               /* tell br_dev_xmit to continue with forwarding */
+               nf_bridge->mask |= BRNF_BRIDGED_DNAT;
+               return dst->neighbour->output(skb);
        }
+free_skb:
+       kfree_skb(skb);
+       return 0;
 }
 
 /* This requires some explaining. If DNAT has taken place,
- * we will need to fix up the destination Ethernet address,
- * and this is a tricky process.
+ * we will need to fix up the destination Ethernet address.
  *
  * There are two cases to consider:
  * 1. The packet was DNAT'ed to a device in the same bridge
@@ -280,62 +303,29 @@ static void __br_dnat_complain(void)
  * call ip_route_input() and to look at skb->dst->dev, which is
  * changed to the destination device if ip_route_input() succeeds.
  *
- * Let us first consider the case that ip_route_input() succeeds:
- *
- * If skb->dst->dev equals the logical bridge device the packet
- * came in on, we can consider this bridging. The packet is passed
- * through the neighbour output function to build a new destination
- * MAC address, which will make the packet enter br_nf_local_out()
- * not much later. In that function it is assured that the iptables
- * FORWARD chain is traversed for the packet.
+ * Let's first consider the case that ip_route_input() succeeds:
  *
+ * If the output device equals the logical bridge device the packet
+ * came in on, we can consider this bridging. The corresponding MAC
+ * address will be obtained in br_nf_pre_routing_finish_bridge.
  * Otherwise, the packet is considered to be routed and we just
  * change the destination MAC address so that the packet will
  * later be passed up to the IP stack to be routed. For a redirected
  * packet, ip_route_input() will give back the localhost as output device,
  * which differs from the bridge device.
  *
- * Let us now consider the case that ip_route_input() fails:
+ * Let's now consider the case that ip_route_input() fails:
  *
  * This can be because the destination address is martian, in which case
  * the packet will be dropped.
- * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input()
- * will fail, while __ip_route_output_key() will return success. The source
- * address for __ip_route_output_key() is set to zero, so __ip_route_output_key
+ * If IP forwarding is disabled, ip_route_input() will fail, while
+ * ip_route_output_key() can return success. The source
+ * address for ip_route_output_key() is set to zero, so ip_route_output_key()
  * thinks we're handling a locally generated packet and won't care
- * if IP forwarding is allowed. We send a warning message to the users's
- * log telling her to put IP forwarding on.
- *
- * ip_route_input() will also fail if there is no route available.
- * In that case we just drop the packet.
- *
- * --Lennert, 20020411
- * --Bart, 20020416 (updated)
- * --Bart, 20021007 (updated)
- * --Bart, 20062711 (updated) */
-static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
-{
-       if (skb->pkt_type == PACKET_OTHERHOST) {
-               skb->pkt_type = PACKET_HOST;
-               skb->nf_bridge->mask |= BRNF_PKT_TYPE;
-       }
-       skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
-
-       skb->dev = bridge_parent(skb->dev);
-       if (skb->dev) {
-               struct dst_entry *dst = skb_dst(skb);
-
-               nf_bridge_pull_encap_header(skb);
-
-               if (dst->hh)
-                       return neigh_hh_output(dst->hh, skb);
-               else if (dst->neighbour)
-                       return dst->neighbour->output(skb);
-       }
-       kfree_skb(skb);
-       return 0;
-}
-
+ * if IP forwarding is enabled. If the output device equals the logical bridge
+ * device, we proceed as if ip_route_input() succeeded. If it differs from the
+ * logical bridge port or if ip_route_output_key() fails we drop the packet.
+ */
 static int br_nf_pre_routing_finish(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
@@ -379,11 +369,6 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
                                        skb_dst_set(skb, (struct dst_entry *)rt);
                                        goto bridged_dnat;
                                }
-                               /* we are sure that forwarding is disabled, so printing
-                                * this message is no problem. Note that the packet could
-                                * still have a martian destination address, in which case
-                                * the packet could be dropped even if forwarding were enabled */
-                               __br_dnat_complain();
                                dst_release((struct dst_entry *)rt);
                        }
 free_skb:
@@ -392,12 +377,11 @@ free_skb:
                } else {
                        if (skb_dst(skb)->dev == dev) {
 bridged_dnat:
-                               /* Tell br_nf_local_out this is a
-                                * bridged frame */
-                               nf_bridge->mask |= BRNF_BRIDGED_DNAT;
                                skb->dev = nf_bridge->physindev;
+                               nf_bridge_update_protocol(skb);
                                nf_bridge_push_encap_header(skb);
-                               NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
+                               NF_HOOK_THRESH(NFPROTO_BRIDGE,
+                                              NF_BR_PRE_ROUTING,
                                               skb, skb->dev, NULL,
                                               br_nf_pre_routing_finish_bridge,
                                               1);
@@ -417,8 +401,9 @@ bridged_dnat:
        }
 
        skb->dev = nf_bridge->physindev;
+       nf_bridge_update_protocol(skb);
        nf_bridge_push_encap_header(skb);
-       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+       NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
                       br_handle_frame_finish, 1);
 
        return 0;
@@ -437,6 +422,10 @@ static struct net_device *setup_pre_routing(struct sk_buff *skb)
        nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
        nf_bridge->physindev = skb->dev;
        skb->dev = bridge_parent(skb->dev);
+       if (skb->protocol == htons(ETH_P_8021Q))
+               nf_bridge->mask |= BRNF_8021Q;
+       else if (skb->protocol == htons(ETH_P_PPP_SES))
+               nf_bridge->mask |= BRNF_PPPoE;
 
        return skb->dev;
 }
@@ -535,7 +524,8 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
        if (!setup_pre_routing(skb))
                return NF_DROP;
 
-       NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
+       skb->protocol = htons(ETH_P_IPV6);
+       NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
                br_nf_pre_routing_finish_ipv6);
 
        return NF_STOLEN;
@@ -607,8 +597,9 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb,
        if (!setup_pre_routing(skb))
                return NF_DROP;
        store_orig_dstaddr(skb);
+       skb->protocol = htons(ETH_P_IP);
 
-       NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
+       NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
                br_nf_pre_routing_finish);
 
        return NF_STOLEN;
@@ -652,11 +643,13 @@ static int br_nf_forward_finish(struct sk_buff *skb)
                        skb->pkt_type = PACKET_OTHERHOST;
                        nf_bridge->mask ^= BRNF_PKT_TYPE;
                }
+               nf_bridge_update_protocol(skb);
        } else {
                in = *((struct net_device **)(skb->cb));
        }
        nf_bridge_push_encap_header(skb);
-       NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
+
+       NF_HOOK_THRESH(NFPROTO_BRIDGE, NF_BR_FORWARD, skb, in,
                       skb->dev, br_forward_finish, 1);
        return 0;
 }
@@ -707,6 +700,10 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
        /* The physdev module checks on this */
        nf_bridge->mask |= BRNF_BRIDGED;
        nf_bridge->physoutdev = skb->dev;
+       if (pf == PF_INET)
+               skb->protocol = htons(ETH_P_IP);
+       else
+               skb->protocol = htons(ETH_P_IPV6);
 
        NF_HOOK(pf, NF_INET_FORWARD, skb, bridge_parent(in), parent,
                br_nf_forward_finish);
@@ -744,60 +741,11 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb,
        return NF_STOLEN;
 }
 
-/* PF_BRIDGE/LOCAL_OUT ***********************************************
- *
- * This function sees both locally originated IP packets and forwarded
- * IP packets (in both cases the destination device is a bridge
- * device). It also sees bridged-and-DNAT'ed packets.
- *
- * If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged
- * and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward()
- * will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority
- * NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
- * will be executed.
- */
-static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb,
-                                   const struct net_device *in,
-                                   const struct net_device *out,
-                                   int (*okfn)(struct sk_buff *))
-{
-       struct net_device *realindev;
-       struct nf_bridge_info *nf_bridge;
-
-       if (!skb->nf_bridge)
-               return NF_ACCEPT;
-
-       /* Need exclusive nf_bridge_info since we might have multiple
-        * different physoutdevs. */
-       if (!nf_bridge_unshare(skb))
-               return NF_DROP;
-
-       nf_bridge = skb->nf_bridge;
-       if (!(nf_bridge->mask & BRNF_BRIDGED_DNAT))
-               return NF_ACCEPT;
-
-       /* Bridged, take PF_BRIDGE/FORWARD.
-        * (see big note in front of br_nf_pre_routing_finish) */
-       nf_bridge->physoutdev = skb->dev;
-       realindev = nf_bridge->physindev;
-
-       if (nf_bridge->mask & BRNF_PKT_TYPE) {
-               skb->pkt_type = PACKET_OTHERHOST;
-               nf_bridge->mask ^= BRNF_PKT_TYPE;
-       }
-       nf_bridge_push_encap_header(skb);
-
-       NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev,
-               br_forward_finish);
-       return NF_STOLEN;
-}
-
 #if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE)
 static int br_nf_dev_queue_xmit(struct sk_buff *skb)
 {
-       if (skb->nfct != NULL &&
-           (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) &&
-           skb->len > skb->dev->mtu &&
+       if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) &&
+           skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu &&
            !skb_is_gso(skb))
                return ip_fragment(skb, br_dev_queue_push_xmit);
        else
@@ -820,21 +768,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
        struct net_device *realoutdev = bridge_parent(skb->dev);
        u_int8_t pf;
 
-#ifdef CONFIG_NETFILTER_DEBUG
-       /* Be very paranoid. This probably won't happen anymore, but let's
-        * keep the check just to be sure... */
-       if (skb_mac_header(skb) < skb->head ||
-           skb_mac_header(skb) + ETH_HLEN > skb->data) {
-               printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
-                      "bad mac.raw pointer.\n");
-               goto print_error;
-       }
-#endif
-
-       if (!nf_bridge)
-               return NF_ACCEPT;
-
-       if (!(nf_bridge->mask & (BRNF_BRIDGED | BRNF_BRIDGED_DNAT)))
+       if (!nf_bridge || !(nf_bridge->mask & BRNF_BRIDGED))
                return NF_ACCEPT;
 
        if (!realoutdev)
@@ -849,13 +783,6 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
        else
                return NF_ACCEPT;
 
-#ifdef CONFIG_NETFILTER_DEBUG
-       if (skb_dst(skb) == NULL) {
-               printk(KERN_INFO "br_netfilter post_routing: skb->dst == NULL\n");
-               goto print_error;
-       }
-#endif
-
        /* We assume any code from br_dev_queue_push_xmit onwards doesn't care
         * about the value of skb->pkt_type. */
        if (skb->pkt_type == PACKET_OTHERHOST) {
@@ -865,24 +792,15 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
 
        nf_bridge_pull_encap_header(skb);
        nf_bridge_save_header(skb);
+       if (pf == PF_INET)
+               skb->protocol = htons(ETH_P_IP);
+       else
+               skb->protocol = htons(ETH_P_IPV6);
 
        NF_HOOK(pf, NF_INET_POST_ROUTING, skb, NULL, realoutdev,
                br_nf_dev_queue_xmit);
 
        return NF_STOLEN;
-
-#ifdef CONFIG_NETFILTER_DEBUG
-print_error:
-       if (skb->dev != NULL) {
-               printk("[%s]", skb->dev->name);
-               if (realoutdev)
-                       printk("[%s]", realoutdev->name);
-       }
-       printk(" head:%p, raw:%p, data:%p\n", skb->head, skb_mac_header(skb),
-              skb->data);
-       dump_stack();
-       return NF_ACCEPT;
-#endif
 }
 
 /* IP/SABOTAGE *****************************************************/
@@ -901,10 +819,8 @@ static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff *skb,
        return NF_ACCEPT;
 }
 
-/* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent
- * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
- * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
- * ip_refrag() can return NF_STOLEN. */
+/* For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
+ * br_dev_queue_push_xmit is called afterwards */
 static struct nf_hook_ops br_nf_ops[] __read_mostly = {
        {
                .hook = br_nf_pre_routing,
@@ -934,13 +850,6 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = {
                .hooknum = NF_BR_FORWARD,
                .priority = NF_BR_PRI_BRNF,
        },
-       {
-               .hook = br_nf_local_out,
-               .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
-               .hooknum = NF_BR_LOCAL_OUT,
-               .priority = NF_BR_PRI_FIRST,
-       },
        {
                .hook = br_nf_post_routing,
                .owner = THIS_MODULE,
index aa56ac2c88293ad7717c62c256eaea185a638cd1..fe0a79018ab238e0b1adf826b87cf3a97184723b 100644 (file)
@@ -42,8 +42,8 @@ static int br_fill_ifinfo(struct sk_buff *skb, const struct net_bridge_port *por
        struct nlmsghdr *nlh;
        u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
 
-       pr_debug("br_fill_info event %d port %s master %s\n",
-                event, dev->name, br->dev->name);
+       br_debug(br, "br_fill_info event %d port %s master %s\n",
+                    event, dev->name, br->dev->name);
 
        nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
        if (nlh == NULL)
@@ -87,7 +87,9 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
        struct sk_buff *skb;
        int err = -ENOBUFS;
 
-       pr_debug("bridge notify event=%d\n", event);
+       br_debug(port->br, "port %u(%s) event %d\n",
+                (unsigned)port->port_no, port->dev->name, event);
+
        skb = nlmsg_new(br_nlmsg_size(), GFP_ATOMIC);
        if (skb == NULL)
                goto errout;
index 763a3ec292e599081ad04394fde8d1e9914a2ea3..717e1fd6133cbfcd3815e7f13d912597524faa9f 100644 (file)
@@ -34,6 +34,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        struct net_device *dev = ptr;
        struct net_bridge_port *p = dev->br_port;
        struct net_bridge *br;
+       int err;
 
        /* not a port of a bridge */
        if (p == NULL)
@@ -82,6 +83,16 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
        case NETDEV_UNREGISTER:
                br_del_if(br, dev);
                break;
+
+       case NETDEV_CHANGENAME:
+               err = br_sysfs_renameif(p);
+               if (err)
+                       return notifier_from_errno(err);
+               break;
+
+       case NETDEV_PRE_TYPE_CHANGE:
+               /* Forbid underlaying device to change its type. */
+               return NOTIFY_BAD;
        }
 
        /* Events that may cause spanning tree to refresh */
index 846d7d1e2075d1ffb7821c3244441203b0a8d726..0f4a74bc6a9b58e06b34194117577d7817b8be01 100644 (file)
@@ -45,6 +45,17 @@ struct mac_addr
        unsigned char   addr[6];
 };
 
+struct br_ip
+{
+       union {
+               __be32  ip4;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+               struct in6_addr ip6;
+#endif
+       } u;
+       __be16          proto;
+};
+
 struct net_bridge_fdb_entry
 {
        struct hlist_node               hlist;
@@ -64,7 +75,7 @@ struct net_bridge_port_group {
        struct rcu_head                 rcu;
        struct timer_list               timer;
        struct timer_list               query_timer;
-       __be32                          addr;
+       struct br_ip                    addr;
        u32                             queries_sent;
 };
 
@@ -77,7 +88,7 @@ struct net_bridge_mdb_entry
        struct rcu_head                 rcu;
        struct timer_list               timer;
        struct timer_list               query_timer;
-       __be32                          addr;
+       struct br_ip                    addr;
        u32                             queries_sent;
 };
 
@@ -128,6 +139,17 @@ struct net_bridge_port
        struct hlist_head               mglist;
        struct hlist_node               rlist;
 #endif
+
+#ifdef CONFIG_SYSFS
+       char                            sysfs_name[IFNAMSIZ];
+#endif
+};
+
+struct br_cpu_netstats {
+       unsigned long   rx_packets;
+       unsigned long   rx_bytes;
+       unsigned long   tx_packets;
+       unsigned long   tx_bytes;
 };
 
 struct net_bridge
@@ -135,6 +157,8 @@ struct net_bridge
        spinlock_t                      lock;
        struct list_head                port_list;
        struct net_device               *dev;
+
+       struct br_cpu_netstats __percpu *stats;
        spinlock_t                      hash_lock;
        struct hlist_head               hash[BR_HASH_SIZE];
        unsigned long                   feature_mask;
@@ -220,6 +244,21 @@ struct br_input_skb_cb {
 # define BR_INPUT_SKB_CB_MROUTERS_ONLY(__skb)  (0)
 #endif
 
+#define br_printk(level, br, format, args...)  \
+       printk(level "%s: " format, (br)->dev->name, ##args)
+
+#define br_err(__br, format, args...)                  \
+       br_printk(KERN_ERR, __br, format, ##args)
+#define br_warn(__br, format, args...)                 \
+       br_printk(KERN_WARNING, __br, format, ##args)
+#define br_notice(__br, format, args...)               \
+       br_printk(KERN_NOTICE, __br, format, ##args)
+#define br_info(__br, format, args...)                 \
+       br_printk(KERN_INFO, __br, format, ##args)
+
+#define br_debug(br, format, args...)                  \
+       pr_debug("%s: " format,  (br)->dev->name, ##args)
+
 extern struct notifier_block br_device_notifier;
 extern const u8 br_group_address[ETH_ALEN];
 
@@ -233,6 +272,18 @@ static inline int br_is_root_bridge(const struct net_bridge *br)
 extern void br_dev_setup(struct net_device *dev);
 extern netdev_tx_t br_dev_xmit(struct sk_buff *skb,
                               struct net_device *dev);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+extern void br_netpoll_cleanup(struct net_device *dev);
+extern void br_netpoll_enable(struct net_bridge *br,
+                             struct net_device *dev);
+extern void br_netpoll_disable(struct net_bridge *br,
+                              struct net_device *dev);
+#else
+#define br_netpoll_cleanup(br)
+#define br_netpoll_enable(br, dev)
+#define br_netpoll_disable(br, dev)
+
+#endif
 
 /* br_fdb.c */
 extern int br_fdb_init(void);
@@ -433,6 +484,7 @@ extern void br_ifinfo_notify(int event, struct net_bridge_port *port);
 /* br_sysfs_if.c */
 extern const struct sysfs_ops brport_sysfs_ops;
 extern int br_sysfs_addif(struct net_bridge_port *p);
+extern int br_sysfs_renameif(struct net_bridge_port *p);
 
 /* br_sysfs_br.c */
 extern int br_sysfs_addbr(struct net_device *dev);
@@ -441,6 +493,7 @@ extern void br_sysfs_delbr(struct net_device *dev);
 #else
 
 #define br_sysfs_addif(p)      (0)
+#define br_sysfs_renameif(p)   (0)
 #define br_sysfs_addbr(dev)    (0)
 #define br_sysfs_delbr(dev)    do { } while(0)
 #endif /* CONFIG_SYSFS */
index edcf14b560f6febf68a814418999cbe63ee6dcfd..57186d84d2bd6497366d7d4d7cca7a694e0b5818 100644 (file)
@@ -31,10 +31,9 @@ static const char *const br_port_state_names[] = {
 
 void br_log_state(const struct net_bridge_port *p)
 {
-       pr_info("%s: port %d(%s) entering %s state\n",
-               p->br->dev->name, p->port_no, p->dev->name,
+       br_info(p->br, "port %u(%s) entering %s state\n",
+               (unsigned) p->port_no, p->dev->name,
                br_port_state_names[p->state]);
-
 }
 
 /* called under bridge lock */
@@ -300,7 +299,7 @@ void br_topology_change_detection(struct net_bridge *br)
        if (br->stp_enabled != BR_KERNEL_STP)
                return;
 
-       pr_info("%s: topology change detected, %s\n", br->dev->name,
+       br_info(br, "topology change detected, %s\n",
                isroot ? "propagating" : "sending tcn bpdu");
 
        if (isroot) {
@@ -469,8 +468,8 @@ void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *b
 void br_received_tcn_bpdu(struct net_bridge_port *p)
 {
        if (br_is_designated_port(p)) {
-               pr_info("%s: received tcn bpdu on port %i(%s)\n",
-                      p->br->dev->name, p->port_no, p->dev->name);
+               br_info(p->br, "port %u(%s) received tcn bpdu\n",
+                       (unsigned) p->port_no, p->dev->name);
 
                br_topology_change_detection(p->br);
                br_topology_change_acknowledge(p);
index d66cce11f3bf93475b85d827dbf6b11de8897886..217bd225a42f1390deb46605039941bd6ea81d1f 100644 (file)
@@ -50,7 +50,7 @@ static void br_send_bpdu(struct net_bridge_port *p,
 
        llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
 
-       NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+       NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
                dev_queue_xmit);
 }
 
index d527119e9f54fd0d226a60c8f20e669ab506c55c..1d8826914cbf20a7fecec51bffeee3551a61e7e4 100644 (file)
@@ -85,17 +85,16 @@ void br_stp_enable_port(struct net_bridge_port *p)
 {
        br_init_port(p);
        br_port_state_selection(p->br);
+       br_log_state(p);
 }
 
 /* called under bridge lock */
 void br_stp_disable_port(struct net_bridge_port *p)
 {
-       struct net_bridge *br;
+       struct net_bridge *br = p->br;
        int wasroot;
 
-       br = p->br;
-       printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-              br->dev->name, p->port_no, p->dev->name, "disabled");
+       br_log_state(p);
 
        wasroot = br_is_root_bridge(br);
        br_become_designated_port(p);
@@ -127,11 +126,10 @@ static void br_stp_start(struct net_bridge *br)
        r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
        if (r == 0) {
                br->stp_enabled = BR_USER_STP;
-               printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
+               br_debug(br, "userspace STP started\n");
        } else {
                br->stp_enabled = BR_KERNEL_STP;
-               printk(KERN_INFO "%s: starting userspace STP failed, "
-                               "starting kernel STP\n", br->dev->name);
+               br_debug(br, "using kernel STP\n");
 
                /* To start timers on any ports left in blocking */
                spin_lock_bh(&br->lock);
@@ -148,9 +146,7 @@ static void br_stp_stop(struct net_bridge *br)
 
        if (br->stp_enabled == BR_USER_STP) {
                r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
-               printk(KERN_INFO "%s: userspace STP stopped, return code %d\n",
-                       br->dev->name, r);
-
+               br_info(br, "userspace STP stopped, return code %d\n", r);
 
                /* To start timers on any ports left in blocking */
                spin_lock_bh(&br->lock);
index 772a140bfdf0f8edc2f9692bf7d001d5dbf97954..7b22456023c5615642b3c1a786bc135065aeb990 100644 (file)
@@ -35,7 +35,7 @@ static void br_hello_timer_expired(unsigned long arg)
 {
        struct net_bridge *br = (struct net_bridge *)arg;
 
-       pr_debug("%s: hello timer expired\n", br->dev->name);
+       br_debug(br, "hello timer expired\n");
        spin_lock(&br->lock);
        if (br->dev->flags & IFF_UP) {
                br_config_bpdu_generation(br);
@@ -55,13 +55,9 @@ static void br_message_age_timer_expired(unsigned long arg)
        if (p->state == BR_STATE_DISABLED)
                return;
 
-
-       pr_info("%s: neighbor %.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x lost on port %d(%s)\n",
-               br->dev->name,
-               id->prio[0], id->prio[1],
-               id->addr[0], id->addr[1], id->addr[2],
-               id->addr[3], id->addr[4], id->addr[5],
-               p->port_no, p->dev->name);
+       br_info(br, "port %u(%s) neighbor %.2x%.2x.%pM lost\n",
+               (unsigned) p->port_no, p->dev->name,
+               id->prio[0], id->prio[1], &id->addr);
 
        /*
         * According to the spec, the message age timer cannot be
@@ -87,8 +83,8 @@ static void br_forward_delay_timer_expired(unsigned long arg)
        struct net_bridge_port *p = (struct net_bridge_port *) arg;
        struct net_bridge *br = p->br;
 
-       pr_debug("%s: %d(%s) forward delay timer\n",
-                br->dev->name, p->port_no, p->dev->name);
+       br_debug(br, "port %u(%s) forward delay timer\n",
+                (unsigned) p->port_no, p->dev->name);
        spin_lock(&br->lock);
        if (p->state == BR_STATE_LISTENING) {
                p->state = BR_STATE_LEARNING;
@@ -107,7 +103,7 @@ static void br_tcn_timer_expired(unsigned long arg)
 {
        struct net_bridge *br = (struct net_bridge *) arg;
 
-       pr_debug("%s: tcn timer expired\n", br->dev->name);
+       br_debug(br, "tcn timer expired\n");
        spin_lock(&br->lock);
        if (br->dev->flags & IFF_UP) {
                br_transmit_tcn(br);
@@ -121,7 +117,7 @@ static void br_topology_change_timer_expired(unsigned long arg)
 {
        struct net_bridge *br = (struct net_bridge *) arg;
 
-       pr_debug("%s: topo change timer expired\n", br->dev->name);
+       br_debug(br, "topo change timer expired\n");
        spin_lock(&br->lock);
        br->topology_change_detected = 0;
        br->topology_change = 0;
@@ -132,8 +128,8 @@ static void br_hold_timer_expired(unsigned long arg)
 {
        struct net_bridge_port *p = (struct net_bridge_port *) arg;
 
-       pr_debug("%s: %d(%s) hold timer expired\n",
-                p->br->dev->name,  p->port_no, p->dev->name);
+       br_debug(p->br, "port %u(%s) hold timer expired\n",
+                (unsigned) p->port_no, p->dev->name);
 
        spin_lock(&p->br->lock);
        if (p->config_pending)
index 0b9916489d6bf0c1eb61ec2048ddeb0472221923..fd5799c9bc8de350df12db5e35331990cc46eb03 100644 (file)
@@ -246,7 +246,7 @@ const struct sysfs_ops brport_sysfs_ops = {
 /*
  * Add sysfs entries to ethernet device added to a bridge.
  * Creates a brport subdirectory with bridge attributes.
- * Puts symlink in bridge's brport subdirectory
+ * Puts symlink in bridge's brif subdirectory
  */
 int br_sysfs_addif(struct net_bridge_port *p)
 {
@@ -257,15 +257,37 @@ int br_sysfs_addif(struct net_bridge_port *p)
        err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
                                SYSFS_BRIDGE_PORT_LINK);
        if (err)
-               goto out2;
+               return err;
 
        for (a = brport_attrs; *a; ++a) {
                err = sysfs_create_file(&p->kobj, &((*a)->attr));
                if (err)
-                       goto out2;
+                       return err;
        }
 
-       err = sysfs_create_link(br->ifobj, &p->kobj, p->dev->name);
-out2:
+       strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
+       return sysfs_create_link(br->ifobj, &p->kobj, p->sysfs_name);
+}
+
+/* Rename bridge's brif symlink */
+int br_sysfs_renameif(struct net_bridge_port *p)
+{
+       struct net_bridge *br = p->br;
+       int err;
+
+       /* If a rename fails, the rollback will cause another
+        * rename call with the existing name.
+        */
+       if (!strncmp(p->sysfs_name, p->dev->name, IFNAMSIZ))
+               return 0;
+
+       err = sysfs_rename_link(br->ifobj, &p->kobj,
+                               p->sysfs_name, p->dev->name);
+       if (err)
+               netdev_notice(br->dev, "unable to rename link %s to %s",
+                             p->sysfs_name, p->dev->name);
+       else
+               strlcpy(p->sysfs_name, p->dev->name, IFNAMSIZ);
+
        return err;
 }
index 5d1176758ca56ab7b993d086ce92ebbe5166fc6b..2a449b7ab8fac3c53cc777aa86a963092824029b 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/netfilter_bridge/ebt_802_3.h>
 
 static bool
-ebt_802_3_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_802_3_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_802_3_info *info = par->matchinfo;
        const struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
@@ -36,14 +36,14 @@ ebt_802_3_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_802_3_mt_check(const struct xt_mtchk_param *par)
+static int ebt_802_3_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_802_3_info *info = par->matchinfo;
 
        if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK)
-               return false;
+               return -EINVAL;
 
-       return true;
+       return 0;
 }
 
 static struct xt_match ebt_802_3_mt_reg __read_mostly = {
index b595f091f35b9cf1c2fc9bd6378edbc5fc5a90a2..8b84c581be3082ea4c8a6a21a362a3077ab17751 100644 (file)
@@ -7,6 +7,7 @@
  *  August, 2003
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/ip.h>
 #include <linux/if_arp.h>
 #include <linux/module.h>
@@ -128,7 +129,7 @@ static int get_ip_src(const struct sk_buff *skb, __be32 *addr)
 }
 
 static bool
-ebt_among_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_among_info *info = par->matchinfo;
        const char *dmac, *smac;
@@ -171,7 +172,7 @@ ebt_among_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_among_mt_check(const struct xt_mtchk_param *par)
+static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_among_info *info = par->matchinfo;
        const struct ebt_entry_match *em =
@@ -186,24 +187,20 @@ static bool ebt_among_mt_check(const struct xt_mtchk_param *par)
        expected_length += ebt_mac_wormhash_size(wh_src);
 
        if (em->match_size != EBT_ALIGN(expected_length)) {
-               printk(KERN_WARNING
-                      "ebtables: among: wrong size: %d "
-                      "against expected %d, rounded to %Zd\n",
-                      em->match_size, expected_length,
-                      EBT_ALIGN(expected_length));
-               return false;
+               pr_info("wrong size: %d against expected %d, rounded to %Zd\n",
+                       em->match_size, expected_length,
+                       EBT_ALIGN(expected_length));
+               return -EINVAL;
        }
        if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
-               printk(KERN_WARNING
-                      "ebtables: among: dst integrity fail: %x\n", -err);
-               return false;
+               pr_info("dst integrity fail: %x\n", -err);
+               return -EINVAL;
        }
        if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
-               printk(KERN_WARNING
-                      "ebtables: among: src integrity fail: %x\n", -err);
-               return false;
+               pr_info("src integrity fail: %x\n", -err);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match ebt_among_mt_reg __read_mostly = {
index e727697c58476ede5ce5ce00d8d3549aa4ef2971..cd457b891b27ec5836653f75b02ac5e8a3d44ef5 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/netfilter_bridge/ebt_arp.h>
 
 static bool
-ebt_arp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_arp_info *info = par->matchinfo;
        const struct arphdr *ah;
@@ -100,7 +100,7 @@ ebt_arp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_arp_mt_check(const struct xt_mtchk_param *par)
+static int ebt_arp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_arp_info *info = par->matchinfo;
        const struct ebt_entry *e = par->entryinfo;
@@ -108,10 +108,10 @@ static bool ebt_arp_mt_check(const struct xt_mtchk_param *par)
        if ((e->ethproto != htons(ETH_P_ARP) &&
           e->ethproto != htons(ETH_P_RARP)) ||
           e->invflags & EBT_IPROTO)
-               return false;
+               return -EINVAL;
        if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_match ebt_arp_mt_reg __read_mostly = {
index f392e9d93f53404d50628494fdec57d573e17fba..070cf134a22f983c915c488a48b09d942e16fcce 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/netfilter_bridge/ebt_arpreply.h>
 
 static unsigned int
-ebt_arpreply_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_arpreply_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_arpreply_info *info = par->targinfo;
        const __be32 *siptr, *diptr;
@@ -57,17 +57,17 @@ ebt_arpreply_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return info->target;
 }
 
-static bool ebt_arpreply_tg_check(const struct xt_tgchk_param *par)
+static int ebt_arpreply_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ebt_arpreply_info *info = par->targinfo;
        const struct ebt_entry *e = par->entryinfo;
 
        if (BASE_CHAIN && info->target == EBT_RETURN)
-               return false;
+               return -EINVAL;
        if (e->ethproto != htons(ETH_P_ARP) ||
            e->invflags & EBT_IPROTO)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target ebt_arpreply_tg_reg __read_mostly = {
index 2bb40d728a35ae37b0ab875b33c9dfd3f490c14b..c59f7bfae6e2c3dc8a2e4f3725f43498ae2542a2 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/netfilter_bridge/ebt_nat.h>
 
 static unsigned int
-ebt_dnat_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_nat_info *info = par->targinfo;
 
@@ -26,13 +26,13 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return info->target;
 }
 
-static bool ebt_dnat_tg_check(const struct xt_tgchk_param *par)
+static int ebt_dnat_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ebt_nat_info *info = par->targinfo;
        unsigned int hook_mask;
 
        if (BASE_CHAIN && info->target == EBT_RETURN)
-               return false;
+               return -EINVAL;
 
        hook_mask = par->hook_mask & ~(1 << NF_BR_NUMHOOKS);
        if ((strcmp(par->table, "nat") != 0 ||
@@ -40,10 +40,10 @@ static bool ebt_dnat_tg_check(const struct xt_tgchk_param *par)
            (1 << NF_BR_LOCAL_OUT)))) &&
            (strcmp(par->table, "broute") != 0 ||
            hook_mask & ~(1 << NF_BR_BROUTING)))
-               return false;
+               return -EINVAL;
        if (INVALID_TARGET)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target ebt_dnat_tg_reg __read_mostly = {
index 5de6df6f86b8acbdb385b56f2bd62a5f16cf92e8..23bca62d58d290f5085094b3b5d8c74b21a7c8fc 100644 (file)
@@ -25,7 +25,7 @@ struct tcpudphdr {
 };
 
 static bool
-ebt_ip_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_ip_info *info = par->matchinfo;
        const struct iphdr *ih;
@@ -77,31 +77,31 @@ ebt_ip_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_ip_mt_check(const struct xt_mtchk_param *par)
+static int ebt_ip_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_ip_info *info = par->matchinfo;
        const struct ebt_entry *e = par->entryinfo;
 
        if (e->ethproto != htons(ETH_P_IP) ||
           e->invflags & EBT_IPROTO)
-               return false;
+               return -EINVAL;
        if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
-               return false;
+               return -EINVAL;
        if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
                if (info->invflags & EBT_IP_PROTO)
-                       return false;
+                       return -EINVAL;
                if (info->protocol != IPPROTO_TCP &&
                    info->protocol != IPPROTO_UDP &&
                    info->protocol != IPPROTO_UDPLITE &&
                    info->protocol != IPPROTO_SCTP &&
                    info->protocol != IPPROTO_DCCP)
-                        return false;
+                        return -EINVAL;
        }
        if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1])
-               return false;
+               return -EINVAL;
        if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_match ebt_ip_mt_reg __read_mostly = {
index bbf2534ef026e37cb604394dd9af48f7b7e82cd9..50a46afc2bcc28c2714c8b0f9cdde95432c569fd 100644 (file)
@@ -4,7 +4,7 @@
  *     Authors:
  *     Manohar Castelino <manohar.r.castelino@intel.com>
  *     Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
- *     Jan Engelhardt <jengelh@computergmbh.de>
+ *     Jan Engelhardt <jengelh@medozas.de>
  *
  * Summary:
  * This is just a modification of the IPv4 code written by
@@ -28,15 +28,13 @@ struct tcpudphdr {
 };
 
 static bool
-ebt_ip6_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_ip6_info *info = par->matchinfo;
        const struct ipv6hdr *ih6;
        struct ipv6hdr _ip6h;
        const struct tcpudphdr *pptr;
        struct tcpudphdr _ports;
-       struct in6_addr tmp_addr;
-       int i;
 
        ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
        if (ih6 == NULL)
@@ -44,18 +42,10 @@ ebt_ip6_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        if (info->bitmask & EBT_IP6_TCLASS &&
           FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS))
                return false;
-       for (i = 0; i < 4; i++)
-               tmp_addr.in6_u.u6_addr32[i] = ih6->saddr.in6_u.u6_addr32[i] &
-                       info->smsk.in6_u.u6_addr32[i];
-       if (info->bitmask & EBT_IP6_SOURCE &&
-               FWINV((ipv6_addr_cmp(&tmp_addr, &info->saddr) != 0),
-                       EBT_IP6_SOURCE))
-               return false;
-       for (i = 0; i < 4; i++)
-               tmp_addr.in6_u.u6_addr32[i] = ih6->daddr.in6_u.u6_addr32[i] &
-                       info->dmsk.in6_u.u6_addr32[i];
-       if (info->bitmask & EBT_IP6_DEST &&
-          FWINV((ipv6_addr_cmp(&tmp_addr, &info->daddr) != 0), EBT_IP6_DEST))
+       if (FWINV(ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk,
+                                      &info->saddr), EBT_IP6_SOURCE) ||
+           FWINV(ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk,
+                                      &info->daddr), EBT_IP6_DEST))
                return false;
        if (info->bitmask & EBT_IP6_PROTO) {
                uint8_t nexthdr = ih6->nexthdr;
@@ -90,30 +80,30 @@ ebt_ip6_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_ip6_mt_check(const struct xt_mtchk_param *par)
+static int ebt_ip6_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_entry *e = par->entryinfo;
        struct ebt_ip6_info *info = par->matchinfo;
 
        if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
-               return false;
+               return -EINVAL;
        if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
-               return false;
+               return -EINVAL;
        if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
                if (info->invflags & EBT_IP6_PROTO)
-                       return false;
+                       return -EINVAL;
                if (info->protocol != IPPROTO_TCP &&
                    info->protocol != IPPROTO_UDP &&
                    info->protocol != IPPROTO_UDPLITE &&
                    info->protocol != IPPROTO_SCTP &&
                    info->protocol != IPPROTO_DCCP)
-                       return false;
+                       return -EINVAL;
        }
        if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
-               return false;
+               return -EINVAL;
        if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_match ebt_ip6_mt_reg __read_mostly = {
@@ -139,4 +129,5 @@ static void __exit ebt_ip6_fini(void)
 module_init(ebt_ip6_init);
 module_exit(ebt_ip6_fini);
 MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
+MODULE_AUTHOR("Kuo-Lang Tseng <kuo-lang.tseng@intel.com>");
 MODULE_LICENSE("GPL");
index 7a8182710eb31f534f359d36bffb85aa674efd7d..517e78befcb2688a76e307ba7e7064e334700cb1 100644 (file)
@@ -10,6 +10,7 @@
  *  September, 2003
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/spinlock.h>
@@ -31,7 +32,7 @@ static DEFINE_SPINLOCK(limit_lock);
 #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
 
 static bool
-ebt_limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ebt_limit_info *info = (void *)par->matchinfo;
        unsigned long now = jiffies;
@@ -64,16 +65,16 @@ user2credits(u_int32_t user)
        return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
 }
 
-static bool ebt_limit_mt_check(const struct xt_mtchk_param *par)
+static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
 {
        struct ebt_limit_info *info = par->matchinfo;
 
        /* Check for overflow. */
        if (info->burst == 0 ||
            user2credits(info->avg * info->burst) < user2credits(info->avg)) {
-               printk("Overflow in ebt_limit, try lower: %u/%u\n",
+               pr_info("overflow, try lower: %u/%u\n",
                        info->avg, info->burst);
-               return false;
+               return -EINVAL;
        }
 
        /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */
@@ -81,7 +82,7 @@ static bool ebt_limit_mt_check(const struct xt_mtchk_param *par)
        info->credit = user2credits(info->avg * info->burst);
        info->credit_cap = user2credits(info->avg * info->burst);
        info->cost = user2credits(info->avg);
-       return true;
+       return 0;
 }
 
 
index e873924ddb5db959efdc791eedd0c41fcbef6338..6e5a8bb9b940ce3eb03e1dc6840f4e84ef4d1f98 100644 (file)
 
 static DEFINE_SPINLOCK(ebt_log_lock);
 
-static bool ebt_log_tg_check(const struct xt_tgchk_param *par)
+static int ebt_log_tg_check(const struct xt_tgchk_param *par)
 {
        struct ebt_log_info *info = par->targinfo;
 
        if (info->bitmask & ~EBT_LOG_MASK)
-               return false;
+               return -EINVAL;
        if (info->loglevel >= 8)
-               return false;
+               return -EINVAL;
        info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
-       return true;
+       return 0;
 }
 
 struct tcpudphdr
@@ -171,7 +171,7 @@ out:
 }
 
 static unsigned int
-ebt_log_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_log_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_log_info *info = par->targinfo;
        struct nf_loginfo li;
index 2b5ce533d6b93c77b2bf7c5906cb29e70415df7a..66697cbd0a8b82c9e132aebda93b96ee09e48fe8 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/netfilter_bridge/ebt_mark_t.h>
 
 static unsigned int
-ebt_mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_mark_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_mark_t_info *info = par->targinfo;
        int action = info->target & -16;
@@ -36,21 +36,21 @@ ebt_mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return info->target | ~EBT_VERDICT_BITS;
 }
 
-static bool ebt_mark_tg_check(const struct xt_tgchk_param *par)
+static int ebt_mark_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ebt_mark_t_info *info = par->targinfo;
        int tmp;
 
        tmp = info->target | ~EBT_VERDICT_BITS;
        if (BASE_CHAIN && tmp == EBT_RETURN)
-               return false;
+               return -EINVAL;
        if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
-               return false;
+               return -EINVAL;
        tmp = info->target & ~EBT_VERDICT_BITS;
        if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
            tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 #ifdef CONFIG_COMPAT
 struct compat_ebt_mark_t_info {
index 8de8c396d913fc7852d9326edaf8742b4dedf11c..d98baefc4c7eef6a5f39039948064a4a95d64120 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/netfilter_bridge/ebt_mark_m.h>
 
 static bool
-ebt_mark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_mark_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_mark_m_info *info = par->matchinfo;
 
@@ -22,17 +22,17 @@ ebt_mark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ((skb->mark & info->mask) == info->mark) ^ info->invert;
 }
 
-static bool ebt_mark_mt_check(const struct xt_mtchk_param *par)
+static int ebt_mark_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_mark_m_info *info = par->matchinfo;
 
        if (info->bitmask & ~EBT_MARK_MASK)
-               return false;
+               return -EINVAL;
        if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
-               return false;
+               return -EINVAL;
        if (!info->bitmask)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 
index 40dbd248b9ae284fb3b13e6b36455c6b8aa6fef9..5be68bbcc3419585c99762a549a5fa8f820cdb06 100644 (file)
@@ -20,7 +20,7 @@
 #include <net/netfilter/nf_log.h>
 
 static unsigned int
-ebt_nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_nflog_info *info = par->targinfo;
        struct nf_loginfo li;
@@ -35,14 +35,14 @@ ebt_nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return EBT_CONTINUE;
 }
 
-static bool ebt_nflog_tg_check(const struct xt_tgchk_param *par)
+static int ebt_nflog_tg_check(const struct xt_tgchk_param *par)
 {
        struct ebt_nflog_info *info = par->targinfo;
 
        if (info->flags & ~EBT_NFLOG_MASK)
-               return false;
+               return -EINVAL;
        info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0';
-       return true;
+       return 0;
 }
 
 static struct xt_target ebt_nflog_tg_reg __read_mostly = {
index e2a07e6cbef381fdc86891debbc960ca8ff8a226..496a565153074e47286f928975898ad66326bcef 100644 (file)
 #include <linux/netfilter_bridge/ebt_pkttype.h>
 
 static bool
-ebt_pkttype_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_pkttype_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_pkttype_info *info = par->matchinfo;
 
        return (skb->pkt_type == info->pkt_type) ^ info->invert;
 }
 
-static bool ebt_pkttype_mt_check(const struct xt_mtchk_param *par)
+static int ebt_pkttype_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_pkttype_info *info = par->matchinfo;
 
        if (info->invert != 0 && info->invert != 1)
-               return false;
+               return -EINVAL;
        /* Allow any pkt_type value */
-       return true;
+       return 0;
 }
 
 static struct xt_match ebt_pkttype_mt_reg __read_mostly = {
index 9be8fbcd370b93eb33137c8e4e2c2f08b432f919..9e19166ba4534321ad2a9139960fd247dd958e36 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/netfilter_bridge/ebt_redirect.h>
 
 static unsigned int
-ebt_redirect_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_redirect_info *info = par->targinfo;
 
@@ -32,23 +32,23 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return info->target;
 }
 
-static bool ebt_redirect_tg_check(const struct xt_tgchk_param *par)
+static int ebt_redirect_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ebt_redirect_info *info = par->targinfo;
        unsigned int hook_mask;
 
        if (BASE_CHAIN && info->target == EBT_RETURN)
-               return false;
+               return -EINVAL;
 
        hook_mask = par->hook_mask & ~(1 << NF_BR_NUMHOOKS);
        if ((strcmp(par->table, "nat") != 0 ||
            hook_mask & ~(1 << NF_BR_PRE_ROUTING)) &&
            (strcmp(par->table, "broute") != 0 ||
            hook_mask & ~(1 << NF_BR_BROUTING)))
-               return false;
+               return -EINVAL;
        if (INVALID_TARGET)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target ebt_redirect_tg_reg __read_mostly = {
index 9c7b520765a2de7c629ee7abe2f9c78fe8f1c69f..f8f0bd1a1d5122e01bae405a1ad78d70be7a25ce 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/netfilter_bridge/ebt_nat.h>
 
 static unsigned int
-ebt_snat_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ebt_nat_info *info = par->targinfo;
 
@@ -42,21 +42,21 @@ out:
        return info->target | ~EBT_VERDICT_BITS;
 }
 
-static bool ebt_snat_tg_check(const struct xt_tgchk_param *par)
+static int ebt_snat_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ebt_nat_info *info = par->targinfo;
        int tmp;
 
        tmp = info->target | ~EBT_VERDICT_BITS;
        if (BASE_CHAIN && tmp == EBT_RETURN)
-               return false;
+               return -EINVAL;
 
        if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
-               return false;
+               return -EINVAL;
        tmp = info->target | EBT_VERDICT_BITS;
        if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target ebt_snat_tg_reg __read_mostly = {
index 92a93d363765ecca1368326f39cd5a0872ff453b..5b33a2e634a67ad231263ccb3c963e598b5bef6e 100644 (file)
@@ -120,7 +120,7 @@ static bool ebt_filter_config(const struct ebt_stp_info *info,
 }
 
 static bool
-ebt_stp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_stp_info *info = par->matchinfo;
        const struct stp_header *sp;
@@ -153,7 +153,7 @@ ebt_stp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_stp_mt_check(const struct xt_mtchk_param *par)
+static int ebt_stp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_stp_info *info = par->matchinfo;
        const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
@@ -162,13 +162,13 @@ static bool ebt_stp_mt_check(const struct xt_mtchk_param *par)
 
        if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
            !(info->bitmask & EBT_STP_MASK))
-               return false;
+               return -EINVAL;
        /* Make sure the match only receives stp frames */
        if (compare_ether_addr(e->destmac, bridge_ula) ||
            compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC))
-               return false;
+               return -EINVAL;
 
-       return true;
+       return 0;
 }
 
 static struct xt_match ebt_stp_mt_reg __read_mostly = {
index f9560f3dbdc7c9ba538a12b1b637766ecf981db8..ae3c7cef1484ff16c0a5ff187e23ea4c799de775 100644 (file)
@@ -27,7 +27,7 @@
  *   flushed even if it is not full yet.
  *
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -44,9 +44,6 @@
 #include <net/sock.h>
 #include "../br_private.h"
 
-#define PRINTR(format, args...) do { if (net_ratelimit()) \
-                               printk(format , ## args); } while (0)
-
 static unsigned int nlbufsiz = NLMSG_GOODSIZE;
 module_param(nlbufsiz, uint, 0600);
 MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
@@ -107,15 +104,14 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size)
        n = max(size, nlbufsiz);
        skb = alloc_skb(n, GFP_ATOMIC);
        if (!skb) {
-               PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
-                      "of size %ub!\n", n);
+               pr_debug("cannot alloc whole buffer of size %ub!\n", n);
                if (n > size) {
                        /* try to allocate only as much as we need for
                         * current packet */
                        skb = alloc_skb(size, GFP_ATOMIC);
                        if (!skb)
-                               PRINTR(KERN_ERR "ebt_ulog: can't even allocate "
-                                      "buffer of size %ub\n", size);
+                               pr_debug("cannot even allocate "
+                                        "buffer of size %ub\n", size);
                }
        }
 
@@ -142,8 +138,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb,
 
        size = NLMSG_SPACE(sizeof(*pm) + copy_len);
        if (size > nlbufsiz) {
-               PRINTR("ebt_ulog: Size %Zd needed, but nlbufsiz=%d\n",
-                      size, nlbufsiz);
+               pr_debug("Size %Zd needed, but nlbufsiz=%d\n", size, nlbufsiz);
                return;
        }
 
@@ -217,8 +212,8 @@ unlock:
        return;
 
 nlmsg_failure:
-       printk(KERN_CRIT "ebt_ulog: error during NLMSG_PUT. This should "
-              "not happen, please report to author.\n");
+       pr_debug("error during NLMSG_PUT. This should "
+                "not happen, please report to author.\n");
        goto unlock;
 alloc_failure:
        goto unlock;
@@ -248,26 +243,26 @@ static void ebt_log_packet(u_int8_t pf, unsigned int hooknum,
 }
 
 static unsigned int
-ebt_ulog_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ebt_ulog_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        ebt_ulog_packet(par->hooknum, skb, par->in, par->out,
                        par->targinfo, NULL);
        return EBT_CONTINUE;
 }
 
-static bool ebt_ulog_tg_check(const struct xt_tgchk_param *par)
+static int ebt_ulog_tg_check(const struct xt_tgchk_param *par)
 {
        struct ebt_ulog_info *uloginfo = par->targinfo;
 
        if (uloginfo->nlgroup > 31)
-               return false;
+               return -EINVAL;
 
        uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0';
 
        if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN)
                uloginfo->qthreshold = EBT_ULOG_MAX_QLEN;
 
-       return true;
+       return 0;
 }
 
 static struct xt_target ebt_ulog_tg_reg __read_mostly = {
@@ -292,8 +287,8 @@ static int __init ebt_ulog_init(void)
        int i;
 
        if (nlbufsiz >= 128*1024) {
-               printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB,"
-                      " please try a smaller nlbufsiz parameter.\n");
+               pr_warning("Netlink buffer has to be <= 128kB,"
+                          " please try a smaller nlbufsiz parameter.\n");
                return -EINVAL;
        }
 
@@ -306,13 +301,10 @@ static int __init ebt_ulog_init(void)
        ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG,
                                          EBT_ULOG_MAXNLGROUPS, NULL, NULL,
                                          THIS_MODULE);
-       if (!ebtulognl) {
-               printk(KERN_WARNING KBUILD_MODNAME ": out of memory trying to "
-                      "call netlink_kernel_create\n");
+       if (!ebtulognl)
                ret = -ENOMEM;
-       } else if ((ret = xt_register_target(&ebt_ulog_tg_reg)) != 0) {
+       else if ((ret = xt_register_target(&ebt_ulog_tg_reg)) != 0)
                netlink_kernel_release(ebtulognl);
-       }
 
        if (ret == 0)
                nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger);
index be1dd2e1f61517fca4e77fb8cebe521ea7c468bf..87b53b3a921daefd40c0fd85ade33d5240f4262a 100644 (file)
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_bridge/ebt_vlan.h>
 
-static int debug;
 #define MODULE_VERS "0.6"
 
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
 MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
 MODULE_DESCRIPTION("Ebtables: 802.1Q VLAN tag match");
 MODULE_LICENSE("GPL");
 
-
-#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
 #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
 #define EXIT_ON_MISMATCH(_MATCH_,_MASK_) {if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return false; }
 
 static bool
-ebt_vlan_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+ebt_vlan_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ebt_vlan_info *info = par->matchinfo;
        const struct vlan_hdr *fp;
@@ -84,32 +79,31 @@ ebt_vlan_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool ebt_vlan_mt_check(const struct xt_mtchk_param *par)
+static int ebt_vlan_mt_check(const struct xt_mtchk_param *par)
 {
        struct ebt_vlan_info *info = par->matchinfo;
        const struct ebt_entry *e = par->entryinfo;
 
        /* Is it 802.1Q frame checked? */
        if (e->ethproto != htons(ETH_P_8021Q)) {
-               DEBUG_MSG
-                   ("passed entry proto %2.4X is not 802.1Q (8100)\n",
-                    (unsigned short) ntohs(e->ethproto));
-               return false;
+               pr_debug("passed entry proto %2.4X is not 802.1Q (8100)\n",
+                        ntohs(e->ethproto));
+               return -EINVAL;
        }
 
        /* Check for bitmask range
         * True if even one bit is out of mask */
        if (info->bitmask & ~EBT_VLAN_MASK) {
-               DEBUG_MSG("bitmask %2X is out of mask (%2X)\n",
-                         info->bitmask, EBT_VLAN_MASK);
-               return false;
+               pr_debug("bitmask %2X is out of mask (%2X)\n",
+                        info->bitmask, EBT_VLAN_MASK);
+               return -EINVAL;
        }
 
        /* Check for inversion flags range */
        if (info->invflags & ~EBT_VLAN_MASK) {
-               DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n",
-                         info->invflags, EBT_VLAN_MASK);
-               return false;
+               pr_debug("inversion flags %2X is out of mask (%2X)\n",
+                        info->invflags, EBT_VLAN_MASK);
+               return -EINVAL;
        }
 
        /* Reserved VLAN ID (VID) values
@@ -121,10 +115,9 @@ static bool ebt_vlan_mt_check(const struct xt_mtchk_param *par)
        if (GET_BITMASK(EBT_VLAN_ID)) {
                if (!!info->id) { /* if id!=0 => check vid range */
                        if (info->id > VLAN_GROUP_ARRAY_LEN) {
-                               DEBUG_MSG
-                                   ("id %d is out of range (1-4096)\n",
-                                    info->id);
-                               return false;
+                               pr_debug("id %d is out of range (1-4096)\n",
+                                        info->id);
+                               return -EINVAL;
                        }
                        /* Note: This is valid VLAN-tagged frame point.
                         * Any value of user_priority are acceptable,
@@ -137,9 +130,9 @@ static bool ebt_vlan_mt_check(const struct xt_mtchk_param *par)
 
        if (GET_BITMASK(EBT_VLAN_PRIO)) {
                if ((unsigned char) info->prio > 7) {
-                       DEBUG_MSG("prio %d is out of range (0-7)\n",
-                            info->prio);
-                       return false;
+                       pr_debug("prio %d is out of range (0-7)\n",
+                                info->prio);
+                       return -EINVAL;
                }
        }
        /* Check for encapsulated proto range - it is possible to be
@@ -147,14 +140,13 @@ static bool ebt_vlan_mt_check(const struct xt_mtchk_param *par)
         * if_ether.h:  ETH_ZLEN        60   -  Min. octets in frame sans FCS */
        if (GET_BITMASK(EBT_VLAN_ENCAP)) {
                if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) {
-                       DEBUG_MSG
-                           ("encap frame length %d is less than minimal\n",
-                            ntohs(info->encap));
-                       return false;
+                       pr_debug("encap frame length %d is less than "
+                                "minimal\n", ntohs(info->encap));
+                       return -EINVAL;
                }
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match ebt_vlan_mt_reg __read_mostly = {
@@ -169,9 +161,7 @@ static struct xt_match ebt_vlan_mt_reg __read_mostly = {
 
 static int __init ebt_vlan_init(void)
 {
-       DEBUG_MSG("ebtables 802.1Q extension module v"
-                 MODULE_VERS "\n");
-       DEBUG_MSG("module debug=%d\n", !!debug);
+       pr_debug("ebtables 802.1Q extension module v" MODULE_VERS "\n");
        return xt_register_match(&ebt_vlan_mt_reg);
 }
 
index f0865fd1e3eca770f2218e576093a139b9676243..59ca00e40dec2401b483bad4a7799775766e9f0d 100644 (file)
@@ -14,8 +14,7 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/kmod.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
@@ -87,7 +86,7 @@ static struct xt_target ebt_standard_target = {
 
 static inline int
 ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
-              struct xt_target_param *par)
+              struct xt_action_param *par)
 {
        par->target   = w->u.watcher;
        par->targinfo = w->data;
@@ -96,8 +95,9 @@ ebt_do_watcher(const struct ebt_entry_watcher *w, struct sk_buff *skb,
        return 0;
 }
 
-static inline int ebt_do_match (struct ebt_entry_match *m,
-   const struct sk_buff *skb, struct xt_match_param *par)
+static inline int
+ebt_do_match(struct ebt_entry_match *m, const struct sk_buff *skb,
+            struct xt_action_param *par)
 {
        par->match     = m->u.match;
        par->matchinfo = m->data;
@@ -186,15 +186,13 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
        struct ebt_entries *chaininfo;
        const char *base;
        const struct ebt_table_info *private;
-       bool hotdrop = false;
-       struct xt_match_param mtpar;
-       struct xt_target_param tgpar;
+       struct xt_action_param acpar;
 
-       mtpar.family  = tgpar.family = NFPROTO_BRIDGE;
-       mtpar.in      = tgpar.in  = in;
-       mtpar.out     = tgpar.out = out;
-       mtpar.hotdrop = &hotdrop;
-       mtpar.hooknum = tgpar.hooknum = hook;
+       acpar.family  = NFPROTO_BRIDGE;
+       acpar.in      = in;
+       acpar.out     = out;
+       acpar.hotdrop = false;
+       acpar.hooknum = hook;
 
        read_lock_bh(&table->lock);
        private = table->private;
@@ -215,9 +213,9 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
                if (ebt_basic_match(point, eth_hdr(skb), in, out))
                        goto letscontinue;
 
-               if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &mtpar) != 0)
+               if (EBT_MATCH_ITERATE(point, ebt_do_match, skb, &acpar) != 0)
                        goto letscontinue;
-               if (hotdrop) {
+               if (acpar.hotdrop) {
                        read_unlock_bh(&table->lock);
                        return NF_DROP;
                }
@@ -228,7 +226,7 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
 
                /* these should only watch: not modify, nor tell us
                   what to do with the packet */
-               EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &tgpar);
+               EBT_WATCHER_ITERATE(point, ebt_do_watcher, skb, &acpar);
 
                t = (struct ebt_entry_target *)
                   (((char *)point) + point->target_offset);
@@ -236,9 +234,9 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
                if (!t->u.target->target)
                        verdict = ((struct ebt_standard_target *)t)->verdict;
                else {
-                       tgpar.target   = t->u.target;
-                       tgpar.targinfo = t->data;
-                       verdict = t->u.target->target(skb, &tgpar);
+                       acpar.target   = t->u.target;
+                       acpar.targinfo = t->data;
+                       verdict = t->u.target->target(skb, &acpar);
                }
                if (verdict == EBT_ACCEPT) {
                        read_unlock_bh(&table->lock);
@@ -363,12 +361,9 @@ ebt_check_match(struct ebt_entry_match *m, struct xt_mtchk_param *par,
            left - sizeof(struct ebt_entry_match) < m->match_size)
                return -EINVAL;
 
-       match = try_then_request_module(xt_find_match(NFPROTO_BRIDGE,
-               m->u.name, 0), "ebt_%s", m->u.name);
+       match = xt_request_find_match(NFPROTO_BRIDGE, m->u.name, 0);
        if (IS_ERR(match))
                return PTR_ERR(match);
-       if (match == NULL)
-               return -ENOENT;
        m->u.match = match;
 
        par->match     = match;
@@ -397,13 +392,9 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
           left - sizeof(struct ebt_entry_watcher) < w->watcher_size)
                return -EINVAL;
 
-       watcher = try_then_request_module(
-                 xt_find_target(NFPROTO_BRIDGE, w->u.name, 0),
-                 "ebt_%s", w->u.name);
+       watcher = xt_request_find_target(NFPROTO_BRIDGE, w->u.name, 0);
        if (IS_ERR(watcher))
                return PTR_ERR(watcher);
-       if (watcher == NULL)
-               return -ENOENT;
        w->u.watcher = watcher;
 
        par->target   = watcher;
@@ -716,15 +707,10 @@ ebt_check_entry(struct ebt_entry *e, struct net *net,
        t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
        gap = e->next_offset - e->target_offset;
 
-       target = try_then_request_module(
-                xt_find_target(NFPROTO_BRIDGE, t->u.name, 0),
-                "ebt_%s", t->u.name);
+       target = xt_request_find_target(NFPROTO_BRIDGE, t->u.name, 0);
        if (IS_ERR(target)) {
                ret = PTR_ERR(target);
                goto cleanup_watchers;
-       } else if (target == NULL) {
-               ret = -ENOENT;
-               goto cleanup_watchers;
        }
 
        t->u.target = target;
@@ -2128,7 +2114,7 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
                        return ret;
                new_offset += ret;
                if (offsets_update && new_offset) {
-                       pr_debug("ebtables: change offset %d to %d\n",
+                       pr_debug("change offset %d to %d\n",
                                offsets_update[i], offsets[j] + new_offset);
                        offsets_update[i] = offsets[j] + new_offset;
                }
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
new file mode 100644 (file)
index 0000000..cd1daf6
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# CAIF net configurations
+#
+
+#menu "CAIF Support"
+comment "CAIF Support"
+menuconfig CAIF
+       tristate "Enable CAIF support"
+       select CRC_CCITT
+       default n
+       ---help---
+       The "Communication CPU to Application CPU Interface" (CAIF) is a packet
+       based connection-oriented MUX protocol developed by ST-Ericsson for use
+       with its modems. It is accessed from user space as sockets (PF_CAIF).
+
+       Say Y (or M) here if you build for a phone product (e.g. Android or
+       MeeGo ) that uses CAIF as transport, if unsure say N.
+
+       If you select to build it as module then CAIF_NETDEV also needs to be
+       built as modules. You will also need to say yes to any CAIF physical
+       devices that your platform requires.
+
+       See Documentation/networking/caif for a further explanation on how to
+       use and configure CAIF.
+
+if CAIF
+
+config  CAIF_DEBUG
+       bool "Enable Debug"
+       default n
+       --- help ---
+       Enable the inclusion of debug code in the CAIF stack.
+       Be aware that doing this will impact performance.
+       If unsure say N.
+
+
+config CAIF_NETDEV
+       tristate "CAIF GPRS Network device"
+       default CAIF
+       ---help---
+       Say Y if you will be using a CAIF based GPRS network device.
+       This can be either built-in or a loadable module,
+       If you select to build it as a built-in then the main CAIF device must
+       also be a built-in.
+       If unsure say Y.
+
+endif
+#endmenu
diff --git a/net/caif/Makefile b/net/caif/Makefile
new file mode 100644 (file)
index 0000000..34852af
--- /dev/null
@@ -0,0 +1,26 @@
+ifeq ($(CONFIG_CAIF_DEBUG),1)
+CAIF_DBG_FLAGS := -DDEBUG
+endif
+
+ccflags-y := $(CAIF_FLAGS) $(CAIF_DBG_FLAGS)
+
+caif-objs := caif_dev.o \
+       cfcnfg.o cfmuxl.o cfctrl.o  \
+       cffrml.o cfveil.o cfdbgl.o\
+       cfserl.o cfdgml.o  \
+       cfrfml.o cfvidl.o cfutill.o \
+       cfsrvl.o cfpkt_skbuff.o caif_config_util.o
+clean-dirs:= .tmp_versions
+
+clean-files:= \
+       Module.symvers \
+       modules.order \
+       *.cmd \
+       *.o \
+       *~
+
+obj-$(CONFIG_CAIF) += caif.o
+obj-$(CONFIG_CAIF_NETDEV) += chnl_net.o
+obj-$(CONFIG_CAIF) += caif_socket.o
+
+export-objs := caif.o
diff --git a/net/caif/caif_config_util.c b/net/caif/caif_config_util.c
new file mode 100644 (file)
index 0000000..6f36580
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <net/caif/cfctrl.h>
+#include <net/caif/cfcnfg.h>
+#include <net/caif/caif_dev.h>
+
+int connect_req_to_link_param(struct cfcnfg *cnfg,
+                               struct caif_connect_request *s,
+                               struct cfctrl_link_param *l)
+{
+       struct dev_info *dev_info;
+       enum cfcnfg_phy_preference pref;
+       memset(l, 0, sizeof(*l));
+       l->priority = s->priority;
+
+       if (s->link_name[0] != '\0')
+               l->phyid = cfcnfg_get_named(cnfg, s->link_name);
+       else {
+               switch (s->link_selector) {
+               case CAIF_LINK_HIGH_BANDW:
+                       pref = CFPHYPREF_HIGH_BW;
+                       break;
+               case CAIF_LINK_LOW_LATENCY:
+                       pref = CFPHYPREF_LOW_LAT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               dev_info = cfcnfg_get_phyid(cnfg, pref);
+               if (dev_info == NULL)
+                       return -ENODEV;
+               l->phyid = dev_info->id;
+       }
+       switch (s->protocol) {
+       case CAIFPROTO_AT:
+               l->linktype = CFCTRL_SRV_VEI;
+               if (s->sockaddr.u.at.type == CAIF_ATTYPE_PLAIN)
+                       l->chtype = 0x02;
+               else
+                       l->chtype = s->sockaddr.u.at.type;
+               l->endpoint = 0x00;
+               break;
+       case CAIFPROTO_DATAGRAM:
+               l->linktype = CFCTRL_SRV_DATAGRAM;
+               l->chtype = 0x00;
+               l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
+               break;
+       case CAIFPROTO_DATAGRAM_LOOP:
+               l->linktype = CFCTRL_SRV_DATAGRAM;
+               l->chtype = 0x03;
+               l->endpoint = 0x00;
+               l->u.datagram.connid = s->sockaddr.u.dgm.connection_id;
+               break;
+       case CAIFPROTO_RFM:
+               l->linktype = CFCTRL_SRV_RFM;
+               l->u.datagram.connid = s->sockaddr.u.rfm.connection_id;
+               strncpy(l->u.rfm.volume, s->sockaddr.u.rfm.volume,
+                       sizeof(l->u.rfm.volume)-1);
+               l->u.rfm.volume[sizeof(l->u.rfm.volume)-1] = 0;
+               break;
+       case CAIFPROTO_UTIL:
+               l->linktype = CFCTRL_SRV_UTIL;
+               l->endpoint = 0x00;
+               l->chtype = 0x00;
+               strncpy(l->u.utility.name, s->sockaddr.u.util.service,
+                       sizeof(l->u.utility.name)-1);
+               l->u.utility.name[sizeof(l->u.utility.name)-1] = 0;
+               caif_assert(sizeof(l->u.utility.name) > 10);
+               l->u.utility.paramlen = s->param.size;
+               if (l->u.utility.paramlen > sizeof(l->u.utility.params))
+                       l->u.utility.paramlen = sizeof(l->u.utility.params);
+
+               memcpy(l->u.utility.params, s->param.data,
+                      l->u.utility.paramlen);
+
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c
new file mode 100644 (file)
index 0000000..e2b86f1
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * CAIF Interface registration.
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Borrowed heavily from file: pn_dev.c. Thanks to
+ *  Remi Denis-Courmont <remi.denis-courmont@nokia.com>
+ *  and Sakari Ailus <sakari.ailus@nokia.com>
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <net/netns/generic.h>
+#include <net/net_namespace.h>
+#include <net/pkt_sched.h>
+#include <net/caif/caif_device.h>
+#include <net/caif/caif_dev.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/cfcnfg.h>
+
+MODULE_LICENSE("GPL");
+#define TIMEOUT (HZ*5)
+
+/* Used for local tracking of the CAIF net devices */
+struct caif_device_entry {
+       struct cflayer layer;
+       struct list_head list;
+       atomic_t in_use;
+       atomic_t state;
+       u16 phyid;
+       struct net_device *netdev;
+       wait_queue_head_t event;
+};
+
+struct caif_device_entry_list {
+       struct list_head list;
+       /* Protects simulanous deletes in list */
+       spinlock_t lock;
+};
+
+struct caif_net {
+       struct caif_device_entry_list caifdevs;
+};
+
+static int caif_net_id;
+static struct cfcnfg *cfg;
+
+static struct caif_device_entry_list *caif_device_list(struct net *net)
+{
+       struct caif_net *caifn;
+       BUG_ON(!net);
+       caifn = net_generic(net, caif_net_id);
+       BUG_ON(!caifn);
+       return &caifn->caifdevs;
+}
+
+/* Allocate new CAIF device. */
+static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
+{
+       struct caif_device_entry_list *caifdevs;
+       struct caif_device_entry *caifd;
+       caifdevs = caif_device_list(dev_net(dev));
+       BUG_ON(!caifdevs);
+       caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC);
+       if (!caifd)
+               return NULL;
+       caifd->netdev = dev;
+       list_add(&caifd->list, &caifdevs->list);
+       init_waitqueue_head(&caifd->event);
+       return caifd;
+}
+
+static struct caif_device_entry *caif_get(struct net_device *dev)
+{
+       struct caif_device_entry_list *caifdevs =
+           caif_device_list(dev_net(dev));
+       struct caif_device_entry *caifd;
+       BUG_ON(!caifdevs);
+       list_for_each_entry(caifd, &caifdevs->list, list) {
+               if (caifd->netdev == dev)
+                       return caifd;
+       }
+       return NULL;
+}
+
+static void caif_device_destroy(struct net_device *dev)
+{
+       struct caif_device_entry_list *caifdevs =
+           caif_device_list(dev_net(dev));
+       struct caif_device_entry *caifd;
+       ASSERT_RTNL();
+       if (dev->type != ARPHRD_CAIF)
+               return;
+
+       spin_lock_bh(&caifdevs->lock);
+       caifd = caif_get(dev);
+       if (caifd == NULL) {
+               spin_unlock_bh(&caifdevs->lock);
+               return;
+       }
+
+       list_del(&caifd->list);
+       spin_unlock_bh(&caifdevs->lock);
+
+       kfree(caifd);
+}
+
+static int transmit(struct cflayer *layer, struct cfpkt *pkt)
+{
+       struct caif_device_entry *caifd =
+           container_of(layer, struct caif_device_entry, layer);
+       struct sk_buff *skb, *skb2;
+       int ret = -EINVAL;
+       skb = cfpkt_tonative(pkt);
+       skb->dev = caifd->netdev;
+       /*
+        * Don't allow SKB to be destroyed upon error, but signal resend
+        * notification to clients. We can't rely on the return value as
+        * congestion (NET_XMIT_CN) sometimes drops the packet, sometimes don't.
+        */
+       if (netif_queue_stopped(caifd->netdev))
+               return -EAGAIN;
+       skb2 = skb_get(skb);
+
+       ret = dev_queue_xmit(skb2);
+
+       if (!ret)
+               kfree_skb(skb);
+       else
+               return -EAGAIN;
+
+       return 0;
+}
+
+static int modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
+{
+       struct caif_device_entry *caifd;
+       struct caif_dev_common *caifdev;
+       caifd = container_of(layr, struct caif_device_entry, layer);
+       caifdev = netdev_priv(caifd->netdev);
+       if (ctrl == _CAIF_MODEMCMD_PHYIF_USEFULL) {
+               atomic_set(&caifd->in_use, 1);
+               wake_up_interruptible(&caifd->event);
+
+       } else if (ctrl == _CAIF_MODEMCMD_PHYIF_USELESS) {
+               atomic_set(&caifd->in_use, 0);
+               wake_up_interruptible(&caifd->event);
+       }
+       return 0;
+}
+
+/*
+ * Stuff received packets to associated sockets.
+ * On error, returns non-zero and releases the skb.
+ */
+static int receive(struct sk_buff *skb, struct net_device *dev,
+                  struct packet_type *pkttype, struct net_device *orig_dev)
+{
+       struct net *net;
+       struct cfpkt *pkt;
+       struct caif_device_entry *caifd;
+       net = dev_net(dev);
+       pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
+       caifd = caif_get(dev);
+       if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+               return NET_RX_DROP;
+
+       if (caifd->layer.up->receive(caifd->layer.up, pkt))
+               return NET_RX_DROP;
+
+       return 0;
+}
+
+static struct packet_type caif_packet_type __read_mostly = {
+       .type = cpu_to_be16(ETH_P_CAIF),
+       .func = receive,
+};
+
+static void dev_flowctrl(struct net_device *dev, int on)
+{
+       struct caif_device_entry *caifd = caif_get(dev);
+       if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+               return;
+
+       caifd->layer.up->ctrlcmd(caifd->layer.up,
+                                on ?
+                                _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND :
+                                _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
+                                caifd->layer.id);
+}
+
+/* notify Caif of device events */
+static int caif_device_notify(struct notifier_block *me, unsigned long what,
+                             void *arg)
+{
+       struct net_device *dev = arg;
+       struct caif_device_entry *caifd = NULL;
+       struct caif_dev_common *caifdev;
+       enum cfcnfg_phy_preference pref;
+       int res = -EINVAL;
+       enum cfcnfg_phy_type phy_type;
+
+       if (dev->type != ARPHRD_CAIF)
+               return 0;
+
+       switch (what) {
+       case NETDEV_REGISTER:
+               pr_info("CAIF: %s():register %s\n", __func__, dev->name);
+               caifd = caif_device_alloc(dev);
+               if (caifd == NULL)
+                       break;
+               caifdev = netdev_priv(dev);
+               caifdev->flowctrl = dev_flowctrl;
+               atomic_set(&caifd->state, what);
+               res = 0;
+               break;
+
+       case NETDEV_UP:
+               pr_info("CAIF: %s(): up %s\n", __func__, dev->name);
+               caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
+               caifdev = netdev_priv(dev);
+               if (atomic_read(&caifd->state) == NETDEV_UP) {
+                       pr_info("CAIF: %s():%s already up\n",
+                               __func__, dev->name);
+                       break;
+               }
+               atomic_set(&caifd->state, what);
+               caifd->layer.transmit = transmit;
+               caifd->layer.modemcmd = modemcmd;
+
+               if (caifdev->use_frag)
+                       phy_type = CFPHYTYPE_FRAG;
+               else
+                       phy_type = CFPHYTYPE_CAIF;
+
+               switch (caifdev->link_select) {
+               case CAIF_LINK_HIGH_BANDW:
+                       pref = CFPHYPREF_HIGH_BW;
+                       break;
+               case CAIF_LINK_LOW_LATENCY:
+                       pref = CFPHYPREF_LOW_LAT;
+                       break;
+               default:
+                       pref = CFPHYPREF_HIGH_BW;
+                       break;
+               }
+
+               cfcnfg_add_phy_layer(get_caif_conf(),
+                                    phy_type,
+                                    dev,
+                                    &caifd->layer,
+                                    &caifd->phyid,
+                                    pref,
+                                    caifdev->use_fcs,
+                                    caifdev->use_stx);
+               strncpy(caifd->layer.name, dev->name,
+                       sizeof(caifd->layer.name) - 1);
+               caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
+               break;
+
+       case NETDEV_GOING_DOWN:
+               caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
+               pr_info("CAIF: %s():going down %s\n", __func__, dev->name);
+
+               if (atomic_read(&caifd->state) == NETDEV_GOING_DOWN ||
+                       atomic_read(&caifd->state) == NETDEV_DOWN)
+                       break;
+
+               atomic_set(&caifd->state, what);
+               if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd)
+                       return -EINVAL;
+               caifd->layer.up->ctrlcmd(caifd->layer.up,
+                                        _CAIF_CTRLCMD_PHYIF_DOWN_IND,
+                                        caifd->layer.id);
+               res = wait_event_interruptible_timeout(caifd->event,
+                                       atomic_read(&caifd->in_use) == 0,
+                                       TIMEOUT);
+               break;
+
+       case NETDEV_DOWN:
+               caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
+               pr_info("CAIF: %s(): down %s\n", __func__, dev->name);
+               if (atomic_read(&caifd->in_use))
+                       pr_warning("CAIF: %s(): "
+                                  "Unregistering an active CAIF device: %s\n",
+                                  __func__, dev->name);
+               cfcnfg_del_phy_layer(get_caif_conf(), &caifd->layer);
+               atomic_set(&caifd->state, what);
+               break;
+
+       case NETDEV_UNREGISTER:
+               caifd = caif_get(dev);
+               pr_info("CAIF: %s(): unregister %s\n", __func__, dev->name);
+               atomic_set(&caifd->state, what);
+               caif_device_destroy(dev);
+               break;
+       }
+       return 0;
+}
+
+static struct notifier_block caif_device_notifier = {
+       .notifier_call = caif_device_notify,
+       .priority = 0,
+};
+
+
+struct cfcnfg *get_caif_conf(void)
+{
+       return cfg;
+}
+EXPORT_SYMBOL(get_caif_conf);
+
+int caif_connect_client(struct caif_connect_request *conn_req,
+                          struct cflayer *client_layer)
+{
+       struct cfctrl_link_param param;
+       int ret;
+       ret = connect_req_to_link_param(get_caif_conf(), conn_req, &param);
+       if (ret)
+               return ret;
+       /* Hook up the adaptation layer. */
+       return cfcnfg_add_adaptation_layer(get_caif_conf(),
+                                               &param, client_layer);
+}
+EXPORT_SYMBOL(caif_connect_client);
+
+int caif_disconnect_client(struct cflayer *adap_layer)
+{
+       return cfcnfg_disconn_adapt_layer(get_caif_conf(), adap_layer);
+}
+EXPORT_SYMBOL(caif_disconnect_client);
+
+void caif_release_client(struct cflayer *adap_layer)
+{
+       cfcnfg_release_adap_layer(adap_layer);
+}
+EXPORT_SYMBOL(caif_release_client);
+
+/* Per-namespace Caif devices handling */
+static int caif_init_net(struct net *net)
+{
+       struct caif_net *caifn = net_generic(net, caif_net_id);
+       INIT_LIST_HEAD(&caifn->caifdevs.list);
+       spin_lock_init(&caifn->caifdevs.lock);
+       return 0;
+}
+
+static void caif_exit_net(struct net *net)
+{
+       struct net_device *dev;
+       int res;
+       rtnl_lock();
+       for_each_netdev(net, dev) {
+               if (dev->type != ARPHRD_CAIF)
+                       continue;
+               res = dev_close(dev);
+               caif_device_destroy(dev);
+       }
+       rtnl_unlock();
+}
+
+static struct pernet_operations caif_net_ops = {
+       .init = caif_init_net,
+       .exit = caif_exit_net,
+       .id   = &caif_net_id,
+       .size = sizeof(struct caif_net),
+};
+
+/* Initialize Caif devices list */
+static int __init caif_device_init(void)
+{
+       int result;
+       cfg = cfcnfg_create();
+       if (!cfg) {
+               pr_warning("CAIF: %s(): can't create cfcnfg.\n", __func__);
+               goto err_cfcnfg_create_failed;
+       }
+       result = register_pernet_device(&caif_net_ops);
+
+       if (result) {
+               kfree(cfg);
+               cfg = NULL;
+               return result;
+       }
+       dev_add_pack(&caif_packet_type);
+       register_netdevice_notifier(&caif_device_notifier);
+
+       return result;
+err_cfcnfg_create_failed:
+       return -ENODEV;
+}
+
+static void __exit caif_device_exit(void)
+{
+       dev_remove_pack(&caif_packet_type);
+       unregister_pernet_device(&caif_net_ops);
+       unregister_netdevice_notifier(&caif_device_notifier);
+       cfcnfg_remove(cfg);
+}
+
+module_init(caif_device_init);
+module_exit(caif_device_exit);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
new file mode 100644 (file)
index 0000000..c3a70c5
--- /dev/null
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/tcp.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/debugfs.h>
+#include <linux/caif/caif_socket.h>
+#include <asm/atomic.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_dev.h>
+#include <net/caif/cfpkt.h>
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(AF_CAIF);
+
+#define CAIF_DEF_SNDBUF (CAIF_MAX_PAYLOAD_SIZE*10)
+#define CAIF_DEF_RCVBUF (CAIF_MAX_PAYLOAD_SIZE*100)
+
+/*
+ * CAIF state is re-using the TCP socket states.
+ * caif_states stored in sk_state reflect the state as reported by
+ * the CAIF stack, while sk_socket->state is the state of the socket.
+ */
+enum caif_states {
+       CAIF_CONNECTED          = TCP_ESTABLISHED,
+       CAIF_CONNECTING = TCP_SYN_SENT,
+       CAIF_DISCONNECTED       = TCP_CLOSE
+};
+
+#define TX_FLOW_ON_BIT 1
+#define RX_FLOW_ON_BIT 2
+
+static struct dentry *debugfsdir;
+
+#ifdef CONFIG_DEBUG_FS
+struct debug_fs_counter {
+       atomic_t caif_nr_socks;
+       atomic_t num_connect_req;
+       atomic_t num_connect_resp;
+       atomic_t num_connect_fail_resp;
+       atomic_t num_disconnect;
+       atomic_t num_remote_shutdown_ind;
+       atomic_t num_tx_flow_off_ind;
+       atomic_t num_tx_flow_on_ind;
+       atomic_t num_rx_flow_off;
+       atomic_t num_rx_flow_on;
+};
+struct debug_fs_counter cnt;
+#define        dbfs_atomic_inc(v) atomic_inc(v)
+#define        dbfs_atomic_dec(v) atomic_dec(v)
+#else
+#define        dbfs_atomic_inc(v)
+#define        dbfs_atomic_dec(v)
+#endif
+
+struct caifsock {
+       struct sock sk; /* must be first member */
+       struct cflayer layer;
+       char name[CAIF_LAYER_NAME_SZ]; /* Used for debugging */
+       u32 flow_state;
+       struct caif_connect_request conn_req;
+       struct mutex readlock;
+       struct dentry *debugfs_socket_dir;
+};
+
+static int rx_flow_is_on(struct caifsock *cf_sk)
+{
+       return test_bit(RX_FLOW_ON_BIT,
+                       (void *) &cf_sk->flow_state);
+}
+
+static int tx_flow_is_on(struct caifsock *cf_sk)
+{
+       return test_bit(TX_FLOW_ON_BIT,
+                       (void *) &cf_sk->flow_state);
+}
+
+static void set_rx_flow_off(struct caifsock *cf_sk)
+{
+        clear_bit(RX_FLOW_ON_BIT,
+                (void *) &cf_sk->flow_state);
+}
+
+static void set_rx_flow_on(struct caifsock *cf_sk)
+{
+        set_bit(RX_FLOW_ON_BIT,
+                       (void *) &cf_sk->flow_state);
+}
+
+static void set_tx_flow_off(struct caifsock *cf_sk)
+{
+        clear_bit(TX_FLOW_ON_BIT,
+               (void *) &cf_sk->flow_state);
+}
+
+static void set_tx_flow_on(struct caifsock *cf_sk)
+{
+        set_bit(TX_FLOW_ON_BIT,
+               (void *) &cf_sk->flow_state);
+}
+
+static void caif_read_lock(struct sock *sk)
+{
+       struct caifsock *cf_sk;
+       cf_sk = container_of(sk, struct caifsock, sk);
+       mutex_lock(&cf_sk->readlock);
+}
+
+static void caif_read_unlock(struct sock *sk)
+{
+       struct caifsock *cf_sk;
+       cf_sk = container_of(sk, struct caifsock, sk);
+       mutex_unlock(&cf_sk->readlock);
+}
+
+int sk_rcvbuf_lowwater(struct caifsock *cf_sk)
+{
+       /* A quarter of full buffer is used a low water mark */
+       return cf_sk->sk.sk_rcvbuf / 4;
+}
+
+void caif_flow_ctrl(struct sock *sk, int mode)
+{
+       struct caifsock *cf_sk;
+       cf_sk = container_of(sk, struct caifsock, sk);
+       if (cf_sk->layer.dn)
+               cf_sk->layer.dn->modemcmd(cf_sk->layer.dn, mode);
+}
+
+/*
+ * Copied from sock.c:sock_queue_rcv_skb(), but changed so packets are
+ * not dropped, but CAIF is sending flow off instead.
+ */
+int caif_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       int err;
+       int skb_len;
+       unsigned long flags;
+       struct sk_buff_head *list = &sk->sk_receive_queue;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+
+       if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+               (unsigned)sk->sk_rcvbuf && rx_flow_is_on(cf_sk)) {
+               trace_printk("CAIF: %s():"
+                       " sending flow OFF (queue len = %d %d)\n",
+                       __func__,
+                       atomic_read(&cf_sk->sk.sk_rmem_alloc),
+                       sk_rcvbuf_lowwater(cf_sk));
+               set_rx_flow_off(cf_sk);
+               if (cf_sk->layer.dn)
+                       cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
+                                               CAIF_MODEMCMD_FLOW_OFF_REQ);
+       }
+
+       err = sk_filter(sk, skb);
+       if (err)
+               return err;
+       if (!sk_rmem_schedule(sk, skb->truesize) && rx_flow_is_on(cf_sk)) {
+               set_rx_flow_off(cf_sk);
+               trace_printk("CAIF: %s():"
+                       " sending flow OFF due to rmem_schedule\n",
+                       __func__);
+               if (cf_sk->layer.dn)
+                       cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
+                                               CAIF_MODEMCMD_FLOW_OFF_REQ);
+       }
+       skb->dev = NULL;
+       skb_set_owner_r(skb, sk);
+       /* Cache the SKB length before we tack it onto the receive
+        * queue. Once it is added it no longer belongs to us and
+        * may be freed by other threads of control pulling packets
+        * from the queue.
+        */
+       skb_len = skb->len;
+       spin_lock_irqsave(&list->lock, flags);
+       if (!sock_flag(sk, SOCK_DEAD))
+               __skb_queue_tail(list, skb);
+       spin_unlock_irqrestore(&list->lock, flags);
+
+       if (!sock_flag(sk, SOCK_DEAD))
+               sk->sk_data_ready(sk, skb_len);
+       else
+               kfree_skb(skb);
+       return 0;
+}
+
+/* Packet Receive Callback function called from CAIF Stack */
+static int caif_sktrecv_cb(struct cflayer *layr, struct cfpkt *pkt)
+{
+       struct caifsock *cf_sk;
+       struct sk_buff *skb;
+
+       cf_sk = container_of(layr, struct caifsock, layer);
+       skb = cfpkt_tonative(pkt);
+
+       if (unlikely(cf_sk->sk.sk_state != CAIF_CONNECTED)) {
+               cfpkt_destroy(pkt);
+               return 0;
+       }
+       caif_queue_rcv_skb(&cf_sk->sk, skb);
+       return 0;
+}
+
+/* Packet Control Callback function called from CAIF */
+static void caif_ctrl_cb(struct cflayer *layr,
+                               enum caif_ctrlcmd flow,
+                               int phyid)
+{
+       struct caifsock *cf_sk = container_of(layr, struct caifsock, layer);
+       switch (flow) {
+       case CAIF_CTRLCMD_FLOW_ON_IND:
+               /* OK from modem to start sending again */
+               dbfs_atomic_inc(&cnt.num_tx_flow_on_ind);
+               set_tx_flow_on(cf_sk);
+               cf_sk->sk.sk_state_change(&cf_sk->sk);
+               break;
+
+       case CAIF_CTRLCMD_FLOW_OFF_IND:
+               /* Modem asks us to shut up */
+               dbfs_atomic_inc(&cnt.num_tx_flow_off_ind);
+               set_tx_flow_off(cf_sk);
+               cf_sk->sk.sk_state_change(&cf_sk->sk);
+               break;
+
+       case CAIF_CTRLCMD_INIT_RSP:
+               /* We're now connected */
+               dbfs_atomic_inc(&cnt.num_connect_resp);
+               cf_sk->sk.sk_state = CAIF_CONNECTED;
+               set_tx_flow_on(cf_sk);
+               cf_sk->sk.sk_state_change(&cf_sk->sk);
+               break;
+
+       case CAIF_CTRLCMD_DEINIT_RSP:
+               /* We're now disconnected */
+               cf_sk->sk.sk_state = CAIF_DISCONNECTED;
+               cf_sk->sk.sk_state_change(&cf_sk->sk);
+               cfcnfg_release_adap_layer(&cf_sk->layer);
+               break;
+
+       case CAIF_CTRLCMD_INIT_FAIL_RSP:
+               /* Connect request failed */
+               dbfs_atomic_inc(&cnt.num_connect_fail_resp);
+               cf_sk->sk.sk_err = ECONNREFUSED;
+               cf_sk->sk.sk_state = CAIF_DISCONNECTED;
+               cf_sk->sk.sk_shutdown = SHUTDOWN_MASK;
+               /*
+                * Socket "standards" seems to require POLLOUT to
+                * be set at connect failure.
+                */
+               set_tx_flow_on(cf_sk);
+               cf_sk->sk.sk_state_change(&cf_sk->sk);
+               break;
+
+       case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+               /* Modem has closed this connection, or device is down. */
+               dbfs_atomic_inc(&cnt.num_remote_shutdown_ind);
+               cf_sk->sk.sk_shutdown = SHUTDOWN_MASK;
+               cf_sk->sk.sk_err = ECONNRESET;
+               set_rx_flow_on(cf_sk);
+               cf_sk->sk.sk_error_report(&cf_sk->sk);
+               break;
+
+       default:
+               pr_debug("CAIF: %s(): Unexpected flow command %d\n",
+                               __func__, flow);
+       }
+}
+
+static void caif_check_flow_release(struct sock *sk)
+{
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+
+       if (cf_sk->layer.dn == NULL || cf_sk->layer.dn->modemcmd == NULL)
+               return;
+       if (rx_flow_is_on(cf_sk))
+               return;
+
+       if (atomic_read(&sk->sk_rmem_alloc) <= sk_rcvbuf_lowwater(cf_sk)) {
+                       dbfs_atomic_inc(&cnt.num_rx_flow_on);
+                       set_rx_flow_on(cf_sk);
+                       cf_sk->layer.dn->modemcmd(cf_sk->layer.dn,
+                                               CAIF_MODEMCMD_FLOW_ON_REQ);
+       }
+}
+/*
+ * Copied from sock.c:sock_queue_rcv_skb(), and added check that user buffer
+ * has sufficient size.
+ */
+
+static int caif_seqpkt_recvmsg(struct kiocb *iocb, struct socket *sock,
+                               struct msghdr *m, size_t buf_len, int flags)
+
+{
+       struct sock *sk = sock->sk;
+       struct sk_buff *skb;
+       int ret = 0;
+       int len;
+
+       if (unlikely(!buf_len))
+               return -EINVAL;
+
+       skb = skb_recv_datagram(sk, flags, 0 , &ret);
+       if (!skb)
+               goto read_error;
+
+       len = skb->len;
+
+       if (skb && skb->len > buf_len && !(flags & MSG_PEEK)) {
+               len = buf_len;
+               /*
+                * Push skb back on receive queue if buffer too small.
+                * This has a built-in race where multi-threaded receive
+                * may get packet in wrong order, but multiple read does
+                * not really guarantee ordered delivery anyway.
+                * Let's optimize for speed without taking locks.
+                */
+
+               skb_queue_head(&sk->sk_receive_queue, skb);
+               ret = -EMSGSIZE;
+               goto read_error;
+       }
+
+       ret = skb_copy_datagram_iovec(skb, 0, m->msg_iov, len);
+       if (ret)
+               goto read_error;
+
+       skb_free_datagram(sk, skb);
+
+       caif_check_flow_release(sk);
+
+       return len;
+
+read_error:
+       return ret;
+}
+
+
+/* Copied from unix_stream_wait_data, identical except for lock call. */
+static long caif_stream_data_wait(struct sock *sk, long timeo)
+{
+       DEFINE_WAIT(wait);
+       lock_sock(sk);
+
+       for (;;) {
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+
+               if (!skb_queue_empty(&sk->sk_receive_queue) ||
+                       sk->sk_err ||
+                       sk->sk_state != CAIF_CONNECTED ||
+                       sock_flag(sk, SOCK_DEAD) ||
+                       (sk->sk_shutdown & RCV_SHUTDOWN) ||
+                       signal_pending(current) ||
+                       !timeo)
+                       break;
+
+               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+               release_sock(sk);
+               timeo = schedule_timeout(timeo);
+               lock_sock(sk);
+               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       }
+
+       finish_wait(sk_sleep(sk), &wait);
+       release_sock(sk);
+       return timeo;
+}
+
+
+/*
+ * Copied from unix_stream_recvmsg, but removed credit checks,
+ * changed locking calls, changed address handling.
+ */
+static int caif_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+                               struct msghdr *msg, size_t size,
+                               int flags)
+{
+       struct sock *sk = sock->sk;
+       int copied = 0;
+       int target;
+       int err = 0;
+       long timeo;
+
+       err = -EOPNOTSUPP;
+       if (flags&MSG_OOB)
+               goto out;
+
+       msg->msg_namelen = 0;
+
+       /*
+        * Lock the socket to prevent queue disordering
+        * while sleeps in memcpy_tomsg
+        */
+       err = -EAGAIN;
+       if (sk->sk_state == CAIF_CONNECTING)
+               goto out;
+
+       caif_read_lock(sk);
+       target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
+       timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
+
+       do {
+               int chunk;
+               struct sk_buff *skb;
+
+               lock_sock(sk);
+               skb = skb_dequeue(&sk->sk_receive_queue);
+               caif_check_flow_release(sk);
+
+               if (skb == NULL) {
+                       if (copied >= target)
+                               goto unlock;
+                       /*
+                        *      POSIX 1003.1g mandates this order.
+                        */
+                       err = sock_error(sk);
+                       if (err)
+                               goto unlock;
+                       err = -ECONNRESET;
+                       if (sk->sk_shutdown & RCV_SHUTDOWN)
+                               goto unlock;
+
+                       err = -EPIPE;
+                       if (sk->sk_state != CAIF_CONNECTED)
+                               goto unlock;
+                       if (sock_flag(sk, SOCK_DEAD))
+                               goto unlock;
+
+                       release_sock(sk);
+
+                       err = -EAGAIN;
+                       if (!timeo)
+                               break;
+
+                       caif_read_unlock(sk);
+
+                       timeo = caif_stream_data_wait(sk, timeo);
+
+                       if (signal_pending(current)) {
+                               err = sock_intr_errno(timeo);
+                               goto out;
+                       }
+                       caif_read_lock(sk);
+                       continue;
+unlock:
+                       release_sock(sk);
+                       break;
+               }
+               release_sock(sk);
+               chunk = min_t(unsigned int, skb->len, size);
+               if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+                       skb_queue_head(&sk->sk_receive_queue, skb);
+                       if (copied == 0)
+                               copied = -EFAULT;
+                       break;
+               }
+               copied += chunk;
+               size -= chunk;
+
+               /* Mark read part of skb as used */
+               if (!(flags & MSG_PEEK)) {
+                       skb_pull(skb, chunk);
+
+                       /* put the skb back if we didn't use it up. */
+                       if (skb->len) {
+                               skb_queue_head(&sk->sk_receive_queue, skb);
+                               break;
+                       }
+                       kfree_skb(skb);
+
+               } else {
+                       /*
+                        * It is questionable, see note in unix_dgram_recvmsg.
+                        */
+                       /* put message back and return */
+                       skb_queue_head(&sk->sk_receive_queue, skb);
+                       break;
+               }
+       } while (size);
+       caif_read_unlock(sk);
+
+out:
+       return copied ? : err;
+}
+
+/*
+ * Copied from sock.c:sock_wait_for_wmem, but change to wait for
+ * CAIF flow-on and sock_writable.
+ */
+static long caif_wait_for_flow_on(struct caifsock *cf_sk,
+                               int wait_writeable, long timeo, int *err)
+{
+       struct sock *sk = &cf_sk->sk;
+       DEFINE_WAIT(wait);
+       for (;;) {
+               *err = 0;
+               if (tx_flow_is_on(cf_sk) &&
+                       (!wait_writeable || sock_writeable(&cf_sk->sk)))
+                       break;
+               *err = -ETIMEDOUT;
+               if (!timeo)
+                       break;
+               *err = -ERESTARTSYS;
+               if (signal_pending(current))
+                       break;
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
+               *err = -ECONNRESET;
+               if (sk->sk_shutdown & SHUTDOWN_MASK)
+                       break;
+               *err = -sk->sk_err;
+               if (sk->sk_err)
+                       break;
+               *err = -EPIPE;
+               if (cf_sk->sk.sk_state != CAIF_CONNECTED)
+                       break;
+               timeo = schedule_timeout(timeo);
+       }
+       finish_wait(sk_sleep(sk), &wait);
+       return timeo;
+}
+
+/*
+ * Transmit a SKB. The device may temporarily request re-transmission
+ * by returning EAGAIN.
+ */
+static int transmit_skb(struct sk_buff *skb, struct caifsock *cf_sk,
+                       int noblock, long timeo)
+{
+       struct cfpkt *pkt;
+       int ret, loopcnt = 0;
+
+       pkt = cfpkt_fromnative(CAIF_DIR_OUT, skb);
+       memset(cfpkt_info(pkt), 0, sizeof(struct caif_payload_info));
+       do {
+
+               ret = -ETIMEDOUT;
+
+               /* Slight paranoia, probably not needed. */
+               if (unlikely(loopcnt++ > 1000)) {
+                       pr_warning("CAIF: %s(): transmit retries failed,"
+                               " error = %d\n", __func__, ret);
+                       break;
+               }
+
+               if (cf_sk->layer.dn != NULL)
+                       ret = cf_sk->layer.dn->transmit(cf_sk->layer.dn, pkt);
+               if (likely(ret >= 0))
+                       break;
+               /* if transmit return -EAGAIN, then retry */
+               if (noblock && ret == -EAGAIN)
+                       break;
+               timeo = caif_wait_for_flow_on(cf_sk, 0, timeo, &ret);
+               if (signal_pending(current)) {
+                       ret = sock_intr_errno(timeo);
+                       break;
+               }
+               if (ret)
+                       break;
+               if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
+                       sock_flag(&cf_sk->sk, SOCK_DEAD) ||
+                       (cf_sk->sk.sk_shutdown & RCV_SHUTDOWN)) {
+                       ret = -EPIPE;
+                       cf_sk->sk.sk_err = EPIPE;
+                       break;
+               }
+       } while (ret == -EAGAIN);
+       return ret;
+}
+
+/* Copied from af_unix:unix_dgram_sendmsg, and adapted to CAIF */
+static int caif_seqpkt_sendmsg(struct kiocb *kiocb, struct socket *sock,
+                       struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       int buffer_size;
+       int ret = 0;
+       struct sk_buff *skb = NULL;
+       int noblock;
+       long timeo;
+       caif_assert(cf_sk);
+       ret = sock_error(sk);
+       if (ret)
+               goto err;
+
+       ret = -EOPNOTSUPP;
+       if (msg->msg_flags&MSG_OOB)
+               goto err;
+
+       ret = -EOPNOTSUPP;
+       if (msg->msg_namelen)
+               goto err;
+
+       ret = -EINVAL;
+       if (unlikely(msg->msg_iov->iov_base == NULL))
+               goto err;
+       noblock = msg->msg_flags & MSG_DONTWAIT;
+
+       buffer_size = len + CAIF_NEEDED_HEADROOM + CAIF_NEEDED_TAILROOM;
+
+       ret = -EMSGSIZE;
+       if (buffer_size > CAIF_MAX_PAYLOAD_SIZE)
+               goto err;
+
+       timeo = sock_sndtimeo(sk, noblock);
+       timeo = caif_wait_for_flow_on(container_of(sk, struct caifsock, sk),
+                               1, timeo, &ret);
+
+       ret = -EPIPE;
+       if (cf_sk->sk.sk_state != CAIF_CONNECTED ||
+               sock_flag(sk, SOCK_DEAD) ||
+               (sk->sk_shutdown & RCV_SHUTDOWN))
+               goto err;
+
+       ret = -ENOMEM;
+       skb = sock_alloc_send_skb(sk, buffer_size, noblock, &ret);
+       if (!skb)
+               goto err;
+       skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+
+       ret = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+
+       if (ret)
+               goto err;
+       ret = transmit_skb(skb, cf_sk, noblock, timeo);
+       if (ret < 0)
+               goto err;
+       return len;
+err:
+       kfree_skb(skb);
+       return ret;
+}
+
+/*
+ * Copied from unix_stream_sendmsg and adapted to CAIF:
+ * Changed removed permission handling and added waiting for flow on
+ * and other minor adaptations.
+ */
+static int caif_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
+                               struct msghdr *msg, size_t len)
+{
+       struct sock *sk = sock->sk;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       int err, size;
+       struct sk_buff *skb;
+       int sent = 0;
+       long timeo;
+
+       err = -EOPNOTSUPP;
+
+       if (unlikely(msg->msg_flags&MSG_OOB))
+               goto out_err;
+
+       if (unlikely(msg->msg_namelen))
+               goto out_err;
+
+       timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
+       timeo = caif_wait_for_flow_on(cf_sk, 1, timeo, &err);
+
+       if (unlikely(sk->sk_shutdown & SEND_SHUTDOWN))
+               goto pipe_err;
+
+       while (sent < len) {
+
+               size = len-sent;
+
+               if (size > CAIF_MAX_PAYLOAD_SIZE)
+                       size = CAIF_MAX_PAYLOAD_SIZE;
+
+               /* If size is more than half of sndbuf, chop up message */
+               if (size > ((sk->sk_sndbuf >> 1) - 64))
+                       size = (sk->sk_sndbuf >> 1) - 64;
+
+               if (size > SKB_MAX_ALLOC)
+                       size = SKB_MAX_ALLOC;
+
+               skb = sock_alloc_send_skb(sk,
+                                       size + CAIF_NEEDED_HEADROOM
+                                       + CAIF_NEEDED_TAILROOM,
+                                       msg->msg_flags&MSG_DONTWAIT,
+                                       &err);
+               if (skb == NULL)
+                       goto out_err;
+
+               skb_reserve(skb, CAIF_NEEDED_HEADROOM);
+               /*
+                *      If you pass two values to the sock_alloc_send_skb
+                *      it tries to grab the large buffer with GFP_NOFS
+                *      (which can fail easily), and if it fails grab the
+                *      fallback size buffer which is under a page and will
+                *      succeed. [Alan]
+                */
+               size = min_t(int, size, skb_tailroom(skb));
+
+               err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+               if (err) {
+                       kfree_skb(skb);
+                       goto out_err;
+               }
+               err = transmit_skb(skb, cf_sk,
+                               msg->msg_flags&MSG_DONTWAIT, timeo);
+               if (err < 0) {
+                       kfree_skb(skb);
+                       goto pipe_err;
+               }
+               sent += size;
+       }
+
+       return sent;
+
+pipe_err:
+       if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL))
+               send_sig(SIGPIPE, current, 0);
+       err = -EPIPE;
+out_err:
+       return sent ? : err;
+}
+
+static int setsockopt(struct socket *sock,
+                       int lvl, int opt, char __user *ov, unsigned int ol)
+{
+       struct sock *sk = sock->sk;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       int prio, linksel;
+       struct ifreq ifreq;
+
+       if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED)
+               return -ENOPROTOOPT;
+
+       switch (opt) {
+       case CAIFSO_LINK_SELECT:
+               if (ol < sizeof(int))
+                       return -EINVAL;
+               if (lvl != SOL_CAIF)
+                       goto bad_sol;
+               if (copy_from_user(&linksel, ov, sizeof(int)))
+                       return -EINVAL;
+               lock_sock(&(cf_sk->sk));
+               cf_sk->conn_req.link_selector = linksel;
+               release_sock(&cf_sk->sk);
+               return 0;
+
+       case SO_PRIORITY:
+               if (lvl != SOL_SOCKET)
+                       goto bad_sol;
+               if (ol < sizeof(int))
+                       return -EINVAL;
+               if (copy_from_user(&prio, ov, sizeof(int)))
+                       return -EINVAL;
+               lock_sock(&(cf_sk->sk));
+               cf_sk->conn_req.priority = prio;
+               release_sock(&cf_sk->sk);
+               return 0;
+
+       case SO_BINDTODEVICE:
+               if (lvl != SOL_SOCKET)
+                       goto bad_sol;
+               if (ol < sizeof(struct ifreq))
+                       return -EINVAL;
+               if (copy_from_user(&ifreq, ov, sizeof(ifreq)))
+                       return -EFAULT;
+               lock_sock(&(cf_sk->sk));
+               strncpy(cf_sk->conn_req.link_name, ifreq.ifr_name,
+                       sizeof(cf_sk->conn_req.link_name));
+               cf_sk->conn_req.link_name
+                       [sizeof(cf_sk->conn_req.link_name)-1] = 0;
+               release_sock(&cf_sk->sk);
+               return 0;
+
+       case CAIFSO_REQ_PARAM:
+               if (lvl != SOL_CAIF)
+                       goto bad_sol;
+               if (cf_sk->sk.sk_protocol != CAIFPROTO_UTIL)
+                       return -ENOPROTOOPT;
+               lock_sock(&(cf_sk->sk));
+               cf_sk->conn_req.param.size = ol;
+               if (ol > sizeof(cf_sk->conn_req.param.data) ||
+                       copy_from_user(&cf_sk->conn_req.param.data, ov, ol)) {
+                       release_sock(&cf_sk->sk);
+                       return -EINVAL;
+               }
+               release_sock(&cf_sk->sk);
+               return 0;
+
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       return 0;
+bad_sol:
+       return -ENOPROTOOPT;
+
+}
+
+/*
+ * caif_connect() - Connect a CAIF Socket
+ * Copied and modified af_irda.c:irda_connect().
+ *
+ * Note : by consulting "errno", the user space caller may learn the cause
+ * of the failure. Most of them are visible in the function, others may come
+ * from subroutines called and are listed here :
+ *  o -EAFNOSUPPORT: bad socket family or type.
+ *  o -ESOCKTNOSUPPORT: bad socket type or protocol
+ *  o -EINVAL: bad socket address, or CAIF link type
+ *  o -ECONNREFUSED: remote end refused the connection.
+ *  o -EINPROGRESS: connect request sent but timed out (or non-blocking)
+ *  o -EISCONN: already connected.
+ *  o -ETIMEDOUT: Connection timed out (send timeout)
+ *  o -ENODEV: No link layer to send request
+ *  o -ECONNRESET: Received Shutdown indication or lost link layer
+ *  o -ENOMEM: Out of memory
+ *
+ *  State Strategy:
+ *  o sk_state: holds the CAIF_* protocol state, it's updated by
+ *     caif_ctrl_cb.
+ *  o sock->state: holds the SS_* socket state and is updated by connect and
+ *     disconnect.
+ */
+static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
+                       int addr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       long timeo;
+       int err;
+       lock_sock(sk);
+
+       err = -EAFNOSUPPORT;
+       if (uaddr->sa_family != AF_CAIF)
+               goto out;
+
+       err = -ESOCKTNOSUPPORT;
+       if (unlikely(!(sk->sk_type == SOCK_STREAM &&
+                      cf_sk->sk.sk_protocol == CAIFPROTO_AT) &&
+                      sk->sk_type != SOCK_SEQPACKET))
+               goto out;
+       switch (sock->state) {
+       case SS_UNCONNECTED:
+               /* Normal case, a fresh connect */
+               caif_assert(sk->sk_state == CAIF_DISCONNECTED);
+               break;
+       case SS_CONNECTING:
+               switch (sk->sk_state) {
+               case CAIF_CONNECTED:
+                       sock->state = SS_CONNECTED;
+                       err = -EISCONN;
+                       goto out;
+               case CAIF_DISCONNECTED:
+                       /* Reconnect allowed */
+                       break;
+               case CAIF_CONNECTING:
+                       err = -EALREADY;
+                       if (flags & O_NONBLOCK)
+                               goto out;
+                       goto wait_connect;
+               }
+               break;
+       case SS_CONNECTED:
+               caif_assert(sk->sk_state == CAIF_CONNECTED ||
+                               sk->sk_state == CAIF_DISCONNECTED);
+               if (sk->sk_shutdown & SHUTDOWN_MASK) {
+                       /* Allow re-connect after SHUTDOWN_IND */
+                       caif_disconnect_client(&cf_sk->layer);
+                       break;
+               }
+               /* No reconnect on a seqpacket socket */
+               err = -EISCONN;
+               goto out;
+       case SS_DISCONNECTING:
+       case SS_FREE:
+               caif_assert(1); /*Should never happen */
+               break;
+       }
+       sk->sk_state = CAIF_DISCONNECTED;
+       sock->state = SS_UNCONNECTED;
+       sk_stream_kill_queues(&cf_sk->sk);
+
+       err = -EINVAL;
+       if (addr_len != sizeof(struct sockaddr_caif) ||
+               !uaddr)
+               goto out;
+
+       memcpy(&cf_sk->conn_req.sockaddr, uaddr,
+               sizeof(struct sockaddr_caif));
+
+       /* Move to connecting socket, start sending Connect Requests */
+       sock->state = SS_CONNECTING;
+       sk->sk_state = CAIF_CONNECTING;
+
+       dbfs_atomic_inc(&cnt.num_connect_req);
+       cf_sk->layer.receive = caif_sktrecv_cb;
+       err = caif_connect_client(&cf_sk->conn_req,
+                               &cf_sk->layer);
+       if (err < 0) {
+               cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
+               cf_sk->sk.sk_state = CAIF_DISCONNECTED;
+               goto out;
+       }
+
+       err = -EINPROGRESS;
+wait_connect:
+
+       if (sk->sk_state != CAIF_CONNECTED && (flags & O_NONBLOCK))
+               goto out;
+
+       timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+
+       release_sock(sk);
+       err = wait_event_interruptible_timeout(*sk_sleep(sk),
+                       sk->sk_state != CAIF_CONNECTING,
+                       timeo);
+       lock_sock(sk);
+       if (err < 0)
+               goto out; /* -ERESTARTSYS */
+       if (err == 0 && sk->sk_state != CAIF_CONNECTED) {
+               err = -ETIMEDOUT;
+               goto out;
+       }
+
+       if (sk->sk_state != CAIF_CONNECTED) {
+               sock->state = SS_UNCONNECTED;
+               err = sock_error(sk);
+               if (!err)
+                       err = -ECONNREFUSED;
+               goto out;
+       }
+       sock->state = SS_CONNECTED;
+       err = 0;
+out:
+       release_sock(sk);
+       return err;
+}
+
+
+/*
+ * caif_release() - Disconnect a CAIF Socket
+ * Copied and modified af_irda.c:irda_release().
+ */
+static int caif_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       int res = 0;
+
+       if (!sk)
+               return 0;
+
+       set_tx_flow_off(cf_sk);
+
+       /*
+        * Ensure that packets are not queued after this point in time.
+        * caif_queue_rcv_skb checks SOCK_DEAD holding the queue lock,
+        * this ensures no packets when sock is dead.
+        */
+       spin_lock(&sk->sk_receive_queue.lock);
+       sock_set_flag(sk, SOCK_DEAD);
+       spin_unlock(&sk->sk_receive_queue.lock);
+       sock->sk = NULL;
+
+       dbfs_atomic_inc(&cnt.num_disconnect);
+
+       if (cf_sk->debugfs_socket_dir != NULL)
+               debugfs_remove_recursive(cf_sk->debugfs_socket_dir);
+
+       lock_sock(&(cf_sk->sk));
+       sk->sk_state = CAIF_DISCONNECTED;
+       sk->sk_shutdown = SHUTDOWN_MASK;
+
+       if (cf_sk->sk.sk_socket->state == SS_CONNECTED ||
+               cf_sk->sk.sk_socket->state == SS_CONNECTING)
+               res = caif_disconnect_client(&cf_sk->layer);
+
+       cf_sk->sk.sk_socket->state = SS_DISCONNECTING;
+       wake_up_interruptible_poll(sk_sleep(sk), POLLERR|POLLHUP);
+
+       sock_orphan(sk);
+       cf_sk->layer.dn = NULL;
+       sk_stream_kill_queues(&cf_sk->sk);
+       release_sock(sk);
+       sock_put(sk);
+       return res;
+}
+
+/* Copied from af_unix.c:unix_poll(), added CAIF tx_flow handling */
+static unsigned int caif_poll(struct file *file,
+                               struct socket *sock, poll_table *wait)
+{
+       struct sock *sk = sock->sk;
+       unsigned int mask;
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+
+       sock_poll_wait(file, sk_sleep(sk), wait);
+       mask = 0;
+
+       /* exceptional events? */
+       if (sk->sk_err)
+               mask |= POLLERR;
+       if (sk->sk_shutdown == SHUTDOWN_MASK)
+               mask |= POLLHUP;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLRDHUP;
+
+       /* readable? */
+       if (!skb_queue_empty(&sk->sk_receive_queue) ||
+               (sk->sk_shutdown & RCV_SHUTDOWN))
+               mask |= POLLIN | POLLRDNORM;
+
+       /* Connection-based need to check for termination and startup */
+       if (sk->sk_state == CAIF_DISCONNECTED)
+               mask |= POLLHUP;
+
+       /*
+        * we set writable also when the other side has shut down the
+        * connection. This prevents stuck sockets.
+        */
+       if (sock_writeable(sk) && tx_flow_is_on(cf_sk))
+               mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+
+       return mask;
+}
+
+static const struct proto_ops caif_seqpacket_ops = {
+       .family = PF_CAIF,
+       .owner = THIS_MODULE,
+       .release = caif_release,
+       .bind = sock_no_bind,
+       .connect = caif_connect,
+       .socketpair = sock_no_socketpair,
+       .accept = sock_no_accept,
+       .getname = sock_no_getname,
+       .poll = caif_poll,
+       .ioctl = sock_no_ioctl,
+       .listen = sock_no_listen,
+       .shutdown = sock_no_shutdown,
+       .setsockopt = setsockopt,
+       .getsockopt = sock_no_getsockopt,
+       .sendmsg = caif_seqpkt_sendmsg,
+       .recvmsg = caif_seqpkt_recvmsg,
+       .mmap = sock_no_mmap,
+       .sendpage = sock_no_sendpage,
+};
+
+static const struct proto_ops caif_stream_ops = {
+       .family = PF_CAIF,
+       .owner = THIS_MODULE,
+       .release = caif_release,
+       .bind = sock_no_bind,
+       .connect = caif_connect,
+       .socketpair = sock_no_socketpair,
+       .accept = sock_no_accept,
+       .getname = sock_no_getname,
+       .poll = caif_poll,
+       .ioctl = sock_no_ioctl,
+       .listen = sock_no_listen,
+       .shutdown = sock_no_shutdown,
+       .setsockopt = setsockopt,
+       .getsockopt = sock_no_getsockopt,
+       .sendmsg = caif_stream_sendmsg,
+       .recvmsg = caif_stream_recvmsg,
+       .mmap = sock_no_mmap,
+       .sendpage = sock_no_sendpage,
+};
+
+/* This function is called when a socket is finally destroyed. */
+static void caif_sock_destructor(struct sock *sk)
+{
+       struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
+       caif_assert(!atomic_read(&sk->sk_wmem_alloc));
+       caif_assert(sk_unhashed(sk));
+       caif_assert(!sk->sk_socket);
+       if (!sock_flag(sk, SOCK_DEAD)) {
+               pr_info("Attempt to release alive CAIF socket: %p\n", sk);
+               return;
+       }
+       sk_stream_kill_queues(&cf_sk->sk);
+       dbfs_atomic_dec(&cnt.caif_nr_socks);
+}
+
+static int caif_create(struct net *net, struct socket *sock, int protocol,
+                       int kern)
+{
+       struct sock *sk = NULL;
+       struct caifsock *cf_sk = NULL;
+       static struct proto prot = {.name = "PF_CAIF",
+               .owner = THIS_MODULE,
+               .obj_size = sizeof(struct caifsock),
+       };
+
+       if (!capable(CAP_SYS_ADMIN) && !capable(CAP_NET_ADMIN))
+               return -EPERM;
+       /*
+        * The sock->type specifies the socket type to use.
+        * The CAIF socket is a packet stream in the sense
+        * that it is packet based. CAIF trusts the reliability
+        * of the link, no resending is implemented.
+        */
+       if (sock->type == SOCK_SEQPACKET)
+               sock->ops = &caif_seqpacket_ops;
+       else if (sock->type == SOCK_STREAM)
+               sock->ops = &caif_stream_ops;
+       else
+               return -ESOCKTNOSUPPORT;
+
+       if (protocol < 0 || protocol >= CAIFPROTO_MAX)
+               return -EPROTONOSUPPORT;
+       /*
+        * Set the socket state to unconnected.  The socket state
+        * is really not used at all in the net/core or socket.c but the
+        * initialization makes sure that sock->state is not uninitialized.
+        */
+       sk = sk_alloc(net, PF_CAIF, GFP_KERNEL, &prot);
+       if (!sk)
+               return -ENOMEM;
+
+       cf_sk = container_of(sk, struct caifsock, sk);
+
+       /* Store the protocol */
+       sk->sk_protocol = (unsigned char) protocol;
+
+       /* Sendbuf dictates the amount of outbound packets not yet sent */
+       sk->sk_sndbuf = CAIF_DEF_SNDBUF;
+       sk->sk_rcvbuf = CAIF_DEF_RCVBUF;
+
+       /*
+        * Lock in order to try to stop someone from opening the socket
+        * too early.
+        */
+       lock_sock(&(cf_sk->sk));
+
+       /* Initialize the nozero default sock structure data. */
+       sock_init_data(sock, sk);
+       sk->sk_destruct = caif_sock_destructor;
+
+       mutex_init(&cf_sk->readlock); /* single task reading lock */
+       cf_sk->layer.ctrlcmd = caif_ctrl_cb;
+       cf_sk->sk.sk_socket->state = SS_UNCONNECTED;
+       cf_sk->sk.sk_state = CAIF_DISCONNECTED;
+
+       set_tx_flow_off(cf_sk);
+       set_rx_flow_on(cf_sk);
+
+       /* Set default options on configuration */
+       cf_sk->conn_req.priority = CAIF_PRIO_NORMAL;
+       cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
+       cf_sk->conn_req.protocol = protocol;
+       /* Increase the number of sockets created. */
+       dbfs_atomic_inc(&cnt.caif_nr_socks);
+#ifdef CONFIG_DEBUG_FS
+       if (!IS_ERR(debugfsdir)) {
+               /* Fill in some information concerning the misc socket. */
+               snprintf(cf_sk->name, sizeof(cf_sk->name), "cfsk%d",
+                               atomic_read(&cnt.caif_nr_socks));
+
+               cf_sk->debugfs_socket_dir =
+                       debugfs_create_dir(cf_sk->name, debugfsdir);
+               debugfs_create_u32("sk_state", S_IRUSR | S_IWUSR,
+                               cf_sk->debugfs_socket_dir,
+                               (u32 *) &cf_sk->sk.sk_state);
+               debugfs_create_u32("flow_state", S_IRUSR | S_IWUSR,
+                               cf_sk->debugfs_socket_dir, &cf_sk->flow_state);
+               debugfs_create_u32("sk_rmem_alloc", S_IRUSR | S_IWUSR,
+                               cf_sk->debugfs_socket_dir,
+                               (u32 *) &cf_sk->sk.sk_rmem_alloc);
+               debugfs_create_u32("sk_wmem_alloc", S_IRUSR | S_IWUSR,
+                               cf_sk->debugfs_socket_dir,
+                               (u32 *) &cf_sk->sk.sk_wmem_alloc);
+               debugfs_create_u32("identity", S_IRUSR | S_IWUSR,
+                               cf_sk->debugfs_socket_dir,
+                               (u32 *) &cf_sk->layer.id);
+       }
+#endif
+       release_sock(&cf_sk->sk);
+       return 0;
+}
+
+
+static struct net_proto_family caif_family_ops = {
+       .family = PF_CAIF,
+       .create = caif_create,
+       .owner = THIS_MODULE,
+};
+
+int af_caif_init(void)
+{
+       int err = sock_register(&caif_family_ops);
+       if (!err)
+               return err;
+       return 0;
+}
+
+static int __init caif_sktinit_module(void)
+{
+#ifdef CONFIG_DEBUG_FS
+       debugfsdir = debugfs_create_dir("caif_sk", NULL);
+       if (!IS_ERR(debugfsdir)) {
+               debugfs_create_u32("num_sockets", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.caif_nr_socks);
+               debugfs_create_u32("num_connect_req", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_connect_req);
+               debugfs_create_u32("num_connect_resp", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_connect_resp);
+               debugfs_create_u32("num_connect_fail_resp", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_connect_fail_resp);
+               debugfs_create_u32("num_disconnect", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_disconnect);
+               debugfs_create_u32("num_remote_shutdown_ind",
+                               S_IRUSR | S_IWUSR, debugfsdir,
+                               (u32 *) &cnt.num_remote_shutdown_ind);
+               debugfs_create_u32("num_tx_flow_off_ind", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_tx_flow_off_ind);
+               debugfs_create_u32("num_tx_flow_on_ind", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_tx_flow_on_ind);
+               debugfs_create_u32("num_rx_flow_off", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_rx_flow_off);
+               debugfs_create_u32("num_rx_flow_on", S_IRUSR | S_IWUSR,
+                               debugfsdir,
+                               (u32 *) &cnt.num_rx_flow_on);
+       }
+#endif
+       return af_caif_init();
+}
+
+static void __exit caif_sktexit_module(void)
+{
+       sock_unregister(PF_CAIF);
+       if (debugfsdir != NULL)
+               debugfs_remove_recursive(debugfsdir);
+}
+module_init(caif_sktinit_module);
+module_exit(caif_sktexit_module);
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
new file mode 100644 (file)
index 0000000..df43f26
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/cfcnfg.h>
+#include <net/caif/cfctrl.h>
+#include <net/caif/cfmuxl.h>
+#include <net/caif/cffrml.h>
+#include <net/caif/cfserl.h>
+#include <net/caif/cfsrvl.h>
+
+#include <linux/module.h>
+#include <asm/atomic.h>
+
+#define MAX_PHY_LAYERS 7
+#define PHY_NAME_LEN 20
+
+#define container_obj(layr) container_of(layr, struct cfcnfg, layer)
+
+/* Information about CAIF physical interfaces held by Config Module in order
+ * to manage physical interfaces
+ */
+struct cfcnfg_phyinfo {
+       /* Pointer to the layer below the MUX (framing layer) */
+       struct cflayer *frm_layer;
+       /* Pointer to the lowest actual physical layer */
+       struct cflayer *phy_layer;
+       /* Unique identifier of the physical interface */
+       unsigned int id;
+       /* Preference of the physical in interface */
+       enum cfcnfg_phy_preference pref;
+
+       /* Reference count, number of channels using the device */
+       int phy_ref_count;
+
+       /* Information about the physical device */
+       struct dev_info dev_info;
+};
+
+struct cfcnfg {
+       struct cflayer layer;
+       struct cflayer *ctrl;
+       struct cflayer *mux;
+       u8 last_phyid;
+       struct cfcnfg_phyinfo phy_layers[MAX_PHY_LAYERS];
+};
+
+static void cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id,
+                            enum cfctrl_srv serv, u8 phyid,
+                            struct cflayer *adapt_layer);
+static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id);
+static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
+                            struct cflayer *adapt_layer);
+static void cfctrl_resp_func(void);
+static void cfctrl_enum_resp(void);
+
+struct cfcnfg *cfcnfg_create(void)
+{
+       struct cfcnfg *this;
+       struct cfctrl_rsp *resp;
+       /* Initiate this layer */
+       this = kzalloc(sizeof(struct cfcnfg), GFP_ATOMIC);
+       if (!this) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       this->mux = cfmuxl_create();
+       if (!this->mux)
+               goto out_of_mem;
+       this->ctrl = cfctrl_create();
+       if (!this->ctrl)
+               goto out_of_mem;
+       /* Initiate response functions */
+       resp = cfctrl_get_respfuncs(this->ctrl);
+       resp->enum_rsp = cfctrl_enum_resp;
+       resp->linkerror_ind = cfctrl_resp_func;
+       resp->linkdestroy_rsp = cfcnfg_linkdestroy_rsp;
+       resp->sleep_rsp = cfctrl_resp_func;
+       resp->wake_rsp = cfctrl_resp_func;
+       resp->restart_rsp = cfctrl_resp_func;
+       resp->radioset_rsp = cfctrl_resp_func;
+       resp->linksetup_rsp = cfcnfg_linkup_rsp;
+       resp->reject_rsp = cfcnfg_reject_rsp;
+
+       this->last_phyid = 1;
+
+       cfmuxl_set_uplayer(this->mux, this->ctrl, 0);
+       layer_set_dn(this->ctrl, this->mux);
+       layer_set_up(this->ctrl, this);
+       return this;
+out_of_mem:
+       pr_warning("CAIF: %s(): Out of memory\n", __func__);
+       kfree(this->mux);
+       kfree(this->ctrl);
+       kfree(this);
+       return NULL;
+}
+EXPORT_SYMBOL(cfcnfg_create);
+
+void cfcnfg_remove(struct cfcnfg *cfg)
+{
+       if (cfg) {
+               kfree(cfg->mux);
+               kfree(cfg->ctrl);
+               kfree(cfg);
+       }
+}
+
+static void cfctrl_resp_func(void)
+{
+}
+
+static void cfctrl_enum_resp(void)
+{
+}
+
+struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
+                                 enum cfcnfg_phy_preference phy_pref)
+{
+       u16 i;
+
+       /* Try to match with specified preference */
+       for (i = 1; i < MAX_PHY_LAYERS; i++) {
+               if (cnfg->phy_layers[i].id == i &&
+                    cnfg->phy_layers[i].pref == phy_pref &&
+                    cnfg->phy_layers[i].frm_layer != NULL) {
+                       caif_assert(cnfg->phy_layers != NULL);
+                       caif_assert(cnfg->phy_layers[i].id == i);
+                       return &cnfg->phy_layers[i].dev_info;
+               }
+       }
+       /* Otherwise just return something */
+       for (i = 1; i < MAX_PHY_LAYERS; i++) {
+               if (cnfg->phy_layers[i].id == i) {
+                       caif_assert(cnfg->phy_layers != NULL);
+                       caif_assert(cnfg->phy_layers[i].id == i);
+                       return &cnfg->phy_layers[i].dev_info;
+               }
+       }
+
+       return NULL;
+}
+
+static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
+                                                       u8 phyid)
+{
+       int i;
+       /* Try to match with specified preference */
+       for (i = 0; i < MAX_PHY_LAYERS; i++)
+               if (cnfg->phy_layers[i].frm_layer != NULL &&
+                   cnfg->phy_layers[i].id == phyid)
+                       return &cnfg->phy_layers[i];
+       return NULL;
+}
+
+int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
+{
+       int i;
+
+       /* Try to match with specified name */
+       for (i = 0; i < MAX_PHY_LAYERS; i++) {
+               if (cnfg->phy_layers[i].frm_layer != NULL
+                   && strcmp(cnfg->phy_layers[i].phy_layer->name,
+                             name) == 0)
+                       return cnfg->phy_layers[i].frm_layer->id;
+       }
+       return 0;
+}
+
+int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
+{
+       u8 channel_id = 0;
+       int ret = 0;
+       struct cflayer *servl = NULL;
+       struct cfcnfg_phyinfo *phyinfo = NULL;
+       u8 phyid = 0;
+       caif_assert(adap_layer != NULL);
+       channel_id = adap_layer->id;
+       if (adap_layer->dn == NULL || channel_id == 0) {
+               pr_err("CAIF: %s():adap_layer->id is 0\n", __func__);
+               ret = -ENOTCONN;
+               goto end;
+       }
+       servl = cfmuxl_remove_uplayer(cnfg->mux, channel_id);
+       if (servl == NULL)
+               goto end;
+       layer_set_up(servl, NULL);
+       ret = cfctrl_linkdown_req(cnfg->ctrl, channel_id, adap_layer);
+       if (servl == NULL) {
+               pr_err("CAIF: %s(): PROTOCOL ERROR "
+                      "- Error removing service_layer Channel_Id(%d)",
+                       __func__, channel_id);
+               ret = -EINVAL;
+               goto end;
+       }
+       caif_assert(channel_id == servl->id);
+       if (adap_layer->dn != NULL) {
+               phyid = cfsrvl_getphyid(adap_layer->dn);
+
+               phyinfo = cfcnfg_get_phyinfo(cnfg, phyid);
+               if (phyinfo == NULL) {
+                       pr_warning("CAIF: %s(): "
+                               "No interface to send disconnect to\n",
+                               __func__);
+                       ret = -ENODEV;
+                       goto end;
+               }
+               if (phyinfo->id != phyid ||
+                       phyinfo->phy_layer->id != phyid ||
+                       phyinfo->frm_layer->id != phyid) {
+                       pr_err("CAIF: %s(): "
+                               "Inconsistency in phy registration\n",
+                               __func__);
+                       ret = -EINVAL;
+                       goto end;
+               }
+       }
+       if (phyinfo != NULL && --phyinfo->phy_ref_count == 0 &&
+               phyinfo->phy_layer != NULL &&
+               phyinfo->phy_layer->modemcmd != NULL) {
+               phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
+                                            _CAIF_MODEMCMD_PHYIF_USELESS);
+       }
+end:
+       cfsrvl_put(servl);
+       cfctrl_cancel_req(cnfg->ctrl, adap_layer);
+       if (adap_layer->ctrlcmd != NULL)
+               adap_layer->ctrlcmd(adap_layer, CAIF_CTRLCMD_DEINIT_RSP, 0);
+       return ret;
+
+}
+EXPORT_SYMBOL(cfcnfg_disconn_adapt_layer);
+
+void cfcnfg_release_adap_layer(struct cflayer *adap_layer)
+{
+       if (adap_layer->dn)
+               cfsrvl_put(adap_layer->dn);
+}
+EXPORT_SYMBOL(cfcnfg_release_adap_layer);
+
+static void cfcnfg_linkdestroy_rsp(struct cflayer *layer, u8 channel_id)
+{
+}
+
+int cfcnfg_add_adaptation_layer(struct cfcnfg *cnfg,
+                               struct cfctrl_link_param *param,
+                               struct cflayer *adap_layer)
+{
+       struct cflayer *frml;
+       if (adap_layer == NULL) {
+               pr_err("CAIF: %s(): adap_layer is zero", __func__);
+               return -EINVAL;
+       }
+       if (adap_layer->receive == NULL) {
+               pr_err("CAIF: %s(): adap_layer->receive is NULL", __func__);
+               return -EINVAL;
+       }
+       if (adap_layer->ctrlcmd == NULL) {
+               pr_err("CAIF: %s(): adap_layer->ctrlcmd == NULL", __func__);
+               return -EINVAL;
+       }
+       frml = cnfg->phy_layers[param->phyid].frm_layer;
+       if (frml == NULL) {
+               pr_err("CAIF: %s(): Specified PHY type does not exist!",
+                       __func__);
+               return -ENODEV;
+       }
+       caif_assert(param->phyid == cnfg->phy_layers[param->phyid].id);
+       caif_assert(cnfg->phy_layers[param->phyid].frm_layer->id ==
+                    param->phyid);
+       caif_assert(cnfg->phy_layers[param->phyid].phy_layer->id ==
+                    param->phyid);
+       /* FIXME: ENUMERATE INITIALLY WHEN ACTIVATING PHYSICAL INTERFACE */
+       cfctrl_enum_req(cnfg->ctrl, param->phyid);
+       return cfctrl_linkup_request(cnfg->ctrl, param, adap_layer);
+}
+EXPORT_SYMBOL(cfcnfg_add_adaptation_layer);
+
+static void cfcnfg_reject_rsp(struct cflayer *layer, u8 channel_id,
+                            struct cflayer *adapt_layer)
+{
+       if (adapt_layer != NULL && adapt_layer->ctrlcmd != NULL)
+               adapt_layer->ctrlcmd(adapt_layer,
+                                    CAIF_CTRLCMD_INIT_FAIL_RSP, 0);
+}
+
+static void
+cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
+                u8 phyid, struct cflayer *adapt_layer)
+{
+       struct cfcnfg *cnfg = container_obj(layer);
+       struct cflayer *servicel = NULL;
+       struct cfcnfg_phyinfo *phyinfo;
+       if (adapt_layer == NULL) {
+               pr_debug("CAIF: %s(): link setup response "
+                               "but no client exist, send linkdown back\n",
+                               __func__);
+               cfctrl_linkdown_req(cnfg->ctrl, channel_id, NULL);
+               return;
+       }
+
+       caif_assert(cnfg != NULL);
+       caif_assert(phyid != 0);
+       phyinfo = &cnfg->phy_layers[phyid];
+       caif_assert(phyinfo != NULL);
+       caif_assert(phyinfo->id == phyid);
+       caif_assert(phyinfo->phy_layer != NULL);
+       caif_assert(phyinfo->phy_layer->id == phyid);
+
+       if (phyinfo != NULL &&
+           phyinfo->phy_ref_count++ == 0 &&
+           phyinfo->phy_layer != NULL &&
+           phyinfo->phy_layer->modemcmd != NULL) {
+               caif_assert(phyinfo->phy_layer->id == phyid);
+               phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
+                                            _CAIF_MODEMCMD_PHYIF_USEFULL);
+
+       }
+       adapt_layer->id = channel_id;
+
+       switch (serv) {
+       case CFCTRL_SRV_VEI:
+               servicel = cfvei_create(channel_id, &phyinfo->dev_info);
+               break;
+       case CFCTRL_SRV_DATAGRAM:
+               servicel = cfdgml_create(channel_id, &phyinfo->dev_info);
+               break;
+       case CFCTRL_SRV_RFM:
+               servicel = cfrfml_create(channel_id, &phyinfo->dev_info);
+               break;
+       case CFCTRL_SRV_UTIL:
+               servicel = cfutill_create(channel_id, &phyinfo->dev_info);
+               break;
+       case CFCTRL_SRV_VIDEO:
+               servicel = cfvidl_create(channel_id, &phyinfo->dev_info);
+               break;
+       case CFCTRL_SRV_DBG:
+               servicel = cfdbgl_create(channel_id, &phyinfo->dev_info);
+               break;
+       default:
+               pr_err("CAIF: %s(): Protocol error. "
+                       "Link setup response - unknown channel type\n",
+                       __func__);
+               return;
+       }
+       if (!servicel) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return;
+       }
+       layer_set_dn(servicel, cnfg->mux);
+       cfmuxl_set_uplayer(cnfg->mux, servicel, channel_id);
+       layer_set_up(servicel, adapt_layer);
+       layer_set_dn(adapt_layer, servicel);
+       cfsrvl_get(servicel);
+       servicel->ctrlcmd(servicel, CAIF_CTRLCMD_INIT_RSP, 0);
+}
+
+void
+cfcnfg_add_phy_layer(struct cfcnfg *cnfg, enum cfcnfg_phy_type phy_type,
+                    void *dev, struct cflayer *phy_layer, u16 *phyid,
+                    enum cfcnfg_phy_preference pref,
+                    bool fcs, bool stx)
+{
+       struct cflayer *frml;
+       struct cflayer *phy_driver = NULL;
+       int i;
+
+
+       if (cnfg->phy_layers[cnfg->last_phyid].frm_layer == NULL) {
+               *phyid = cnfg->last_phyid;
+
+               /* range: * 1..(MAX_PHY_LAYERS-1) */
+               cnfg->last_phyid =
+                   (cnfg->last_phyid % (MAX_PHY_LAYERS - 1)) + 1;
+       } else {
+               *phyid = 0;
+               for (i = 1; i < MAX_PHY_LAYERS; i++) {
+                       if (cnfg->phy_layers[i].frm_layer == NULL) {
+                               *phyid = i;
+                               break;
+                       }
+               }
+       }
+       if (*phyid == 0) {
+               pr_err("CAIF: %s(): No Available PHY ID\n", __func__);
+               return;
+       }
+
+       switch (phy_type) {
+       case CFPHYTYPE_FRAG:
+               phy_driver =
+                   cfserl_create(CFPHYTYPE_FRAG, *phyid, stx);
+               if (!phy_driver) {
+                       pr_warning("CAIF: %s(): Out of memory\n", __func__);
+                       return;
+               }
+
+               break;
+       case CFPHYTYPE_CAIF:
+               phy_driver = NULL;
+               break;
+       default:
+               pr_err("CAIF: %s(): %d", __func__, phy_type);
+               return;
+               break;
+       }
+
+       phy_layer->id = *phyid;
+       cnfg->phy_layers[*phyid].pref = pref;
+       cnfg->phy_layers[*phyid].id = *phyid;
+       cnfg->phy_layers[*phyid].dev_info.id = *phyid;
+       cnfg->phy_layers[*phyid].dev_info.dev = dev;
+       cnfg->phy_layers[*phyid].phy_layer = phy_layer;
+       cnfg->phy_layers[*phyid].phy_ref_count = 0;
+       phy_layer->type = phy_type;
+       frml = cffrml_create(*phyid, fcs);
+       if (!frml) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return;
+       }
+       cnfg->phy_layers[*phyid].frm_layer = frml;
+       cfmuxl_set_dnlayer(cnfg->mux, frml, *phyid);
+       layer_set_up(frml, cnfg->mux);
+
+       if (phy_driver != NULL) {
+               phy_driver->id = *phyid;
+               layer_set_dn(frml, phy_driver);
+               layer_set_up(phy_driver, frml);
+               layer_set_dn(phy_driver, phy_layer);
+               layer_set_up(phy_layer, phy_driver);
+       } else {
+               layer_set_dn(frml, phy_layer);
+               layer_set_up(phy_layer, frml);
+       }
+}
+EXPORT_SYMBOL(cfcnfg_add_phy_layer);
+
+int cfcnfg_del_phy_layer(struct cfcnfg *cnfg, struct cflayer *phy_layer)
+{
+       struct cflayer *frml, *frml_dn;
+       u16 phyid;
+       phyid = phy_layer->id;
+       caif_assert(phyid == cnfg->phy_layers[phyid].id);
+       caif_assert(phy_layer == cnfg->phy_layers[phyid].phy_layer);
+       caif_assert(phy_layer->id == phyid);
+       caif_assert(cnfg->phy_layers[phyid].frm_layer->id == phyid);
+
+       memset(&cnfg->phy_layers[phy_layer->id], 0,
+              sizeof(struct cfcnfg_phyinfo));
+       frml = cfmuxl_remove_dnlayer(cnfg->mux, phy_layer->id);
+       frml_dn = frml->dn;
+       cffrml_set_uplayer(frml, NULL);
+       cffrml_set_dnlayer(frml, NULL);
+       kfree(frml);
+
+       if (phy_layer != frml_dn) {
+               layer_set_up(frml_dn, NULL);
+               layer_set_dn(frml_dn, NULL);
+               kfree(frml_dn);
+       }
+       layer_set_up(phy_layer, NULL);
+       return 0;
+}
+EXPORT_SYMBOL(cfcnfg_del_phy_layer);
diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c
new file mode 100644 (file)
index 0000000..0ffe1e1
--- /dev/null
@@ -0,0 +1,692 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/cfctrl.h>
+
+#define container_obj(layr) container_of(layr, struct cfctrl, serv.layer)
+#define UTILITY_NAME_LENGTH 16
+#define CFPKT_CTRL_PKT_LEN 20
+
+
+#ifdef CAIF_NO_LOOP
+static int handle_loop(struct cfctrl *ctrl,
+                             int cmd, struct cfpkt *pkt){
+       return CAIF_FAILURE;
+}
+#else
+static int handle_loop(struct cfctrl *ctrl,
+               int cmd, struct cfpkt *pkt);
+#endif
+static int cfctrl_recv(struct cflayer *layr, struct cfpkt *pkt);
+static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                          int phyid);
+
+
+struct cflayer *cfctrl_create(void)
+{
+       struct dev_info dev_info;
+       struct cfctrl *this =
+               kmalloc(sizeof(struct cfctrl), GFP_ATOMIC);
+       if (!this) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
+       memset(&dev_info, 0, sizeof(dev_info));
+       dev_info.id = 0xff;
+       memset(this, 0, sizeof(*this));
+       cfsrvl_init(&this->serv, 0, &dev_info);
+       spin_lock_init(&this->info_list_lock);
+       atomic_set(&this->req_seq_no, 1);
+       atomic_set(&this->rsp_seq_no, 1);
+       this->serv.layer.receive = cfctrl_recv;
+       sprintf(this->serv.layer.name, "ctrl");
+       this->serv.layer.ctrlcmd = cfctrl_ctrlcmd;
+       spin_lock_init(&this->loop_linkid_lock);
+       this->loop_linkid = 1;
+       return &this->serv.layer;
+}
+
+static bool param_eq(struct cfctrl_link_param *p1, struct cfctrl_link_param *p2)
+{
+       bool eq =
+           p1->linktype == p2->linktype &&
+           p1->priority == p2->priority &&
+           p1->phyid == p2->phyid &&
+           p1->endpoint == p2->endpoint && p1->chtype == p2->chtype;
+
+       if (!eq)
+               return false;
+
+       switch (p1->linktype) {
+       case CFCTRL_SRV_VEI:
+               return true;
+       case CFCTRL_SRV_DATAGRAM:
+               return p1->u.datagram.connid == p2->u.datagram.connid;
+       case CFCTRL_SRV_RFM:
+               return
+                   p1->u.rfm.connid == p2->u.rfm.connid &&
+                   strcmp(p1->u.rfm.volume, p2->u.rfm.volume) == 0;
+       case CFCTRL_SRV_UTIL:
+               return
+                   p1->u.utility.fifosize_kb == p2->u.utility.fifosize_kb
+                   && p1->u.utility.fifosize_bufs ==
+                   p2->u.utility.fifosize_bufs
+                   && strcmp(p1->u.utility.name, p2->u.utility.name) == 0
+                   && p1->u.utility.paramlen == p2->u.utility.paramlen
+                   && memcmp(p1->u.utility.params, p2->u.utility.params,
+                             p1->u.utility.paramlen) == 0;
+
+       case CFCTRL_SRV_VIDEO:
+               return p1->u.video.connid == p2->u.video.connid;
+       case CFCTRL_SRV_DBG:
+               return true;
+       case CFCTRL_SRV_DECM:
+               return false;
+       default:
+               return false;
+       }
+       return false;
+}
+
+bool cfctrl_req_eq(struct cfctrl_request_info *r1,
+                  struct cfctrl_request_info *r2)
+{
+       if (r1->cmd != r2->cmd)
+               return false;
+       if (r1->cmd == CFCTRL_CMD_LINK_SETUP)
+               return param_eq(&r1->param, &r2->param);
+       else
+               return r1->channel_id == r2->channel_id;
+}
+
+/* Insert request at the end */
+void cfctrl_insert_req(struct cfctrl *ctrl,
+                             struct cfctrl_request_info *req)
+{
+       struct cfctrl_request_info *p;
+       spin_lock(&ctrl->info_list_lock);
+       req->next = NULL;
+       atomic_inc(&ctrl->req_seq_no);
+       req->sequence_no = atomic_read(&ctrl->req_seq_no);
+       if (ctrl->first_req == NULL) {
+               ctrl->first_req = req;
+               spin_unlock(&ctrl->info_list_lock);
+               return;
+       }
+       p = ctrl->first_req;
+       while (p->next != NULL)
+               p = p->next;
+       p->next = req;
+       spin_unlock(&ctrl->info_list_lock);
+}
+
+/* Compare and remove request */
+struct cfctrl_request_info *cfctrl_remove_req(struct cfctrl *ctrl,
+                                             struct cfctrl_request_info *req)
+{
+       struct cfctrl_request_info *p;
+       struct cfctrl_request_info *ret;
+
+       spin_lock(&ctrl->info_list_lock);
+       if (ctrl->first_req == NULL) {
+               spin_unlock(&ctrl->info_list_lock);
+               return NULL;
+       }
+
+       if (cfctrl_req_eq(req, ctrl->first_req)) {
+               ret = ctrl->first_req;
+               caif_assert(ctrl->first_req);
+               atomic_set(&ctrl->rsp_seq_no,
+                                ctrl->first_req->sequence_no);
+               ctrl->first_req = ctrl->first_req->next;
+               spin_unlock(&ctrl->info_list_lock);
+               return ret;
+       }
+
+       p = ctrl->first_req;
+
+       while (p->next != NULL) {
+               if (cfctrl_req_eq(req, p->next)) {
+                       pr_warning("CAIF: %s(): Requests are not "
+                                       "received in order\n",
+                                       __func__);
+                       ret = p->next;
+                       atomic_set(&ctrl->rsp_seq_no,
+                                       p->next->sequence_no);
+                       p->next = p->next->next;
+                       spin_unlock(&ctrl->info_list_lock);
+                       return ret;
+               }
+               p = p->next;
+       }
+       spin_unlock(&ctrl->info_list_lock);
+
+       pr_warning("CAIF: %s(): Request does not match\n",
+                  __func__);
+       return NULL;
+}
+
+struct cfctrl_rsp *cfctrl_get_respfuncs(struct cflayer *layer)
+{
+       struct cfctrl *this = container_obj(layer);
+       return &this->res;
+}
+
+void cfctrl_set_dnlayer(struct cflayer *this, struct cflayer *dn)
+{
+       this->dn = dn;
+}
+
+void cfctrl_set_uplayer(struct cflayer *this, struct cflayer *up)
+{
+       this->up = up;
+}
+
+static void init_info(struct caif_payload_info *info, struct cfctrl *cfctrl)
+{
+       info->hdr_len = 0;
+       info->channel_id = cfctrl->serv.layer.id;
+       info->dev_info = &cfctrl->serv.dev_info;
+}
+
+void cfctrl_enum_req(struct cflayer *layer, u8 physlinkid)
+{
+       struct cfctrl *cfctrl = container_obj(layer);
+       int ret;
+       struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+       if (!pkt) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return;
+       }
+       caif_assert(offsetof(struct cfctrl, serv.layer) == 0);
+       init_info(cfpkt_info(pkt), cfctrl);
+       cfpkt_info(pkt)->dev_info->id = physlinkid;
+       cfctrl->serv.dev_info.id = physlinkid;
+       cfpkt_addbdy(pkt, CFCTRL_CMD_ENUM);
+       cfpkt_addbdy(pkt, physlinkid);
+       ret =
+           cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
+       if (ret < 0) {
+               pr_err("CAIF: %s(): Could not transmit enum message\n",
+                       __func__);
+               cfpkt_destroy(pkt);
+       }
+}
+
+int cfctrl_linkup_request(struct cflayer *layer,
+                          struct cfctrl_link_param *param,
+                          struct cflayer *user_layer)
+{
+       struct cfctrl *cfctrl = container_obj(layer);
+       u32 tmp32;
+       u16 tmp16;
+       u8 tmp8;
+       struct cfctrl_request_info *req;
+       int ret;
+       char utility_name[16];
+       struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+       if (!pkt) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return -ENOMEM;
+       }
+       cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_SETUP);
+       cfpkt_addbdy(pkt, (param->chtype << 4) + param->linktype);
+       cfpkt_addbdy(pkt, (param->priority << 3) + param->phyid);
+       cfpkt_addbdy(pkt, param->endpoint & 0x03);
+
+       switch (param->linktype) {
+       case CFCTRL_SRV_VEI:
+               break;
+       case CFCTRL_SRV_VIDEO:
+               cfpkt_addbdy(pkt, (u8) param->u.video.connid);
+               break;
+       case CFCTRL_SRV_DBG:
+               break;
+       case CFCTRL_SRV_DATAGRAM:
+               tmp32 = cpu_to_le32(param->u.datagram.connid);
+               cfpkt_add_body(pkt, &tmp32, 4);
+               break;
+       case CFCTRL_SRV_RFM:
+               /* Construct a frame, convert DatagramConnectionID to network
+                * format long and copy it out...
+                */
+               tmp32 = cpu_to_le32(param->u.rfm.connid);
+               cfpkt_add_body(pkt, &tmp32, 4);
+               /* Add volume name, including zero termination... */
+               cfpkt_add_body(pkt, param->u.rfm.volume,
+                              strlen(param->u.rfm.volume) + 1);
+               break;
+       case CFCTRL_SRV_UTIL:
+               tmp16 = cpu_to_le16(param->u.utility.fifosize_kb);
+               cfpkt_add_body(pkt, &tmp16, 2);
+               tmp16 = cpu_to_le16(param->u.utility.fifosize_bufs);
+               cfpkt_add_body(pkt, &tmp16, 2);
+               memset(utility_name, 0, sizeof(utility_name));
+               strncpy(utility_name, param->u.utility.name,
+                       UTILITY_NAME_LENGTH - 1);
+               cfpkt_add_body(pkt, utility_name, UTILITY_NAME_LENGTH);
+               tmp8 = param->u.utility.paramlen;
+               cfpkt_add_body(pkt, &tmp8, 1);
+               cfpkt_add_body(pkt, param->u.utility.params,
+                              param->u.utility.paramlen);
+               break;
+       default:
+               pr_warning("CAIF: %s():Request setup of bad link type = %d\n",
+                          __func__, param->linktype);
+               return -EINVAL;
+       }
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return -ENOMEM;
+       }
+       req->client_layer = user_layer;
+       req->cmd = CFCTRL_CMD_LINK_SETUP;
+       req->param = *param;
+       cfctrl_insert_req(cfctrl, req);
+       init_info(cfpkt_info(pkt), cfctrl);
+       /*
+        * NOTE:Always send linkup and linkdown request on the same
+        *      device as the payload. Otherwise old queued up payload
+        *      might arrive with the newly allocated channel ID.
+        */
+       cfpkt_info(pkt)->dev_info->id = param->phyid;
+       ret =
+           cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
+       if (ret < 0) {
+               pr_err("CAIF: %s(): Could not transmit linksetup request\n",
+                       __func__);
+               cfpkt_destroy(pkt);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+int cfctrl_linkdown_req(struct cflayer *layer, u8 channelid,
+                               struct cflayer *client)
+{
+       int ret;
+       struct cfctrl *cfctrl = container_obj(layer);
+       struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+       if (!pkt) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return -ENOMEM;
+       }
+       cfpkt_addbdy(pkt, CFCTRL_CMD_LINK_DESTROY);
+       cfpkt_addbdy(pkt, channelid);
+       init_info(cfpkt_info(pkt), cfctrl);
+       ret =
+           cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
+       if (ret < 0) {
+               pr_err("CAIF: %s(): Could not transmit link-down request\n",
+                       __func__);
+               cfpkt_destroy(pkt);
+       }
+       return ret;
+}
+
+void cfctrl_sleep_req(struct cflayer *layer)
+{
+       int ret;
+       struct cfctrl *cfctrl = container_obj(layer);
+       struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+       if (!pkt) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return;
+       }
+       cfpkt_addbdy(pkt, CFCTRL_CMD_SLEEP);
+       init_info(cfpkt_info(pkt), cfctrl);
+       ret =
+           cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
+       if (ret < 0)
+               cfpkt_destroy(pkt);
+}
+
+void cfctrl_wake_req(struct cflayer *layer)
+{
+       int ret;
+       struct cfctrl *cfctrl = container_obj(layer);
+       struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+       if (!pkt) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return;
+       }
+       cfpkt_addbdy(pkt, CFCTRL_CMD_WAKE);
+       init_info(cfpkt_info(pkt), cfctrl);
+       ret =
+           cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
+       if (ret < 0)
+               cfpkt_destroy(pkt);
+}
+
+void cfctrl_getstartreason_req(struct cflayer *layer)
+{
+       int ret;
+       struct cfctrl *cfctrl = container_obj(layer);
+       struct cfpkt *pkt = cfpkt_create(CFPKT_CTRL_PKT_LEN);
+       if (!pkt) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return;
+       }
+       cfpkt_addbdy(pkt, CFCTRL_CMD_START_REASON);
+       init_info(cfpkt_info(pkt), cfctrl);
+       ret =
+           cfctrl->serv.layer.dn->transmit(cfctrl->serv.layer.dn, pkt);
+       if (ret < 0)
+               cfpkt_destroy(pkt);
+}
+
+
+void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
+{
+       struct cfctrl_request_info *p, *req;
+       struct cfctrl *ctrl = container_obj(layr);
+       spin_lock(&ctrl->info_list_lock);
+
+       if (ctrl->first_req == NULL) {
+               spin_unlock(&ctrl->info_list_lock);
+               return;
+       }
+
+       if (ctrl->first_req->client_layer == adap_layer) {
+
+               req = ctrl->first_req;
+               ctrl->first_req = ctrl->first_req->next;
+               kfree(req);
+       }
+
+       p = ctrl->first_req;
+       while (p != NULL && p->next != NULL) {
+               if (p->next->client_layer == adap_layer) {
+
+                       req = p->next;
+                       p->next = p->next->next;
+                       kfree(p->next);
+               }
+               p = p->next;
+       }
+
+       spin_unlock(&ctrl->info_list_lock);
+}
+
+static int cfctrl_recv(struct cflayer *layer, struct cfpkt *pkt)
+{
+       u8 cmdrsp;
+       u8 cmd;
+       int ret = -1;
+       u16 tmp16;
+       u8 len;
+       u8 param[255];
+       u8 linkid;
+       struct cfctrl *cfctrl = container_obj(layer);
+       struct cfctrl_request_info rsp, *req;
+
+
+       cfpkt_extr_head(pkt, &cmdrsp, 1);
+       cmd = cmdrsp & CFCTRL_CMD_MASK;
+       if (cmd != CFCTRL_CMD_LINK_ERR
+           && CFCTRL_RSP_BIT != (CFCTRL_RSP_BIT & cmdrsp)) {
+               if (handle_loop(cfctrl, cmd, pkt) == CAIF_FAILURE)
+                       cmdrsp |= CFCTRL_ERR_BIT;
+       }
+
+       switch (cmd) {
+       case CFCTRL_CMD_LINK_SETUP:
+               {
+                       enum cfctrl_srv serv;
+                       enum cfctrl_srv servtype;
+                       u8 endpoint;
+                       u8 physlinkid;
+                       u8 prio;
+                       u8 tmp;
+                       u32 tmp32;
+                       u8 *cp;
+                       int i;
+                       struct cfctrl_link_param linkparam;
+                       memset(&linkparam, 0, sizeof(linkparam));
+
+                       cfpkt_extr_head(pkt, &tmp, 1);
+
+                       serv = tmp & CFCTRL_SRV_MASK;
+                       linkparam.linktype = serv;
+
+                       servtype = tmp >> 4;
+                       linkparam.chtype = servtype;
+
+                       cfpkt_extr_head(pkt, &tmp, 1);
+                       physlinkid = tmp & 0x07;
+                       prio = tmp >> 3;
+
+                       linkparam.priority = prio;
+                       linkparam.phyid = physlinkid;
+                       cfpkt_extr_head(pkt, &endpoint, 1);
+                       linkparam.endpoint = endpoint & 0x03;
+
+                       switch (serv) {
+                       case CFCTRL_SRV_VEI:
+                       case CFCTRL_SRV_DBG:
+                               if (CFCTRL_ERR_BIT & cmdrsp)
+                                       break;
+                               /* Link ID */
+                               cfpkt_extr_head(pkt, &linkid, 1);
+                               break;
+                       case CFCTRL_SRV_VIDEO:
+                               cfpkt_extr_head(pkt, &tmp, 1);
+                               linkparam.u.video.connid = tmp;
+                               if (CFCTRL_ERR_BIT & cmdrsp)
+                                       break;
+                               /* Link ID */
+                               cfpkt_extr_head(pkt, &linkid, 1);
+                               break;
+
+                       case CFCTRL_SRV_DATAGRAM:
+                               cfpkt_extr_head(pkt, &tmp32, 4);
+                               linkparam.u.datagram.connid =
+                                   le32_to_cpu(tmp32);
+                               if (CFCTRL_ERR_BIT & cmdrsp)
+                                       break;
+                               /* Link ID */
+                               cfpkt_extr_head(pkt, &linkid, 1);
+                               break;
+                       case CFCTRL_SRV_RFM:
+                               /* Construct a frame, convert
+                                * DatagramConnectionID
+                                * to network format long and copy it out...
+                                */
+                               cfpkt_extr_head(pkt, &tmp32, 4);
+                               linkparam.u.rfm.connid =
+                                 le32_to_cpu(tmp32);
+                               cp = (u8 *) linkparam.u.rfm.volume;
+                               for (cfpkt_extr_head(pkt, &tmp, 1);
+                                    cfpkt_more(pkt) && tmp != '\0';
+                                    cfpkt_extr_head(pkt, &tmp, 1))
+                                       *cp++ = tmp;
+                               *cp = '\0';
+
+                               if (CFCTRL_ERR_BIT & cmdrsp)
+                                       break;
+                               /* Link ID */
+                               cfpkt_extr_head(pkt, &linkid, 1);
+
+                               break;
+                       case CFCTRL_SRV_UTIL:
+                               /* Construct a frame, convert
+                                * DatagramConnectionID
+                                * to network format long and copy it out...
+                                */
+                               /* Fifosize KB */
+                               cfpkt_extr_head(pkt, &tmp16, 2);
+                               linkparam.u.utility.fifosize_kb =
+                                   le16_to_cpu(tmp16);
+                               /* Fifosize bufs */
+                               cfpkt_extr_head(pkt, &tmp16, 2);
+                               linkparam.u.utility.fifosize_bufs =
+                                   le16_to_cpu(tmp16);
+                               /* name */
+                               cp = (u8 *) linkparam.u.utility.name;
+                               caif_assert(sizeof(linkparam.u.utility.name)
+                                            >= UTILITY_NAME_LENGTH);
+                               for (i = 0;
+                                    i < UTILITY_NAME_LENGTH
+                                    && cfpkt_more(pkt); i++) {
+                                       cfpkt_extr_head(pkt, &tmp, 1);
+                                       *cp++ = tmp;
+                               }
+                               /* Length */
+                               cfpkt_extr_head(pkt, &len, 1);
+                               linkparam.u.utility.paramlen = len;
+                               /* Param Data */
+                               cp = linkparam.u.utility.params;
+                               while (cfpkt_more(pkt) && len--) {
+                                       cfpkt_extr_head(pkt, &tmp, 1);
+                                       *cp++ = tmp;
+                               }
+                               if (CFCTRL_ERR_BIT & cmdrsp)
+                                       break;
+                               /* Link ID */
+                               cfpkt_extr_head(pkt, &linkid, 1);
+                               /* Length */
+                               cfpkt_extr_head(pkt, &len, 1);
+                               /* Param Data */
+                               cfpkt_extr_head(pkt, &param, len);
+                               break;
+                       default:
+                               pr_warning("CAIF: %s(): Request setup "
+                                          "- invalid link type (%d)",
+                                          __func__, serv);
+                               goto error;
+                       }
+
+                       rsp.cmd = cmd;
+                       rsp.param = linkparam;
+                       req = cfctrl_remove_req(cfctrl, &rsp);
+
+                       if (CFCTRL_ERR_BIT == (CFCTRL_ERR_BIT & cmdrsp) ||
+                               cfpkt_erroneous(pkt)) {
+                               pr_err("CAIF: %s(): Invalid O/E bit or parse "
+                                      "error on CAIF control channel",
+                                       __func__);
+                               cfctrl->res.reject_rsp(cfctrl->serv.layer.up,
+                                                      0,
+                                                      req ? req->client_layer
+                                                      : NULL);
+                       } else {
+                               cfctrl->res.linksetup_rsp(cfctrl->serv.
+                                                         layer.up, linkid,
+                                                         serv, physlinkid,
+                                                         req ? req->
+                                                         client_layer : NULL);
+                       }
+
+                       if (req != NULL)
+                               kfree(req);
+               }
+               break;
+       case CFCTRL_CMD_LINK_DESTROY:
+               cfpkt_extr_head(pkt, &linkid, 1);
+               cfctrl->res.linkdestroy_rsp(cfctrl->serv.layer.up, linkid);
+               break;
+       case CFCTRL_CMD_LINK_ERR:
+               pr_err("CAIF: %s(): Frame Error Indication received\n",
+                       __func__);
+               cfctrl->res.linkerror_ind();
+               break;
+       case CFCTRL_CMD_ENUM:
+               cfctrl->res.enum_rsp();
+               break;
+       case CFCTRL_CMD_SLEEP:
+               cfctrl->res.sleep_rsp();
+               break;
+       case CFCTRL_CMD_WAKE:
+               cfctrl->res.wake_rsp();
+               break;
+       case CFCTRL_CMD_LINK_RECONF:
+               cfctrl->res.restart_rsp();
+               break;
+       case CFCTRL_CMD_RADIO_SET:
+               cfctrl->res.radioset_rsp();
+               break;
+       default:
+               pr_err("CAIF: %s(): Unrecognized Control Frame\n", __func__);
+               goto error;
+               break;
+       }
+       ret = 0;
+error:
+       cfpkt_destroy(pkt);
+       return ret;
+}
+
+static void cfctrl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                       int phyid)
+{
+       struct cfctrl *this = container_obj(layr);
+       switch (ctrl) {
+       case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
+       case CAIF_CTRLCMD_FLOW_OFF_IND:
+               spin_lock(&this->info_list_lock);
+               if (this->first_req != NULL) {
+                       pr_debug("CAIF: %s(): Received flow off in "
+                                  "control layer", __func__);
+               }
+               spin_unlock(&this->info_list_lock);
+               break;
+       default:
+               break;
+       }
+}
+
+#ifndef CAIF_NO_LOOP
+static int handle_loop(struct cfctrl *ctrl, int cmd, struct cfpkt *pkt)
+{
+       static int last_linkid;
+       u8 linkid, linktype, tmp;
+       switch (cmd) {
+       case CFCTRL_CMD_LINK_SETUP:
+               spin_lock(&ctrl->loop_linkid_lock);
+               for (linkid = last_linkid + 1; linkid < 255; linkid++)
+                       if (!ctrl->loop_linkused[linkid])
+                               goto found;
+               for (linkid = last_linkid - 1; linkid > 0; linkid--)
+                       if (!ctrl->loop_linkused[linkid])
+                               goto found;
+               spin_unlock(&ctrl->loop_linkid_lock);
+               pr_err("CAIF: %s(): Out of link-ids\n", __func__);
+               return -EINVAL;
+found:
+               if (!ctrl->loop_linkused[linkid])
+                       ctrl->loop_linkused[linkid] = 1;
+
+               last_linkid = linkid;
+
+               cfpkt_add_trail(pkt, &linkid, 1);
+               spin_unlock(&ctrl->loop_linkid_lock);
+               cfpkt_peek_head(pkt, &linktype, 1);
+               if (linktype ==  CFCTRL_SRV_UTIL) {
+                       tmp = 0x01;
+                       cfpkt_add_trail(pkt, &tmp, 1);
+                       cfpkt_add_trail(pkt, &tmp, 1);
+               }
+               break;
+
+       case CFCTRL_CMD_LINK_DESTROY:
+               spin_lock(&ctrl->loop_linkid_lock);
+               cfpkt_peek_head(pkt, &linkid, 1);
+               ctrl->loop_linkused[linkid] = 0;
+               spin_unlock(&ctrl->loop_linkid_lock);
+               break;
+       default:
+               break;
+       }
+       return CAIF_SUCCESS;
+}
+#endif
diff --git a/net/caif/cfdbgl.c b/net/caif/cfdbgl.c
new file mode 100644 (file)
index 0000000..ab6b6dc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt);
+
+struct cflayer *cfdbgl_create(u8 channel_id, struct dev_info *dev_info)
+{
+       struct cfsrvl *dbg = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+       if (!dbg) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+       memset(dbg, 0, sizeof(struct cfsrvl));
+       cfsrvl_init(dbg, channel_id, dev_info);
+       dbg->layer.receive = cfdbgl_receive;
+       dbg->layer.transmit = cfdbgl_transmit;
+       snprintf(dbg->layer.name, CAIF_LAYER_NAME_SZ - 1, "dbg%d", channel_id);
+       return &dbg->layer;
+}
+
+static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       return layr->up->receive(layr->up, pkt);
+}
+
+static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       return layr->dn->transmit(layr->dn, pkt);
+}
diff --git a/net/caif/cfdgml.c b/net/caif/cfdgml.c
new file mode 100644 (file)
index 0000000..5319484
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
+#define DGM_CMD_BIT  0x80
+#define DGM_FLOW_OFF 0x81
+#define DGM_FLOW_ON  0x80
+#define DGM_CTRL_PKT_SIZE 1
+
+static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt);
+
+struct cflayer *cfdgml_create(u8 channel_id, struct dev_info *dev_info)
+{
+       struct cfsrvl *dgm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+       if (!dgm) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+       memset(dgm, 0, sizeof(struct cfsrvl));
+       cfsrvl_init(dgm, channel_id, dev_info);
+       dgm->layer.receive = cfdgml_receive;
+       dgm->layer.transmit = cfdgml_transmit;
+       snprintf(dgm->layer.name, CAIF_LAYER_NAME_SZ - 1, "dgm%d", channel_id);
+       dgm->layer.name[CAIF_LAYER_NAME_SZ - 1] = '\0';
+       return &dgm->layer;
+}
+
+static int cfdgml_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 cmd = -1;
+       u8 dgmhdr[3];
+       int ret;
+       caif_assert(layr->up != NULL);
+       caif_assert(layr->receive != NULL);
+       caif_assert(layr->ctrlcmd != NULL);
+
+       if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+
+       if ((cmd & DGM_CMD_BIT) == 0) {
+               if (cfpkt_extr_head(pkt, &dgmhdr, 3) < 0) {
+                       pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+                       cfpkt_destroy(pkt);
+                       return -EPROTO;
+               }
+               ret = layr->up->receive(layr->up, pkt);
+               return ret;
+       }
+
+       switch (cmd) {
+       case DGM_FLOW_OFF:      /* FLOW OFF */
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+               cfpkt_destroy(pkt);
+               return 0;
+       case DGM_FLOW_ON:       /* FLOW ON */
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+               cfpkt_destroy(pkt);
+               return 0;
+       default:
+               cfpkt_destroy(pkt);
+               pr_info("CAIF: %s(): Unknown datagram control %d (0x%x)\n",
+                       __func__, cmd, cmd);
+               return -EPROTO;
+       }
+}
+
+static int cfdgml_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u32 zero = 0;
+       struct caif_payload_info *info;
+       struct cfsrvl *service = container_obj(layr);
+       int ret;
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       cfpkt_add_head(pkt, &zero, 4);
+
+       /* Add info for MUX-layer to route the packet out. */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       /* To optimize alignment, we add up the size of CAIF header
+        * before payload.
+        */
+       info->hdr_len = 4;
+       info->dev_info = &service->dev_info;
+       ret = layr->dn->transmit(layr->dn, pkt);
+       if (ret < 0) {
+               u32 tmp32;
+               cfpkt_extr_head(pkt, &tmp32, 4);
+       }
+       return ret;
+}
diff --git a/net/caif/cffrml.c b/net/caif/cffrml.c
new file mode 100644 (file)
index 0000000..e86a4ca
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * CAIF Framing Layer.
+ *
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/crc-ccitt.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/cffrml.h>
+
+#define container_obj(layr) container_of(layr, struct cffrml, layer)
+
+struct cffrml {
+       struct cflayer layer;
+       bool dofcs;             /* !< FCS active */
+};
+
+static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt);
+static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                               int phyid);
+
+static u32 cffrml_rcv_error;
+static u32 cffrml_rcv_checsum_error;
+struct cflayer *cffrml_create(u16 phyid, bool use_fcs)
+{
+       struct cffrml *this = kmalloc(sizeof(struct cffrml), GFP_ATOMIC);
+       if (!this) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cffrml, layer) == 0);
+
+       memset(this, 0, sizeof(struct cflayer));
+       this->layer.receive = cffrml_receive;
+       this->layer.transmit = cffrml_transmit;
+       this->layer.ctrlcmd = cffrml_ctrlcmd;
+       snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "frm%d", phyid);
+       this->dofcs = use_fcs;
+       this->layer.id = phyid;
+       return (struct cflayer *) this;
+}
+
+void cffrml_set_uplayer(struct cflayer *this, struct cflayer *up)
+{
+       this->up = up;
+}
+
+void cffrml_set_dnlayer(struct cflayer *this, struct cflayer *dn)
+{
+       this->dn = dn;
+}
+
+static u16 cffrml_checksum(u16 chks, void *buf, u16 len)
+{
+       /* FIXME: FCS should be moved to glue in order to use OS-Specific
+        * solutions
+        */
+       return crc_ccitt(chks, buf, len);
+}
+
+static int cffrml_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u16 tmp;
+       u16 len;
+       u16 hdrchks;
+       u16 pktchks;
+       struct cffrml *this;
+       this = container_obj(layr);
+
+       cfpkt_extr_head(pkt, &tmp, 2);
+       len = le16_to_cpu(tmp);
+
+       /* Subtract for FCS on length if FCS is not used. */
+       if (!this->dofcs)
+               len -= 2;
+
+       if (cfpkt_setlen(pkt, len) < 0) {
+               ++cffrml_rcv_error;
+               pr_err("CAIF: %s():Framing length error (%d)\n", __func__, len);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+       /*
+        * Don't do extract if FCS is false, rather do setlen - then we don't
+        * get a cache-miss.
+        */
+       if (this->dofcs) {
+               cfpkt_extr_trail(pkt, &tmp, 2);
+               hdrchks = le16_to_cpu(tmp);
+               pktchks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
+               if (pktchks != hdrchks) {
+                       cfpkt_add_trail(pkt, &tmp, 2);
+                       ++cffrml_rcv_error;
+                       ++cffrml_rcv_checsum_error;
+                       pr_info("CAIF: %s(): Frame checksum error "
+                               "(0x%x != 0x%x)\n", __func__, hdrchks, pktchks);
+                       return -EILSEQ;
+               }
+       }
+       if (cfpkt_erroneous(pkt)) {
+               ++cffrml_rcv_error;
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+       return layr->up->receive(layr->up, pkt);
+}
+
+static int cffrml_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       int tmp;
+       u16 chks;
+       u16 len;
+       int ret;
+       struct cffrml *this = container_obj(layr);
+       if (this->dofcs) {
+               chks = cfpkt_iterate(pkt, cffrml_checksum, 0xffff);
+               tmp = cpu_to_le16(chks);
+               cfpkt_add_trail(pkt, &tmp, 2);
+       } else {
+               cfpkt_pad_trail(pkt, 2);
+       }
+       len = cfpkt_getlen(pkt);
+       tmp = cpu_to_le16(len);
+       cfpkt_add_head(pkt, &tmp, 2);
+       cfpkt_info(pkt)->hdr_len += 2;
+       if (cfpkt_erroneous(pkt)) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               return -EPROTO;
+       }
+       ret = layr->dn->transmit(layr->dn, pkt);
+       if (ret < 0) {
+               /* Remove header on faulty packet. */
+               cfpkt_extr_head(pkt, &tmp, 2);
+       }
+       return ret;
+}
+
+static void cffrml_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                                       int phyid)
+{
+       if (layr->up->ctrlcmd)
+               layr->up->ctrlcmd(layr->up, ctrl, layr->id);
+}
diff --git a/net/caif/cfmuxl.c b/net/caif/cfmuxl.c
new file mode 100644 (file)
index 0000000..7372f27
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/cfmuxl.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cffrml.h>
+
+#define container_obj(layr) container_of(layr, struct cfmuxl, layer)
+
+#define CAIF_CTRL_CHANNEL 0
+#define UP_CACHE_SIZE 8
+#define DN_CACHE_SIZE 8
+
+struct cfmuxl {
+       struct cflayer layer;
+       struct list_head srvl_list;
+       struct list_head frml_list;
+       struct cflayer *up_cache[UP_CACHE_SIZE];
+       struct cflayer *dn_cache[DN_CACHE_SIZE];
+       /*
+        * Set when inserting or removing downwards layers.
+        */
+       spinlock_t transmit_lock;
+
+       /*
+        * Set when inserting or removing upwards layers.
+        */
+       spinlock_t receive_lock;
+
+};
+
+static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt);
+static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                               int phyid);
+static struct cflayer *get_up(struct cfmuxl *muxl, u16 id);
+
+struct cflayer *cfmuxl_create(void)
+{
+       struct cfmuxl *this = kmalloc(sizeof(struct cfmuxl), GFP_ATOMIC);
+       if (!this)
+               return NULL;
+       memset(this, 0, sizeof(*this));
+       this->layer.receive = cfmuxl_receive;
+       this->layer.transmit = cfmuxl_transmit;
+       this->layer.ctrlcmd = cfmuxl_ctrlcmd;
+       INIT_LIST_HEAD(&this->srvl_list);
+       INIT_LIST_HEAD(&this->frml_list);
+       spin_lock_init(&this->transmit_lock);
+       spin_lock_init(&this->receive_lock);
+       snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "mux");
+       return &this->layer;
+}
+
+int cfmuxl_set_uplayer(struct cflayer *layr, struct cflayer *up, u8 linkid)
+{
+       struct cfmuxl *muxl = container_obj(layr);
+       spin_lock(&muxl->receive_lock);
+       cfsrvl_get(up);
+       list_add(&up->node, &muxl->srvl_list);
+       spin_unlock(&muxl->receive_lock);
+       return 0;
+}
+
+bool cfmuxl_is_phy_inuse(struct cflayer *layr, u8 phyid)
+{
+       struct list_head *node;
+       struct cflayer *layer;
+       struct cfmuxl *muxl = container_obj(layr);
+       bool match = false;
+       spin_lock(&muxl->receive_lock);
+
+       list_for_each(node, &muxl->srvl_list) {
+               layer = list_entry(node, struct cflayer, node);
+               if (cfsrvl_phyid_match(layer, phyid)) {
+                       match = true;
+                       break;
+               }
+
+       }
+       spin_unlock(&muxl->receive_lock);
+       return match;
+}
+
+u8 cfmuxl_get_phyid(struct cflayer *layr, u8 channel_id)
+{
+       struct cflayer *up;
+       int phyid;
+       struct cfmuxl *muxl = container_obj(layr);
+       spin_lock(&muxl->receive_lock);
+       up = get_up(muxl, channel_id);
+       if (up != NULL)
+               phyid = cfsrvl_getphyid(up);
+       else
+               phyid = 0;
+       spin_unlock(&muxl->receive_lock);
+       return phyid;
+}
+
+int cfmuxl_set_dnlayer(struct cflayer *layr, struct cflayer *dn, u8 phyid)
+{
+       struct cfmuxl *muxl = (struct cfmuxl *) layr;
+       spin_lock(&muxl->transmit_lock);
+       list_add(&dn->node, &muxl->frml_list);
+       spin_unlock(&muxl->transmit_lock);
+       return 0;
+}
+
+static struct cflayer *get_from_id(struct list_head *list, u16 id)
+{
+       struct list_head *node;
+       struct cflayer *layer;
+       list_for_each(node, list) {
+               layer = list_entry(node, struct cflayer, node);
+               if (layer->id == id)
+                       return layer;
+       }
+       return NULL;
+}
+
+struct cflayer *cfmuxl_remove_dnlayer(struct cflayer *layr, u8 phyid)
+{
+       struct cfmuxl *muxl = container_obj(layr);
+       struct cflayer *dn;
+       spin_lock(&muxl->transmit_lock);
+       memset(muxl->dn_cache, 0, sizeof(muxl->dn_cache));
+       dn = get_from_id(&muxl->frml_list, phyid);
+       if (dn == NULL) {
+               spin_unlock(&muxl->transmit_lock);
+               return NULL;
+       }
+       list_del(&dn->node);
+       caif_assert(dn != NULL);
+       spin_unlock(&muxl->transmit_lock);
+       return dn;
+}
+
+/* Invariant: lock is taken */
+static struct cflayer *get_up(struct cfmuxl *muxl, u16 id)
+{
+       struct cflayer *up;
+       int idx = id % UP_CACHE_SIZE;
+       up = muxl->up_cache[idx];
+       if (up == NULL || up->id != id) {
+               up = get_from_id(&muxl->srvl_list, id);
+               muxl->up_cache[idx] = up;
+       }
+       return up;
+}
+
+/* Invariant: lock is taken */
+static struct cflayer *get_dn(struct cfmuxl *muxl, struct dev_info *dev_info)
+{
+       struct cflayer *dn;
+       int idx = dev_info->id % DN_CACHE_SIZE;
+       dn = muxl->dn_cache[idx];
+       if (dn == NULL || dn->id != dev_info->id) {
+               dn = get_from_id(&muxl->frml_list, dev_info->id);
+               muxl->dn_cache[idx] = dn;
+       }
+       return dn;
+}
+
+struct cflayer *cfmuxl_remove_uplayer(struct cflayer *layr, u8 id)
+{
+       struct cflayer *up;
+       struct cfmuxl *muxl = container_obj(layr);
+       spin_lock(&muxl->receive_lock);
+       up = get_up(muxl, id);
+       if (up == NULL)
+               return NULL;
+       memset(muxl->up_cache, 0, sizeof(muxl->up_cache));
+       list_del(&up->node);
+       cfsrvl_put(up);
+       spin_unlock(&muxl->receive_lock);
+       return up;
+}
+
+static int cfmuxl_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       int ret;
+       struct cfmuxl *muxl = container_obj(layr);
+       u8 id;
+       struct cflayer *up;
+       if (cfpkt_extr_head(pkt, &id, 1) < 0) {
+               pr_err("CAIF: %s(): erroneous Caif Packet\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+
+       spin_lock(&muxl->receive_lock);
+       up = get_up(muxl, id);
+       spin_unlock(&muxl->receive_lock);
+       if (up == NULL) {
+               pr_info("CAIF: %s():Received data on unknown link ID = %d "
+                       "(0x%x)  up == NULL", __func__, id, id);
+               cfpkt_destroy(pkt);
+               /*
+                * Don't return ERROR, since modem misbehaves and sends out
+                * flow on before linksetup response.
+                */
+               return /* CFGLU_EPROT; */ 0;
+       }
+       cfsrvl_get(up);
+       ret = up->receive(up, pkt);
+       cfsrvl_put(up);
+       return ret;
+}
+
+static int cfmuxl_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       int ret;
+       struct cfmuxl *muxl = container_obj(layr);
+       u8 linkid;
+       struct cflayer *dn;
+       struct caif_payload_info *info = cfpkt_info(pkt);
+       dn = get_dn(muxl, cfpkt_info(pkt)->dev_info);
+       if (dn == NULL) {
+               pr_warning("CAIF: %s(): Send data on unknown phy "
+                          "ID = %d (0x%x)\n",
+                          __func__, info->dev_info->id, info->dev_info->id);
+               return -ENOTCONN;
+       }
+       info->hdr_len += 1;
+       linkid = info->channel_id;
+       cfpkt_add_head(pkt, &linkid, 1);
+       ret = dn->transmit(dn, pkt);
+       /* Remove MUX protocol header upon error. */
+       if (ret < 0)
+               cfpkt_extr_head(pkt, &linkid, 1);
+       return ret;
+}
+
+static void cfmuxl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                               int phyid)
+{
+       struct cfmuxl *muxl = container_obj(layr);
+       struct list_head *node;
+       struct cflayer *layer;
+       list_for_each(node, &muxl->srvl_list) {
+               layer = list_entry(node, struct cflayer, node);
+               if (cfsrvl_phyid_match(layer, phyid))
+                       layer->ctrlcmd(layer, ctrl, phyid);
+       }
+}
diff --git a/net/caif/cfpkt_skbuff.c b/net/caif/cfpkt_skbuff.c
new file mode 100644 (file)
index 0000000..83fff2f
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/hardirq.h>
+#include <net/caif/cfpkt.h>
+
+#define PKT_PREFIX CAIF_NEEDED_HEADROOM
+#define PKT_POSTFIX CAIF_NEEDED_TAILROOM
+#define PKT_LEN_WHEN_EXTENDING 128
+#define PKT_ERROR(pkt, errmsg) do {       \
+    cfpkt_priv(pkt)->erronous = true;     \
+    skb_reset_tail_pointer(&pkt->skb);    \
+    pr_warning("CAIF: " errmsg);\
+  } while (0)
+
+struct cfpktq {
+       struct sk_buff_head head;
+       atomic_t count;
+       /* Lock protects count updates */
+       spinlock_t lock;
+};
+
+/*
+ * net/caif/ is generic and does not
+ * understand SKB, so we do this typecast
+ */
+struct cfpkt {
+       struct sk_buff skb;
+};
+
+/* Private data inside SKB */
+struct cfpkt_priv_data {
+       struct dev_info dev_info;
+       bool erronous;
+};
+
+inline struct cfpkt_priv_data *cfpkt_priv(struct cfpkt *pkt)
+{
+       return (struct cfpkt_priv_data *) pkt->skb.cb;
+}
+
+inline bool is_erronous(struct cfpkt *pkt)
+{
+       return cfpkt_priv(pkt)->erronous;
+}
+
+inline struct sk_buff *pkt_to_skb(struct cfpkt *pkt)
+{
+       return &pkt->skb;
+}
+
+inline struct cfpkt *skb_to_pkt(struct sk_buff *skb)
+{
+       return (struct cfpkt *) skb;
+}
+
+
+struct cfpkt *cfpkt_fromnative(enum caif_direction dir, void *nativepkt)
+{
+       struct cfpkt *pkt = skb_to_pkt(nativepkt);
+       cfpkt_priv(pkt)->erronous = false;
+       return pkt;
+}
+EXPORT_SYMBOL(cfpkt_fromnative);
+
+void *cfpkt_tonative(struct cfpkt *pkt)
+{
+       return (void *) pkt;
+}
+EXPORT_SYMBOL(cfpkt_tonative);
+
+static struct cfpkt *cfpkt_create_pfx(u16 len, u16 pfx)
+{
+       struct sk_buff *skb;
+
+       if (likely(in_interrupt()))
+               skb = alloc_skb(len + pfx, GFP_ATOMIC);
+       else
+               skb = alloc_skb(len + pfx, GFP_KERNEL);
+
+       if (unlikely(skb == NULL))
+               return NULL;
+
+       skb_reserve(skb, pfx);
+       return skb_to_pkt(skb);
+}
+
+inline struct cfpkt *cfpkt_create(u16 len)
+{
+       return cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+}
+EXPORT_SYMBOL(cfpkt_create);
+
+void cfpkt_destroy(struct cfpkt *pkt)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       kfree_skb(skb);
+}
+EXPORT_SYMBOL(cfpkt_destroy);
+
+inline bool cfpkt_more(struct cfpkt *pkt)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       return skb->len > 0;
+}
+EXPORT_SYMBOL(cfpkt_more);
+
+int cfpkt_peek_head(struct cfpkt *pkt, void *data, u16 len)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       if (skb_headlen(skb) >= len) {
+               memcpy(data, skb->data, len);
+               return 0;
+       }
+       return !cfpkt_extr_head(pkt, data, len) &&
+           !cfpkt_add_head(pkt, data, len);
+}
+EXPORT_SYMBOL(cfpkt_peek_head);
+
+int cfpkt_extr_head(struct cfpkt *pkt, void *data, u16 len)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       u8 *from;
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+
+       if (unlikely(len > skb->len)) {
+               PKT_ERROR(pkt, "cfpkt_extr_head read beyond end of packet\n");
+               return -EPROTO;
+       }
+
+       if (unlikely(len > skb_headlen(skb))) {
+               if (unlikely(skb_linearize(skb) != 0)) {
+                       PKT_ERROR(pkt, "cfpkt_extr_head linearize failed\n");
+                       return -EPROTO;
+               }
+       }
+       from = skb_pull(skb, len);
+       from -= len;
+       memcpy(data, from, len);
+       return 0;
+}
+EXPORT_SYMBOL(cfpkt_extr_head);
+
+int cfpkt_extr_trail(struct cfpkt *pkt, void *dta, u16 len)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       u8 *data = dta;
+       u8 *from;
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+
+       if (unlikely(skb_linearize(skb) != 0)) {
+               PKT_ERROR(pkt, "cfpkt_extr_trail linearize failed\n");
+               return -EPROTO;
+       }
+       if (unlikely(skb->data + len > skb_tail_pointer(skb))) {
+               PKT_ERROR(pkt, "cfpkt_extr_trail read beyond end of packet\n");
+               return -EPROTO;
+       }
+       from = skb_tail_pointer(skb) - len;
+       skb_trim(skb, skb->len - len);
+       memcpy(data, from, len);
+       return 0;
+}
+EXPORT_SYMBOL(cfpkt_extr_trail);
+
+int cfpkt_pad_trail(struct cfpkt *pkt, u16 len)
+{
+       return cfpkt_add_body(pkt, NULL, len);
+}
+EXPORT_SYMBOL(cfpkt_pad_trail);
+
+int cfpkt_add_body(struct cfpkt *pkt, const void *data, u16 len)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       struct sk_buff *lastskb;
+       u8 *to;
+       u16 addlen = 0;
+
+
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+
+       lastskb = skb;
+
+       /* Check whether we need to add space at the tail */
+       if (unlikely(skb_tailroom(skb) < len)) {
+               if (likely(len < PKT_LEN_WHEN_EXTENDING))
+                       addlen = PKT_LEN_WHEN_EXTENDING;
+               else
+                       addlen = len;
+       }
+
+       /* Check whether we need to change the SKB before writing to the tail */
+       if (unlikely((addlen > 0) || skb_cloned(skb) || skb_shared(skb))) {
+
+               /* Make sure data is writable */
+               if (unlikely(skb_cow_data(skb, addlen, &lastskb) < 0)) {
+                       PKT_ERROR(pkt, "cfpkt_add_body: cow failed\n");
+                       return -EPROTO;
+               }
+               /*
+                * Is the SKB non-linear after skb_cow_data()? If so, we are
+                * going to add data to the last SKB, so we need to adjust
+                * lengths of the top SKB.
+                */
+               if (lastskb != skb) {
+                       pr_warning("CAIF: %s(): Packet is non-linear\n",
+                                  __func__);
+                       skb->len += len;
+                       skb->data_len += len;
+               }
+       }
+
+       /* All set to put the last SKB and optionally write data there. */
+       to = skb_put(lastskb, len);
+       if (likely(data))
+               memcpy(to, data, len);
+       return 0;
+}
+EXPORT_SYMBOL(cfpkt_add_body);
+
+inline int cfpkt_addbdy(struct cfpkt *pkt, u8 data)
+{
+       return cfpkt_add_body(pkt, &data, 1);
+}
+EXPORT_SYMBOL(cfpkt_addbdy);
+
+int cfpkt_add_head(struct cfpkt *pkt, const void *data2, u16 len)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       struct sk_buff *lastskb;
+       u8 *to;
+       const u8 *data = data2;
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+       if (unlikely(skb_headroom(skb) < len)) {
+               PKT_ERROR(pkt, "cfpkt_add_head: no headroom\n");
+               return -EPROTO;
+       }
+
+       /* Make sure data is writable */
+       if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+               PKT_ERROR(pkt, "cfpkt_add_head: cow failed\n");
+               return -EPROTO;
+       }
+
+       to = skb_push(skb, len);
+       memcpy(to, data, len);
+       return 0;
+}
+EXPORT_SYMBOL(cfpkt_add_head);
+
+inline int cfpkt_add_trail(struct cfpkt *pkt, const void *data, u16 len)
+{
+       return cfpkt_add_body(pkt, data, len);
+}
+EXPORT_SYMBOL(cfpkt_add_trail);
+
+inline u16 cfpkt_getlen(struct cfpkt *pkt)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       return skb->len;
+}
+EXPORT_SYMBOL(cfpkt_getlen);
+
+inline u16 cfpkt_iterate(struct cfpkt *pkt,
+                           u16 (*iter_func)(u16, void *, u16),
+                           u16 data)
+{
+       /*
+        * Don't care about the performance hit of linearizing,
+        * Checksum should not be used on high-speed interfaces anyway.
+        */
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+       if (unlikely(skb_linearize(&pkt->skb) != 0)) {
+               PKT_ERROR(pkt, "cfpkt_iterate: linearize failed\n");
+               return -EPROTO;
+       }
+       return iter_func(data, pkt->skb.data, cfpkt_getlen(pkt));
+}
+EXPORT_SYMBOL(cfpkt_iterate);
+
+int cfpkt_setlen(struct cfpkt *pkt, u16 len)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+
+
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+
+       if (likely(len <= skb->len)) {
+               if (unlikely(skb->data_len))
+                       ___pskb_trim(skb, len);
+               else
+                       skb_trim(skb, len);
+
+                       return cfpkt_getlen(pkt);
+       }
+
+       /* Need to expand SKB */
+       if (unlikely(!cfpkt_pad_trail(pkt, len - skb->len)))
+               PKT_ERROR(pkt, "cfpkt_setlen: skb_pad_trail failed\n");
+
+       return cfpkt_getlen(pkt);
+}
+EXPORT_SYMBOL(cfpkt_setlen);
+
+struct cfpkt *cfpkt_create_uplink(const unsigned char *data, unsigned int len)
+{
+       struct cfpkt *pkt = cfpkt_create_pfx(len + PKT_POSTFIX, PKT_PREFIX);
+       if (unlikely(data != NULL))
+               cfpkt_add_body(pkt, data, len);
+       return pkt;
+}
+EXPORT_SYMBOL(cfpkt_create_uplink);
+
+struct cfpkt *cfpkt_append(struct cfpkt *dstpkt,
+                            struct cfpkt *addpkt,
+                            u16 expectlen)
+{
+       struct sk_buff *dst = pkt_to_skb(dstpkt);
+       struct sk_buff *add = pkt_to_skb(addpkt);
+       u16 addlen = skb_headlen(add);
+       u16 neededtailspace;
+       struct sk_buff *tmp;
+       u16 dstlen;
+       u16 createlen;
+       if (unlikely(is_erronous(dstpkt) || is_erronous(addpkt))) {
+               cfpkt_destroy(addpkt);
+               return dstpkt;
+       }
+       if (expectlen > addlen)
+               neededtailspace = expectlen;
+       else
+               neededtailspace = addlen;
+
+       if (dst->tail + neededtailspace > dst->end) {
+               /* Create a dumplicate of 'dst' with more tail space */
+               dstlen = skb_headlen(dst);
+               createlen = dstlen + neededtailspace;
+               tmp = pkt_to_skb(
+                       cfpkt_create(createlen + PKT_PREFIX + PKT_POSTFIX));
+               if (!tmp)
+                       return NULL;
+               skb_set_tail_pointer(tmp, dstlen);
+               tmp->len = dstlen;
+               memcpy(tmp->data, dst->data, dstlen);
+               cfpkt_destroy(dstpkt);
+               dst = tmp;
+       }
+       memcpy(skb_tail_pointer(dst), add->data, skb_headlen(add));
+       cfpkt_destroy(addpkt);
+       dst->tail += addlen;
+       dst->len += addlen;
+       return skb_to_pkt(dst);
+}
+EXPORT_SYMBOL(cfpkt_append);
+
+struct cfpkt *cfpkt_split(struct cfpkt *pkt, u16 pos)
+{
+       struct sk_buff *skb2;
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       u8 *split = skb->data + pos;
+       u16 len2nd = skb_tail_pointer(skb) - split;
+
+       if (unlikely(is_erronous(pkt)))
+               return NULL;
+
+       if (skb->data + pos > skb_tail_pointer(skb)) {
+               PKT_ERROR(pkt,
+                         "cfpkt_split: trying to split beyond end of packet");
+               return NULL;
+       }
+
+       /* Create a new packet for the second part of the data */
+       skb2 = pkt_to_skb(
+               cfpkt_create_pfx(len2nd + PKT_PREFIX + PKT_POSTFIX,
+                                PKT_PREFIX));
+
+       if (skb2 == NULL)
+               return NULL;
+
+       /* Reduce the length of the original packet */
+       skb_set_tail_pointer(skb, pos);
+       skb->len = pos;
+
+       memcpy(skb2->data, split, len2nd);
+       skb2->tail += len2nd;
+       skb2->len += len2nd;
+       return skb_to_pkt(skb2);
+}
+EXPORT_SYMBOL(cfpkt_split);
+
+char *cfpkt_log_pkt(struct cfpkt *pkt, char *buf, int buflen)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       char *p = buf;
+       int i;
+
+       /*
+        * Sanity check buffer length, it needs to be at least as large as
+        * the header info: ~=50+ bytes
+        */
+       if (buflen < 50)
+               return NULL;
+
+       snprintf(buf, buflen, "%s: pkt:%p len:%ld(%ld+%ld) {%ld,%ld} data: [",
+               is_erronous(pkt) ? "ERRONOUS-SKB" :
+                (skb->data_len != 0 ? "COMPLEX-SKB" : "SKB"),
+                skb,
+                (long) skb->len,
+                (long) (skb_tail_pointer(skb) - skb->data),
+                (long) skb->data_len,
+                (long) (skb->data - skb->head),
+                (long) (skb_tail_pointer(skb) - skb->head));
+       p = buf + strlen(buf);
+
+       for (i = 0; i < skb_tail_pointer(skb) - skb->data && i < 300; i++) {
+               if (p > buf + buflen - 10) {
+                       sprintf(p, "...");
+                       p = buf + strlen(buf);
+                       break;
+               }
+               sprintf(p, "%02x,", skb->data[i]);
+               p = buf + strlen(buf);
+       }
+       sprintf(p, "]\n");
+       return buf;
+}
+EXPORT_SYMBOL(cfpkt_log_pkt);
+
+int cfpkt_raw_append(struct cfpkt *pkt, void **buf, unsigned int buflen)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+       struct sk_buff *lastskb;
+
+       caif_assert(buf != NULL);
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+       /* Make sure SKB is writable */
+       if (unlikely(skb_cow_data(skb, 0, &lastskb) < 0)) {
+               PKT_ERROR(pkt, "cfpkt_raw_append: skb_cow_data failed\n");
+               return -EPROTO;
+       }
+
+       if (unlikely(skb_linearize(skb) != 0)) {
+               PKT_ERROR(pkt, "cfpkt_raw_append: linearize failed\n");
+               return -EPROTO;
+       }
+
+       if (unlikely(skb_tailroom(skb) < buflen)) {
+               PKT_ERROR(pkt, "cfpkt_raw_append: buffer too short - failed\n");
+               return -EPROTO;
+       }
+
+       *buf = skb_put(skb, buflen);
+       return 1;
+}
+EXPORT_SYMBOL(cfpkt_raw_append);
+
+int cfpkt_raw_extract(struct cfpkt *pkt, void **buf, unsigned int buflen)
+{
+       struct sk_buff *skb = pkt_to_skb(pkt);
+
+       caif_assert(buf != NULL);
+       if (unlikely(is_erronous(pkt)))
+               return -EPROTO;
+
+       if (unlikely(buflen > skb->len)) {
+               PKT_ERROR(pkt, "cfpkt_raw_extract: buflen too large "
+                               "- failed\n");
+               return -EPROTO;
+       }
+
+       if (unlikely(buflen > skb_headlen(skb))) {
+               if (unlikely(skb_linearize(skb) != 0)) {
+                       PKT_ERROR(pkt, "cfpkt_raw_extract: linearize failed\n");
+                       return -EPROTO;
+               }
+       }
+
+       *buf = skb->data;
+       skb_pull(skb, buflen);
+
+       return 1;
+}
+EXPORT_SYMBOL(cfpkt_raw_extract);
+
+inline bool cfpkt_erroneous(struct cfpkt *pkt)
+{
+       return cfpkt_priv(pkt)->erronous;
+}
+EXPORT_SYMBOL(cfpkt_erroneous);
+
+struct cfpktq *cfpktq_create(void)
+{
+       struct cfpktq *q = kmalloc(sizeof(struct cfpktq), GFP_ATOMIC);
+       if (!q)
+               return NULL;
+       skb_queue_head_init(&q->head);
+       atomic_set(&q->count, 0);
+       spin_lock_init(&q->lock);
+       return q;
+}
+EXPORT_SYMBOL(cfpktq_create);
+
+void cfpkt_queue(struct cfpktq *pktq, struct cfpkt *pkt, unsigned short prio)
+{
+       atomic_inc(&pktq->count);
+       spin_lock(&pktq->lock);
+       skb_queue_tail(&pktq->head, pkt_to_skb(pkt));
+       spin_unlock(&pktq->lock);
+
+}
+EXPORT_SYMBOL(cfpkt_queue);
+
+struct cfpkt *cfpkt_qpeek(struct cfpktq *pktq)
+{
+       struct cfpkt *tmp;
+       spin_lock(&pktq->lock);
+       tmp = skb_to_pkt(skb_peek(&pktq->head));
+       spin_unlock(&pktq->lock);
+       return tmp;
+}
+EXPORT_SYMBOL(cfpkt_qpeek);
+
+struct cfpkt *cfpkt_dequeue(struct cfpktq *pktq)
+{
+       struct cfpkt *pkt;
+       spin_lock(&pktq->lock);
+       pkt = skb_to_pkt(skb_dequeue(&pktq->head));
+       if (pkt) {
+               atomic_dec(&pktq->count);
+               caif_assert(atomic_read(&pktq->count) >= 0);
+       }
+       spin_unlock(&pktq->lock);
+       return pkt;
+}
+EXPORT_SYMBOL(cfpkt_dequeue);
+
+int cfpkt_qcount(struct cfpktq *pktq)
+{
+       return atomic_read(&pktq->count);
+}
+EXPORT_SYMBOL(cfpkt_qcount);
+
+struct cfpkt *cfpkt_clone_release(struct cfpkt *pkt)
+{
+       struct cfpkt *clone;
+       clone  = skb_to_pkt(skb_clone(pkt_to_skb(pkt), GFP_ATOMIC));
+       /* Free original packet. */
+       cfpkt_destroy(pkt);
+       if (!clone)
+               return NULL;
+       return clone;
+}
+EXPORT_SYMBOL(cfpkt_clone_release);
+
+struct caif_payload_info *cfpkt_info(struct cfpkt *pkt)
+{
+       return (struct caif_payload_info *)&pkt_to_skb(pkt)->cb;
+}
+EXPORT_SYMBOL(cfpkt_info);
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c
new file mode 100644 (file)
index 0000000..cd2830f
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
+
+#define RFM_SEGMENTATION_BIT 0x01
+#define RFM_PAYLOAD  0x00
+#define RFM_CMD_BIT  0x80
+#define RFM_FLOW_OFF 0x81
+#define RFM_FLOW_ON  0x80
+#define RFM_SET_PIN  0x82
+#define RFM_CTRL_PKT_SIZE 1
+
+static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt);
+static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl);
+
+struct cflayer *cfrfml_create(u8 channel_id, struct dev_info *dev_info)
+{
+       struct cfsrvl *rfm = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+       if (!rfm) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+       memset(rfm, 0, sizeof(struct cfsrvl));
+       cfsrvl_init(rfm, channel_id, dev_info);
+       rfm->layer.modemcmd = cfservl_modemcmd;
+       rfm->layer.receive = cfrfml_receive;
+       rfm->layer.transmit = cfrfml_transmit;
+       snprintf(rfm->layer.name, CAIF_LAYER_NAME_SZ, "rfm%d", channel_id);
+       return &rfm->layer;
+}
+
+static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
+{
+       return -EPROTO;
+}
+
+static int cfrfml_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 tmp;
+       bool segmented;
+       int ret;
+       caif_assert(layr->up != NULL);
+       caif_assert(layr->receive != NULL);
+
+       /*
+        * RFM is taking care of segmentation and stripping of
+        * segmentation bit.
+        */
+       if (cfpkt_extr_head(pkt, &tmp, 1) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+       segmented = tmp & RFM_SEGMENTATION_BIT;
+       caif_assert(!segmented);
+
+       ret = layr->up->receive(layr->up, pkt);
+       return ret;
+}
+
+static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 tmp = 0;
+       int ret;
+       struct cfsrvl *service = container_obj(layr);
+
+       caif_assert(layr->dn != NULL);
+       caif_assert(layr->dn->transmit != NULL);
+
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+               pr_err("CAIF: %s():Packet too large - size=%d\n",
+                       __func__, cfpkt_getlen(pkt));
+               return -EOVERFLOW;
+       }
+       if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               return -EPROTO;
+       }
+
+       /* Add info for MUX-layer to route the packet out. */
+       cfpkt_info(pkt)->channel_id = service->layer.id;
+       /*
+        * To optimize alignment, we add up the size of CAIF header before
+        * payload.
+        */
+       cfpkt_info(pkt)->hdr_len = 1;
+       cfpkt_info(pkt)->dev_info = &service->dev_info;
+       ret = layr->dn->transmit(layr->dn, pkt);
+       if (ret < 0)
+               cfpkt_extr_head(pkt, &tmp, 1);
+       return ret;
+}
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
new file mode 100644 (file)
index 0000000..06029ea
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/cfserl.h>
+
+#define container_obj(layr) ((struct cfserl *) layr)
+
+#define CFSERL_STX 0x02
+#define CAIF_MINIUM_PACKET_SIZE 4
+struct cfserl {
+       struct cflayer layer;
+       struct cfpkt *incomplete_frm;
+       /* Protects parallel processing of incoming packets */
+       spinlock_t sync;
+       bool usestx;
+};
+#define STXLEN(layr) (layr->usestx ? 1 : 0)
+
+static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt);
+static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                               int phyid);
+
+struct cflayer *cfserl_create(int type, int instance, bool use_stx)
+{
+       struct cfserl *this = kmalloc(sizeof(struct cfserl), GFP_ATOMIC);
+       if (!this) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfserl, layer) == 0);
+       memset(this, 0, sizeof(struct cfserl));
+       this->layer.receive = cfserl_receive;
+       this->layer.transmit = cfserl_transmit;
+       this->layer.ctrlcmd = cfserl_ctrlcmd;
+       this->layer.type = type;
+       this->usestx = use_stx;
+       spin_lock_init(&this->sync);
+       snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1");
+       return &this->layer;
+}
+
+static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
+{
+       struct cfserl *layr = container_obj(l);
+       u16 pkt_len;
+       struct cfpkt *pkt = NULL;
+       struct cfpkt *tail_pkt = NULL;
+       u8 tmp8;
+       u16 tmp;
+       u8 stx = CFSERL_STX;
+       int ret;
+       u16 expectlen = 0;
+       caif_assert(newpkt != NULL);
+       spin_lock(&layr->sync);
+
+       if (layr->incomplete_frm != NULL) {
+
+               layr->incomplete_frm =
+                   cfpkt_append(layr->incomplete_frm, newpkt, expectlen);
+               pkt = layr->incomplete_frm;
+       } else {
+               pkt = newpkt;
+       }
+       layr->incomplete_frm = NULL;
+
+       do {
+               /* Search for STX at start of pkt if STX is used */
+               if (layr->usestx) {
+                       cfpkt_extr_head(pkt, &tmp8, 1);
+                       if (tmp8 != CFSERL_STX) {
+                               while (cfpkt_more(pkt)
+                                      && tmp8 != CFSERL_STX) {
+                                       cfpkt_extr_head(pkt, &tmp8, 1);
+                               }
+                               if (!cfpkt_more(pkt)) {
+                                       cfpkt_destroy(pkt);
+                                       layr->incomplete_frm = NULL;
+                                       spin_unlock(&layr->sync);
+                                       return -EPROTO;
+                               }
+                       }
+               }
+
+               pkt_len = cfpkt_getlen(pkt);
+
+               /*
+                *  pkt_len is the accumulated length of the packet data
+                *  we have received so far.
+                *  Exit if frame doesn't hold length.
+                */
+
+               if (pkt_len < 2) {
+                       if (layr->usestx)
+                               cfpkt_add_head(pkt, &stx, 1);
+                       layr->incomplete_frm = pkt;
+                       spin_unlock(&layr->sync);
+                       return 0;
+               }
+
+               /*
+                *  Find length of frame.
+                *  expectlen is the length we need for a full frame.
+                */
+               cfpkt_peek_head(pkt, &tmp, 2);
+               expectlen = le16_to_cpu(tmp) + 2;
+               /*
+                * Frame error handling
+                */
+               if (expectlen < CAIF_MINIUM_PACKET_SIZE
+                   || expectlen > CAIF_MAX_FRAMESIZE) {
+                       if (!layr->usestx) {
+                               if (pkt != NULL)
+                                       cfpkt_destroy(pkt);
+                               layr->incomplete_frm = NULL;
+                               expectlen = 0;
+                               spin_unlock(&layr->sync);
+                               return -EPROTO;
+                       }
+                       continue;
+               }
+
+               if (pkt_len < expectlen) {
+                       /* Too little received data */
+                       if (layr->usestx)
+                               cfpkt_add_head(pkt, &stx, 1);
+                       layr->incomplete_frm = pkt;
+                       spin_unlock(&layr->sync);
+                       return 0;
+               }
+
+               /*
+                * Enough data for at least one frame.
+                * Split the frame, if too long
+                */
+               if (pkt_len > expectlen)
+                       tail_pkt = cfpkt_split(pkt, expectlen);
+               else
+                       tail_pkt = NULL;
+
+               /* Send the first part of packet upwards.*/
+               spin_unlock(&layr->sync);
+               ret = layr->layer.up->receive(layr->layer.up, pkt);
+               spin_lock(&layr->sync);
+               if (ret == -EILSEQ) {
+                       if (layr->usestx) {
+                               if (tail_pkt != NULL)
+                                       pkt = cfpkt_append(pkt, tail_pkt, 0);
+
+                               /* Start search for next STX if frame failed */
+                               continue;
+                       } else {
+                               cfpkt_destroy(pkt);
+                               pkt = NULL;
+                       }
+               }
+
+               pkt = tail_pkt;
+
+       } while (pkt != NULL);
+
+       spin_unlock(&layr->sync);
+       return 0;
+}
+
+static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt)
+{
+       struct cfserl *layr = container_obj(layer);
+       int ret;
+       u8 tmp8 = CFSERL_STX;
+       if (layr->usestx)
+               cfpkt_add_head(newpkt, &tmp8, 1);
+       ret = layer->dn->transmit(layer->dn, newpkt);
+       if (ret < 0)
+               cfpkt_extr_head(newpkt, &tmp8, 1);
+
+       return ret;
+}
+
+static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                               int phyid)
+{
+       layr->up->ctrlcmd(layr->up, ctrl, phyid);
+}
diff --git a/net/caif/cfsrvl.c b/net/caif/cfsrvl.c
new file mode 100644 (file)
index 0000000..aff31f3
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+#define SRVL_CTRL_PKT_SIZE 1
+#define SRVL_FLOW_OFF 0x81
+#define SRVL_FLOW_ON  0x80
+#define SRVL_SET_PIN  0x82
+#define SRVL_CTRL_PKT_SIZE 1
+
+#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
+
+static void cfservl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl,
+                               int phyid)
+{
+       struct cfsrvl *service = container_obj(layr);
+       caif_assert(layr->up != NULL);
+       caif_assert(layr->up->ctrlcmd != NULL);
+       switch (ctrl) {
+       case CAIF_CTRLCMD_INIT_RSP:
+               service->open = true;
+               layr->up->ctrlcmd(layr->up, ctrl, phyid);
+               break;
+       case CAIF_CTRLCMD_DEINIT_RSP:
+       case CAIF_CTRLCMD_INIT_FAIL_RSP:
+               service->open = false;
+               layr->up->ctrlcmd(layr->up, ctrl, phyid);
+               break;
+       case _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND:
+               if (phyid != service->dev_info.id)
+                       break;
+               if (service->modem_flow_on)
+                       layr->up->ctrlcmd(layr->up,
+                                         CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
+               service->phy_flow_on = false;
+               break;
+       case _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND:
+               if (phyid != service->dev_info.id)
+                       return;
+               if (service->modem_flow_on) {
+                       layr->up->ctrlcmd(layr->up,
+                                          CAIF_CTRLCMD_FLOW_ON_IND,
+                                          phyid);
+               }
+               service->phy_flow_on = true;
+               break;
+       case CAIF_CTRLCMD_FLOW_OFF_IND:
+               if (service->phy_flow_on) {
+                       layr->up->ctrlcmd(layr->up,
+                                         CAIF_CTRLCMD_FLOW_OFF_IND, phyid);
+               }
+               service->modem_flow_on = false;
+               break;
+       case CAIF_CTRLCMD_FLOW_ON_IND:
+               if (service->phy_flow_on) {
+                       layr->up->ctrlcmd(layr->up,
+                                         CAIF_CTRLCMD_FLOW_ON_IND, phyid);
+               }
+               service->modem_flow_on = true;
+               break;
+       case _CAIF_CTRLCMD_PHYIF_DOWN_IND:
+               /* In case interface is down, let's fake a remove shutdown */
+               layr->up->ctrlcmd(layr->up,
+                               CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, phyid);
+               break;
+       case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+               layr->up->ctrlcmd(layr->up, ctrl, phyid);
+               break;
+       default:
+               pr_warning("CAIF: %s(): "
+                          "Unexpected ctrl in cfsrvl (%d)\n", __func__, ctrl);
+               /* We have both modem and phy flow on, send flow on */
+               layr->up->ctrlcmd(layr->up, ctrl, phyid);
+               service->phy_flow_on = true;
+               break;
+       }
+}
+
+static int cfservl_modemcmd(struct cflayer *layr, enum caif_modemcmd ctrl)
+{
+       struct cfsrvl *service = container_obj(layr);
+       caif_assert(layr != NULL);
+       caif_assert(layr->dn != NULL);
+       caif_assert(layr->dn->transmit != NULL);
+       switch (ctrl) {
+       case CAIF_MODEMCMD_FLOW_ON_REQ:
+               {
+                       struct cfpkt *pkt;
+                       struct caif_payload_info *info;
+                       u8 flow_on = SRVL_FLOW_ON;
+                       pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+                       if (!pkt) {
+                               pr_warning("CAIF: %s(): Out of memory\n",
+                                       __func__);
+                               return -ENOMEM;
+                       }
+
+                       if (cfpkt_add_head(pkt, &flow_on, 1) < 0) {
+                               pr_err("CAIF: %s(): Packet is erroneous!\n",
+                                       __func__);
+                               cfpkt_destroy(pkt);
+                               return -EPROTO;
+                       }
+                       info = cfpkt_info(pkt);
+                       info->channel_id = service->layer.id;
+                       info->hdr_len = 1;
+                       info->dev_info = &service->dev_info;
+                       return layr->dn->transmit(layr->dn, pkt);
+               }
+       case CAIF_MODEMCMD_FLOW_OFF_REQ:
+               {
+                       struct cfpkt *pkt;
+                       struct caif_payload_info *info;
+                       u8 flow_off = SRVL_FLOW_OFF;
+                       pkt = cfpkt_create(SRVL_CTRL_PKT_SIZE);
+                       if (cfpkt_add_head(pkt, &flow_off, 1) < 0) {
+                               pr_err("CAIF: %s(): Packet is erroneous!\n",
+                                       __func__);
+                               cfpkt_destroy(pkt);
+                               return -EPROTO;
+                       }
+                       info = cfpkt_info(pkt);
+                       info->channel_id = service->layer.id;
+                       info->hdr_len = 1;
+                       info->dev_info = &service->dev_info;
+                       return layr->dn->transmit(layr->dn, pkt);
+               }
+       default:
+         break;
+       }
+       return -EINVAL;
+}
+
+void cfservl_destroy(struct cflayer *layer)
+{
+       kfree(layer);
+}
+
+void cfsrvl_init(struct cfsrvl *service,
+                u8 channel_id,
+                struct dev_info *dev_info)
+{
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+       service->open = false;
+       service->modem_flow_on = true;
+       service->phy_flow_on = true;
+       service->layer.id = channel_id;
+       service->layer.ctrlcmd = cfservl_ctrlcmd;
+       service->layer.modemcmd = cfservl_modemcmd;
+       service->dev_info = *dev_info;
+       kref_init(&service->ref);
+}
+
+void cfsrvl_release(struct kref *kref)
+{
+       struct cfsrvl *service = container_of(kref, struct cfsrvl, ref);
+       kfree(service);
+}
+
+bool cfsrvl_ready(struct cfsrvl *service, int *err)
+{
+       if (service->open && service->modem_flow_on && service->phy_flow_on)
+               return true;
+       if (!service->open) {
+               *err = -ENOTCONN;
+               return false;
+       }
+       caif_assert(!(service->modem_flow_on && service->phy_flow_on));
+       *err = -EAGAIN;
+       return false;
+}
+u8 cfsrvl_getphyid(struct cflayer *layer)
+{
+       struct cfsrvl *servl = container_obj(layer);
+       return servl->dev_info.id;
+}
+
+bool cfsrvl_phyid_match(struct cflayer *layer, int phyid)
+{
+       struct cfsrvl *servl = container_obj(layer);
+       return servl->dev_info.id == phyid;
+}
diff --git a/net/caif/cfutill.c b/net/caif/cfutill.c
new file mode 100644 (file)
index 0000000..5fd2c9e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+#define container_obj(layr) ((struct cfsrvl *) layr)
+#define UTIL_PAYLOAD  0x00
+#define UTIL_CMD_BIT  0x80
+#define UTIL_REMOTE_SHUTDOWN 0x82
+#define UTIL_FLOW_OFF 0x81
+#define UTIL_FLOW_ON  0x80
+#define UTIL_CTRL_PKT_SIZE 1
+static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt);
+
+struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
+{
+       struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+       if (!util) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+       memset(util, 0, sizeof(struct cfsrvl));
+       cfsrvl_init(util, channel_id, dev_info);
+       util->layer.receive = cfutill_receive;
+       util->layer.transmit = cfutill_transmit;
+       snprintf(util->layer.name, CAIF_LAYER_NAME_SZ - 1, "util1");
+       return &util->layer;
+}
+
+static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 cmd = -1;
+       struct cfsrvl *service = container_obj(layr);
+       caif_assert(layr != NULL);
+       caif_assert(layr->up != NULL);
+       caif_assert(layr->up->receive != NULL);
+       caif_assert(layr->up->ctrlcmd != NULL);
+       if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+
+       switch (cmd) {
+       case UTIL_PAYLOAD:
+               return layr->up->receive(layr->up, pkt);
+       case UTIL_FLOW_OFF:
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+               cfpkt_destroy(pkt);
+               return 0;
+       case UTIL_FLOW_ON:
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+               cfpkt_destroy(pkt);
+               return 0;
+       case UTIL_REMOTE_SHUTDOWN:      /* Remote Shutdown Request */
+               pr_err("CAIF: %s(): REMOTE SHUTDOWN REQUEST RECEIVED\n",
+                       __func__);
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
+               service->open = false;
+               cfpkt_destroy(pkt);
+               return 0;
+       default:
+               cfpkt_destroy(pkt);
+               pr_warning("CAIF: %s(): Unknown service control %d (0x%x)\n",
+                          __func__, cmd, cmd);
+               return -EPROTO;
+       }
+}
+
+static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 zero = 0;
+       struct caif_payload_info *info;
+       int ret;
+       struct cfsrvl *service = container_obj(layr);
+       caif_assert(layr != NULL);
+       caif_assert(layr->dn != NULL);
+       caif_assert(layr->dn->transmit != NULL);
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+               pr_err("CAIF: %s(): packet too large size=%d\n",
+                       __func__, cfpkt_getlen(pkt));
+               return -EOVERFLOW;
+       }
+
+       cfpkt_add_head(pkt, &zero, 1);
+       /* Add info for MUX-layer to route the packet out. */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       /*
+        * To optimize alignment, we add up the size of CAIF header before
+        * payload.
+        */
+       info->hdr_len = 1;
+       info->dev_info = &service->dev_info;
+       ret = layr->dn->transmit(layr->dn, pkt);
+       if (ret < 0) {
+               u32 tmp32;
+               cfpkt_extr_head(pkt, &tmp32, 4);
+       }
+       return ret;
+}
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c
new file mode 100644 (file)
index 0000000..0fd827f
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+#define VEI_PAYLOAD  0x00
+#define VEI_CMD_BIT  0x80
+#define VEI_FLOW_OFF 0x81
+#define VEI_FLOW_ON  0x80
+#define VEI_SET_PIN  0x82
+#define VEI_CTRL_PKT_SIZE 1
+#define container_obj(layr) container_of(layr, struct cfsrvl, layer)
+
+static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt);
+
+struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info)
+{
+       struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+       if (!vei) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+       memset(vei, 0, sizeof(struct cfsrvl));
+       cfsrvl_init(vei, channel_id, dev_info);
+       vei->layer.receive = cfvei_receive;
+       vei->layer.transmit = cfvei_transmit;
+       snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ - 1, "vei%d", channel_id);
+       return &vei->layer;
+}
+
+static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 cmd;
+       int ret;
+       caif_assert(layr->up != NULL);
+       caif_assert(layr->receive != NULL);
+       caif_assert(layr->ctrlcmd != NULL);
+
+
+       if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+       switch (cmd) {
+       case VEI_PAYLOAD:
+               ret = layr->up->receive(layr->up, pkt);
+               return ret;
+       case VEI_FLOW_OFF:
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
+               cfpkt_destroy(pkt);
+               return 0;
+       case VEI_FLOW_ON:
+               layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
+               cfpkt_destroy(pkt);
+               return 0;
+       case VEI_SET_PIN:       /* SET RS232 PIN */
+               cfpkt_destroy(pkt);
+               return 0;
+       default:                /* SET RS232 PIN */
+               pr_warning("CAIF: %s():Unknown VEI control packet %d (0x%x)!\n",
+                          __func__, cmd, cmd);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+}
+
+static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u8 tmp = 0;
+       struct caif_payload_info *info;
+       int ret;
+       struct cfsrvl *service = container_obj(layr);
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+       caif_assert(layr->dn != NULL);
+       caif_assert(layr->dn->transmit != NULL);
+       if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) {
+               pr_warning("CAIF: %s(): Packet too large - size=%d\n",
+                          __func__, cfpkt_getlen(pkt));
+               return -EOVERFLOW;
+       }
+
+       if (cfpkt_add_head(pkt, &tmp, 1) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               return -EPROTO;
+       }
+
+       /* Add info-> for MUX-layer to route the packet out. */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       info->hdr_len = 1;
+       info->dev_info = &service->dev_info;
+       ret = layr->dn->transmit(layr->dn, pkt);
+       if (ret < 0)
+               cfpkt_extr_head(pkt, &tmp, 1);
+       return ret;
+}
diff --git a/net/caif/cfvidl.c b/net/caif/cfvidl.c
new file mode 100644 (file)
index 0000000..89ad4ea
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Author:     Sjur Brendeland/sjur.brandeland@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfsrvl.h>
+#include <net/caif/cfpkt.h>
+
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
+static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt);
+static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt);
+
+struct cflayer *cfvidl_create(u8 channel_id, struct dev_info *dev_info)
+{
+       struct cfsrvl *vid = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
+       if (!vid) {
+               pr_warning("CAIF: %s(): Out of memory\n", __func__);
+               return NULL;
+       }
+       caif_assert(offsetof(struct cfsrvl, layer) == 0);
+
+       memset(vid, 0, sizeof(struct cfsrvl));
+       cfsrvl_init(vid, channel_id, dev_info);
+       vid->layer.receive = cfvidl_receive;
+       vid->layer.transmit = cfvidl_transmit;
+       snprintf(vid->layer.name, CAIF_LAYER_NAME_SZ - 1, "vid1");
+       return &vid->layer;
+}
+
+static int cfvidl_receive(struct cflayer *layr, struct cfpkt *pkt)
+{
+       u32 videoheader;
+       if (cfpkt_extr_head(pkt, &videoheader, 4) < 0) {
+               pr_err("CAIF: %s(): Packet is erroneous!\n", __func__);
+               cfpkt_destroy(pkt);
+               return -EPROTO;
+       }
+       return layr->up->receive(layr->up, pkt);
+}
+
+static int cfvidl_transmit(struct cflayer *layr, struct cfpkt *pkt)
+{
+       struct cfsrvl *service = container_obj(layr);
+       struct caif_payload_info *info;
+       u32 videoheader = 0;
+       int ret;
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+       cfpkt_add_head(pkt, &videoheader, 4);
+       /* Add info for MUX-layer to route the packet out */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       info->dev_info = &service->dev_info;
+       ret = layr->dn->transmit(layr->dn, pkt);
+       if (ret < 0)
+               cfpkt_extr_head(pkt, &videoheader, 4);
+       return ret;
+}
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
new file mode 100644 (file)
index 0000000..610966a
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Authors:    Sjur Brendeland/sjur.brandeland@stericsson.com
+ *             Daniel Martensson / Daniel.Martensson@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/if_ether.h>
+#include <linux/moduleparam.h>
+#include <linux/ip.h>
+#include <linux/sched.h>
+#include <linux/sockios.h>
+#include <linux/caif/if_caif.h>
+#include <net/rtnetlink.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/cfcnfg.h>
+#include <net/caif/cfpkt.h>
+#include <net/caif/caif_dev.h>
+
+/* GPRS PDP connection has MTU to 1500 */
+#define SIZE_MTU 1500
+/* 5 sec. connect timeout */
+#define CONNECT_TIMEOUT (5 * HZ)
+#define CAIF_NET_DEFAULT_QUEUE_LEN 500
+
+#undef pr_debug
+#define pr_debug pr_warning
+
+/*This list is protected by the rtnl lock. */
+static LIST_HEAD(chnl_net_list);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("caif");
+
+enum caif_states {
+       CAIF_CONNECTED          = 1,
+       CAIF_CONNECTING,
+       CAIF_DISCONNECTED,
+       CAIF_SHUTDOWN
+};
+
+struct chnl_net {
+       struct cflayer chnl;
+       struct net_device_stats stats;
+       struct caif_connect_request conn_req;
+       struct list_head list_field;
+       struct net_device *netdev;
+       char name[256];
+       wait_queue_head_t netmgmt_wq;
+       /* Flow status to remember and control the transmission. */
+       bool flowenabled;
+       enum caif_states state;
+};
+
+static void robust_list_del(struct list_head *delete_node)
+{
+       struct list_head *list_node;
+       struct list_head *n;
+       ASSERT_RTNL();
+       list_for_each_safe(list_node, n, &chnl_net_list) {
+               if (list_node == delete_node) {
+                       list_del(list_node);
+                       return;
+               }
+       }
+       WARN_ON(1);
+}
+
+static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
+{
+       struct sk_buff *skb;
+       struct chnl_net *priv  = container_of(layr, struct chnl_net, chnl);
+       int pktlen;
+       int err = 0;
+
+       priv = container_of(layr, struct chnl_net, chnl);
+
+       if (!priv)
+               return -EINVAL;
+
+       /* Get length of CAIF packet. */
+       pktlen = cfpkt_getlen(pkt);
+
+       skb = (struct sk_buff *) cfpkt_tonative(pkt);
+       /* Pass some minimum information and
+        * send the packet to the net stack.
+        */
+       skb->dev = priv->netdev;
+       skb->protocol = htons(ETH_P_IP);
+
+       /* If we change the header in loop mode, the checksum is corrupted. */
+       if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       else
+               skb->ip_summed = CHECKSUM_NONE;
+
+       if (in_interrupt())
+               netif_rx(skb);
+       else
+               netif_rx_ni(skb);
+
+       /* Update statistics. */
+       priv->netdev->stats.rx_packets++;
+       priv->netdev->stats.rx_bytes += pktlen;
+
+       return err;
+}
+
+static int delete_device(struct chnl_net *dev)
+{
+       ASSERT_RTNL();
+       if (dev->netdev)
+               unregister_netdevice(dev->netdev);
+       return 0;
+}
+
+static void close_work(struct work_struct *work)
+{
+       struct chnl_net *dev = NULL;
+       struct list_head *list_node;
+       struct list_head *_tmp;
+       /* May be called with or without RTNL lock held */
+       int islocked = rtnl_is_locked();
+       if (!islocked)
+               rtnl_lock();
+       list_for_each_safe(list_node, _tmp, &chnl_net_list) {
+               dev = list_entry(list_node, struct chnl_net, list_field);
+               if (dev->state == CAIF_SHUTDOWN)
+                       dev_close(dev->netdev);
+       }
+       if (!islocked)
+               rtnl_unlock();
+}
+static DECLARE_WORK(close_worker, close_work);
+
+static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
+                               int phyid)
+{
+       struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
+       pr_debug("CAIF: %s(): NET flowctrl func called flow: %s\n",
+               __func__,
+               flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
+               flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
+               flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
+               flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" :
+               flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" :
+               flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ?
+                "REMOTE_SHUTDOWN" : "UKNOWN CTRL COMMAND");
+
+
+
+       switch (flow) {
+       case CAIF_CTRLCMD_FLOW_OFF_IND:
+               priv->flowenabled = false;
+               netif_stop_queue(priv->netdev);
+               break;
+       case CAIF_CTRLCMD_DEINIT_RSP:
+               priv->state = CAIF_DISCONNECTED;
+               break;
+       case CAIF_CTRLCMD_INIT_FAIL_RSP:
+               priv->state = CAIF_DISCONNECTED;
+               wake_up_interruptible(&priv->netmgmt_wq);
+               break;
+       case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
+               priv->state = CAIF_SHUTDOWN;
+               netif_tx_disable(priv->netdev);
+               schedule_work(&close_worker);
+               break;
+       case CAIF_CTRLCMD_FLOW_ON_IND:
+               priv->flowenabled = true;
+               netif_wake_queue(priv->netdev);
+               break;
+       case CAIF_CTRLCMD_INIT_RSP:
+               priv->state = CAIF_CONNECTED;
+               priv->flowenabled = true;
+               netif_wake_queue(priv->netdev);
+               wake_up_interruptible(&priv->netmgmt_wq);
+               break;
+       default:
+               break;
+       }
+}
+
+static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct chnl_net *priv;
+       struct cfpkt *pkt = NULL;
+       int len;
+       int result = -1;
+       /* Get our private data. */
+       priv = netdev_priv(dev);
+
+       if (skb->len > priv->netdev->mtu) {
+               pr_warning("CAIF: %s(): Size of skb exceeded MTU\n", __func__);
+               return -ENOSPC;
+       }
+
+       if (!priv->flowenabled) {
+               pr_debug("CAIF: %s(): dropping packets flow off\n", __func__);
+               return NETDEV_TX_BUSY;
+       }
+
+       if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
+               swap(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
+
+       /* Store original SKB length. */
+       len = skb->len;
+
+       pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
+
+       /* Send the packet down the stack. */
+       result = priv->chnl.dn->transmit(priv->chnl.dn, pkt);
+       if (result) {
+               if (result == -EAGAIN)
+                       result = NETDEV_TX_BUSY;
+               return result;
+       }
+
+       /* Update statistics. */
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += len;
+
+       return NETDEV_TX_OK;
+}
+
+static int chnl_net_open(struct net_device *dev)
+{
+       struct chnl_net *priv = NULL;
+       int result = -1;
+       ASSERT_RTNL();
+       priv = netdev_priv(dev);
+       if (!priv) {
+               pr_debug("CAIF: %s(): chnl_net_open: no priv\n", __func__);
+               return -ENODEV;
+       }
+
+       if (priv->state != CAIF_CONNECTING) {
+               priv->state = CAIF_CONNECTING;
+               result = caif_connect_client(&priv->conn_req, &priv->chnl);
+               if (result != 0) {
+                               priv->state = CAIF_DISCONNECTED;
+                               pr_debug("CAIF: %s(): err: "
+                                       "Unable to register and open device,"
+                                       " Err:%d\n",
+                                       __func__,
+                                       result);
+                               return result;
+               }
+       }
+
+       result = wait_event_interruptible_timeout(priv->netmgmt_wq,
+                                               priv->state != CAIF_CONNECTING,
+                                               CONNECT_TIMEOUT);
+
+       if (result == -ERESTARTSYS) {
+               pr_debug("CAIF: %s(): wait_event_interruptible"
+                        " woken by a signal\n", __func__);
+               return -ERESTARTSYS;
+       }
+       if (result == 0) {
+               pr_debug("CAIF: %s(): connect timeout\n", __func__);
+               caif_disconnect_client(&priv->chnl);
+               priv->state = CAIF_DISCONNECTED;
+               pr_debug("CAIF: %s(): state disconnected\n", __func__);
+               return -ETIMEDOUT;
+       }
+
+       if (priv->state != CAIF_CONNECTED) {
+               pr_debug("CAIF: %s(): connect failed\n", __func__);
+               return -ECONNREFUSED;
+       }
+       pr_debug("CAIF: %s(): CAIF Netdevice connected\n", __func__);
+       return 0;
+}
+
+static int chnl_net_stop(struct net_device *dev)
+{
+       struct chnl_net *priv;
+
+       ASSERT_RTNL();
+       priv = netdev_priv(dev);
+       priv->state = CAIF_DISCONNECTED;
+       caif_disconnect_client(&priv->chnl);
+       return 0;
+}
+
+static int chnl_net_init(struct net_device *dev)
+{
+       struct chnl_net *priv;
+       ASSERT_RTNL();
+       priv = netdev_priv(dev);
+       strncpy(priv->name, dev->name, sizeof(priv->name));
+       return 0;
+}
+
+static void chnl_net_uninit(struct net_device *dev)
+{
+       struct chnl_net *priv;
+       ASSERT_RTNL();
+       priv = netdev_priv(dev);
+       robust_list_del(&priv->list_field);
+}
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_open = chnl_net_open,
+       .ndo_stop = chnl_net_stop,
+       .ndo_init = chnl_net_init,
+       .ndo_uninit = chnl_net_uninit,
+       .ndo_start_xmit = chnl_net_start_xmit,
+};
+
+static void ipcaif_net_setup(struct net_device *dev)
+{
+       struct chnl_net *priv;
+       dev->netdev_ops = &netdev_ops;
+       dev->destructor = free_netdev;
+       dev->flags |= IFF_NOARP;
+       dev->flags |= IFF_POINTOPOINT;
+       dev->needed_headroom = CAIF_NEEDED_HEADROOM;
+       dev->needed_tailroom = CAIF_NEEDED_TAILROOM;
+       dev->mtu = SIZE_MTU;
+       dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
+
+       priv = netdev_priv(dev);
+       priv->chnl.receive = chnl_recv_cb;
+       priv->chnl.ctrlcmd = chnl_flowctrl_cb;
+       priv->netdev = dev;
+       priv->conn_req.protocol = CAIFPROTO_DATAGRAM;
+       priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
+       priv->conn_req.priority = CAIF_PRIO_LOW;
+       /* Insert illegal value */
+       priv->conn_req.sockaddr.u.dgm.connection_id = -1;
+       priv->flowenabled = false;
+
+       ASSERT_RTNL();
+       init_waitqueue_head(&priv->netmgmt_wq);
+       list_add(&priv->list_field, &chnl_net_list);
+}
+
+
+static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct chnl_net *priv;
+       u8 loop;
+       priv = netdev_priv(dev);
+       NLA_PUT_U32(skb, IFLA_CAIF_IPV4_CONNID,
+                   priv->conn_req.sockaddr.u.dgm.connection_id);
+       NLA_PUT_U32(skb, IFLA_CAIF_IPV6_CONNID,
+                   priv->conn_req.sockaddr.u.dgm.connection_id);
+       loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP;
+       NLA_PUT_U8(skb, IFLA_CAIF_LOOPBACK, loop);
+
+
+       return 0;
+nla_put_failure:
+       return -EMSGSIZE;
+
+}
+
+static void caif_netlink_parms(struct nlattr *data[],
+                               struct caif_connect_request *conn_req)
+{
+       if (!data) {
+               pr_warning("CAIF: %s: no params data found\n", __func__);
+               return;
+       }
+       if (data[IFLA_CAIF_IPV4_CONNID])
+               conn_req->sockaddr.u.dgm.connection_id =
+                       nla_get_u32(data[IFLA_CAIF_IPV4_CONNID]);
+       if (data[IFLA_CAIF_IPV6_CONNID])
+               conn_req->sockaddr.u.dgm.connection_id =
+                       nla_get_u32(data[IFLA_CAIF_IPV6_CONNID]);
+       if (data[IFLA_CAIF_LOOPBACK]) {
+               if (nla_get_u8(data[IFLA_CAIF_LOOPBACK]))
+                       conn_req->protocol = CAIFPROTO_DATAGRAM_LOOP;
+               else
+                       conn_req->protocol = CAIFPROTO_DATAGRAM;
+       }
+}
+
+static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[])
+{
+       int ret;
+       struct chnl_net *caifdev;
+       ASSERT_RTNL();
+       caifdev = netdev_priv(dev);
+       caif_netlink_parms(data, &caifdev->conn_req);
+       dev_net_set(caifdev->netdev, src_net);
+
+       ret = register_netdevice(dev);
+       if (ret)
+               pr_warning("CAIF: %s(): device rtml registration failed\n",
+                          __func__);
+       return ret;
+}
+
+static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
+                               struct nlattr *data[])
+{
+       struct chnl_net *caifdev;
+       ASSERT_RTNL();
+       caifdev = netdev_priv(dev);
+       caif_netlink_parms(data, &caifdev->conn_req);
+       netdev_state_change(dev);
+       return 0;
+}
+
+static size_t ipcaif_get_size(const struct net_device *dev)
+{
+       return
+               /* IFLA_CAIF_IPV4_CONNID */
+               nla_total_size(4) +
+               /* IFLA_CAIF_IPV6_CONNID */
+               nla_total_size(4) +
+               /* IFLA_CAIF_LOOPBACK */
+               nla_total_size(2) +
+               0;
+}
+
+static const struct nla_policy ipcaif_policy[IFLA_CAIF_MAX + 1] = {
+       [IFLA_CAIF_IPV4_CONNID]       = { .type = NLA_U32 },
+       [IFLA_CAIF_IPV6_CONNID]       = { .type = NLA_U32 },
+       [IFLA_CAIF_LOOPBACK]          = { .type = NLA_U8 }
+};
+
+
+static struct rtnl_link_ops ipcaif_link_ops __read_mostly = {
+       .kind           = "caif",
+       .priv_size      = sizeof(struct chnl_net),
+       .setup          = ipcaif_net_setup,
+       .maxtype        = IFLA_CAIF_MAX,
+       .policy         = ipcaif_policy,
+       .newlink        = ipcaif_newlink,
+       .changelink     = ipcaif_changelink,
+       .get_size       = ipcaif_get_size,
+       .fill_info      = ipcaif_fill_info,
+
+};
+
+static int __init chnl_init_module(void)
+{
+       return rtnl_link_register(&ipcaif_link_ops);
+}
+
+static void __exit chnl_exit_module(void)
+{
+       struct chnl_net *dev = NULL;
+       struct list_head *list_node;
+       struct list_head *_tmp;
+       rtnl_link_unregister(&ipcaif_link_ops);
+       rtnl_lock();
+       list_for_each_safe(list_node, _tmp, &chnl_net_list) {
+               dev = list_entry(list_node, struct chnl_net, list_field);
+               list_del(list_node);
+               delete_device(dev);
+       }
+       rtnl_unlock();
+}
+
+module_init(chnl_init_module);
+module_exit(chnl_exit_module);
index 907dc871fac8bcf5e6d3cbce2c79f9a53706ccfa..9c65e9deb9c3ff6d6f958f4b52ee7e85d6299935 100644 (file)
@@ -713,8 +713,6 @@ static void bcm_remove_op(struct bcm_op *op)
                kfree(op->last_frames);
 
        kfree(op);
-
-       return;
 }
 
 static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
index 08791ac3e05adcde7f36c54daf66b573e1921d71..51c3eec850ef426bc2614f309ad08182b595df69 100644 (file)
@@ -7,7 +7,7 @@ obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
-obj-y               += dev.o ethtool.o dev_mcast.o dst.o netevent.o \
+obj-y               += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
                        neighbour.o rtnetlink.o utils.o link_watch.o filter.o
 
 obj-$(CONFIG_XFRM) += flow.o
index 2dccd4ee591b3a755242c05b8889489a380dc8bd..e0097531417aeeced3650a7f166ac648ae2fa798 100644 (file)
@@ -86,7 +86,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
        int error;
        DEFINE_WAIT_FUNC(wait, receiver_wake_function);
 
-       prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
        /* Socket errors? */
        error = sock_error(sk);
@@ -115,7 +115,7 @@ static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
        error = 0;
        *timeo_p = schedule_timeout(*timeo_p);
 out:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return error;
 interrupted:
        error = sock_intr_errno(*timeo_p);
@@ -229,9 +229,18 @@ EXPORT_SYMBOL(skb_free_datagram);
 
 void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
 {
-       lock_sock(sk);
-       skb_free_datagram(sk, skb);
-       release_sock(sk);
+       if (likely(atomic_read(&skb->users) == 1))
+               smp_rmb();
+       else if (likely(!atomic_dec_and_test(&skb->users)))
+               return;
+
+       lock_sock_bh(sk);
+       skb_orphan(skb);
+       sk_mem_reclaim_partial(sk);
+       unlock_sock_bh(sk);
+
+       /* skb is now orphaned, can be freed outside of locked section */
+       __kfree_skb(skb);
 }
 EXPORT_SYMBOL(skb_free_datagram_locked);
 
@@ -726,7 +735,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* exceptional events? */
index 264137fce3a25496c349b141b8276d6900f80412..6c820650b80fbe63105303eed14d92fc0115a5a8 100644 (file)
 #include <linux/jhash.h>
 #include <linux/random.h>
 #include <trace/events/napi.h>
+#include <linux/pci.h>
 
 #include "net-sysfs.h"
 
@@ -207,6 +208,20 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
        return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)];
 }
 
+static inline void rps_lock(struct softnet_data *sd)
+{
+#ifdef CONFIG_RPS
+       spin_lock(&sd->input_pkt_queue.lock);
+#endif
+}
+
+static inline void rps_unlock(struct softnet_data *sd)
+{
+#ifdef CONFIG_RPS
+       spin_unlock(&sd->input_pkt_queue.lock);
+#endif
+}
+
 /* Device list insertion */
 static int list_netdevice(struct net_device *dev)
 {
@@ -249,7 +264,7 @@ static RAW_NOTIFIER_HEAD(netdev_chain);
  *     queue in the local softnet handler.
  */
 
-DEFINE_PER_CPU(struct softnet_data, softnet_data);
+DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data);
 EXPORT_PER_CPU_SYMBOL(softnet_data);
 
 #ifdef CONFIG_LOCKDEP
@@ -773,14 +788,17 @@ EXPORT_SYMBOL(__dev_getfirstbyhwtype);
 
 struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
 {
-       struct net_device *dev;
+       struct net_device *dev, *ret = NULL;
 
-       rtnl_lock();
-       dev = __dev_getfirstbyhwtype(net, type);
-       if (dev)
-               dev_hold(dev);
-       rtnl_unlock();
-       return dev;
+       rcu_read_lock();
+       for_each_netdev_rcu(net, dev)
+               if (dev->type == type) {
+                       dev_hold(dev);
+                       ret = dev;
+                       break;
+               }
+       rcu_read_unlock();
+       return ret;
 }
 EXPORT_SYMBOL(dev_getfirstbyhwtype);
 
@@ -1085,9 +1103,9 @@ void netdev_state_change(struct net_device *dev)
 }
 EXPORT_SYMBOL(netdev_state_change);
 
-void netdev_bonding_change(struct net_device *dev, unsigned long event)
+int netdev_bonding_change(struct net_device *dev, unsigned long event)
 {
-       call_netdevice_notifiers(event, dev);
+       return call_netdevice_notifiers(event, dev);
 }
 EXPORT_SYMBOL(netdev_bonding_change);
 
@@ -1417,6 +1435,7 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
 
 int call_netdevice_notifiers(unsigned long val, struct net_device *dev)
 {
+       ASSERT_RTNL();
        return raw_notifier_call_chain(&netdev_chain, val, dev);
 }
 
@@ -1435,7 +1454,7 @@ void net_disable_timestamp(void)
 }
 EXPORT_SYMBOL(net_disable_timestamp);
 
-static inline void net_timestamp(struct sk_buff *skb)
+static inline void net_timestamp_set(struct sk_buff *skb)
 {
        if (atomic_read(&netstamp_needed))
                __net_timestamp(skb);
@@ -1443,6 +1462,12 @@ static inline void net_timestamp(struct sk_buff *skb)
                skb->tstamp.tv64 = 0;
 }
 
+static inline void net_timestamp_check(struct sk_buff *skb)
+{
+       if (!skb->tstamp.tv64 && atomic_read(&netstamp_needed))
+               __net_timestamp(skb);
+}
+
 /**
  * dev_forward_skb - loopback an skb to another netif
  *
@@ -1489,9 +1514,9 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 
 #ifdef CONFIG_NET_CLS_ACT
        if (!(skb->tstamp.tv64 && (G_TC_FROM(skb->tc_verd) & AT_INGRESS)))
-               net_timestamp(skb);
+               net_timestamp_set(skb);
 #else
-       net_timestamp(skb);
+       net_timestamp_set(skb);
 #endif
 
        rcu_read_lock();
@@ -1537,8 +1562,9 @@ static inline void __netif_reschedule(struct Qdisc *q)
 
        local_irq_save(flags);
        sd = &__get_cpu_var(softnet_data);
-       q->next_sched = sd->output_queue;
-       sd->output_queue = q;
+       q->next_sched = NULL;
+       *sd->output_queue_tailp = q;
+       sd->output_queue_tailp = &q->next_sched;
        raise_softirq_irqoff(NET_TX_SOFTIRQ);
        local_irq_restore(flags);
 }
@@ -1783,18 +1809,27 @@ EXPORT_SYMBOL(netdev_rx_csum_fault);
  * 2. No high memory really exists on this machine.
  */
 
-static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
+static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_HIGHMEM
        int i;
+       if (!(dev->features & NETIF_F_HIGHDMA)) {
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+                       if (PageHighMem(skb_shinfo(skb)->frags[i].page))
+                               return 1;
+       }
 
-       if (dev->features & NETIF_F_HIGHDMA)
-               return 0;
-
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
-               if (PageHighMem(skb_shinfo(skb)->frags[i].page))
-                       return 1;
+       if (PCI_DMA_BUS_IS_PHYS) {
+               struct device *pdev = dev->dev.parent;
 
+               if (!pdev)
+                       return 0;
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       dma_addr_t addr = page_to_phys(skb_shinfo(skb)->frags[i].page);
+                       if (!pdev->dma_mask || addr + PAGE_SIZE - 1 > *pdev->dma_mask)
+                               return 1;
+               }
+       }
 #endif
        return 0;
 }
@@ -1852,6 +1887,17 @@ static int dev_gso_segment(struct sk_buff *skb)
        return 0;
 }
 
+/*
+ * Try to orphan skb early, right before transmission by the device.
+ * We cannot orphan skb if tx timestamp is requested, since
+ * drivers need to call skb_tstamp_tx() to send the timestamp.
+ */
+static inline void skb_orphan_try(struct sk_buff *skb)
+{
+       if (!skb_tx(skb)->flags)
+               skb_orphan(skb);
+}
+
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        struct netdev_queue *txq)
 {
@@ -1862,13 +1908,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                if (!list_empty(&ptype_all))
                        dev_queue_xmit_nit(skb, dev);
 
-               if (netif_needs_gso(dev, skb)) {
-                       if (unlikely(dev_gso_segment(skb)))
-                               goto out_kfree_skb;
-                       if (skb->next)
-                               goto gso;
-               }
-
                /*
                 * If device doesnt need skb->dst, release it right now while
                 * its hot in this cpu cache
@@ -1876,23 +1915,18 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
                        skb_dst_drop(skb);
 
+               skb_orphan_try(skb);
+
+               if (netif_needs_gso(dev, skb)) {
+                       if (unlikely(dev_gso_segment(skb)))
+                               goto out_kfree_skb;
+                       if (skb->next)
+                               goto gso;
+               }
+
                rc = ops->ndo_start_xmit(skb, dev);
                if (rc == NETDEV_TX_OK)
                        txq_trans_update(txq);
-               /*
-                * TODO: if skb_orphan() was called by
-                * dev->hard_start_xmit() (for example, the unmodified
-                * igb driver does that; bnx2 doesn't), then
-                * skb_tx_software_timestamp() will be unable to send
-                * back the time stamp.
-                *
-                * How can this be prevented? Always create another
-                * reference to the socket before calling
-                * dev->hard_start_xmit()? Prevent that skb_orphan()
-                * does anything in dev->hard_start_xmit() by clearing
-                * the skb destructor before the call and restoring it
-                * afterwards, then doing the skb_orphan() ourselves?
-                */
                return rc;
        }
 
@@ -1931,7 +1965,7 @@ out_kfree_skb:
        return rc;
 }
 
-static u32 skb_tx_hashrnd;
+static u32 hashrnd __read_mostly;
 
 u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)
 {
@@ -1947,9 +1981,9 @@ u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)
        if (skb->sk && skb->sk->sk_hash)
                hash = skb->sk->sk_hash;
        else
-               hash = skb->protocol;
+               hash = (__force u16) skb->protocol;
 
-       hash = jhash_1word(hash, skb_tx_hashrnd);
+       hash = jhash_1word(hash, hashrnd);
 
        return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
 }
@@ -1959,10 +1993,9 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
 {
        if (unlikely(queue_index >= dev->real_num_tx_queues)) {
                if (net_ratelimit()) {
-                       WARN(1, "%s selects TX queue %d, but "
-                            "real number of TX queues is %d\n",
-                            dev->name, queue_index,
-                            dev->real_num_tx_queues);
+                       pr_warning("%s selects TX queue %d, but "
+                               "real number of TX queues is %d\n",
+                               dev->name, queue_index, dev->real_num_tx_queues);
                }
                return 0;
        }
@@ -1989,7 +2022,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
                                queue_index = skb_tx_hash(dev, skb);
 
                        if (sk) {
-                               struct dst_entry *dst = rcu_dereference_bh(sk->sk_dst_cache);
+                               struct dst_entry *dst = rcu_dereference_check(sk->sk_dst_cache, 1);
 
                                if (dst && skb_dst(skb) == dst)
                                        sk_tx_queue_set(sk, queue_index);
@@ -2019,6 +2052,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
                 * waiting to be sent out; and the qdisc is not running -
                 * xmit the skb directly.
                 */
+               if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
+                       skb_dst_force(skb);
                __qdisc_update_bstats(q, skb->len);
                if (sch_direct_xmit(skb, q, dev, txq, root_lock))
                        __qdisc_run(q);
@@ -2027,6 +2062,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
 
                rc = NET_XMIT_SUCCESS;
        } else {
+               skb_dst_force(skb);
                rc = qdisc_enqueue_root(skb, q);
                qdisc_run(q);
        }
@@ -2174,11 +2210,249 @@ EXPORT_SYMBOL(dev_queue_xmit);
   =======================================================================*/
 
 int netdev_max_backlog __read_mostly = 1000;
+int netdev_tstamp_prequeue __read_mostly = 1;
 int netdev_budget __read_mostly = 300;
 int weight_p __read_mostly = 64;            /* old backlog weight */
 
-DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
+/* Called with irq disabled */
+static inline void ____napi_schedule(struct softnet_data *sd,
+                                    struct napi_struct *napi)
+{
+       list_add_tail(&napi->poll_list, &sd->poll_list);
+       __raise_softirq_irqoff(NET_RX_SOFTIRQ);
+}
+
+#ifdef CONFIG_RPS
+
+/* One global table that all flow-based protocols share. */
+struct rps_sock_flow_table *rps_sock_flow_table __read_mostly;
+EXPORT_SYMBOL(rps_sock_flow_table);
+
+/*
+ * get_rps_cpu is called from netif_receive_skb and returns the target
+ * CPU from the RPS map of the receiving queue for a given skb.
+ * rcu_read_lock must be held on entry.
+ */
+static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
+                      struct rps_dev_flow **rflowp)
+{
+       struct ipv6hdr *ip6;
+       struct iphdr *ip;
+       struct netdev_rx_queue *rxqueue;
+       struct rps_map *map;
+       struct rps_dev_flow_table *flow_table;
+       struct rps_sock_flow_table *sock_flow_table;
+       int cpu = -1;
+       u8 ip_proto;
+       u16 tcpu;
+       u32 addr1, addr2, ihl;
+       union {
+               u32 v32;
+               u16 v16[2];
+       } ports;
+
+       if (skb_rx_queue_recorded(skb)) {
+               u16 index = skb_get_rx_queue(skb);
+               if (unlikely(index >= dev->num_rx_queues)) {
+                       if (net_ratelimit()) {
+                               pr_warning("%s received packet on queue "
+                                       "%u, but number of RX queues is %u\n",
+                                       dev->name, index, dev->num_rx_queues);
+                       }
+                       goto done;
+               }
+               rxqueue = dev->_rx + index;
+       } else
+               rxqueue = dev->_rx;
+
+       if (!rxqueue->rps_map && !rxqueue->rps_flow_table)
+               goto done;
+
+       if (skb->rxhash)
+               goto got_hash; /* Skip hash computation on packet header */
+
+       switch (skb->protocol) {
+       case __constant_htons(ETH_P_IP):
+               if (!pskb_may_pull(skb, sizeof(*ip)))
+                       goto done;
+
+               ip = (struct iphdr *) skb->data;
+               ip_proto = ip->protocol;
+               addr1 = (__force u32) ip->saddr;
+               addr2 = (__force u32) ip->daddr;
+               ihl = ip->ihl;
+               break;
+       case __constant_htons(ETH_P_IPV6):
+               if (!pskb_may_pull(skb, sizeof(*ip6)))
+                       goto done;
+
+               ip6 = (struct ipv6hdr *) skb->data;
+               ip_proto = ip6->nexthdr;
+               addr1 = (__force u32) ip6->saddr.s6_addr32[3];
+               addr2 = (__force u32) ip6->daddr.s6_addr32[3];
+               ihl = (40 >> 2);
+               break;
+       default:
+               goto done;
+       }
+       switch (ip_proto) {
+       case IPPROTO_TCP:
+       case IPPROTO_UDP:
+       case IPPROTO_DCCP:
+       case IPPROTO_ESP:
+       case IPPROTO_AH:
+       case IPPROTO_SCTP:
+       case IPPROTO_UDPLITE:
+               if (pskb_may_pull(skb, (ihl * 4) + 4)) {
+                       ports.v32 = * (__force u32 *) (skb->data + (ihl * 4));
+                       if (ports.v16[1] < ports.v16[0])
+                               swap(ports.v16[0], ports.v16[1]);
+                       break;
+               }
+       default:
+               ports.v32 = 0;
+               break;
+       }
+
+       /* get a consistent hash (same value on both flow directions) */
+       if (addr2 < addr1)
+               swap(addr1, addr2);
+       skb->rxhash = jhash_3words(addr1, addr2, ports.v32, hashrnd);
+       if (!skb->rxhash)
+               skb->rxhash = 1;
+
+got_hash:
+       flow_table = rcu_dereference(rxqueue->rps_flow_table);
+       sock_flow_table = rcu_dereference(rps_sock_flow_table);
+       if (flow_table && sock_flow_table) {
+               u16 next_cpu;
+               struct rps_dev_flow *rflow;
+
+               rflow = &flow_table->flows[skb->rxhash & flow_table->mask];
+               tcpu = rflow->cpu;
+
+               next_cpu = sock_flow_table->ents[skb->rxhash &
+                   sock_flow_table->mask];
+
+               /*
+                * If the desired CPU (where last recvmsg was done) is
+                * different from current CPU (one in the rx-queue flow
+                * table entry), switch if one of the following holds:
+                *   - Current CPU is unset (equal to RPS_NO_CPU).
+                *   - Current CPU is offline.
+                *   - The current CPU's queue tail has advanced beyond the
+                *     last packet that was enqueued using this table entry.
+                *     This guarantees that all previous packets for the flow
+                *     have been dequeued, thus preserving in order delivery.
+                */
+               if (unlikely(tcpu != next_cpu) &&
+                   (tcpu == RPS_NO_CPU || !cpu_online(tcpu) ||
+                    ((int)(per_cpu(softnet_data, tcpu).input_queue_head -
+                     rflow->last_qtail)) >= 0)) {
+                       tcpu = rflow->cpu = next_cpu;
+                       if (tcpu != RPS_NO_CPU)
+                               rflow->last_qtail = per_cpu(softnet_data,
+                                   tcpu).input_queue_head;
+               }
+               if (tcpu != RPS_NO_CPU && cpu_online(tcpu)) {
+                       *rflowp = rflow;
+                       cpu = tcpu;
+                       goto done;
+               }
+       }
+
+       map = rcu_dereference(rxqueue->rps_map);
+       if (map) {
+               tcpu = map->cpus[((u64) skb->rxhash * map->len) >> 32];
+
+               if (cpu_online(tcpu)) {
+                       cpu = tcpu;
+                       goto done;
+               }
+       }
+
+done:
+       return cpu;
+}
+
+/* Called from hardirq (IPI) context */
+static void rps_trigger_softirq(void *data)
+{
+       struct softnet_data *sd = data;
+
+       ____napi_schedule(sd, &sd->backlog);
+       sd->received_rps++;
+}
+
+#endif /* CONFIG_RPS */
+
+/*
+ * Check if this softnet_data structure is another cpu one
+ * If yes, queue it to our IPI list and return 1
+ * If no, return 0
+ */
+static int rps_ipi_queued(struct softnet_data *sd)
+{
+#ifdef CONFIG_RPS
+       struct softnet_data *mysd = &__get_cpu_var(softnet_data);
+
+       if (sd != mysd) {
+               sd->rps_ipi_next = mysd->rps_ipi_list;
+               mysd->rps_ipi_list = sd;
+
+               __raise_softirq_irqoff(NET_RX_SOFTIRQ);
+               return 1;
+       }
+#endif /* CONFIG_RPS */
+       return 0;
+}
+
+/*
+ * enqueue_to_backlog is called to queue an skb to a per CPU backlog
+ * queue (may be a remote CPU queue).
+ */
+static int enqueue_to_backlog(struct sk_buff *skb, int cpu,
+                             unsigned int *qtail)
+{
+       struct softnet_data *sd;
+       unsigned long flags;
+
+       sd = &per_cpu(softnet_data, cpu);
+
+       local_irq_save(flags);
+
+       rps_lock(sd);
+       if (skb_queue_len(&sd->input_pkt_queue) <= netdev_max_backlog) {
+               if (skb_queue_len(&sd->input_pkt_queue)) {
+enqueue:
+                       __skb_queue_tail(&sd->input_pkt_queue, skb);
+#ifdef CONFIG_RPS
+                       *qtail = sd->input_queue_head +
+                                       skb_queue_len(&sd->input_pkt_queue);
+#endif
+                       rps_unlock(sd);
+                       local_irq_restore(flags);
+                       return NET_RX_SUCCESS;
+               }
+
+               /* Schedule NAPI for backlog device
+                * We can use non atomic operation since we own the queue lock
+                */
+               if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) {
+                       if (!rps_ipi_queued(sd))
+                               ____napi_schedule(sd, &sd->backlog);
+               }
+               goto enqueue;
+       }
+
+       sd->dropped++;
+       rps_unlock(sd);
+
+       local_irq_restore(flags);
 
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
 
 /**
  *     netif_rx        -       post buffer to the network code
@@ -2197,41 +2471,38 @@ DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
 
 int netif_rx(struct sk_buff *skb)
 {
-       struct softnet_data *queue;
-       unsigned long flags;
+       int ret;
 
        /* if netpoll wants it, pretend we never saw it */
        if (netpoll_rx(skb))
                return NET_RX_DROP;
 
-       if (!skb->tstamp.tv64)
-               net_timestamp(skb);
+       if (netdev_tstamp_prequeue)
+               net_timestamp_check(skb);
 
-       /*
-        * The code is rearranged so that the path is the most
-        * short when CPU is congested, but is still operating.
-        */
-       local_irq_save(flags);
-       queue = &__get_cpu_var(softnet_data);
+#ifdef CONFIG_RPS
+       {
+               struct rps_dev_flow voidflow, *rflow = &voidflow;
+               int cpu;
 
-       __get_cpu_var(netdev_rx_stat).total++;
-       if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
-               if (queue->input_pkt_queue.qlen) {
-enqueue:
-                       __skb_queue_tail(&queue->input_pkt_queue, skb);
-                       local_irq_restore(flags);
-                       return NET_RX_SUCCESS;
-               }
+               rcu_read_lock();
 
-               napi_schedule(&queue->backlog);
-               goto enqueue;
-       }
+               cpu = get_rps_cpu(skb->dev, skb, &rflow);
+               if (cpu < 0)
+                       cpu = smp_processor_id();
 
-       __get_cpu_var(netdev_rx_stat).dropped++;
-       local_irq_restore(flags);
+               ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
 
-       kfree_skb(skb);
-       return NET_RX_DROP;
+               rcu_read_unlock();
+       }
+#else
+       {
+               unsigned int qtail;
+               ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
+               put_cpu();
+       }
+#endif
+       return ret;
 }
 EXPORT_SYMBOL(netif_rx);
 
@@ -2276,6 +2547,7 @@ static void net_tx_action(struct softirq_action *h)
                local_irq_disable();
                head = sd->output_queue;
                sd->output_queue = NULL;
+               sd->output_queue_tailp = &sd->output_queue;
                local_irq_enable();
 
                while (head) {
@@ -2352,7 +2624,8 @@ static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
 #endif
 
 #if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
-struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *skb) __read_mostly;
+struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *p,
+                                            struct sk_buff *skb) __read_mostly;
 EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
 
 static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
@@ -2360,14 +2633,17 @@ static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
                                             int *ret,
                                             struct net_device *orig_dev)
 {
-       if (skb->dev->macvlan_port == NULL)
+       struct macvlan_port *port;
+
+       port = rcu_dereference(skb->dev->macvlan_port);
+       if (!port)
                return skb;
 
        if (*pt_prev) {
                *ret = deliver_skb(skb, *pt_prev, orig_dev);
                *pt_prev = NULL;
        }
-       return macvlan_handle_frame_hook(skb);
+       return macvlan_handle_frame_hook(port, skb);
 }
 #else
 #define handle_macvlan(skb, pt_prev, ret, orig_dev)    (skb)
@@ -2468,22 +2744,56 @@ void netif_nit_deliver(struct sk_buff *skb)
        rcu_read_unlock();
 }
 
-/**
- *     netif_receive_skb - process receive buffer from network
- *     @skb: buffer to process
- *
- *     netif_receive_skb() is the main receive data processing function.
- *     It always succeeds. The buffer may be dropped during processing
- *     for congestion control or by the protocol layers.
- *
- *     This function may only be called from softirq context and interrupts
- *     should be enabled.
- *
- *     Return values (usually ignored):
- *     NET_RX_SUCCESS: no congestion
- *     NET_RX_DROP: packet was dropped
+static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
+                                             struct net_device *master)
+{
+       if (skb->pkt_type == PACKET_HOST) {
+               u16 *dest = (u16 *) eth_hdr(skb)->h_dest;
+
+               memcpy(dest, master->dev_addr, ETH_ALEN);
+       }
+}
+
+/* On bonding slaves other than the currently active slave, suppress
+ * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
+ * ARP on active-backup slaves with arp_validate enabled.
  */
-int netif_receive_skb(struct sk_buff *skb)
+int __skb_bond_should_drop(struct sk_buff *skb, struct net_device *master)
+{
+       struct net_device *dev = skb->dev;
+
+       if (master->priv_flags & IFF_MASTER_ARPMON)
+               dev->last_rx = jiffies;
+
+       if ((master->priv_flags & IFF_MASTER_ALB) && master->br_port) {
+               /* Do address unmangle. The local destination address
+                * will be always the one master has. Provides the right
+                * functionality in a bridge.
+                */
+               skb_bond_set_mac_by_master(skb, master);
+       }
+
+       if (dev->priv_flags & IFF_SLAVE_INACTIVE) {
+               if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
+                   skb->protocol == __cpu_to_be16(ETH_P_ARP))
+                       return 0;
+
+               if (master->priv_flags & IFF_MASTER_ALB) {
+                       if (skb->pkt_type != PACKET_BROADCAST &&
+                           skb->pkt_type != PACKET_MULTICAST)
+                               return 0;
+               }
+               if (master->priv_flags & IFF_MASTER_8023AD &&
+                   skb->protocol == __cpu_to_be16(ETH_P_SLOW))
+                       return 0;
+
+               return 1;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(__skb_bond_should_drop);
+
+static int __netif_receive_skb(struct sk_buff *skb)
 {
        struct packet_type *ptype, *pt_prev;
        struct net_device *orig_dev;
@@ -2493,8 +2803,8 @@ int netif_receive_skb(struct sk_buff *skb)
        int ret = NET_RX_DROP;
        __be16 type;
 
-       if (!skb->tstamp.tv64)
-               net_timestamp(skb);
+       if (!netdev_tstamp_prequeue)
+               net_timestamp_check(skb);
 
        if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb))
                return NET_RX_SUCCESS;
@@ -2516,7 +2826,7 @@ int netif_receive_skb(struct sk_buff *skb)
                        skb->dev = master;
        }
 
-       __get_cpu_var(netdev_rx_stat).total++;
+       __get_cpu_var(softnet_data).processed++;
 
        skb_reset_network_header(skb);
        skb_reset_transport_header(skb);
@@ -2594,20 +2904,77 @@ out:
        rcu_read_unlock();
        return ret;
 }
+
+/**
+ *     netif_receive_skb - process receive buffer from network
+ *     @skb: buffer to process
+ *
+ *     netif_receive_skb() is the main receive data processing function.
+ *     It always succeeds. The buffer may be dropped during processing
+ *     for congestion control or by the protocol layers.
+ *
+ *     This function may only be called from softirq context and interrupts
+ *     should be enabled.
+ *
+ *     Return values (usually ignored):
+ *     NET_RX_SUCCESS: no congestion
+ *     NET_RX_DROP: packet was dropped
+ */
+int netif_receive_skb(struct sk_buff *skb)
+{
+       if (netdev_tstamp_prequeue)
+               net_timestamp_check(skb);
+
+#ifdef CONFIG_RPS
+       {
+               struct rps_dev_flow voidflow, *rflow = &voidflow;
+               int cpu, ret;
+
+               rcu_read_lock();
+
+               cpu = get_rps_cpu(skb->dev, skb, &rflow);
+
+               if (cpu >= 0) {
+                       ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
+                       rcu_read_unlock();
+               } else {
+                       rcu_read_unlock();
+                       ret = __netif_receive_skb(skb);
+               }
+
+               return ret;
+       }
+#else
+       return __netif_receive_skb(skb);
+#endif
+}
 EXPORT_SYMBOL(netif_receive_skb);
 
-/* Network device is going away, flush any packets still pending  */
+/* Network device is going away, flush any packets still pending
+ * Called with irqs disabled.
+ */
 static void flush_backlog(void *arg)
 {
        struct net_device *dev = arg;
-       struct softnet_data *queue = &__get_cpu_var(softnet_data);
+       struct softnet_data *sd = &__get_cpu_var(softnet_data);
        struct sk_buff *skb, *tmp;
 
-       skb_queue_walk_safe(&queue->input_pkt_queue, skb, tmp)
+       rps_lock(sd);
+       skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) {
                if (skb->dev == dev) {
-                       __skb_unlink(skb, &queue->input_pkt_queue);
+                       __skb_unlink(skb, &sd->input_pkt_queue);
                        kfree_skb(skb);
+                       input_queue_head_add(sd, 1);
                }
+       }
+       rps_unlock(sd);
+
+       skb_queue_walk_safe(&sd->process_queue, skb, tmp) {
+               if (skb->dev == dev) {
+                       __skb_unlink(skb, &sd->process_queue);
+                       kfree_skb(skb);
+               }
+       }
 }
 
 static int napi_gro_complete(struct sk_buff *skb)
@@ -2910,33 +3277,91 @@ gro_result_t napi_gro_frags(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(napi_gro_frags);
 
-static int process_backlog(struct napi_struct *napi, int quota)
+/*
+ * net_rps_action sends any pending IPI's for rps.
+ * Note: called with local irq disabled, but exits with local irq enabled.
+ */
+static void net_rps_action_and_irq_enable(struct softnet_data *sd)
 {
-       int work = 0;
-       struct softnet_data *queue = &__get_cpu_var(softnet_data);
-       unsigned long start_time = jiffies;
+#ifdef CONFIG_RPS
+       struct softnet_data *remsd = sd->rps_ipi_list;
 
-       napi->weight = weight_p;
-       do {
-               struct sk_buff *skb;
+       if (remsd) {
+               sd->rps_ipi_list = NULL;
 
-               local_irq_disable();
-               skb = __skb_dequeue(&queue->input_pkt_queue);
-               if (!skb) {
-                       __napi_complete(napi);
-                       local_irq_enable();
-                       break;
-               }
                local_irq_enable();
 
-               netif_receive_skb(skb);
-       } while (++work < quota && jiffies == start_time);
+               /* Send pending IPI's to kick RPS processing on remote cpus. */
+               while (remsd) {
+                       struct softnet_data *next = remsd->rps_ipi_next;
 
-       return work;
+                       if (cpu_online(remsd->cpu))
+                               __smp_call_function_single(remsd->cpu,
+                                                          &remsd->csd, 0);
+                       remsd = next;
+               }
+       } else
+#endif
+               local_irq_enable();
 }
 
-/**
- * __napi_schedule - schedule for receive
+static int process_backlog(struct napi_struct *napi, int quota)
+{
+       int work = 0;
+       struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
+
+#ifdef CONFIG_RPS
+       /* Check if we have pending ipi, its better to send them now,
+        * not waiting net_rx_action() end.
+        */
+       if (sd->rps_ipi_list) {
+               local_irq_disable();
+               net_rps_action_and_irq_enable(sd);
+       }
+#endif
+       napi->weight = weight_p;
+       local_irq_disable();
+       while (work < quota) {
+               struct sk_buff *skb;
+               unsigned int qlen;
+
+               while ((skb = __skb_dequeue(&sd->process_queue))) {
+                       local_irq_enable();
+                       __netif_receive_skb(skb);
+                       if (++work >= quota)
+                               return work;
+                       local_irq_disable();
+               }
+
+               rps_lock(sd);
+               qlen = skb_queue_len(&sd->input_pkt_queue);
+               if (qlen) {
+                       input_queue_head_add(sd, qlen);
+                       skb_queue_splice_tail_init(&sd->input_pkt_queue,
+                                                  &sd->process_queue);
+               }
+               if (qlen < quota - work) {
+                       /*
+                        * Inline a custom version of __napi_complete().
+                        * only current cpu owns and manipulates this napi,
+                        * and NAPI_STATE_SCHED is the only possible flag set on backlog.
+                        * we can use a plain write instead of clear_bit(),
+                        * and we dont need an smp_mb() memory barrier.
+                        */
+                       list_del(&napi->poll_list);
+                       napi->state = 0;
+
+                       quota = work + qlen;
+               }
+               rps_unlock(sd);
+       }
+       local_irq_enable();
+
+       return work;
+}
+
+/**
+ * __napi_schedule - schedule for receive
  * @n: entry to schedule
  *
  * The entry's receive function will be scheduled to run
@@ -2946,8 +3371,7 @@ void __napi_schedule(struct napi_struct *n)
        unsigned long flags;
 
        local_irq_save(flags);
-       list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list);
-       __raise_softirq_irqoff(NET_RX_SOFTIRQ);
+       ____napi_schedule(&__get_cpu_var(softnet_data), n);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__napi_schedule);
@@ -3018,17 +3442,16 @@ void netif_napi_del(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(netif_napi_del);
 
-
 static void net_rx_action(struct softirq_action *h)
 {
-       struct list_head *list = &__get_cpu_var(softnet_data).poll_list;
+       struct softnet_data *sd = &__get_cpu_var(softnet_data);
        unsigned long time_limit = jiffies + 2;
        int budget = netdev_budget;
        void *have;
 
        local_irq_disable();
 
-       while (!list_empty(list)) {
+       while (!list_empty(&sd->poll_list)) {
                struct napi_struct *n;
                int work, weight;
 
@@ -3046,7 +3469,7 @@ static void net_rx_action(struct softirq_action *h)
                 * entries to the tail of this list, and only ->poll()
                 * calls can remove this head entry from the list.
                 */
-               n = list_first_entry(list, struct napi_struct, poll_list);
+               n = list_first_entry(&sd->poll_list, struct napi_struct, poll_list);
 
                have = netpoll_poll_lock(n);
 
@@ -3081,13 +3504,13 @@ static void net_rx_action(struct softirq_action *h)
                                napi_complete(n);
                                local_irq_disable();
                        } else
-                               list_move_tail(&n->poll_list, list);
+                               list_move_tail(&n->poll_list, &sd->poll_list);
                }
 
                netpoll_poll_unlock(have);
        }
 out:
-       local_irq_enable();
+       net_rps_action_and_irq_enable(sd);
 
 #ifdef CONFIG_NET_DMA
        /*
@@ -3100,7 +3523,7 @@ out:
        return;
 
 softnet_break:
-       __get_cpu_var(netdev_rx_stat).time_squeeze++;
+       sd->time_squeeze++;
        __raise_softirq_irqoff(NET_RX_SOFTIRQ);
        goto out;
 }
@@ -3301,17 +3724,17 @@ static int dev_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct netif_rx_stats *softnet_get_online(loff_t *pos)
+static struct softnet_data *softnet_get_online(loff_t *pos)
 {
-       struct netif_rx_stats *rc = NULL;
+       struct softnet_data *sd = NULL;
 
        while (*pos < nr_cpu_ids)
                if (cpu_online(*pos)) {
-                       rc = &per_cpu(netdev_rx_stat, *pos);
+                       sd = &per_cpu(softnet_data, *pos);
                        break;
                } else
                        ++*pos;
-       return rc;
+       return sd;
 }
 
 static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
@@ -3331,12 +3754,12 @@ static void softnet_seq_stop(struct seq_file *seq, void *v)
 
 static int softnet_seq_show(struct seq_file *seq, void *v)
 {
-       struct netif_rx_stats *s = v;
+       struct softnet_data *sd = v;
 
-       seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
-                  s->total, s->dropped, s->time_squeeze, 0,
+       seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+                  sd->processed, sd->dropped, sd->time_squeeze, 0,
                   0, 0, 0, 0, /* was fastroute */
-                  s->cpu_collision);
+                  sd->cpu_collision, sd->received_rps);
        return 0;
 }
 
@@ -3559,11 +3982,10 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
 
        slave->master = master;
 
-       synchronize_net();
-
-       if (old)
+       if (old) {
+               synchronize_net();
                dev_put(old);
-
+       }
        if (master)
                slave->flags |= IFF_SLAVE;
        else
@@ -3740,562 +4162,6 @@ void dev_set_rx_mode(struct net_device *dev)
        netif_addr_unlock_bh(dev);
 }
 
-/* hw addresses list handling functions */
-
-static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
-                        int addr_len, unsigned char addr_type)
-{
-       struct netdev_hw_addr *ha;
-       int alloc_size;
-
-       if (addr_len > MAX_ADDR_LEN)
-               return -EINVAL;
-
-       list_for_each_entry(ha, &list->list, list) {
-               if (!memcmp(ha->addr, addr, addr_len) &&
-                   ha->type == addr_type) {
-                       ha->refcount++;
-                       return 0;
-               }
-       }
-
-
-       alloc_size = sizeof(*ha);
-       if (alloc_size < L1_CACHE_BYTES)
-               alloc_size = L1_CACHE_BYTES;
-       ha = kmalloc(alloc_size, GFP_ATOMIC);
-       if (!ha)
-               return -ENOMEM;
-       memcpy(ha->addr, addr, addr_len);
-       ha->type = addr_type;
-       ha->refcount = 1;
-       ha->synced = false;
-       list_add_tail_rcu(&ha->list, &list->list);
-       list->count++;
-       return 0;
-}
-
-static void ha_rcu_free(struct rcu_head *head)
-{
-       struct netdev_hw_addr *ha;
-
-       ha = container_of(head, struct netdev_hw_addr, rcu_head);
-       kfree(ha);
-}
-
-static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr,
-                        int addr_len, unsigned char addr_type)
-{
-       struct netdev_hw_addr *ha;
-
-       list_for_each_entry(ha, &list->list, list) {
-               if (!memcmp(ha->addr, addr, addr_len) &&
-                   (ha->type == addr_type || !addr_type)) {
-                       if (--ha->refcount)
-                               return 0;
-                       list_del_rcu(&ha->list);
-                       call_rcu(&ha->rcu_head, ha_rcu_free);
-                       list->count--;
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
-                                 struct netdev_hw_addr_list *from_list,
-                                 int addr_len,
-                                 unsigned char addr_type)
-{
-       int err;
-       struct netdev_hw_addr *ha, *ha2;
-       unsigned char type;
-
-       list_for_each_entry(ha, &from_list->list, list) {
-               type = addr_type ? addr_type : ha->type;
-               err = __hw_addr_add(to_list, ha->addr, addr_len, type);
-               if (err)
-                       goto unroll;
-       }
-       return 0;
-
-unroll:
-       list_for_each_entry(ha2, &from_list->list, list) {
-               if (ha2 == ha)
-                       break;
-               type = addr_type ? addr_type : ha2->type;
-               __hw_addr_del(to_list, ha2->addr, addr_len, type);
-       }
-       return err;
-}
-
-static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
-                                  struct netdev_hw_addr_list *from_list,
-                                  int addr_len,
-                                  unsigned char addr_type)
-{
-       struct netdev_hw_addr *ha;
-       unsigned char type;
-
-       list_for_each_entry(ha, &from_list->list, list) {
-               type = addr_type ? addr_type : ha->type;
-               __hw_addr_del(to_list, ha->addr, addr_len, addr_type);
-       }
-}
-
-static int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
-                         struct netdev_hw_addr_list *from_list,
-                         int addr_len)
-{
-       int err = 0;
-       struct netdev_hw_addr *ha, *tmp;
-
-       list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
-               if (!ha->synced) {
-                       err = __hw_addr_add(to_list, ha->addr,
-                                           addr_len, ha->type);
-                       if (err)
-                               break;
-                       ha->synced = true;
-                       ha->refcount++;
-               } else if (ha->refcount == 1) {
-                       __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
-                       __hw_addr_del(from_list, ha->addr, addr_len, ha->type);
-               }
-       }
-       return err;
-}
-
-static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
-                            struct netdev_hw_addr_list *from_list,
-                            int addr_len)
-{
-       struct netdev_hw_addr *ha, *tmp;
-
-       list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
-               if (ha->synced) {
-                       __hw_addr_del(to_list, ha->addr,
-                                     addr_len, ha->type);
-                       ha->synced = false;
-                       __hw_addr_del(from_list, ha->addr,
-                                     addr_len, ha->type);
-               }
-       }
-}
-
-static void __hw_addr_flush(struct netdev_hw_addr_list *list)
-{
-       struct netdev_hw_addr *ha, *tmp;
-
-       list_for_each_entry_safe(ha, tmp, &list->list, list) {
-               list_del_rcu(&ha->list);
-               call_rcu(&ha->rcu_head, ha_rcu_free);
-       }
-       list->count = 0;
-}
-
-static void __hw_addr_init(struct netdev_hw_addr_list *list)
-{
-       INIT_LIST_HEAD(&list->list);
-       list->count = 0;
-}
-
-/* Device addresses handling functions */
-
-static void dev_addr_flush(struct net_device *dev)
-{
-       /* rtnl_mutex must be held here */
-
-       __hw_addr_flush(&dev->dev_addrs);
-       dev->dev_addr = NULL;
-}
-
-static int dev_addr_init(struct net_device *dev)
-{
-       unsigned char addr[MAX_ADDR_LEN];
-       struct netdev_hw_addr *ha;
-       int err;
-
-       /* rtnl_mutex must be held here */
-
-       __hw_addr_init(&dev->dev_addrs);
-       memset(addr, 0, sizeof(addr));
-       err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr),
-                           NETDEV_HW_ADDR_T_LAN);
-       if (!err) {
-               /*
-                * Get the first (previously created) address from the list
-                * and set dev_addr pointer to this location.
-                */
-               ha = list_first_entry(&dev->dev_addrs.list,
-                                     struct netdev_hw_addr, list);
-               dev->dev_addr = ha->addr;
-       }
-       return err;
-}
-
-/**
- *     dev_addr_add    - Add a device address
- *     @dev: device
- *     @addr: address to add
- *     @addr_type: address type
- *
- *     Add a device address to the device or increase the reference count if
- *     it already exists.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_add(struct net_device *dev, unsigned char *addr,
-                unsigned char addr_type)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_addr_add);
-
-/**
- *     dev_addr_del    - Release a device address.
- *     @dev: device
- *     @addr: address to delete
- *     @addr_type: address type
- *
- *     Release reference to a device address and remove it from the device
- *     if the reference count drops to zero.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_del(struct net_device *dev, unsigned char *addr,
-                unsigned char addr_type)
-{
-       int err;
-       struct netdev_hw_addr *ha;
-
-       ASSERT_RTNL();
-
-       /*
-        * We can not remove the first address from the list because
-        * dev->dev_addr points to that.
-        */
-       ha = list_first_entry(&dev->dev_addrs.list,
-                             struct netdev_hw_addr, list);
-       if (ha->addr == dev->dev_addr && ha->refcount == 1)
-               return -ENOENT;
-
-       err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
-                           addr_type);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_addr_del);
-
-/**
- *     dev_addr_add_multiple   - Add device addresses from another device
- *     @to_dev: device to which addresses will be added
- *     @from_dev: device from which addresses will be added
- *     @addr_type: address type - 0 means type will be used from from_dev
- *
- *     Add device addresses of the one device to another.
- **
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_add_multiple(struct net_device *to_dev,
-                         struct net_device *from_dev,
-                         unsigned char addr_type)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       if (from_dev->addr_len != to_dev->addr_len)
-               return -EINVAL;
-       err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
-                                    to_dev->addr_len, addr_type);
-       if (!err)
-               call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_addr_add_multiple);
-
-/**
- *     dev_addr_del_multiple   - Delete device addresses by another device
- *     @to_dev: device where the addresses will be deleted
- *     @from_dev: device by which addresses the addresses will be deleted
- *     @addr_type: address type - 0 means type will used from from_dev
- *
- *     Deletes addresses in to device by the list of addresses in from device.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_addr_del_multiple(struct net_device *to_dev,
-                         struct net_device *from_dev,
-                         unsigned char addr_type)
-{
-       ASSERT_RTNL();
-
-       if (from_dev->addr_len != to_dev->addr_len)
-               return -EINVAL;
-       __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
-                              to_dev->addr_len, addr_type);
-       call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
-       return 0;
-}
-EXPORT_SYMBOL(dev_addr_del_multiple);
-
-/* multicast addresses handling functions */
-
-int __dev_addr_delete(struct dev_addr_list **list, int *count,
-                     void *addr, int alen, int glbl)
-{
-       struct dev_addr_list *da;
-
-       for (; (da = *list) != NULL; list = &da->next) {
-               if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
-                   alen == da->da_addrlen) {
-                       if (glbl) {
-                               int old_glbl = da->da_gusers;
-                               da->da_gusers = 0;
-                               if (old_glbl == 0)
-                                       break;
-                       }
-                       if (--da->da_users)
-                               return 0;
-
-                       *list = da->next;
-                       kfree(da);
-                       (*count)--;
-                       return 0;
-               }
-       }
-       return -ENOENT;
-}
-
-int __dev_addr_add(struct dev_addr_list **list, int *count,
-                  void *addr, int alen, int glbl)
-{
-       struct dev_addr_list *da;
-
-       for (da = *list; da != NULL; da = da->next) {
-               if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
-                   da->da_addrlen == alen) {
-                       if (glbl) {
-                               int old_glbl = da->da_gusers;
-                               da->da_gusers = 1;
-                               if (old_glbl)
-                                       return 0;
-                       }
-                       da->da_users++;
-                       return 0;
-               }
-       }
-
-       da = kzalloc(sizeof(*da), GFP_ATOMIC);
-       if (da == NULL)
-               return -ENOMEM;
-       memcpy(da->da_addr, addr, alen);
-       da->da_addrlen = alen;
-       da->da_users = 1;
-       da->da_gusers = glbl ? 1 : 0;
-       da->next = *list;
-       *list = da;
-       (*count)++;
-       return 0;
-}
-
-/**
- *     dev_unicast_delete      - Release secondary unicast address.
- *     @dev: device
- *     @addr: address to delete
- *
- *     Release reference to a secondary unicast address and remove it
- *     from the device if the reference count drops to zero.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_unicast_delete(struct net_device *dev, void *addr)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       netif_addr_lock_bh(dev);
-       err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
-                           NETDEV_HW_ADDR_T_UNICAST);
-       if (!err)
-               __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_unicast_delete);
-
-/**
- *     dev_unicast_add         - add a secondary unicast address
- *     @dev: device
- *     @addr: address to add
- *
- *     Add a secondary unicast address to the device or increase
- *     the reference count if it already exists.
- *
- *     The caller must hold the rtnl_mutex.
- */
-int dev_unicast_add(struct net_device *dev, void *addr)
-{
-       int err;
-
-       ASSERT_RTNL();
-
-       netif_addr_lock_bh(dev);
-       err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
-                           NETDEV_HW_ADDR_T_UNICAST);
-       if (!err)
-               __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
-       return err;
-}
-EXPORT_SYMBOL(dev_unicast_add);
-
-int __dev_addr_sync(struct dev_addr_list **to, int *to_count,
-                   struct dev_addr_list **from, int *from_count)
-{
-       struct dev_addr_list *da, *next;
-       int err = 0;
-
-       da = *from;
-       while (da != NULL) {
-               next = da->next;
-               if (!da->da_synced) {
-                       err = __dev_addr_add(to, to_count,
-                                            da->da_addr, da->da_addrlen, 0);
-                       if (err < 0)
-                               break;
-                       da->da_synced = 1;
-                       da->da_users++;
-               } else if (da->da_users == 1) {
-                       __dev_addr_delete(to, to_count,
-                                         da->da_addr, da->da_addrlen, 0);
-                       __dev_addr_delete(from, from_count,
-                                         da->da_addr, da->da_addrlen, 0);
-               }
-               da = next;
-       }
-       return err;
-}
-EXPORT_SYMBOL_GPL(__dev_addr_sync);
-
-void __dev_addr_unsync(struct dev_addr_list **to, int *to_count,
-                      struct dev_addr_list **from, int *from_count)
-{
-       struct dev_addr_list *da, *next;
-
-       da = *from;
-       while (da != NULL) {
-               next = da->next;
-               if (da->da_synced) {
-                       __dev_addr_delete(to, to_count,
-                                         da->da_addr, da->da_addrlen, 0);
-                       da->da_synced = 0;
-                       __dev_addr_delete(from, from_count,
-                                         da->da_addr, da->da_addrlen, 0);
-               }
-               da = next;
-       }
-}
-EXPORT_SYMBOL_GPL(__dev_addr_unsync);
-
-/**
- *     dev_unicast_sync - Synchronize device's unicast list to another device
- *     @to: destination device
- *     @from: source device
- *
- *     Add newly added addresses to the destination device and release
- *     addresses that have no users left. The source device must be
- *     locked by netif_tx_lock_bh.
- *
- *     This function is intended to be called from the dev->set_rx_mode
- *     function of layered software devices.
- */
-int dev_unicast_sync(struct net_device *to, struct net_device *from)
-{
-       int err = 0;
-
-       if (to->addr_len != from->addr_len)
-               return -EINVAL;
-
-       netif_addr_lock_bh(to);
-       err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
-       if (!err)
-               __dev_set_rx_mode(to);
-       netif_addr_unlock_bh(to);
-       return err;
-}
-EXPORT_SYMBOL(dev_unicast_sync);
-
-/**
- *     dev_unicast_unsync - Remove synchronized addresses from the destination device
- *     @to: destination device
- *     @from: source device
- *
- *     Remove all addresses that were added to the destination device by
- *     dev_unicast_sync(). This function is intended to be called from the
- *     dev->stop function of layered software devices.
- */
-void dev_unicast_unsync(struct net_device *to, struct net_device *from)
-{
-       if (to->addr_len != from->addr_len)
-               return;
-
-       netif_addr_lock_bh(from);
-       netif_addr_lock(to);
-       __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
-       __dev_set_rx_mode(to);
-       netif_addr_unlock(to);
-       netif_addr_unlock_bh(from);
-}
-EXPORT_SYMBOL(dev_unicast_unsync);
-
-static void dev_unicast_flush(struct net_device *dev)
-{
-       netif_addr_lock_bh(dev);
-       __hw_addr_flush(&dev->uc);
-       netif_addr_unlock_bh(dev);
-}
-
-static void dev_unicast_init(struct net_device *dev)
-{
-       __hw_addr_init(&dev->uc);
-}
-
-
-static void __dev_addr_discard(struct dev_addr_list **list)
-{
-       struct dev_addr_list *tmp;
-
-       while (*list != NULL) {
-               tmp = *list;
-               *list = tmp->next;
-               if (tmp->da_users > tmp->da_gusers)
-                       printk("__dev_addr_discard: address leakage! "
-                              "da_users=%d\n", tmp->da_users);
-               kfree(tmp);
-       }
-}
-
-static void dev_addr_discard(struct net_device *dev)
-{
-       netif_addr_lock_bh(dev);
-
-       __dev_addr_discard(&dev->mc_list);
-       netdev_mc_count(dev) = 0;
-
-       netif_addr_unlock_bh(dev);
-}
-
 /**
  *     dev_get_flags - get flags reported to userspace
  *     @dev: device
@@ -4606,8 +4472,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        return -EINVAL;
                if (!netif_device_present(dev))
                        return -ENODEV;
-               return dev_mc_add(dev, ifr->ifr_hwaddr.sa_data,
-                                 dev->addr_len, 1);
+               return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
 
        case SIOCDELMULTI:
                if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
@@ -4615,8 +4480,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
                        return -EINVAL;
                if (!netif_device_present(dev))
                        return -ENODEV;
-               return dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data,
-                                    dev->addr_len, 1);
+               return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
 
        case SIOCSIFTXQLEN:
                if (ifr->ifr_qlen < 0)
@@ -4923,8 +4787,8 @@ static void rollback_registered_many(struct list_head *head)
                /*
                 *      Flush the unicast and multicast chains
                 */
-               dev_unicast_flush(dev);
-               dev_addr_discard(dev);
+               dev_uc_flush(dev);
+               dev_mc_flush(dev);
 
                if (dev->netdev_ops->ndo_uninit)
                        dev->netdev_ops->ndo_uninit(dev);
@@ -5073,6 +4937,24 @@ int register_netdevice(struct net_device *dev)
 
        dev->iflink = -1;
 
+#ifdef CONFIG_RPS
+       if (!dev->num_rx_queues) {
+               /*
+                * Allocate a single RX queue if driver never called
+                * alloc_netdev_mq
+                */
+
+               dev->_rx = kzalloc(sizeof(struct netdev_rx_queue), GFP_KERNEL);
+               if (!dev->_rx) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               dev->_rx->first = dev->_rx;
+               atomic_set(&dev->_rx->count, 1);
+               dev->num_rx_queues = 1;
+       }
+#endif
        /* Init, if this function is available */
        if (dev->netdev_ops->ndo_init) {
                ret = dev->netdev_ops->ndo_init(dev);
@@ -5433,6 +5315,10 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        struct net_device *dev;
        size_t alloc_size;
        struct net_device *p;
+#ifdef CONFIG_RPS
+       struct netdev_rx_queue *rx;
+       int i;
+#endif
 
        BUG_ON(strlen(name) >= sizeof(dev->name));
 
@@ -5458,13 +5344,32 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
                goto free_p;
        }
 
+#ifdef CONFIG_RPS
+       rx = kcalloc(queue_count, sizeof(struct netdev_rx_queue), GFP_KERNEL);
+       if (!rx) {
+               printk(KERN_ERR "alloc_netdev: Unable to allocate "
+                      "rx queues.\n");
+               goto free_tx;
+       }
+
+       atomic_set(&rx->count, queue_count);
+
+       /*
+        * Set a pointer to first element in the array which holds the
+        * reference count.
+        */
+       for (i = 0; i < queue_count; i++)
+               rx[i].first = rx;
+#endif
+
        dev = PTR_ALIGN(p, NETDEV_ALIGN);
        dev->padded = (char *)dev - (char *)p;
 
        if (dev_addr_init(dev))
-               goto free_tx;
+               goto free_rx;
 
-       dev_unicast_init(dev);
+       dev_mc_init(dev);
+       dev_uc_init(dev);
 
        dev_net_set(dev, &init_net);
 
@@ -5472,6 +5377,11 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        dev->num_tx_queues = queue_count;
        dev->real_num_tx_queues = queue_count;
 
+#ifdef CONFIG_RPS
+       dev->_rx = rx;
+       dev->num_rx_queues = queue_count;
+#endif
+
        dev->gso_max_size = GSO_MAX_SIZE;
 
        netdev_init_queues(dev);
@@ -5486,9 +5396,12 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
        strcpy(dev->name, name);
        return dev;
 
+free_rx:
+#ifdef CONFIG_RPS
+       kfree(rx);
 free_tx:
+#endif
        kfree(tx);
-
 free_p:
        kfree(p);
        return NULL;
@@ -5690,8 +5603,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
        /*
         *      Flush the unicast and multicast chains
         */
-       dev_unicast_flush(dev);
-       dev_addr_discard(dev);
+       dev_uc_flush(dev);
+       dev_mc_flush(dev);
 
        netdev_unregister_kobject(dev);
 
@@ -5734,7 +5647,6 @@ static int dev_cpu_callback(struct notifier_block *nfb,
                            void *ocpu)
 {
        struct sk_buff **list_skb;
-       struct Qdisc **list_net;
        struct sk_buff *skb;
        unsigned int cpu, oldcpu = (unsigned long)ocpu;
        struct softnet_data *sd, *oldsd;
@@ -5755,19 +5667,23 @@ static int dev_cpu_callback(struct notifier_block *nfb,
        *list_skb = oldsd->completion_queue;
        oldsd->completion_queue = NULL;
 
-       /* Find end of our output_queue. */
-       list_net = &sd->output_queue;
-       while (*list_net)
-               list_net = &(*list_net)->next_sched;
        /* Append output queue from offline CPU. */
-       *list_net = oldsd->output_queue;
-       oldsd->output_queue = NULL;
+       if (oldsd->output_queue) {
+               *sd->output_queue_tailp = oldsd->output_queue;
+               sd->output_queue_tailp = oldsd->output_queue_tailp;
+               oldsd->output_queue = NULL;
+               oldsd->output_queue_tailp = &oldsd->output_queue;
+       }
 
        raise_softirq_irqoff(NET_TX_SOFTIRQ);
        local_irq_enable();
 
        /* Process offline CPU's input_pkt_queue */
-       while ((skb = __skb_dequeue(&oldsd->input_pkt_queue)))
+       while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) {
+               netif_rx(skb);
+               input_queue_head_add(oldsd, 1);
+       }
+       while ((skb = __skb_dequeue(&oldsd->process_queue)))
                netif_rx(skb);
 
        return NOTIFY_OK;
@@ -5984,17 +5900,26 @@ static int __init net_dev_init(void)
         */
 
        for_each_possible_cpu(i) {
-               struct softnet_data *queue;
+               struct softnet_data *sd = &per_cpu(softnet_data, i);
 
-               queue = &per_cpu(softnet_data, i);
-               skb_queue_head_init(&queue->input_pkt_queue);
-               queue->completion_queue = NULL;
-               INIT_LIST_HEAD(&queue->poll_list);
+               memset(sd, 0, sizeof(*sd));
+               skb_queue_head_init(&sd->input_pkt_queue);
+               skb_queue_head_init(&sd->process_queue);
+               sd->completion_queue = NULL;
+               INIT_LIST_HEAD(&sd->poll_list);
+               sd->output_queue = NULL;
+               sd->output_queue_tailp = &sd->output_queue;
+#ifdef CONFIG_RPS
+               sd->csd.func = rps_trigger_softirq;
+               sd->csd.info = sd;
+               sd->csd.flags = 0;
+               sd->cpu = i;
+#endif
 
-               queue->backlog.poll = process_backlog;
-               queue->backlog.weight = weight_p;
-               queue->backlog.gro_list = NULL;
-               queue->backlog.gro_count = 0;
+               sd->backlog.poll = process_backlog;
+               sd->backlog.weight = weight_p;
+               sd->backlog.gro_list = NULL;
+               sd->backlog.gro_count = 0;
        }
 
        dev_boot_phase = 0;
@@ -6029,7 +5954,7 @@ subsys_initcall(net_dev_init);
 
 static int __init initialize_hashrnd(void)
 {
-       get_random_bytes(&skb_tx_hashrnd, sizeof(skb_tx_hashrnd));
+       get_random_bytes(&hashrnd, sizeof(hashrnd));
        return 0;
 }
 
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
new file mode 100644 (file)
index 0000000..508f9c1
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * net/core/dev_addr_lists.c - Functions for handling net device lists
+ * Copyright (c) 2010 Jiri Pirko <jpirko@redhat.com>
+ *
+ * This file contains functions for working with unicast, multicast and device
+ * addresses lists.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+
+/*
+ * General list handling functions
+ */
+
+static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
+                           unsigned char *addr, int addr_len,
+                           unsigned char addr_type, bool global)
+{
+       struct netdev_hw_addr *ha;
+       int alloc_size;
+
+       if (addr_len > MAX_ADDR_LEN)
+               return -EINVAL;
+
+       list_for_each_entry(ha, &list->list, list) {
+               if (!memcmp(ha->addr, addr, addr_len) &&
+                   ha->type == addr_type) {
+                       if (global) {
+                               /* check if addr is already used as global */
+                               if (ha->global_use)
+                                       return 0;
+                               else
+                                       ha->global_use = true;
+                       }
+                       ha->refcount++;
+                       return 0;
+               }
+       }
+
+
+       alloc_size = sizeof(*ha);
+       if (alloc_size < L1_CACHE_BYTES)
+               alloc_size = L1_CACHE_BYTES;
+       ha = kmalloc(alloc_size, GFP_ATOMIC);
+       if (!ha)
+               return -ENOMEM;
+       memcpy(ha->addr, addr, addr_len);
+       ha->type = addr_type;
+       ha->refcount = 1;
+       ha->global_use = global;
+       ha->synced = false;
+       list_add_tail_rcu(&ha->list, &list->list);
+       list->count++;
+       return 0;
+}
+
+static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
+                        int addr_len, unsigned char addr_type)
+{
+       return __hw_addr_add_ex(list, addr, addr_len, addr_type, false);
+}
+
+static void ha_rcu_free(struct rcu_head *head)
+{
+       struct netdev_hw_addr *ha;
+
+       ha = container_of(head, struct netdev_hw_addr, rcu_head);
+       kfree(ha);
+}
+
+static int __hw_addr_del_ex(struct netdev_hw_addr_list *list,
+                           unsigned char *addr, int addr_len,
+                           unsigned char addr_type, bool global)
+{
+       struct netdev_hw_addr *ha;
+
+       list_for_each_entry(ha, &list->list, list) {
+               if (!memcmp(ha->addr, addr, addr_len) &&
+                   (ha->type == addr_type || !addr_type)) {
+                       if (global) {
+                               if (!ha->global_use)
+                                       break;
+                               else
+                                       ha->global_use = false;
+                       }
+                       if (--ha->refcount)
+                               return 0;
+                       list_del_rcu(&ha->list);
+                       call_rcu(&ha->rcu_head, ha_rcu_free);
+                       list->count--;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr,
+                        int addr_len, unsigned char addr_type)
+{
+       return __hw_addr_del_ex(list, addr, addr_len, addr_type, false);
+}
+
+int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
+                          struct netdev_hw_addr_list *from_list,
+                          int addr_len, unsigned char addr_type)
+{
+       int err;
+       struct netdev_hw_addr *ha, *ha2;
+       unsigned char type;
+
+       list_for_each_entry(ha, &from_list->list, list) {
+               type = addr_type ? addr_type : ha->type;
+               err = __hw_addr_add(to_list, ha->addr, addr_len, type);
+               if (err)
+                       goto unroll;
+       }
+       return 0;
+
+unroll:
+       list_for_each_entry(ha2, &from_list->list, list) {
+               if (ha2 == ha)
+                       break;
+               type = addr_type ? addr_type : ha2->type;
+               __hw_addr_del(to_list, ha2->addr, addr_len, type);
+       }
+       return err;
+}
+EXPORT_SYMBOL(__hw_addr_add_multiple);
+
+void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
+                           struct netdev_hw_addr_list *from_list,
+                           int addr_len, unsigned char addr_type)
+{
+       struct netdev_hw_addr *ha;
+       unsigned char type;
+
+       list_for_each_entry(ha, &from_list->list, list) {
+               type = addr_type ? addr_type : ha->type;
+               __hw_addr_del(to_list, ha->addr, addr_len, addr_type);
+       }
+}
+EXPORT_SYMBOL(__hw_addr_del_multiple);
+
+int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
+                  struct netdev_hw_addr_list *from_list,
+                  int addr_len)
+{
+       int err = 0;
+       struct netdev_hw_addr *ha, *tmp;
+
+       list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
+               if (!ha->synced) {
+                       err = __hw_addr_add(to_list, ha->addr,
+                                           addr_len, ha->type);
+                       if (err)
+                               break;
+                       ha->synced = true;
+                       ha->refcount++;
+               } else if (ha->refcount == 1) {
+                       __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
+                       __hw_addr_del(from_list, ha->addr, addr_len, ha->type);
+               }
+       }
+       return err;
+}
+EXPORT_SYMBOL(__hw_addr_sync);
+
+void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
+                     struct netdev_hw_addr_list *from_list,
+                     int addr_len)
+{
+       struct netdev_hw_addr *ha, *tmp;
+
+       list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
+               if (ha->synced) {
+                       __hw_addr_del(to_list, ha->addr,
+                                     addr_len, ha->type);
+                       ha->synced = false;
+                       __hw_addr_del(from_list, ha->addr,
+                                     addr_len, ha->type);
+               }
+       }
+}
+EXPORT_SYMBOL(__hw_addr_unsync);
+
+void __hw_addr_flush(struct netdev_hw_addr_list *list)
+{
+       struct netdev_hw_addr *ha, *tmp;
+
+       list_for_each_entry_safe(ha, tmp, &list->list, list) {
+               list_del_rcu(&ha->list);
+               call_rcu(&ha->rcu_head, ha_rcu_free);
+       }
+       list->count = 0;
+}
+EXPORT_SYMBOL(__hw_addr_flush);
+
+void __hw_addr_init(struct netdev_hw_addr_list *list)
+{
+       INIT_LIST_HEAD(&list->list);
+       list->count = 0;
+}
+EXPORT_SYMBOL(__hw_addr_init);
+
+/*
+ * Device addresses handling functions
+ */
+
+/**
+ *     dev_addr_flush - Flush device address list
+ *     @dev: device
+ *
+ *     Flush device address list and reset ->dev_addr.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+void dev_addr_flush(struct net_device *dev)
+{
+       /* rtnl_mutex must be held here */
+
+       __hw_addr_flush(&dev->dev_addrs);
+       dev->dev_addr = NULL;
+}
+EXPORT_SYMBOL(dev_addr_flush);
+
+/**
+ *     dev_addr_init - Init device address list
+ *     @dev: device
+ *
+ *     Init device address list and create the first element,
+ *     used by ->dev_addr.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+int dev_addr_init(struct net_device *dev)
+{
+       unsigned char addr[MAX_ADDR_LEN];
+       struct netdev_hw_addr *ha;
+       int err;
+
+       /* rtnl_mutex must be held here */
+
+       __hw_addr_init(&dev->dev_addrs);
+       memset(addr, 0, sizeof(addr));
+       err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr),
+                           NETDEV_HW_ADDR_T_LAN);
+       if (!err) {
+               /*
+                * Get the first (previously created) address from the list
+                * and set dev_addr pointer to this location.
+                */
+               ha = list_first_entry(&dev->dev_addrs.list,
+                                     struct netdev_hw_addr, list);
+               dev->dev_addr = ha->addr;
+       }
+       return err;
+}
+EXPORT_SYMBOL(dev_addr_init);
+
+/**
+ *     dev_addr_add - Add a device address
+ *     @dev: device
+ *     @addr: address to add
+ *     @addr_type: address type
+ *
+ *     Add a device address to the device or increase the reference count if
+ *     it already exists.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+int dev_addr_add(struct net_device *dev, unsigned char *addr,
+                unsigned char addr_type)
+{
+       int err;
+
+       ASSERT_RTNL();
+
+       err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type);
+       if (!err)
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+       return err;
+}
+EXPORT_SYMBOL(dev_addr_add);
+
+/**
+ *     dev_addr_del - Release a device address.
+ *     @dev: device
+ *     @addr: address to delete
+ *     @addr_type: address type
+ *
+ *     Release reference to a device address and remove it from the device
+ *     if the reference count drops to zero.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+int dev_addr_del(struct net_device *dev, unsigned char *addr,
+                unsigned char addr_type)
+{
+       int err;
+       struct netdev_hw_addr *ha;
+
+       ASSERT_RTNL();
+
+       /*
+        * We can not remove the first address from the list because
+        * dev->dev_addr points to that.
+        */
+       ha = list_first_entry(&dev->dev_addrs.list,
+                             struct netdev_hw_addr, list);
+       if (ha->addr == dev->dev_addr && ha->refcount == 1)
+               return -ENOENT;
+
+       err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
+                           addr_type);
+       if (!err)
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+       return err;
+}
+EXPORT_SYMBOL(dev_addr_del);
+
+/**
+ *     dev_addr_add_multiple - Add device addresses from another device
+ *     @to_dev: device to which addresses will be added
+ *     @from_dev: device from which addresses will be added
+ *     @addr_type: address type - 0 means type will be used from from_dev
+ *
+ *     Add device addresses of the one device to another.
+ **
+ *     The caller must hold the rtnl_mutex.
+ */
+int dev_addr_add_multiple(struct net_device *to_dev,
+                         struct net_device *from_dev,
+                         unsigned char addr_type)
+{
+       int err;
+
+       ASSERT_RTNL();
+
+       if (from_dev->addr_len != to_dev->addr_len)
+               return -EINVAL;
+       err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
+                                    to_dev->addr_len, addr_type);
+       if (!err)
+               call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
+       return err;
+}
+EXPORT_SYMBOL(dev_addr_add_multiple);
+
+/**
+ *     dev_addr_del_multiple - Delete device addresses by another device
+ *     @to_dev: device where the addresses will be deleted
+ *     @from_dev: device by which addresses the addresses will be deleted
+ *     @addr_type: address type - 0 means type will used from from_dev
+ *
+ *     Deletes addresses in to device by the list of addresses in from device.
+ *
+ *     The caller must hold the rtnl_mutex.
+ */
+int dev_addr_del_multiple(struct net_device *to_dev,
+                         struct net_device *from_dev,
+                         unsigned char addr_type)
+{
+       ASSERT_RTNL();
+
+       if (from_dev->addr_len != to_dev->addr_len)
+               return -EINVAL;
+       __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
+                              to_dev->addr_len, addr_type);
+       call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
+       return 0;
+}
+EXPORT_SYMBOL(dev_addr_del_multiple);
+
+/*
+ * Unicast list handling functions
+ */
+
+/**
+ *     dev_uc_add - Add a secondary unicast address
+ *     @dev: device
+ *     @addr: address to add
+ *
+ *     Add a secondary unicast address to the device or increase
+ *     the reference count if it already exists.
+ */
+int dev_uc_add(struct net_device *dev, unsigned char *addr)
+{
+       int err;
+
+       netif_addr_lock_bh(dev);
+       err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
+                           NETDEV_HW_ADDR_T_UNICAST);
+       if (!err)
+               __dev_set_rx_mode(dev);
+       netif_addr_unlock_bh(dev);
+       return err;
+}
+EXPORT_SYMBOL(dev_uc_add);
+
+/**
+ *     dev_uc_del - Release secondary unicast address.
+ *     @dev: device
+ *     @addr: address to delete
+ *
+ *     Release reference to a secondary unicast address and remove it
+ *     from the device if the reference count drops to zero.
+ */
+int dev_uc_del(struct net_device *dev, unsigned char *addr)
+{
+       int err;
+
+       netif_addr_lock_bh(dev);
+       err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
+                           NETDEV_HW_ADDR_T_UNICAST);
+       if (!err)
+               __dev_set_rx_mode(dev);
+       netif_addr_unlock_bh(dev);
+       return err;
+}
+EXPORT_SYMBOL(dev_uc_del);
+
+/**
+ *     dev_uc_sync - Synchronize device's unicast list to another device
+ *     @to: destination device
+ *     @from: source device
+ *
+ *     Add newly added addresses to the destination device and release
+ *     addresses that have no users left. The source device must be
+ *     locked by netif_tx_lock_bh.
+ *
+ *     This function is intended to be called from the dev->set_rx_mode
+ *     function of layered software devices.
+ */
+int dev_uc_sync(struct net_device *to, struct net_device *from)
+{
+       int err = 0;
+
+       if (to->addr_len != from->addr_len)
+               return -EINVAL;
+
+       netif_addr_lock_bh(to);
+       err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
+       if (!err)
+               __dev_set_rx_mode(to);
+       netif_addr_unlock_bh(to);
+       return err;
+}
+EXPORT_SYMBOL(dev_uc_sync);
+
+/**
+ *     dev_uc_unsync - Remove synchronized addresses from the destination device
+ *     @to: destination device
+ *     @from: source device
+ *
+ *     Remove all addresses that were added to the destination device by
+ *     dev_uc_sync(). This function is intended to be called from the
+ *     dev->stop function of layered software devices.
+ */
+void dev_uc_unsync(struct net_device *to, struct net_device *from)
+{
+       if (to->addr_len != from->addr_len)
+               return;
+
+       netif_addr_lock_bh(from);
+       netif_addr_lock(to);
+       __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
+       __dev_set_rx_mode(to);
+       netif_addr_unlock(to);
+       netif_addr_unlock_bh(from);
+}
+EXPORT_SYMBOL(dev_uc_unsync);
+
+/**
+ *     dev_uc_flush - Flush unicast addresses
+ *     @dev: device
+ *
+ *     Flush unicast addresses.
+ */
+void dev_uc_flush(struct net_device *dev)
+{
+       netif_addr_lock_bh(dev);
+       __hw_addr_flush(&dev->uc);
+       netif_addr_unlock_bh(dev);
+}
+EXPORT_SYMBOL(dev_uc_flush);
+
+/**
+ *     dev_uc_flush - Init unicast address list
+ *     @dev: device
+ *
+ *     Init unicast address list.
+ */
+void dev_uc_init(struct net_device *dev)
+{
+       __hw_addr_init(&dev->uc);
+}
+EXPORT_SYMBOL(dev_uc_init);
+
+/*
+ * Multicast list handling functions
+ */
+
+static int __dev_mc_add(struct net_device *dev, unsigned char *addr,
+                       bool global)
+{
+       int err;
+
+       netif_addr_lock_bh(dev);
+       err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len,
+                              NETDEV_HW_ADDR_T_MULTICAST, global);
+       if (!err)
+               __dev_set_rx_mode(dev);
+       netif_addr_unlock_bh(dev);
+       return err;
+}
+/**
+ *     dev_mc_add - Add a multicast address
+ *     @dev: device
+ *     @addr: address to add
+ *
+ *     Add a multicast address to the device or increase
+ *     the reference count if it already exists.
+ */
+int dev_mc_add(struct net_device *dev, unsigned char *addr)
+{
+       return __dev_mc_add(dev, addr, false);
+}
+EXPORT_SYMBOL(dev_mc_add);
+
+/**
+ *     dev_mc_add_global - Add a global multicast address
+ *     @dev: device
+ *     @addr: address to add
+ *
+ *     Add a global multicast address to the device.
+ */
+int dev_mc_add_global(struct net_device *dev, unsigned char *addr)
+{
+       return __dev_mc_add(dev, addr, true);
+}
+EXPORT_SYMBOL(dev_mc_add_global);
+
+static int __dev_mc_del(struct net_device *dev, unsigned char *addr,
+                       bool global)
+{
+       int err;
+
+       netif_addr_lock_bh(dev);
+       err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len,
+                              NETDEV_HW_ADDR_T_MULTICAST, global);
+       if (!err)
+               __dev_set_rx_mode(dev);
+       netif_addr_unlock_bh(dev);
+       return err;
+}
+
+/**
+ *     dev_mc_del - Delete a multicast address.
+ *     @dev: device
+ *     @addr: address to delete
+ *
+ *     Release reference to a multicast address and remove it
+ *     from the device if the reference count drops to zero.
+ */
+int dev_mc_del(struct net_device *dev, unsigned char *addr)
+{
+       return __dev_mc_del(dev, addr, false);
+}
+EXPORT_SYMBOL(dev_mc_del);
+
+/**
+ *     dev_mc_del_global - Delete a global multicast address.
+ *     @dev: device
+ *     @addr: address to delete
+ *
+ *     Release reference to a multicast address and remove it
+ *     from the device if the reference count drops to zero.
+ */
+int dev_mc_del_global(struct net_device *dev, unsigned char *addr)
+{
+       return __dev_mc_del(dev, addr, true);
+}
+EXPORT_SYMBOL(dev_mc_del_global);
+
+/**
+ *     dev_mc_sync - Synchronize device's unicast list to another device
+ *     @to: destination device
+ *     @from: source device
+ *
+ *     Add newly added addresses to the destination device and release
+ *     addresses that have no users left. The source device must be
+ *     locked by netif_tx_lock_bh.
+ *
+ *     This function is intended to be called from the dev->set_multicast_list
+ *     or dev->set_rx_mode function of layered software devices.
+ */
+int dev_mc_sync(struct net_device *to, struct net_device *from)
+{
+       int err = 0;
+
+       if (to->addr_len != from->addr_len)
+               return -EINVAL;
+
+       netif_addr_lock_bh(to);
+       err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len);
+       if (!err)
+               __dev_set_rx_mode(to);
+       netif_addr_unlock_bh(to);
+       return err;
+}
+EXPORT_SYMBOL(dev_mc_sync);
+
+/**
+ *     dev_mc_unsync - Remove synchronized addresses from the destination device
+ *     @to: destination device
+ *     @from: source device
+ *
+ *     Remove all addresses that were added to the destination device by
+ *     dev_mc_sync(). This function is intended to be called from the
+ *     dev->stop function of layered software devices.
+ */
+void dev_mc_unsync(struct net_device *to, struct net_device *from)
+{
+       if (to->addr_len != from->addr_len)
+               return;
+
+       netif_addr_lock_bh(from);
+       netif_addr_lock(to);
+       __hw_addr_unsync(&to->mc, &from->mc, to->addr_len);
+       __dev_set_rx_mode(to);
+       netif_addr_unlock(to);
+       netif_addr_unlock_bh(from);
+}
+EXPORT_SYMBOL(dev_mc_unsync);
+
+/**
+ *     dev_mc_flush - Flush multicast addresses
+ *     @dev: device
+ *
+ *     Flush multicast addresses.
+ */
+void dev_mc_flush(struct net_device *dev)
+{
+       netif_addr_lock_bh(dev);
+       __hw_addr_flush(&dev->mc);
+       netif_addr_unlock_bh(dev);
+}
+EXPORT_SYMBOL(dev_mc_flush);
+
+/**
+ *     dev_mc_flush - Init multicast address list
+ *     @dev: device
+ *
+ *     Init multicast address list.
+ */
+void dev_mc_init(struct net_device *dev)
+{
+       __hw_addr_init(&dev->mc);
+}
+EXPORT_SYMBOL(dev_mc_init);
+
+#ifdef CONFIG_PROC_FS
+#include <linux/seq_file.h>
+
+static int dev_mc_seq_show(struct seq_file *seq, void *v)
+{
+       struct netdev_hw_addr *ha;
+       struct net_device *dev = v;
+
+       if (v == SEQ_START_TOKEN)
+               return 0;
+
+       netif_addr_lock_bh(dev);
+       netdev_for_each_mc_addr(ha, dev) {
+               int i;
+
+               seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
+                          dev->name, ha->refcount, ha->global_use);
+
+               for (i = 0; i < dev->addr_len; i++)
+                       seq_printf(seq, "%02x", ha->addr[i]);
+
+               seq_putc(seq, '\n');
+       }
+       netif_addr_unlock_bh(dev);
+       return 0;
+}
+
+static const struct seq_operations dev_mc_seq_ops = {
+       .start = dev_seq_start,
+       .next  = dev_seq_next,
+       .stop  = dev_seq_stop,
+       .show  = dev_mc_seq_show,
+};
+
+static int dev_mc_seq_open(struct inode *inode, struct file *file)
+{
+       return seq_open_net(inode, file, &dev_mc_seq_ops,
+                           sizeof(struct seq_net_private));
+}
+
+static const struct file_operations dev_mc_seq_fops = {
+       .owner   = THIS_MODULE,
+       .open    = dev_mc_seq_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release_net,
+};
+
+#endif
+
+static int __net_init dev_mc_net_init(struct net *net)
+{
+       if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops))
+               return -ENOMEM;
+       return 0;
+}
+
+static void __net_exit dev_mc_net_exit(struct net *net)
+{
+       proc_net_remove(net, "dev_mcast");
+}
+
+static struct pernet_operations __net_initdata dev_mc_net_ops = {
+       .init = dev_mc_net_init,
+       .exit = dev_mc_net_exit,
+};
+
+void __init dev_mcast_init(void)
+{
+       register_pernet_subsys(&dev_mc_net_ops);
+}
+
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
deleted file mode 100644 (file)
index 3dc295b..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- *     Linux NET3:     Multicast List maintenance.
- *
- *     Authors:
- *             Tim Kordas <tjk@nostromo.eeap.cwru.edu>
- *             Richard Underwood <richard@wuzz.demon.co.uk>
- *
- *     Stir fried together from the IP multicast and CAP patches above
- *             Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- *     Fixes:
- *             Alan Cox        :       Update the device on a real delete
- *                                     rather than any time but...
- *             Alan Cox        :       IFF_ALLMULTI support.
- *             Alan Cox        :       New format set_multicast_list() calls.
- *             Gleb Natapov    :       Remove dev_mc_lock.
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <net/net_namespace.h>
-#include <net/ip.h>
-#include <net/route.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/arp.h>
-
-
-/*
- *     Device multicast list maintenance.
- *
- *     This is used both by IP and by the user level maintenance functions.
- *     Unlike BSD we maintain a usage count on a given multicast address so
- *     that a casual user application can add/delete multicasts used by
- *     protocols without doing damage to the protocols when it deletes the
- *     entries. It also helps IP as it tracks overlapping maps.
- *
- *     Device mc lists are changed by bh at least if IPv6 is enabled,
- *     so that it must be bh protected.
- *
- *     We block accesses to device mc filters with netif_tx_lock.
- */
-
-/*
- *     Delete a device level multicast
- */
-
-int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
-{
-       int err;
-
-       netif_addr_lock_bh(dev);
-       err = __dev_addr_delete(&dev->mc_list, &dev->mc_count,
-                               addr, alen, glbl);
-       if (!err) {
-               /*
-                *      We have altered the list, so the card
-                *      loaded filter is now wrong. Fix it
-                */
-
-               __dev_set_rx_mode(dev);
-       }
-       netif_addr_unlock_bh(dev);
-       return err;
-}
-
-/*
- *     Add a device level multicast
- */
-
-int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
-{
-       int err;
-
-       netif_addr_lock_bh(dev);
-       if (alen != dev->addr_len)
-               err = -EINVAL;
-       else
-               err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);
-       if (!err)
-               __dev_set_rx_mode(dev);
-       netif_addr_unlock_bh(dev);
-       return err;
-}
-
-/**
- *     dev_mc_sync     - Synchronize device's multicast list to another device
- *     @to: destination device
- *     @from: source device
- *
- *     Add newly added addresses to the destination device and release
- *     addresses that have no users left. The source device must be
- *     locked by netif_tx_lock_bh.
- *
- *     This function is intended to be called from the dev->set_multicast_list
- *     or dev->set_rx_mode function of layered software devices.
- */
-int dev_mc_sync(struct net_device *to, struct net_device *from)
-{
-       int err = 0;
-
-       netif_addr_lock_bh(to);
-       err = __dev_addr_sync(&to->mc_list, &to->mc_count,
-                             &from->mc_list, &from->mc_count);
-       if (!err)
-               __dev_set_rx_mode(to);
-       netif_addr_unlock_bh(to);
-
-       return err;
-}
-EXPORT_SYMBOL(dev_mc_sync);
-
-
-/**
- *     dev_mc_unsync   - Remove synchronized addresses from the destination
- *                       device
- *     @to: destination device
- *     @from: source device
- *
- *     Remove all addresses that were added to the destination device by
- *     dev_mc_sync(). This function is intended to be called from the
- *     dev->stop function of layered software devices.
- */
-void dev_mc_unsync(struct net_device *to, struct net_device *from)
-{
-       netif_addr_lock_bh(from);
-       netif_addr_lock(to);
-
-       __dev_addr_unsync(&to->mc_list, &to->mc_count,
-                         &from->mc_list, &from->mc_count);
-       __dev_set_rx_mode(to);
-
-       netif_addr_unlock(to);
-       netif_addr_unlock_bh(from);
-}
-EXPORT_SYMBOL(dev_mc_unsync);
-
-#ifdef CONFIG_PROC_FS
-static int dev_mc_seq_show(struct seq_file *seq, void *v)
-{
-       struct dev_addr_list *m;
-       struct net_device *dev = v;
-
-       if (v == SEQ_START_TOKEN)
-               return 0;
-
-       netif_addr_lock_bh(dev);
-       for (m = dev->mc_list; m; m = m->next) {
-               int i;
-
-               seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex,
-                          dev->name, m->dmi_users, m->dmi_gusers);
-
-               for (i = 0; i < m->dmi_addrlen; i++)
-                       seq_printf(seq, "%02x", m->dmi_addr[i]);
-
-               seq_putc(seq, '\n');
-       }
-       netif_addr_unlock_bh(dev);
-       return 0;
-}
-
-static const struct seq_operations dev_mc_seq_ops = {
-       .start = dev_seq_start,
-       .next  = dev_seq_next,
-       .stop  = dev_seq_stop,
-       .show  = dev_mc_seq_show,
-};
-
-static int dev_mc_seq_open(struct inode *inode, struct file *file)
-{
-       return seq_open_net(inode, file, &dev_mc_seq_ops,
-                           sizeof(struct seq_net_private));
-}
-
-static const struct file_operations dev_mc_seq_fops = {
-       .owner   = THIS_MODULE,
-       .open    = dev_mc_seq_open,
-       .read    = seq_read,
-       .llseek  = seq_lseek,
-       .release = seq_release_net,
-};
-
-#endif
-
-static int __net_init dev_mc_net_init(struct net *net)
-{
-       if (!proc_net_fops_create(net, "dev_mcast", 0, &dev_mc_seq_fops))
-               return -ENOMEM;
-       return 0;
-}
-
-static void __net_exit dev_mc_net_exit(struct net *net)
-{
-       proc_net_remove(net, "dev_mcast");
-}
-
-static struct pernet_operations __net_initdata dev_mc_net_ops = {
-       .init = dev_mc_net_init,
-       .exit = dev_mc_net_exit,
-};
-
-void __init dev_mcast_init(void)
-{
-       register_pernet_subsys(&dev_mc_net_ops);
-}
-
-EXPORT_SYMBOL(dev_mc_add);
-EXPORT_SYMBOL(dev_mc_delete);
index f307bc18f6a0002a0a1f7d1c2268a8cc260e0805..9920722cc82b84490cc75d2010976d5652ae4f4b 100644 (file)
@@ -44,7 +44,7 @@ static atomic_t                        dst_total = ATOMIC_INIT(0);
  */
 static struct {
        spinlock_t              lock;
-       struct dst_entry        *list;
+       struct dst_entry        *list;
        unsigned long           timer_inc;
        unsigned long           timer_expires;
 } dst_garbage = {
@@ -52,7 +52,7 @@ static struct {
        .timer_inc = DST_GC_MAX,
 };
 static void dst_gc_task(struct work_struct *work);
-static void ___dst_free(struct dst_entry * dst);
+static void ___dst_free(struct dst_entry *dst);
 
 static DECLARE_DELAYED_WORK(dst_gc_work, dst_gc_task);
 
@@ -136,8 +136,8 @@ loop:
                }
                expires = dst_garbage.timer_expires;
                /*
-                * if the next desired timer is more than 4 seconds in the future
-                * then round the timer to whole seconds
+                * if the next desired timer is more than 4 seconds in the
+                * future then round the timer to whole seconds
                 */
                if (expires > 4*HZ)
                        expires = round_jiffies_relative(expires);
@@ -152,7 +152,8 @@ loop:
                " expires: %lu elapsed: %lu us\n",
                atomic_read(&dst_total), delayed, work_performed,
                expires,
-               elapsed.tv_sec * USEC_PER_SEC + elapsed.tv_nsec / NSEC_PER_USEC);
+               elapsed.tv_sec * USEC_PER_SEC +
+                 elapsed.tv_nsec / NSEC_PER_USEC);
 #endif
 }
 
@@ -163,9 +164,9 @@ int dst_discard(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(dst_discard);
 
-void * dst_alloc(struct dst_ops * ops)
+void *dst_alloc(struct dst_ops *ops)
 {
-       struct dst_entry * dst;
+       struct dst_entry *dst;
 
        if (ops->gc && atomic_read(&ops->entries) > ops->gc_thresh) {
                if (ops->gc(ops))
@@ -185,19 +186,20 @@ void * dst_alloc(struct dst_ops * ops)
        atomic_inc(&ops->entries);
        return dst;
 }
+EXPORT_SYMBOL(dst_alloc);
 
-static void ___dst_free(struct dst_entry * dst)
+static void ___dst_free(struct dst_entry *dst)
 {
        /* The first case (dev==NULL) is required, when
           protocol module is unloaded.
         */
-       if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) {
+       if (dst->dev == NULL || !(dst->dev->flags&IFF_UP))
                dst->input = dst->output = dst_discard;
-       }
        dst->obsolete = 2;
 }
+EXPORT_SYMBOL(__dst_free);
 
-void __dst_free(struct dst_entry * dst)
+void __dst_free(struct dst_entry *dst)
 {
        spin_lock_bh(&dst_garbage.lock);
        ___dst_free(dst);
@@ -262,15 +264,16 @@ again:
        }
        return NULL;
 }
+EXPORT_SYMBOL(dst_destroy);
 
 void dst_release(struct dst_entry *dst)
 {
        if (dst) {
-               int newrefcnt;
+               int newrefcnt;
 
                smp_mb__before_atomic_dec();
-               newrefcnt = atomic_dec_return(&dst->__refcnt);
-               WARN_ON(newrefcnt < 0);
+               newrefcnt = atomic_dec_return(&dst->__refcnt);
+               WARN_ON(newrefcnt < 0);
        }
 }
 EXPORT_SYMBOL(dst_release);
@@ -283,8 +286,8 @@ EXPORT_SYMBOL(dst_release);
  *
  * Commented and originally written by Alexey.
  */
-static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
-                             int unregister)
+static void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+                      int unregister)
 {
        if (dst->ops->ifdown)
                dst->ops->ifdown(dst, dev, unregister);
@@ -306,7 +309,8 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
        }
 }
 
-static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int dst_dev_event(struct notifier_block *this, unsigned long event,
+                        void *ptr)
 {
        struct net_device *dev = ptr;
        struct dst_entry *dst, *last = NULL;
@@ -329,9 +333,8 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void
                        last->next = dst;
                else
                        dst_busy_list = dst;
-               for (; dst; dst = dst->next) {
+               for (; dst; dst = dst->next)
                        dst_ifdown(dst, dev, event != NETDEV_DOWN);
-               }
                mutex_unlock(&dst_gc_mutex);
                break;
        }
@@ -346,7 +349,3 @@ void __init dst_init(void)
 {
        register_netdevice_notifier(&dst_dev_notifier);
 }
-
-EXPORT_SYMBOL(__dst_free);
-EXPORT_SYMBOL(dst_alloc);
-EXPORT_SYMBOL(dst_destroy);
index 9d55c57f318a7ac93f9362ee5245f07c473c906c..a0f4964033d289b8d1b4959d4d1196ccc094bdff 100644 (file)
@@ -18,8 +18,8 @@
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/bitops.h>
+#include <linux/uaccess.h>
 #include <linux/slab.h>
-#include <asm/uaccess.h>
 
 /*
  * Some useful ethtool_ops methods that're device independent.
@@ -31,6 +31,7 @@ u32 ethtool_op_get_link(struct net_device *dev)
 {
        return netif_carrier_ok(dev) ? 1 : 0;
 }
+EXPORT_SYMBOL(ethtool_op_get_link);
 
 u32 ethtool_op_get_rx_csum(struct net_device *dev)
 {
@@ -63,6 +64,7 @@ int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
 
        return 0;
 }
+EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
 
 int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
 {
@@ -73,11 +75,13 @@ int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
 
        return 0;
 }
+EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
 
 u32 ethtool_op_get_sg(struct net_device *dev)
 {
        return (dev->features & NETIF_F_SG) != 0;
 }
+EXPORT_SYMBOL(ethtool_op_get_sg);
 
 int ethtool_op_set_sg(struct net_device *dev, u32 data)
 {
@@ -88,11 +92,13 @@ int ethtool_op_set_sg(struct net_device *dev, u32 data)
 
        return 0;
 }
+EXPORT_SYMBOL(ethtool_op_set_sg);
 
 u32 ethtool_op_get_tso(struct net_device *dev)
 {
        return (dev->features & NETIF_F_TSO) != 0;
 }
+EXPORT_SYMBOL(ethtool_op_get_tso);
 
 int ethtool_op_set_tso(struct net_device *dev, u32 data)
 {
@@ -103,11 +109,13 @@ int ethtool_op_set_tso(struct net_device *dev, u32 data)
 
        return 0;
 }
+EXPORT_SYMBOL(ethtool_op_set_tso);
 
 u32 ethtool_op_get_ufo(struct net_device *dev)
 {
        return (dev->features & NETIF_F_UFO) != 0;
 }
+EXPORT_SYMBOL(ethtool_op_get_ufo);
 
 int ethtool_op_set_ufo(struct net_device *dev, u32 data)
 {
@@ -117,12 +125,13 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data)
                dev->features &= ~NETIF_F_UFO;
        return 0;
 }
+EXPORT_SYMBOL(ethtool_op_set_ufo);
 
 /* the following list of flags are the same as their associated
  * NETIF_F_xxx values in include/linux/netdevice.h
  */
 static const u32 flags_dup_features =
-       (ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
+       (ETH_FLAG_LRO | ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH);
 
 u32 ethtool_op_get_flags(struct net_device *dev)
 {
@@ -133,6 +142,7 @@ u32 ethtool_op_get_flags(struct net_device *dev)
 
        return dev->features & flags_dup_features;
 }
+EXPORT_SYMBOL(ethtool_op_get_flags);
 
 int ethtool_op_set_flags(struct net_device *dev, u32 data)
 {
@@ -153,9 +163,15 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data)
                features &= ~NETIF_F_NTUPLE;
        }
 
+       if (data & ETH_FLAG_RXHASH)
+               features |= NETIF_F_RXHASH;
+       else
+               features &= ~NETIF_F_RXHASH;
+
        dev->features = features;
        return 0;
 }
+EXPORT_SYMBOL(ethtool_op_set_flags);
 
 void ethtool_ntuple_flush(struct net_device *dev)
 {
@@ -201,7 +217,8 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
        return dev->ethtool_ops->set_settings(dev, &cmd);
 }
 
-static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
+static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
+                                                 void __user *useraddr)
 {
        struct ethtool_drvinfo info;
        const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -241,7 +258,7 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, void _
 }
 
 static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev,
-                                          void __user *useraddr)
+                                                   void __user *useraddr)
 {
        struct ethtool_sset_info info;
        const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -300,7 +317,8 @@ out:
        return ret;
 }
 
-static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
+static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
+                                               void __user *useraddr)
 {
        struct ethtool_rxnfc cmd;
 
@@ -313,7 +331,8 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, void __u
        return dev->ethtool_ops->set_rxnfc(dev, &cmd);
 }
 
-static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
+static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
+                                               void __user *useraddr)
 {
        struct ethtool_rxnfc info;
        const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -358,8 +377,8 @@ err_out:
 }
 
 static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
-                              struct ethtool_rx_ntuple_flow_spec *spec,
-                              struct ethtool_rx_ntuple_flow_spec_container *fsc)
+                       struct ethtool_rx_ntuple_flow_spec *spec,
+                       struct ethtool_rx_ntuple_flow_spec_container *fsc)
 {
 
        /* don't add filters forever */
@@ -385,7 +404,8 @@ static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
        list->count++;
 }
 
-static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)
+static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
+                                                   void __user *useraddr)
 {
        struct ethtool_rx_ntuple cmd;
        const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -502,7 +522,7 @@ static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        goto unknown_filter;
-               };
+               }
 
                /* now the rest of the filters */
                switch (fsc->fs.flow_type) {
@@ -510,125 +530,125 @@ static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
                case UDP_V4_FLOW:
                case SCTP_V4_FLOW:
                        sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.ip4src);
+                               fsc->fs.h_u.tcp_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.tcp_ip4_spec.ip4src);
+                               fsc->fs.m_u.tcp_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.ip4dst);
+                               fsc->fs.h_u.tcp_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.tcp_ip4_spec.ip4dst);
+                               fsc->fs.m_u.tcp_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tSrc Port: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.psrc,
-                               fsc->fs.m_u.tcp_ip4_spec.psrc);
+                               fsc->fs.h_u.tcp_ip4_spec.psrc,
+                               fsc->fs.m_u.tcp_ip4_spec.psrc);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest Port: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.pdst,
-                               fsc->fs.m_u.tcp_ip4_spec.pdst);
+                               fsc->fs.h_u.tcp_ip4_spec.pdst,
+                               fsc->fs.m_u.tcp_ip4_spec.pdst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tTOS: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.tos,
-                               fsc->fs.m_u.tcp_ip4_spec.tos);
+                               fsc->fs.h_u.tcp_ip4_spec.tos,
+                               fsc->fs.m_u.tcp_ip4_spec.tos);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        break;
                case AH_ESP_V4_FLOW:
                case ESP_V4_FLOW:
                        sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.ip4src);
+                               fsc->fs.h_u.ah_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.ah_ip4_spec.ip4src);
+                               fsc->fs.m_u.ah_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.ip4dst);
+                               fsc->fs.h_u.ah_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.ah_ip4_spec.ip4dst);
+                               fsc->fs.m_u.ah_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tSPI: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.spi,
-                               fsc->fs.m_u.ah_ip4_spec.spi);
+                               fsc->fs.h_u.ah_ip4_spec.spi,
+                               fsc->fs.m_u.ah_ip4_spec.spi);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tTOS: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.tos,
-                               fsc->fs.m_u.ah_ip4_spec.tos);
+                               fsc->fs.h_u.ah_ip4_spec.tos,
+                               fsc->fs.m_u.ah_ip4_spec.tos);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        break;
                case IP_USER_FLOW:
                        sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.raw_ip4_spec.ip4src);
+                               fsc->fs.h_u.raw_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.raw_ip4_spec.ip4src);
+                               fsc->fs.m_u.raw_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.raw_ip4_spec.ip4dst);
+                               fsc->fs.h_u.raw_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.raw_ip4_spec.ip4dst);
+                               fsc->fs.m_u.raw_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        break;
                case IPV4_FLOW:
                        sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip4src);
+                               fsc->fs.h_u.usr_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.usr_ip4_spec.ip4src);
+                               fsc->fs.m_u.usr_ip4_spec.ip4src);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip4dst);
+                               fsc->fs.h_u.usr_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.usr_ip4_spec.ip4dst);
+                               fsc->fs.m_u.usr_ip4_spec.ip4dst);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
-                               fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
+                               fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
+                               fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tTOS: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.tos,
-                               fsc->fs.m_u.usr_ip4_spec.tos);
+                               fsc->fs.h_u.usr_ip4_spec.tos,
+                               fsc->fs.m_u.usr_ip4_spec.tos);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tIP Version: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip_ver,
-                               fsc->fs.m_u.usr_ip4_spec.ip_ver);
+                               fsc->fs.h_u.usr_ip4_spec.ip_ver,
+                               fsc->fs.m_u.usr_ip4_spec.ip_ver);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        sprintf(p, "\tProtocol: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.proto,
-                               fsc->fs.m_u.usr_ip4_spec.proto);
+                               fsc->fs.h_u.usr_ip4_spec.proto,
+                               fsc->fs.m_u.usr_ip4_spec.proto);
                        p += ETH_GSTRING_LEN;
                        num_strings++;
                        break;
-               };
+               }
                sprintf(p, "\tVLAN: %d, mask: 0x%x\n",
-                       fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
+                       fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
                p += ETH_GSTRING_LEN;
                num_strings++;
                sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data);
@@ -641,7 +661,7 @@ static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
                        sprintf(p, "\tAction: Drop\n");
                else
                        sprintf(p, "\tAction: Direct to queue %d\n",
-                               fsc->fs.action);
+                               fsc->fs.action);
                p += ETH_GSTRING_LEN;
                num_strings++;
 unknown_filter:
@@ -853,7 +873,8 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
        return ret;
 }
 
-static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
+static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev,
+                                                  void __user *useraddr)
 {
        struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
 
@@ -867,7 +888,8 @@ static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev, void
        return 0;
 }
 
-static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
+static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev,
+                                                  void __user *useraddr)
 {
        struct ethtool_coalesce coalesce;
 
@@ -971,6 +993,7 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr)
 
        return dev->ethtool_ops->set_tx_csum(dev, edata.data);
 }
+EXPORT_SYMBOL(ethtool_op_set_tx_csum);
 
 static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr)
 {
@@ -1042,7 +1065,7 @@ static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
 
        edata.data = dev->features & NETIF_F_GSO;
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
-                return -EFAULT;
+               return -EFAULT;
        return 0;
 }
 
@@ -1065,7 +1088,7 @@ static int ethtool_get_gro(struct net_device *dev, char __user *useraddr)
 
        edata.data = dev->features & NETIF_F_GRO;
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
-                return -EFAULT;
+               return -EFAULT;
        return 0;
 }
 
@@ -1277,7 +1300,8 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
        return actor(dev, edata.data);
 }
 
-static noinline_for_stack int ethtool_flash_device(struct net_device *dev, char __user *useraddr)
+static noinline_for_stack int ethtool_flash_device(struct net_device *dev,
+                                                  char __user *useraddr)
 {
        struct ethtool_flash efl;
 
@@ -1306,11 +1330,11 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        if (!dev->ethtool_ops)
                return -EOPNOTSUPP;
 
-       if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
+       if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
                return -EFAULT;
 
        /* Allow some commands to be done by anyone */
-       switch(ethcmd) {
+       switch (ethcmd) {
        case ETHTOOL_GDRVINFO:
        case ETHTOOL_GMSGLVL:
        case ETHTOOL_GCOALESCE:
@@ -1338,10 +1362,11 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
                        return -EPERM;
        }
 
-       if (dev->ethtool_ops->begin)
-               if ((rc = dev->ethtool_ops->begin(dev)) < 0)
+       if (dev->ethtool_ops->begin) {
+               rc = dev->ethtool_ops->begin(dev);
+               if (rc  < 0)
                        return rc;
-
+       }
        old_features = dev->features;
 
        switch (ethcmd) {
@@ -1531,16 +1556,3 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
 
        return rc;
 }
-
-EXPORT_SYMBOL(ethtool_op_get_link);
-EXPORT_SYMBOL(ethtool_op_get_sg);
-EXPORT_SYMBOL(ethtool_op_get_tso);
-EXPORT_SYMBOL(ethtool_op_set_sg);
-EXPORT_SYMBOL(ethtool_op_set_tso);
-EXPORT_SYMBOL(ethtool_op_set_tx_csum);
-EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
-EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
-EXPORT_SYMBOL(ethtool_op_set_ufo);
-EXPORT_SYMBOL(ethtool_op_get_ufo);
-EXPORT_SYMBOL(ethtool_op_set_flags);
-EXPORT_SYMBOL(ethtool_op_get_flags);
index d2c3e7dc2e5f17baedd875cdd805186a7678b2aa..42e84e08a1becd4b64a65a74758bf4e13783a8ae 100644 (file)
@@ -39,6 +39,24 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
 }
 EXPORT_SYMBOL(fib_default_rule_add);
 
+u32 fib_default_rule_pref(struct fib_rules_ops *ops)
+{
+       struct list_head *pos;
+       struct fib_rule *rule;
+
+       if (!list_empty(&ops->rules_list)) {
+               pos = ops->rules_list.next;
+               if (pos->next != &ops->rules_list) {
+                       rule = list_entry(pos->next, struct fib_rule, list);
+                       if (rule->pref)
+                               return rule->pref - 1;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(fib_default_rule_pref);
+
 static void notify_rule_change(int event, struct fib_rule *rule,
                               struct fib_rules_ops *ops, struct nlmsghdr *nlh,
                               u32 pid);
@@ -104,12 +122,12 @@ errout:
 }
 
 struct fib_rules_ops *
-fib_rules_register(struct fib_rules_ops *tmpl, struct net *net)
+fib_rules_register(const struct fib_rules_ops *tmpl, struct net *net)
 {
        struct fib_rules_ops *ops;
        int err;
 
-       ops = kmemdup(tmpl, sizeof (*ops), GFP_KERNEL);
+       ops = kmemdup(tmpl, sizeof(*ops), GFP_KERNEL);
        if (ops == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -124,7 +142,6 @@ fib_rules_register(struct fib_rules_ops *tmpl, struct net *net)
 
        return ops;
 }
-
 EXPORT_SYMBOL_GPL(fib_rules_register);
 
 void fib_rules_cleanup_ops(struct fib_rules_ops *ops)
@@ -158,7 +175,6 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
 
        call_rcu(&ops->rcu, fib_rules_put_rcu);
 }
-
 EXPORT_SYMBOL_GPL(fib_rules_unregister);
 
 static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
@@ -221,7 +237,6 @@ out:
 
        return err;
 }
-
 EXPORT_SYMBOL_GPL(fib_rules_lookup);
 
 static int validate_rulemsg(struct fib_rule_hdr *frh, struct nlattr **tb,
@@ -520,6 +535,7 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
                return -EMSGSIZE;
 
        frh = nlmsg_data(nlh);
+       frh->family = ops->family;
        frh->table = rule->table;
        NLA_PUT_U32(skb, FRA_TABLE, rule->table);
        frh->res1 = 0;
@@ -614,7 +630,7 @@ static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
                        break;
 
                cb->args[1] = 0;
-       skip:
+skip:
                idx++;
        }
        rcu_read_unlock();
@@ -686,7 +702,6 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
        struct fib_rules_ops *ops;
 
        ASSERT_RTNL();
-       rcu_read_lock();
 
        switch (event) {
        case NETDEV_REGISTER:
@@ -700,8 +715,6 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
                break;
        }
 
-       rcu_read_unlock();
-
        return NOTIFY_DONE;
 }
 
index ff943bed21afe0b90cc797628ff76795c79981f4..da69fb728d328f1b47236cebaaea7ae26f3bcd47 100644 (file)
@@ -302,6 +302,8 @@ load_b:
                        A = skb->pkt_type;
                        continue;
                case SKF_AD_IFINDEX:
+                       if (!skb->dev)
+                               return 0;
                        A = skb->dev->ifindex;
                        continue;
                case SKF_AD_MARK:
@@ -310,6 +312,11 @@ load_b:
                case SKF_AD_QUEUE:
                        A = skb->queue_mapping;
                        continue;
+               case SKF_AD_HATYPE:
+                       if (!skb->dev)
+                               return 0;
+                       A = skb->dev->type;
+                       continue;
                case SKF_AD_NLATTR: {
                        struct nlattr *nla;
 
index 96015871eceadeacc65d8b572fdcf0d757ecccca..161900674009d832752a2b3929586b53522f064f 100644 (file)
 #include <linux/security.h>
 
 struct flow_cache_entry {
-       struct flow_cache_entry *next;
-       u16                     family;
-       u8                      dir;
-       u32                     genid;
-       struct flowi            key;
-       void                    *object;
-       atomic_t                *object_ref;
+       union {
+               struct hlist_node       hlist;
+               struct list_head        gc_list;
+       } u;
+       u16                             family;
+       u8                              dir;
+       u32                             genid;
+       struct flowi                    key;
+       struct flow_cache_object        *object;
 };
 
-atomic_t flow_cache_genid = ATOMIC_INIT(0);
-
-static u32 flow_hash_shift;
-#define flow_hash_size (1 << flow_hash_shift)
-static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL };
-
-#define flow_table(cpu) (per_cpu(flow_tables, cpu))
-
-static struct kmem_cache *flow_cachep __read_mostly;
+struct flow_cache_percpu {
+       struct hlist_head               *hash_table;
+       int                             hash_count;
+       u32                             hash_rnd;
+       int                             hash_rnd_recalc;
+       struct tasklet_struct           flush_tasklet;
+};
 
-static int flow_lwm, flow_hwm;
+struct flow_flush_info {
+       struct flow_cache               *cache;
+       atomic_t                        cpuleft;
+       struct completion               completion;
+};
 
-struct flow_percpu_info {
-       int hash_rnd_recalc;
-       u32 hash_rnd;
-       int count;
+struct flow_cache {
+       u32                             hash_shift;
+       unsigned long                   order;
+       struct flow_cache_percpu        *percpu;
+       struct notifier_block           hotcpu_notifier;
+       int                             low_watermark;
+       int                             high_watermark;
+       struct timer_list               rnd_timer;
 };
-static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info) = { 0 };
 
-#define flow_hash_rnd_recalc(cpu) \
-       (per_cpu(flow_hash_info, cpu).hash_rnd_recalc)
-#define flow_hash_rnd(cpu) \
-       (per_cpu(flow_hash_info, cpu).hash_rnd)
-#define flow_count(cpu) \
-       (per_cpu(flow_hash_info, cpu).count)
+atomic_t flow_cache_genid = ATOMIC_INIT(0);
+static struct flow_cache flow_cache_global;
+static struct kmem_cache *flow_cachep;
 
-static struct timer_list flow_hash_rnd_timer;
+static DEFINE_SPINLOCK(flow_cache_gc_lock);
+static LIST_HEAD(flow_cache_gc_list);
 
-#define FLOW_HASH_RND_PERIOD   (10 * 60 * HZ)
-
-struct flow_flush_info {
-       atomic_t cpuleft;
-       struct completion completion;
-};
-static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets) = { NULL };
-
-#define flow_flush_tasklet(cpu) (&per_cpu(flow_flush_tasklets, cpu))
+#define flow_cache_hash_size(cache)    (1 << (cache)->hash_shift)
+#define FLOW_HASH_RND_PERIOD           (10 * 60 * HZ)
 
 static void flow_cache_new_hashrnd(unsigned long arg)
 {
+       struct flow_cache *fc = (void *) arg;
        int i;
 
        for_each_possible_cpu(i)
-               flow_hash_rnd_recalc(i) = 1;
+               per_cpu_ptr(fc->percpu, i)->hash_rnd_recalc = 1;
 
-       flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
-       add_timer(&flow_hash_rnd_timer);
+       fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+       add_timer(&fc->rnd_timer);
+}
+
+static int flow_entry_valid(struct flow_cache_entry *fle)
+{
+       if (atomic_read(&flow_cache_genid) != fle->genid)
+               return 0;
+       if (fle->object && !fle->object->ops->check(fle->object))
+               return 0;
+       return 1;
 }
 
-static void flow_entry_kill(int cpu, struct flow_cache_entry *fle)
+static void flow_entry_kill(struct flow_cache_entry *fle)
 {
        if (fle->object)
-               atomic_dec(fle->object_ref);
+               fle->object->ops->delete(fle->object);
        kmem_cache_free(flow_cachep, fle);
-       flow_count(cpu)--;
 }
 
-static void __flow_cache_shrink(int cpu, int shrink_to)
+static void flow_cache_gc_task(struct work_struct *work)
 {
-       struct flow_cache_entry *fle, **flp;
-       int i;
+       struct list_head gc_list;
+       struct flow_cache_entry *fce, *n;
 
-       for (i = 0; i < flow_hash_size; i++) {
-               int k = 0;
+       INIT_LIST_HEAD(&gc_list);
+       spin_lock_bh(&flow_cache_gc_lock);
+       list_splice_tail_init(&flow_cache_gc_list, &gc_list);
+       spin_unlock_bh(&flow_cache_gc_lock);
 
-               flp = &flow_table(cpu)[i];
-               while ((fle = *flp) != NULL && k < shrink_to) {
-                       k++;
-                       flp = &fle->next;
-               }
-               while ((fle = *flp) != NULL) {
-                       *flp = fle->next;
-                       flow_entry_kill(cpu, fle);
-               }
+       list_for_each_entry_safe(fce, n, &gc_list, u.gc_list)
+               flow_entry_kill(fce);
+}
+static DECLARE_WORK(flow_cache_gc_work, flow_cache_gc_task);
+
+static void flow_cache_queue_garbage(struct flow_cache_percpu *fcp,
+                                    int deleted, struct list_head *gc_list)
+{
+       if (deleted) {
+               fcp->hash_count -= deleted;
+               spin_lock_bh(&flow_cache_gc_lock);
+               list_splice_tail(gc_list, &flow_cache_gc_list);
+               spin_unlock_bh(&flow_cache_gc_lock);
+               schedule_work(&flow_cache_gc_work);
        }
 }
 
-static void flow_cache_shrink(int cpu)
+static void __flow_cache_shrink(struct flow_cache *fc,
+                               struct flow_cache_percpu *fcp,
+                               int shrink_to)
 {
-       int shrink_to = flow_lwm / flow_hash_size;
+       struct flow_cache_entry *fle;
+       struct hlist_node *entry, *tmp;
+       LIST_HEAD(gc_list);
+       int i, deleted = 0;
+
+       for (i = 0; i < flow_cache_hash_size(fc); i++) {
+               int saved = 0;
+
+               hlist_for_each_entry_safe(fle, entry, tmp,
+                                         &fcp->hash_table[i], u.hlist) {
+                       if (saved < shrink_to &&
+                           flow_entry_valid(fle)) {
+                               saved++;
+                       } else {
+                               deleted++;
+                               hlist_del(&fle->u.hlist);
+                               list_add_tail(&fle->u.gc_list, &gc_list);
+                       }
+               }
+       }
 
-       __flow_cache_shrink(cpu, shrink_to);
+       flow_cache_queue_garbage(fcp, deleted, &gc_list);
 }
 
-static void flow_new_hash_rnd(int cpu)
+static void flow_cache_shrink(struct flow_cache *fc,
+                             struct flow_cache_percpu *fcp)
 {
-       get_random_bytes(&flow_hash_rnd(cpu), sizeof(u32));
-       flow_hash_rnd_recalc(cpu) = 0;
+       int shrink_to = fc->low_watermark / flow_cache_hash_size(fc);
 
-       __flow_cache_shrink(cpu, 0);
+       __flow_cache_shrink(fc, fcp, shrink_to);
 }
 
-static u32 flow_hash_code(struct flowi *key, int cpu)
+static void flow_new_hash_rnd(struct flow_cache *fc,
+                             struct flow_cache_percpu *fcp)
+{
+       get_random_bytes(&fcp->hash_rnd, sizeof(u32));
+       fcp->hash_rnd_recalc = 0;
+       __flow_cache_shrink(fc, fcp, 0);
+}
+
+static u32 flow_hash_code(struct flow_cache *fc,
+                         struct flow_cache_percpu *fcp,
+                         struct flowi *key)
 {
        u32 *k = (u32 *) key;
 
-       return (jhash2(k, (sizeof(*key) / sizeof(u32)), flow_hash_rnd(cpu)) &
-               (flow_hash_size - 1));
+       return (jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd)
+               & (flow_cache_hash_size(fc) - 1));
 }
 
 #if (BITS_PER_LONG == 64)
@@ -165,114 +210,117 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2)
        return 0;
 }
 
-void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir,
-                       flow_resolve_t resolver)
+struct flow_cache_object *
+flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir,
+                 flow_resolve_t resolver, void *ctx)
 {
-       struct flow_cache_entry *fle, **head;
+       struct flow_cache *fc = &flow_cache_global;
+       struct flow_cache_percpu *fcp;
+       struct flow_cache_entry *fle, *tfle;
+       struct hlist_node *entry;
+       struct flow_cache_object *flo;
        unsigned int hash;
-       int cpu;
 
        local_bh_disable();
-       cpu = smp_processor_id();
+       fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
 
        fle = NULL;
+       flo = NULL;
        /* Packet really early in init?  Making flow_cache_init a
         * pre-smp initcall would solve this.  --RR */
-       if (!flow_table(cpu))
+       if (!fcp->hash_table)
                goto nocache;
 
-       if (flow_hash_rnd_recalc(cpu))
-               flow_new_hash_rnd(cpu);
-       hash = flow_hash_code(key, cpu);
+       if (fcp->hash_rnd_recalc)
+               flow_new_hash_rnd(fc, fcp);
 
-       head = &flow_table(cpu)[hash];
-       for (fle = *head; fle; fle = fle->next) {
-               if (fle->family == family &&
-                   fle->dir == dir &&
-                   flow_key_compare(key, &fle->key) == 0) {
-                       if (fle->genid == atomic_read(&flow_cache_genid)) {
-                               void *ret = fle->object;
-
-                               if (ret)
-                                       atomic_inc(fle->object_ref);
-                               local_bh_enable();
-
-                               return ret;
-                       }
+       hash = flow_hash_code(fc, fcp, key);
+       hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) {
+               if (tfle->family == family &&
+                   tfle->dir == dir &&
+                   flow_key_compare(key, &tfle->key) == 0) {
+                       fle = tfle;
                        break;
                }
        }
 
-       if (!fle) {
-               if (flow_count(cpu) > flow_hwm)
-                       flow_cache_shrink(cpu);
+       if (unlikely(!fle)) {
+               if (fcp->hash_count > fc->high_watermark)
+                       flow_cache_shrink(fc, fcp);
 
                fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC);
                if (fle) {
-                       fle->next = *head;
-                       *head = fle;
                        fle->family = family;
                        fle->dir = dir;
                        memcpy(&fle->key, key, sizeof(*key));
                        fle->object = NULL;
-                       flow_count(cpu)++;
+                       hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]);
+                       fcp->hash_count++;
                }
+       } else if (likely(fle->genid == atomic_read(&flow_cache_genid))) {
+               flo = fle->object;
+               if (!flo)
+                       goto ret_object;
+               flo = flo->ops->get(flo);
+               if (flo)
+                       goto ret_object;
+       } else if (fle->object) {
+               flo = fle->object;
+               flo->ops->delete(flo);
+               fle->object = NULL;
        }
 
 nocache:
-       {
-               int err;
-               void *obj;
-               atomic_t *obj_ref;
-
-               err = resolver(net, key, family, dir, &obj, &obj_ref);
-
-               if (fle && !err) {
-                       fle->genid = atomic_read(&flow_cache_genid);
-
-                       if (fle->object)
-                               atomic_dec(fle->object_ref);
-
-                       fle->object = obj;
-                       fle->object_ref = obj_ref;
-                       if (obj)
-                               atomic_inc(fle->object_ref);
-               }
-               local_bh_enable();
-
-               if (err)
-                       obj = ERR_PTR(err);
-               return obj;
+       flo = NULL;
+       if (fle) {
+               flo = fle->object;
+               fle->object = NULL;
        }
+       flo = resolver(net, key, family, dir, flo, ctx);
+       if (fle) {
+               fle->genid = atomic_read(&flow_cache_genid);
+               if (!IS_ERR(flo))
+                       fle->object = flo;
+               else
+                       fle->genid--;
+       } else {
+               if (flo && !IS_ERR(flo))
+                       flo->ops->delete(flo);
+       }
+ret_object:
+       local_bh_enable();
+       return flo;
 }
 
 static void flow_cache_flush_tasklet(unsigned long data)
 {
        struct flow_flush_info *info = (void *)data;
-       int i;
-       int cpu;
-
-       cpu = smp_processor_id();
-       for (i = 0; i < flow_hash_size; i++) {
-               struct flow_cache_entry *fle;
-
-               fle = flow_table(cpu)[i];
-               for (; fle; fle = fle->next) {
-                       unsigned genid = atomic_read(&flow_cache_genid);
-
-                       if (!fle->object || fle->genid == genid)
+       struct flow_cache *fc = info->cache;
+       struct flow_cache_percpu *fcp;
+       struct flow_cache_entry *fle;
+       struct hlist_node *entry, *tmp;
+       LIST_HEAD(gc_list);
+       int i, deleted = 0;
+
+       fcp = per_cpu_ptr(fc->percpu, smp_processor_id());
+       for (i = 0; i < flow_cache_hash_size(fc); i++) {
+               hlist_for_each_entry_safe(fle, entry, tmp,
+                                         &fcp->hash_table[i], u.hlist) {
+                       if (flow_entry_valid(fle))
                                continue;
 
-                       fle->object = NULL;
-                       atomic_dec(fle->object_ref);
+                       deleted++;
+                       hlist_del(&fle->u.hlist);
+                       list_add_tail(&fle->u.gc_list, &gc_list);
                }
        }
 
+       flow_cache_queue_garbage(fcp, deleted, &gc_list);
+
        if (atomic_dec_and_test(&info->cpuleft))
                complete(&info->completion);
 }
 
-static void flow_cache_flush_per_cpu(void *) __attribute__((__unused__));
 static void flow_cache_flush_per_cpu(void *data)
 {
        struct flow_flush_info *info = data;
@@ -280,8 +328,7 @@ static void flow_cache_flush_per_cpu(void *data)
        struct tasklet_struct *tasklet;
 
        cpu = smp_processor_id();
-
-       tasklet = flow_flush_tasklet(cpu);
+       tasklet = &per_cpu_ptr(info->cache->percpu, cpu)->flush_tasklet;
        tasklet->data = (unsigned long)info;
        tasklet_schedule(tasklet);
 }
@@ -294,6 +341,7 @@ void flow_cache_flush(void)
        /* Don't want cpus going down or up during this. */
        get_online_cpus();
        mutex_lock(&flow_flush_sem);
+       info.cache = &flow_cache_global;
        atomic_set(&info.cpuleft, num_online_cpus());
        init_completion(&info.completion);
 
@@ -307,62 +355,75 @@ void flow_cache_flush(void)
        put_online_cpus();
 }
 
-static void __init flow_cache_cpu_prepare(int cpu)
+static void __init flow_cache_cpu_prepare(struct flow_cache *fc,
+                                         struct flow_cache_percpu *fcp)
 {
-       struct tasklet_struct *tasklet;
-       unsigned long order;
-
-       for (order = 0;
-            (PAGE_SIZE << order) <
-                    (sizeof(struct flow_cache_entry *)*flow_hash_size);
-            order++)
-               /* NOTHING */;
-
-       flow_table(cpu) = (struct flow_cache_entry **)
-               __get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
-       if (!flow_table(cpu))
-               panic("NET: failed to allocate flow cache order %lu\n", order);
-
-       flow_hash_rnd_recalc(cpu) = 1;
-       flow_count(cpu) = 0;
-
-       tasklet = flow_flush_tasklet(cpu);
-       tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
+       fcp->hash_table = (struct hlist_head *)
+               __get_free_pages(GFP_KERNEL|__GFP_ZERO, fc->order);
+       if (!fcp->hash_table)
+               panic("NET: failed to allocate flow cache order %lu\n", fc->order);
+
+       fcp->hash_rnd_recalc = 1;
+       fcp->hash_count = 0;
+       tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0);
 }
 
 static int flow_cache_cpu(struct notifier_block *nfb,
                          unsigned long action,
                          void *hcpu)
 {
+       struct flow_cache *fc = container_of(nfb, struct flow_cache, hotcpu_notifier);
+       int cpu = (unsigned long) hcpu;
+       struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
+
        if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
-               __flow_cache_shrink((unsigned long)hcpu, 0);
+               __flow_cache_shrink(fc, fcp, 0);
        return NOTIFY_OK;
 }
 
-static int __init flow_cache_init(void)
+static int flow_cache_init(struct flow_cache *fc)
 {
+       unsigned long order;
        int i;
 
-       flow_cachep = kmem_cache_create("flow_cache",
-                                       sizeof(struct flow_cache_entry),
-                                       0, SLAB_PANIC,
-                                       NULL);
-       flow_hash_shift = 10;
-       flow_lwm = 2 * flow_hash_size;
-       flow_hwm = 4 * flow_hash_size;
+       fc->hash_shift = 10;
+       fc->low_watermark = 2 * flow_cache_hash_size(fc);
+       fc->high_watermark = 4 * flow_cache_hash_size(fc);
+
+       for (order = 0;
+            (PAGE_SIZE << order) <
+                    (sizeof(struct hlist_head)*flow_cache_hash_size(fc));
+            order++)
+               /* NOTHING */;
+       fc->order = order;
+       fc->percpu = alloc_percpu(struct flow_cache_percpu);
 
-       setup_timer(&flow_hash_rnd_timer, flow_cache_new_hashrnd, 0);
-       flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
-       add_timer(&flow_hash_rnd_timer);
+       setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd,
+                   (unsigned long) fc);
+       fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+       add_timer(&fc->rnd_timer);
 
        for_each_possible_cpu(i)
-               flow_cache_cpu_prepare(i);
+               flow_cache_cpu_prepare(fc, per_cpu_ptr(fc->percpu, i));
+
+       fc->hotcpu_notifier = (struct notifier_block){
+               .notifier_call = flow_cache_cpu,
+       };
+       register_hotcpu_notifier(&fc->hotcpu_notifier);
 
-       hotcpu_notifier(flow_cache_cpu, 0);
        return 0;
 }
 
-module_init(flow_cache_init);
+static int __init flow_cache_init_global(void)
+{
+       flow_cachep = kmem_cache_create("flow_cache",
+                                       sizeof(struct flow_cache_entry),
+                                       0, SLAB_PANIC, NULL);
+
+       return flow_cache_init(&flow_cache_global);
+}
+
+module_init(flow_cache_init_global);
 
 EXPORT_SYMBOL(flow_cache_genid);
 EXPORT_SYMBOL(flow_cache_lookup);
index 59cfc7d8fc450c26a17b094280dec7a2842461e9..c57c4b228bb5b849599124e058322aabe8d203d8 100644 (file)
@@ -17,6 +17,7 @@
 #include <net/sock.h>
 #include <linux/rtnetlink.h>
 #include <linux/wireless.h>
+#include <linux/vmalloc.h>
 #include <net/wext.h>
 
 #include "net-sysfs.h"
@@ -467,6 +468,304 @@ static struct attribute_group wireless_group = {
 };
 #endif
 
+#ifdef CONFIG_RPS
+/*
+ * RX queue sysfs structures and functions.
+ */
+struct rx_queue_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct netdev_rx_queue *queue,
+           struct rx_queue_attribute *attr, char *buf);
+       ssize_t (*store)(struct netdev_rx_queue *queue,
+           struct rx_queue_attribute *attr, const char *buf, size_t len);
+};
+#define to_rx_queue_attr(_attr) container_of(_attr,            \
+    struct rx_queue_attribute, attr)
+
+#define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj)
+
+static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr,
+                                 char *buf)
+{
+       struct rx_queue_attribute *attribute = to_rx_queue_attr(attr);
+       struct netdev_rx_queue *queue = to_rx_queue(kobj);
+
+       if (!attribute->show)
+               return -EIO;
+
+       return attribute->show(queue, attribute, buf);
+}
+
+static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct rx_queue_attribute *attribute = to_rx_queue_attr(attr);
+       struct netdev_rx_queue *queue = to_rx_queue(kobj);
+
+       if (!attribute->store)
+               return -EIO;
+
+       return attribute->store(queue, attribute, buf, count);
+}
+
+static struct sysfs_ops rx_queue_sysfs_ops = {
+       .show = rx_queue_attr_show,
+       .store = rx_queue_attr_store,
+};
+
+static ssize_t show_rps_map(struct netdev_rx_queue *queue,
+                           struct rx_queue_attribute *attribute, char *buf)
+{
+       struct rps_map *map;
+       cpumask_var_t mask;
+       size_t len = 0;
+       int i;
+
+       if (!zalloc_cpumask_var(&mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       rcu_read_lock();
+       map = rcu_dereference(queue->rps_map);
+       if (map)
+               for (i = 0; i < map->len; i++)
+                       cpumask_set_cpu(map->cpus[i], mask);
+
+       len += cpumask_scnprintf(buf + len, PAGE_SIZE, mask);
+       if (PAGE_SIZE - len < 3) {
+               rcu_read_unlock();
+               free_cpumask_var(mask);
+               return -EINVAL;
+       }
+       rcu_read_unlock();
+
+       free_cpumask_var(mask);
+       len += sprintf(buf + len, "\n");
+       return len;
+}
+
+static void rps_map_release(struct rcu_head *rcu)
+{
+       struct rps_map *map = container_of(rcu, struct rps_map, rcu);
+
+       kfree(map);
+}
+
+static ssize_t store_rps_map(struct netdev_rx_queue *queue,
+                     struct rx_queue_attribute *attribute,
+                     const char *buf, size_t len)
+{
+       struct rps_map *old_map, *map;
+       cpumask_var_t mask;
+       int err, cpu, i;
+       static DEFINE_SPINLOCK(rps_map_lock);
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits);
+       if (err) {
+               free_cpumask_var(mask);
+               return err;
+       }
+
+       map = kzalloc(max_t(unsigned,
+           RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES),
+           GFP_KERNEL);
+       if (!map) {
+               free_cpumask_var(mask);
+               return -ENOMEM;
+       }
+
+       i = 0;
+       for_each_cpu_and(cpu, mask, cpu_online_mask)
+               map->cpus[i++] = cpu;
+
+       if (i)
+               map->len = i;
+       else {
+               kfree(map);
+               map = NULL;
+       }
+
+       spin_lock(&rps_map_lock);
+       old_map = queue->rps_map;
+       rcu_assign_pointer(queue->rps_map, map);
+       spin_unlock(&rps_map_lock);
+
+       if (old_map)
+               call_rcu(&old_map->rcu, rps_map_release);
+
+       free_cpumask_var(mask);
+       return len;
+}
+
+static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,
+                                          struct rx_queue_attribute *attr,
+                                          char *buf)
+{
+       struct rps_dev_flow_table *flow_table;
+       unsigned int val = 0;
+
+       rcu_read_lock();
+       flow_table = rcu_dereference(queue->rps_flow_table);
+       if (flow_table)
+               val = flow_table->mask + 1;
+       rcu_read_unlock();
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static void rps_dev_flow_table_release_work(struct work_struct *work)
+{
+       struct rps_dev_flow_table *table = container_of(work,
+           struct rps_dev_flow_table, free_work);
+
+       vfree(table);
+}
+
+static void rps_dev_flow_table_release(struct rcu_head *rcu)
+{
+       struct rps_dev_flow_table *table = container_of(rcu,
+           struct rps_dev_flow_table, rcu);
+
+       INIT_WORK(&table->free_work, rps_dev_flow_table_release_work);
+       schedule_work(&table->free_work);
+}
+
+static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue,
+                                    struct rx_queue_attribute *attr,
+                                    const char *buf, size_t len)
+{
+       unsigned int count;
+       char *endp;
+       struct rps_dev_flow_table *table, *old_table;
+       static DEFINE_SPINLOCK(rps_dev_flow_lock);
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       count = simple_strtoul(buf, &endp, 0);
+       if (endp == buf)
+               return -EINVAL;
+
+       if (count) {
+               int i;
+
+               if (count > 1<<30) {
+                       /* Enforce a limit to prevent overflow */
+                       return -EINVAL;
+               }
+               count = roundup_pow_of_two(count);
+               table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(count));
+               if (!table)
+                       return -ENOMEM;
+
+               table->mask = count - 1;
+               for (i = 0; i < count; i++)
+                       table->flows[i].cpu = RPS_NO_CPU;
+       } else
+               table = NULL;
+
+       spin_lock(&rps_dev_flow_lock);
+       old_table = queue->rps_flow_table;
+       rcu_assign_pointer(queue->rps_flow_table, table);
+       spin_unlock(&rps_dev_flow_lock);
+
+       if (old_table)
+               call_rcu(&old_table->rcu, rps_dev_flow_table_release);
+
+       return len;
+}
+
+static struct rx_queue_attribute rps_cpus_attribute =
+       __ATTR(rps_cpus, S_IRUGO | S_IWUSR, show_rps_map, store_rps_map);
+
+
+static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute =
+       __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR,
+           show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt);
+
+static struct attribute *rx_queue_default_attrs[] = {
+       &rps_cpus_attribute.attr,
+       &rps_dev_flow_table_cnt_attribute.attr,
+       NULL
+};
+
+static void rx_queue_release(struct kobject *kobj)
+{
+       struct netdev_rx_queue *queue = to_rx_queue(kobj);
+       struct netdev_rx_queue *first = queue->first;
+
+       if (queue->rps_map)
+               call_rcu(&queue->rps_map->rcu, rps_map_release);
+
+       if (queue->rps_flow_table)
+               call_rcu(&queue->rps_flow_table->rcu,
+                   rps_dev_flow_table_release);
+
+       if (atomic_dec_and_test(&first->count))
+               kfree(first);
+}
+
+static struct kobj_type rx_queue_ktype = {
+       .sysfs_ops = &rx_queue_sysfs_ops,
+       .release = rx_queue_release,
+       .default_attrs = rx_queue_default_attrs,
+};
+
+static int rx_queue_add_kobject(struct net_device *net, int index)
+{
+       struct netdev_rx_queue *queue = net->_rx + index;
+       struct kobject *kobj = &queue->kobj;
+       int error = 0;
+
+       kobj->kset = net->queues_kset;
+       error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL,
+           "rx-%u", index);
+       if (error) {
+               kobject_put(kobj);
+               return error;
+       }
+
+       kobject_uevent(kobj, KOBJ_ADD);
+
+       return error;
+}
+
+static int rx_queue_register_kobjects(struct net_device *net)
+{
+       int i;
+       int error = 0;
+
+       net->queues_kset = kset_create_and_add("queues",
+           NULL, &net->dev.kobj);
+       if (!net->queues_kset)
+               return -ENOMEM;
+       for (i = 0; i < net->num_rx_queues; i++) {
+               error = rx_queue_add_kobject(net, i);
+               if (error)
+                       break;
+       }
+
+       if (error)
+               while (--i >= 0)
+                       kobject_put(&net->_rx[i].kobj);
+
+       return error;
+}
+
+static void rx_queue_remove_kobjects(struct net_device *net)
+{
+       int i;
+
+       for (i = 0; i < net->num_rx_queues; i++)
+               kobject_put(&net->_rx[i].kobj);
+       kset_unregister(net->queues_kset);
+}
+#endif /* CONFIG_RPS */
 #endif /* CONFIG_SYSFS */
 
 #ifdef CONFIG_HOTPLUG
@@ -530,6 +829,10 @@ void netdev_unregister_kobject(struct net_device * net)
        if (!net_eq(dev_net(net), &init_net))
                return;
 
+#ifdef CONFIG_RPS
+       rx_queue_remove_kobjects(net);
+#endif
+
        device_del(dev);
 }
 
@@ -538,6 +841,7 @@ int netdev_register_kobject(struct net_device *net)
 {
        struct device *dev = &(net->dev);
        const struct attribute_group **groups = net->sysfs_groups;
+       int error = 0;
 
        dev->class = &net_class;
        dev->platform_data = net;
@@ -564,7 +868,19 @@ int netdev_register_kobject(struct net_device *net)
        if (!net_eq(dev_net(net), &init_net))
                return 0;
 
-       return device_add(dev);
+       error = device_add(dev);
+       if (error)
+               return error;
+
+#ifdef CONFIG_RPS
+       error = rx_queue_register_kobjects(net);
+       if (error) {
+               device_del(dev);
+               return error;
+       }
+#endif
+
+       return error;
 }
 
 int netdev_class_create_file(struct class_attribute *class_attr)
index bd8c4712ea247582f885203960db9bd7a2a310ce..c988e685433acad2bb471097d79ec024509cee9d 100644 (file)
@@ -27,6 +27,51 @@ EXPORT_SYMBOL(init_net);
 
 #define INITIAL_NET_GEN_PTRS   13 /* +1 for len +2 for rcu_head */
 
+static void net_generic_release(struct rcu_head *rcu)
+{
+       struct net_generic *ng;
+
+       ng = container_of(rcu, struct net_generic, rcu);
+       kfree(ng);
+}
+
+static int net_assign_generic(struct net *net, int id, void *data)
+{
+       struct net_generic *ng, *old_ng;
+
+       BUG_ON(!mutex_is_locked(&net_mutex));
+       BUG_ON(id == 0);
+
+       ng = old_ng = net->gen;
+       if (old_ng->len >= id)
+               goto assign;
+
+       ng = kzalloc(sizeof(struct net_generic) +
+                       id * sizeof(void *), GFP_KERNEL);
+       if (ng == NULL)
+               return -ENOMEM;
+
+       /*
+        * Some synchronisation notes:
+        *
+        * The net_generic explores the net->gen array inside rcu
+        * read section. Besides once set the net->gen->ptr[x]
+        * pointer never changes (see rules in netns/generic.h).
+        *
+        * That said, we simply duplicate this array and schedule
+        * the old copy for kfree after a grace period.
+        */
+
+       ng->len = id;
+       memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
+
+       rcu_assign_pointer(net->gen, ng);
+       call_rcu(&old_ng->rcu, net_generic_release);
+assign:
+       ng->ptr[id - 1] = data;
+       return 0;
+}
+
 static int ops_init(const struct pernet_operations *ops, struct net *net)
 {
        int err;
@@ -469,10 +514,10 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys);
  *     addition run the exit method for all existing network
  *     namespaces.
  */
-void unregister_pernet_subsys(struct pernet_operations *module)
+void unregister_pernet_subsys(struct pernet_operations *ops)
 {
        mutex_lock(&net_mutex);
-       unregister_pernet_operations(module);
+       unregister_pernet_operations(ops);
        mutex_unlock(&net_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
@@ -526,49 +571,3 @@ void unregister_pernet_device(struct pernet_operations *ops)
        mutex_unlock(&net_mutex);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_device);
-
-static void net_generic_release(struct rcu_head *rcu)
-{
-       struct net_generic *ng;
-
-       ng = container_of(rcu, struct net_generic, rcu);
-       kfree(ng);
-}
-
-int net_assign_generic(struct net *net, int id, void *data)
-{
-       struct net_generic *ng, *old_ng;
-
-       BUG_ON(!mutex_is_locked(&net_mutex));
-       BUG_ON(id == 0);
-
-       ng = old_ng = net->gen;
-       if (old_ng->len >= id)
-               goto assign;
-
-       ng = kzalloc(sizeof(struct net_generic) +
-                       id * sizeof(void *), GFP_KERNEL);
-       if (ng == NULL)
-               return -ENOMEM;
-
-       /*
-        * Some synchronisation notes:
-        *
-        * The net_generic explores the net->gen array inside rcu
-        * read section. Besides once set the net->gen->ptr[x]
-        * pointer never changes (see rules in netns/generic.h).
-        *
-        * That said, we simply duplicate this array and schedule
-        * the old copy for kfree after a grace period.
-        */
-
-       ng->len = id;
-       memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
-
-       rcu_assign_pointer(net->gen, ng);
-       call_rcu(&old_ng->rcu, net_generic_release);
-assign:
-       ng->ptr[id - 1] = data;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(net_assign_generic);
index a58f59b975974ec6d0daf13bbe71aecc1d2e0bd2..94825b109551e81b1c22a09459b5e0262a97d5e4 100644 (file)
@@ -179,9 +179,8 @@ static void service_arp_queue(struct netpoll_info *npi)
        }
 }
 
-void netpoll_poll(struct netpoll *np)
+void netpoll_poll_dev(struct net_device *dev)
 {
-       struct net_device *dev = np->dev;
        const struct net_device_ops *ops;
 
        if (!dev || !netif_running(dev))
@@ -201,6 +200,11 @@ void netpoll_poll(struct netpoll *np)
        zap_completion_queue();
 }
 
+void netpoll_poll(struct netpoll *np)
+{
+       netpoll_poll_dev(np->dev);
+}
+
 static void refill_skbs(void)
 {
        struct sk_buff *skb;
@@ -282,7 +286,7 @@ static int netpoll_owner_active(struct net_device *dev)
        return 0;
 }
 
-static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
 {
        int status = NETDEV_TX_BUSY;
        unsigned long tries;
@@ -308,7 +312,9 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
                     tries > 0; --tries) {
                        if (__netif_tx_trylock(txq)) {
                                if (!netif_tx_queue_stopped(txq)) {
+                                       dev->priv_flags |= IFF_IN_NETPOLL;
                                        status = ops->ndo_start_xmit(skb, dev);
+                                       dev->priv_flags &= ~IFF_IN_NETPOLL;
                                        if (status == NETDEV_TX_OK)
                                                txq_trans_update(txq);
                                }
@@ -756,7 +762,10 @@ int netpoll_setup(struct netpoll *np)
                atomic_inc(&npinfo->refcnt);
        }
 
-       if (!ndev->netdev_ops->ndo_poll_controller) {
+       npinfo->netpoll = np;
+
+       if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
+           !ndev->netdev_ops->ndo_poll_controller) {
                printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
                       np->name, np->dev_name);
                err = -ENOTSUPP;
@@ -878,6 +887,7 @@ void netpoll_cleanup(struct netpoll *np)
                        }
 
                        if (atomic_dec_and_test(&npinfo->refcnt)) {
+                               const struct net_device_ops *ops;
                                skb_queue_purge(&npinfo->arp_tx);
                                skb_queue_purge(&npinfo->txq);
                                cancel_rearming_delayed_work(&npinfo->tx_work);
@@ -885,7 +895,11 @@ void netpoll_cleanup(struct netpoll *np)
                                /* clean after last, unfinished work */
                                __skb_queue_purge(&npinfo->txq);
                                kfree(npinfo);
-                               np->dev->npinfo = NULL;
+                               ops = np->dev->netdev_ops;
+                               if (ops->ndo_netpoll_cleanup)
+                                       ops->ndo_netpoll_cleanup(np->dev);
+                               else
+                                       np->dev->npinfo = NULL;
                        }
                }
 
@@ -908,6 +922,7 @@ void netpoll_set_trap(int trap)
                atomic_dec(&trapped);
 }
 
+EXPORT_SYMBOL(netpoll_send_skb);
 EXPORT_SYMBOL(netpoll_set_trap);
 EXPORT_SYMBOL(netpoll_trap);
 EXPORT_SYMBOL(netpoll_print_options);
@@ -915,4 +930,5 @@ EXPORT_SYMBOL(netpoll_parse_options);
 EXPORT_SYMBOL(netpoll_setup);
 EXPORT_SYMBOL(netpoll_cleanup);
 EXPORT_SYMBOL(netpoll_send_udp);
+EXPORT_SYMBOL(netpoll_poll_dev);
 EXPORT_SYMBOL(netpoll_poll);
index 43923811bd6aa34399ed89617c1f4282aba55660..2ad68da418df6a6d6d4ae81db9e78d4a8f6ae981 100644 (file)
 #include <asm/dma.h>
 #include <asm/div64.h>         /* do_div */
 
-#define VERSION        "2.72"
+#define VERSION        "2.73"
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
 #define MPLS_STACK_BOTTOM htonl(0x00000100)
 #define F_IPSEC_ON    (1<<12)  /* ipsec on for flows */
 #define F_QUEUE_MAP_RND (1<<13)        /* queue map Random */
 #define F_QUEUE_MAP_CPU (1<<14)        /* queue map mirrors smp_processor_id() */
+#define F_NODE          (1<<15)        /* Node memory alloc*/
 
 /* Thread control flag bits */
 #define T_STOP        (1<<0)   /* Stop run */
@@ -372,6 +373,7 @@ struct pktgen_dev {
 
        u16 queue_map_min;
        u16 queue_map_max;
+       int node;               /* Memory node */
 
 #ifdef CONFIG_XFRM
        __u8    ipsmode;                /* IPSEC mode (config) */
@@ -607,6 +609,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->traffic_class)
                seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
 
+       if (pkt_dev->node >= 0)
+               seq_printf(seq, "     node: %d\n", pkt_dev->node);
+
        seq_printf(seq, "     Flags: ");
 
        if (pkt_dev->flags & F_IPV6)
@@ -660,6 +665,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->flags & F_SVID_RND)
                seq_printf(seq, "SVID_RND  ");
 
+       if (pkt_dev->flags & F_NODE)
+               seq_printf(seq, "NODE_ALLOC  ");
+
        seq_puts(seq, "\n");
 
        /* not really stopped, more like last-running-at */
@@ -1074,6 +1082,21 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->dst_mac_count);
                return count;
        }
+       if (!strcmp(name, "node")) {
+               len = num_arg(&user_buffer[i], 10, &value);
+               if (len < 0)
+                       return len;
+
+               i += len;
+
+               if (node_possible(value)) {
+                       pkt_dev->node = value;
+                       sprintf(pg_result, "OK: node=%d", pkt_dev->node);
+               }
+               else
+                       sprintf(pg_result, "ERROR: node not possible");
+               return count;
+       }
        if (!strcmp(name, "flag")) {
                char f[32];
                memset(f, 0, 32);
@@ -1166,12 +1189,18 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!IPV6") == 0)
                        pkt_dev->flags &= ~F_IPV6;
 
+               else if (strcmp(f, "NODE_ALLOC") == 0)
+                       pkt_dev->flags |= F_NODE;
+
+               else if (strcmp(f, "!NODE_ALLOC") == 0)
+                       pkt_dev->flags &= ~F_NODE;
+
                else {
                        sprintf(pg_result,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
                                f,
                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
-                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n");
+                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n");
                        return count;
                }
                sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
@@ -2572,9 +2601,27 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        mod_cur_headers(pkt_dev);
 
        datalen = (odev->hard_header_len + 16) & ~0xf;
-       skb = __netdev_alloc_skb(odev,
-                                pkt_dev->cur_pkt_size + 64
-                                + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT);
+
+       if (pkt_dev->flags & F_NODE) {
+               int node;
+
+               if (pkt_dev->node >= 0)
+                       node = pkt_dev->node;
+               else
+                       node =  numa_node_id();
+
+               skb = __alloc_skb(NET_SKB_PAD + pkt_dev->cur_pkt_size + 64
+                                 + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT, 0, node);
+               if (likely(skb)) {
+                       skb_reserve(skb, NET_SKB_PAD);
+                       skb->dev = odev;
+               }
+       }
+       else
+         skb = __netdev_alloc_skb(odev,
+                                  pkt_dev->cur_pkt_size + 64
+                                  + datalen + pkt_dev->pkt_overhead, GFP_NOWAIT);
+
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
@@ -3674,6 +3721,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        pkt_dev->svlan_p = 0;
        pkt_dev->svlan_cfi = 0;
        pkt_dev->svlan_id = 0xffff;
+       pkt_dev->node = -1;
 
        err = pktgen_setup_dev(pkt_dev, ifname);
        if (err)
index 31e85d327aa2ccd7e4ec6e9ae8699ada83bbb879..e4b9870e4706f7f4cf3e84b798f752c7e972f2fb 100644 (file)
@@ -98,7 +98,7 @@ int lockdep_rtnl_is_held(void)
 EXPORT_SYMBOL(lockdep_rtnl_is_held);
 #endif /* #ifdef CONFIG_PROVE_LOCKING */
 
-static struct rtnl_link *rtnl_msg_handlers[NPROTO];
+static struct rtnl_link *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];
 
 static inline int rtm_msgindex(int msgtype)
 {
@@ -118,7 +118,11 @@ static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex)
 {
        struct rtnl_link *tab;
 
-       tab = rtnl_msg_handlers[protocol];
+       if (protocol <= RTNL_FAMILY_MAX)
+               tab = rtnl_msg_handlers[protocol];
+       else
+               tab = NULL;
+
        if (tab == NULL || tab[msgindex].doit == NULL)
                tab = rtnl_msg_handlers[PF_UNSPEC];
 
@@ -129,7 +133,11 @@ static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
 {
        struct rtnl_link *tab;
 
-       tab = rtnl_msg_handlers[protocol];
+       if (protocol <= RTNL_FAMILY_MAX)
+               tab = rtnl_msg_handlers[protocol];
+       else
+               tab = NULL;
+
        if (tab == NULL || tab[msgindex].dumpit == NULL)
                tab = rtnl_msg_handlers[PF_UNSPEC];
 
@@ -159,7 +167,7 @@ int __rtnl_register(int protocol, int msgtype,
        struct rtnl_link *tab;
        int msgindex;
 
-       BUG_ON(protocol < 0 || protocol >= NPROTO);
+       BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
        msgindex = rtm_msgindex(msgtype);
 
        tab = rtnl_msg_handlers[protocol];
@@ -211,7 +219,7 @@ int rtnl_unregister(int protocol, int msgtype)
 {
        int msgindex;
 
-       BUG_ON(protocol < 0 || protocol >= NPROTO);
+       BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
        msgindex = rtm_msgindex(msgtype);
 
        if (rtnl_msg_handlers[protocol] == NULL)
@@ -233,7 +241,7 @@ EXPORT_SYMBOL_GPL(rtnl_unregister);
  */
 void rtnl_unregister_all(int protocol)
 {
-       BUG_ON(protocol < 0 || protocol >= NPROTO);
+       BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX);
 
        kfree(rtnl_msg_handlers[protocol]);
        rtnl_msg_handlers[protocol] = NULL;
@@ -600,7 +608,41 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
 
        a->rx_compressed = b->rx_compressed;
        a->tx_compressed = b->tx_compressed;
-};
+}
+
+static void copy_rtnl_link_stats64(void *v, const struct net_device_stats *b)
+{
+       struct rtnl_link_stats64 a;
+
+       a.rx_packets = b->rx_packets;
+       a.tx_packets = b->tx_packets;
+       a.rx_bytes = b->rx_bytes;
+       a.tx_bytes = b->tx_bytes;
+       a.rx_errors = b->rx_errors;
+       a.tx_errors = b->tx_errors;
+       a.rx_dropped = b->rx_dropped;
+       a.tx_dropped = b->tx_dropped;
+
+       a.multicast = b->multicast;
+       a.collisions = b->collisions;
+
+       a.rx_length_errors = b->rx_length_errors;
+       a.rx_over_errors = b->rx_over_errors;
+       a.rx_crc_errors = b->rx_crc_errors;
+       a.rx_frame_errors = b->rx_frame_errors;
+       a.rx_fifo_errors = b->rx_fifo_errors;
+       a.rx_missed_errors = b->rx_missed_errors;
+
+       a.tx_aborted_errors = b->tx_aborted_errors;
+       a.tx_carrier_errors = b->tx_carrier_errors;
+       a.tx_fifo_errors = b->tx_fifo_errors;
+       a.tx_heartbeat_errors = b->tx_heartbeat_errors;
+       a.tx_window_errors = b->tx_window_errors;
+
+       a.rx_compressed = b->rx_compressed;
+       a.tx_compressed = b->tx_compressed;
+       memcpy(v, &a, sizeof(a));
+}
 
 /* All VF info */
 static inline int rtnl_vfinfo_size(const struct net_device *dev)
@@ -618,6 +660,31 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev)
                return 0;
 }
 
+static size_t rtnl_port_size(const struct net_device *dev)
+{
+       size_t port_size = nla_total_size(4)            /* PORT_VF */
+               + nla_total_size(PORT_PROFILE_MAX)      /* PORT_PROFILE */
+               + nla_total_size(sizeof(struct ifla_port_vsi))
+                                                       /* PORT_VSI_TYPE */
+               + nla_total_size(PORT_UUID_MAX)         /* PORT_INSTANCE_UUID */
+               + nla_total_size(PORT_UUID_MAX)         /* PORT_HOST_UUID */
+               + nla_total_size(1)                     /* PROT_VDP_REQUEST */
+               + nla_total_size(2);                    /* PORT_VDP_RESPONSE */
+       size_t vf_ports_size = nla_total_size(sizeof(struct nlattr));
+       size_t vf_port_size = nla_total_size(sizeof(struct nlattr))
+               + port_size;
+       size_t port_self_size = nla_total_size(sizeof(struct nlattr))
+               + port_size;
+
+       if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
+               return 0;
+       if (dev_num_vf(dev->dev.parent))
+               return port_self_size + vf_ports_size +
+                       vf_port_size * dev_num_vf(dev->dev.parent);
+       else
+               return port_self_size;
+}
+
 static inline size_t if_nlmsg_size(const struct net_device *dev)
 {
        return NLMSG_ALIGN(sizeof(struct ifinfomsg))
@@ -626,6 +693,7 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)
               + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */
               + nla_total_size(sizeof(struct rtnl_link_ifmap))
               + nla_total_size(sizeof(struct rtnl_link_stats))
+              + nla_total_size(sizeof(struct rtnl_link_stats64))
               + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
               + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */
               + nla_total_size(4) /* IFLA_TXQLEN */
@@ -637,9 +705,82 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)
               + nla_total_size(1) /* IFLA_LINKMODE */
               + nla_total_size(4) /* IFLA_NUM_VF */
               + rtnl_vfinfo_size(dev) /* IFLA_VFINFO_LIST */
+              + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
               + rtnl_link_get_size(dev); /* IFLA_LINKINFO */
 }
 
+static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
+{
+       struct nlattr *vf_ports;
+       struct nlattr *vf_port;
+       int vf;
+       int err;
+
+       vf_ports = nla_nest_start(skb, IFLA_VF_PORTS);
+       if (!vf_ports)
+               return -EMSGSIZE;
+
+       for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) {
+               vf_port = nla_nest_start(skb, IFLA_VF_PORT);
+               if (!vf_port) {
+                       nla_nest_cancel(skb, vf_ports);
+                       return -EMSGSIZE;
+               }
+               NLA_PUT_U32(skb, IFLA_PORT_VF, vf);
+               err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb);
+               if (err) {
+nla_put_failure:
+                       nla_nest_cancel(skb, vf_port);
+                       continue;
+               }
+               nla_nest_end(skb, vf_port);
+       }
+
+       nla_nest_end(skb, vf_ports);
+
+       return 0;
+}
+
+static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
+{
+       struct nlattr *port_self;
+       int err;
+
+       port_self = nla_nest_start(skb, IFLA_PORT_SELF);
+       if (!port_self)
+               return -EMSGSIZE;
+
+       err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb);
+       if (err) {
+               nla_nest_cancel(skb, port_self);
+               return err;
+       }
+
+       nla_nest_end(skb, port_self);
+
+       return 0;
+}
+
+static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)
+{
+       int err;
+
+       if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
+               return 0;
+
+       err = rtnl_port_self_fill(skb, dev);
+       if (err)
+               return err;
+
+       if (dev_num_vf(dev->dev.parent)) {
+               err = rtnl_vf_ports_fill(skb, dev);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                            int type, u32 pid, u32 seq, u32 change,
                            unsigned int flags)
@@ -705,13 +846,21 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
        stats = dev_get_stats(dev);
        copy_rtnl_link_stats(nla_data(attr), stats);
 
+       attr = nla_reserve(skb, IFLA_STATS64,
+                       sizeof(struct rtnl_link_stats64));
+       if (attr == NULL)
+               goto nla_put_failure;
+       copy_rtnl_link_stats64(nla_data(attr), stats);
+
+       if (dev->dev.parent)
+               NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
+
        if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {
                int i;
 
                struct nlattr *vfinfo, *vf;
                int num_vfs = dev_num_vf(dev->dev.parent);
 
-               NLA_PUT_U32(skb, IFLA_NUM_VF, num_vfs);
                vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST);
                if (!vfinfo)
                        goto nla_put_failure;
@@ -739,6 +888,10 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
                }
                nla_nest_end(skb, vfinfo);
        }
+
+       if (rtnl_port_fill(skb, dev))
+               goto nla_put_failure;
+
        if (dev->rtnl_link_ops) {
                if (rtnl_link_fill(skb, dev) < 0)
                        goto nla_put_failure;
@@ -800,6 +953,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_NET_NS_PID]       = { .type = NLA_U32 },
        [IFLA_IFALIAS]          = { .type = NLA_STRING, .len = IFALIASZ-1 },
        [IFLA_VFINFO_LIST]      = {. type = NLA_NESTED },
+       [IFLA_VF_PORTS]         = { .type = NLA_NESTED },
+       [IFLA_PORT_SELF]        = { .type = NLA_NESTED },
 };
 EXPORT_SYMBOL(ifla_policy);
 
@@ -821,6 +976,20 @@ static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = {
                                    .len = sizeof(struct ifla_vf_tx_rate) },
 };
 
+static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
+       [IFLA_PORT_VF]          = { .type = NLA_U32 },
+       [IFLA_PORT_PROFILE]     = { .type = NLA_STRING,
+                                   .len = PORT_PROFILE_MAX },
+       [IFLA_PORT_VSI_TYPE]    = { .type = NLA_BINARY,
+                                   .len = sizeof(struct ifla_port_vsi)},
+       [IFLA_PORT_INSTANCE_UUID] = { .type = NLA_BINARY,
+                                     .len = PORT_UUID_MAX },
+       [IFLA_PORT_HOST_UUID]   = { .type = NLA_STRING,
+                                   .len = PORT_UUID_MAX },
+       [IFLA_PORT_REQUEST]     = { .type = NLA_U8, },
+       [IFLA_PORT_RESPONSE]    = { .type = NLA_U16, },
+};
+
 struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
 {
        struct net *net;
@@ -1040,6 +1209,53 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
        }
        err = 0;
 
+       if (tb[IFLA_VF_PORTS]) {
+               struct nlattr *port[IFLA_PORT_MAX+1];
+               struct nlattr *attr;
+               int vf;
+               int rem;
+
+               err = -EOPNOTSUPP;
+               if (!ops->ndo_set_vf_port)
+                       goto errout;
+
+               nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) {
+                       if (nla_type(attr) != IFLA_VF_PORT)
+                               continue;
+                       err = nla_parse_nested(port, IFLA_PORT_MAX,
+                               attr, ifla_port_policy);
+                       if (err < 0)
+                               goto errout;
+                       if (!port[IFLA_PORT_VF]) {
+                               err = -EOPNOTSUPP;
+                               goto errout;
+                       }
+                       vf = nla_get_u32(port[IFLA_PORT_VF]);
+                       err = ops->ndo_set_vf_port(dev, vf, port);
+                       if (err < 0)
+                               goto errout;
+                       modified = 1;
+               }
+       }
+       err = 0;
+
+       if (tb[IFLA_PORT_SELF]) {
+               struct nlattr *port[IFLA_PORT_MAX+1];
+
+               err = nla_parse_nested(port, IFLA_PORT_MAX,
+                       tb[IFLA_PORT_SELF], ifla_port_policy);
+               if (err < 0)
+                       goto errout;
+
+               err = -EOPNOTSUPP;
+               if (ops->ndo_set_vf_port)
+                       err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port);
+               if (err < 0)
+                       goto errout;
+               modified = 1;
+       }
+       err = 0;
+
 errout:
        if (err < 0 && modified && net_ratelimit())
                printk(KERN_WARNING "A link change request failed with "
@@ -1397,7 +1613,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 
        if (s_idx == 0)
                s_idx = 1;
-       for (idx = 1; idx < NPROTO; idx++) {
+       for (idx = 1; idx <= RTNL_FAMILY_MAX; idx++) {
                int type = cb->nlh->nlmsg_type-RTM_BASE;
                if (idx < s_idx || idx == PF_PACKET)
                        continue;
@@ -1465,9 +1681,6 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                return 0;
 
        family = ((struct rtgenmsg *)NLMSG_DATA(nlh))->rtgen_family;
-       if (family >= NPROTO)
-               return -EAFNOSUPPORT;
-
        sz_idx = type>>2;
        kind = type&3;
 
@@ -1535,6 +1748,7 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
        case NETDEV_POST_INIT:
        case NETDEV_REGISTER:
        case NETDEV_CHANGE:
+       case NETDEV_PRE_TYPE_CHANGE:
        case NETDEV_GOING_DOWN:
        case NETDEV_UNREGISTER:
        case NETDEV_UNREGISTER_BATCH:
index 93c4e060c91e7bffb121d51eeccd264337214491..c543dd252433c84eafc9ef3b0a0d3be644211dd3 100644 (file)
@@ -117,7 +117,7 @@ static const struct pipe_buf_operations sock_pipe_buf_ops = {
  *
  *     Out of line support code for skb_put(). Not user callable.
  */
-void skb_over_panic(struct sk_buff *skb, int sz, void *here)
+static void skb_over_panic(struct sk_buff *skb, int sz, void *here)
 {
        printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p "
                          "data:%p tail:%#lx end:%#lx dev:%s\n",
@@ -126,7 +126,6 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here)
               skb->dev ? skb->dev->name : "<NULL>");
        BUG();
 }
-EXPORT_SYMBOL(skb_over_panic);
 
 /**
  *     skb_under_panic -       private function
@@ -137,7 +136,7 @@ EXPORT_SYMBOL(skb_over_panic);
  *     Out of line support code for skb_push(). Not user callable.
  */
 
-void skb_under_panic(struct sk_buff *skb, int sz, void *here)
+static void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 {
        printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p "
                          "data:%p tail:%#lx end:%#lx dev:%s\n",
@@ -146,7 +145,6 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
               skb->dev ? skb->dev->name : "<NULL>");
        BUG();
 }
-EXPORT_SYMBOL(skb_under_panic);
 
 /*     Allocate a new skbuff. We do this ourselves so we can fill in a few
  *     'private' fields and also do memory statistics to find all the
@@ -183,12 +181,14 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
        if (!skb)
                goto out;
+       prefetchw(skb);
 
        size = SKB_DATA_ALIGN(size);
        data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),
                        gfp_mask, node);
        if (!data)
                goto nodata;
+       prefetchw(data + size);
 
        /*
         * Only clear those fields we need to clear, not those that we will
@@ -210,15 +210,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
 
        /* make sure we initialize shinfo sequentially */
        shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
-       shinfo->nr_frags  = 0;
-       shinfo->gso_size = 0;
-       shinfo->gso_segs = 0;
-       shinfo->gso_type = 0;
-       shinfo->ip6_frag_id = 0;
-       shinfo->tx_flags.flags = 0;
-       skb_frag_list_init(skb);
-       memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
 
        if (fclone) {
                struct sk_buff *child = skb + 1;
@@ -507,16 +500,10 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size)
                return 0;
 
        skb_release_head_state(skb);
+
        shinfo = skb_shinfo(skb);
+       memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
        atomic_set(&shinfo->dataref, 1);
-       shinfo->nr_frags = 0;
-       shinfo->gso_size = 0;
-       shinfo->gso_segs = 0;
-       shinfo->gso_type = 0;
-       shinfo->ip6_frag_id = 0;
-       shinfo->tx_flags.flags = 0;
-       skb_frag_list_init(skb);
-       memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
 
        memset(skb, 0, offsetof(struct sk_buff, tail));
        skb->data = skb->head + NET_SKB_PAD;
@@ -533,7 +520,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->transport_header   = old->transport_header;
        new->network_header     = old->network_header;
        new->mac_header         = old->mac_header;
-       skb_dst_set(new, dst_clone(skb_dst(old)));
+       skb_dst_copy(new, old);
+       new->rxhash             = old->rxhash;
 #ifdef CONFIG_XFRM
        new->sp                 = secpath_get(old->sp);
 #endif
@@ -581,6 +569,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
        C(len);
        C(data_len);
        C(mac_len);
+       C(rxhash);
        n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
        n->cloned = 1;
        n->nohdr = 0;
@@ -1051,7 +1040,7 @@ EXPORT_SYMBOL(skb_push);
  */
 unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
 {
-       return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
+       return skb_pull_inline(skb, len);
 }
 EXPORT_SYMBOL(skb_pull);
 
index c5812bbc2cc91128d9797154d43f1cbc104ab979..bf88a167c8f2ce5f008858454c103d762b0575ad 100644 (file)
@@ -307,6 +307,11 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
         */
        skb_len = skb->len;
 
+       /* we escape from rcu protected region, make sure we dont leak
+        * a norefcounted dst
+        */
+       skb_dst_force(skb);
+
        spin_lock_irqsave(&list->lock, flags);
        skb->dropcount = atomic_read(&sk->sk_drops);
        __skb_queue_tail(list, skb);
@@ -327,6 +332,10 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
 
        skb->dev = NULL;
 
+       if (sk_rcvqueues_full(sk, skb)) {
+               atomic_inc(&sk->sk_drops);
+               goto discard_and_relse;
+       }
        if (nested)
                bh_lock_sock_nested(sk);
        else
@@ -364,11 +373,11 @@ EXPORT_SYMBOL(sk_reset_txq);
 
 struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
 {
-       struct dst_entry *dst = sk->sk_dst_cache;
+       struct dst_entry *dst = __sk_dst_get(sk);
 
        if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
                sk_tx_queue_clear(sk);
-               sk->sk_dst_cache = NULL;
+               rcu_assign_pointer(sk->sk_dst_cache, NULL);
                dst_release(dst);
                return NULL;
        }
@@ -1157,7 +1166,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
                skb_queue_head_init(&newsk->sk_async_wait_queue);
 #endif
 
-               rwlock_init(&newsk->sk_dst_lock);
+               spin_lock_init(&newsk->sk_dst_lock);
                rwlock_init(&newsk->sk_callback_lock);
                lockdep_set_class_and_name(&newsk->sk_callback_lock,
                                af_callback_keys + newsk->sk_family,
@@ -1207,7 +1216,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
                 */
                sk_refcnt_debug_inc(newsk);
                sk_set_socket(newsk, NULL);
-               newsk->sk_sleep  = NULL;
+               newsk->sk_wq = NULL;
 
                if (newsk->sk_prot->sockets_allocated)
                        percpu_counter_inc(newsk->sk_prot->sockets_allocated);
@@ -1227,6 +1236,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
        sk->sk_route_caps = dst->dev->features;
        if (sk->sk_route_caps & NETIF_F_GSO)
                sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
+       sk->sk_route_caps &= ~sk->sk_route_nocaps;
        if (sk_can_gso(sk)) {
                if (dst->header_len) {
                        sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
@@ -1395,7 +1405,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
                if (signal_pending(current))
                        break;
                set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf)
                        break;
                if (sk->sk_shutdown & SEND_SHUTDOWN)
@@ -1404,7 +1414,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
                        break;
                timeo = schedule_timeout(timeo);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return timeo;
 }
 
@@ -1531,6 +1541,7 @@ static void __release_sock(struct sock *sk)
                do {
                        struct sk_buff *next = skb->next;
 
+                       WARN_ON_ONCE(skb_dst_is_noref(skb));
                        skb->next = NULL;
                        sk_backlog_rcv(sk, skb);
 
@@ -1570,11 +1581,11 @@ int sk_wait_data(struct sock *sk, long *timeo)
        int rc;
        DEFINE_WAIT(wait);
 
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        rc = sk_wait_event(sk, timeo, !skb_queue_empty(&sk->sk_receive_queue));
        clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return rc;
 }
 EXPORT_SYMBOL(sk_wait_data);
@@ -1796,41 +1807,53 @@ EXPORT_SYMBOL(sock_no_sendpage);
 
 static void sock_def_wakeup(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
-       if (sk_has_sleeper(sk))
-               wake_up_interruptible_all(sk->sk_sleep);
-       read_unlock(&sk->sk_callback_lock);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible_all(&wq->wait);
+       rcu_read_unlock();
 }
 
 static void sock_def_error_report(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
-       if (sk_has_sleeper(sk))
-               wake_up_interruptible_poll(sk->sk_sleep, POLLERR);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible_poll(&wq->wait, POLLERR);
        sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR);
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 static void sock_def_readable(struct sock *sk, int len)
 {
-       read_lock(&sk->sk_callback_lock);
-       if (sk_has_sleeper(sk))
-               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN |
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
                                                POLLRDNORM | POLLRDBAND);
        sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 static void sock_def_write_space(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
 
        /* Do not wake up a writer until he can make "significant"
         * progress.  --DaveM
         */
        if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
-               if (sk_has_sleeper(sk))
-                       wake_up_interruptible_sync_poll(sk->sk_sleep, POLLOUT |
+               wq = rcu_dereference(sk->sk_wq);
+               if (wq_has_sleeper(wq))
+                       wake_up_interruptible_sync_poll(&wq->wait, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
 
                /* Should agree with poll, otherwise some programs break */
@@ -1838,7 +1861,7 @@ static void sock_def_write_space(struct sock *sk)
                        sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
 
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 static void sock_def_destruct(struct sock *sk)
@@ -1885,7 +1908,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        sk->sk_allocation       =       GFP_KERNEL;
        sk->sk_rcvbuf           =       sysctl_rmem_default;
        sk->sk_sndbuf           =       sysctl_wmem_default;
-       sk->sk_backlog.limit    =       sk->sk_rcvbuf << 1;
        sk->sk_state            =       TCP_CLOSE;
        sk_set_socket(sk, sock);
 
@@ -1893,12 +1915,12 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        if (sock) {
                sk->sk_type     =       sock->type;
-               sk->sk_sleep    =       &sock->wait;
+               sk->sk_wq       =       sock->wq;
                sock->sk        =       sk;
        } else
-               sk->sk_sleep    =       NULL;
+               sk->sk_wq       =       NULL;
 
-       rwlock_init(&sk->sk_dst_lock);
+       spin_lock_init(&sk->sk_dst_lock);
        rwlock_init(&sk->sk_callback_lock);
        lockdep_set_class_and_name(&sk->sk_callback_lock,
                        af_callback_keys + sk->sk_family,
index a37debfeb1b2bcb3309d93fc5d45b5f82e202d6e..cc196f42b8d89a24dd752d11879338d72e80346e 100644 (file)
 void sk_stream_write_space(struct sock *sk)
 {
        struct socket *sock = sk->sk_socket;
+       struct socket_wq *wq;
 
        if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock) {
                clear_bit(SOCK_NOSPACE, &sock->flags);
 
-               if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                       wake_up_interruptible_poll(sk->sk_sleep, POLLOUT |
+               rcu_read_lock();
+               wq = rcu_dereference(sk->sk_wq);
+               if (wq_has_sleeper(wq))
+                       wake_up_interruptible_poll(&wq->wait, POLLOUT |
                                                POLLWRNORM | POLLWRBAND);
-               if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN))
+               if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN))
                        sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT);
+               rcu_read_unlock();
        }
 }
 
@@ -66,13 +70,13 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p)
                if (signal_pending(tsk))
                        return sock_intr_errno(*timeo_p);
 
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                sk->sk_write_pending++;
                done = sk_wait_event(sk, timeo_p,
                                     !sk->sk_err &&
                                     !((1 << sk->sk_state) &
                                       ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)));
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
                sk->sk_write_pending--;
        } while (!done);
        return 0;
@@ -96,13 +100,13 @@ void sk_stream_wait_close(struct sock *sk, long timeout)
                DEFINE_WAIT(wait);
 
                do {
-                       prepare_to_wait(sk->sk_sleep, &wait,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_INTERRUPTIBLE);
                        if (sk_wait_event(sk, &timeout, !sk_stream_closing(sk)))
                                break;
                } while (!signal_pending(current) && timeout);
 
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
        }
 }
 
@@ -126,7 +130,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
        while (1) {
                set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
                if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
                        goto do_error;
@@ -157,7 +161,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
                *timeo_p = current_timeo;
        }
 out:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return err;
 
 do_error:
index b7b6b8208f755ceb6f64c0f7a90a0673e172410a..01eee5d984be4b6d838357a56e0211508d0e31ba 100644 (file)
 #include <linux/socket.h>
 #include <linux/netdevice.h>
 #include <linux/ratelimit.h>
+#include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
 #include <net/ip.h>
 #include <net/sock.h>
 
+#ifdef CONFIG_RPS
+static int rps_sock_flow_sysctl(ctl_table *table, int write,
+                               void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       unsigned int orig_size, size;
+       int ret, i;
+       ctl_table tmp = {
+               .data = &size,
+               .maxlen = sizeof(size),
+               .mode = table->mode
+       };
+       struct rps_sock_flow_table *orig_sock_table, *sock_table;
+       static DEFINE_MUTEX(sock_flow_mutex);
+
+       mutex_lock(&sock_flow_mutex);
+
+       orig_sock_table = rps_sock_flow_table;
+       size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0;
+
+       ret = proc_dointvec(&tmp, write, buffer, lenp, ppos);
+
+       if (write) {
+               if (size) {
+                       if (size > 1<<30) {
+                               /* Enforce limit to prevent overflow */
+                               mutex_unlock(&sock_flow_mutex);
+                               return -EINVAL;
+                       }
+                       size = roundup_pow_of_two(size);
+                       if (size != orig_size) {
+                               sock_table =
+                                   vmalloc(RPS_SOCK_FLOW_TABLE_SIZE(size));
+                               if (!sock_table) {
+                                       mutex_unlock(&sock_flow_mutex);
+                                       return -ENOMEM;
+                               }
+
+                               sock_table->mask = size - 1;
+                       } else
+                               sock_table = orig_sock_table;
+
+                       for (i = 0; i < size; i++)
+                               sock_table->ents[i] = RPS_NO_CPU;
+               } else
+                       sock_table = NULL;
+
+               if (sock_table != orig_sock_table) {
+                       rcu_assign_pointer(rps_sock_flow_table, sock_table);
+                       synchronize_rcu();
+                       vfree(orig_sock_table);
+               }
+       }
+
+       mutex_unlock(&sock_flow_mutex);
+
+       return ret;
+}
+#endif /* CONFIG_RPS */
+
 static struct ctl_table net_core_table[] = {
 #ifdef CONFIG_NET
        {
@@ -61,6 +121,13 @@ static struct ctl_table net_core_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "netdev_tstamp_prequeue",
+               .data           = &netdev_tstamp_prequeue,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
        {
                .procname       = "message_cost",
                .data           = &net_ratelimit_state.interval,
@@ -82,6 +149,14 @@ static struct ctl_table net_core_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+#ifdef CONFIG_RPS
+       {
+               .procname       = "rps_sock_flow_entries",
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = rps_sock_flow_sysctl
+       },
+#endif
 #endif /* CONFIG_NET */
        {
                .procname       = "netdev_budget",
index bcd7632299f5244ab631f60f84115d211b838d68..d3235899c7e3392ea2ef24ecc0a60c74e87ed508 100644 (file)
@@ -208,7 +208,7 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
                goto restart_timer;
        }
 
-       ccid3_pr_debug("%s(%p, state=%s) - entry \n", dccp_role(sk), sk,
+       ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk,
                       ccid3_tx_state_name(hc->tx_state));
 
        if (hc->tx_state == TFRC_SSTATE_FBACK)
index 5ef32c2f0d6a964a9ab35e813798adbe209b71a6..a10a61a1ded2911ee4a18ab0f3d75e9380513b82 100644 (file)
@@ -189,7 +189,7 @@ enum {
 #define DCCP_MIB_MAX   __DCCP_MIB_MAX
 struct dccp_mib {
        unsigned long   mibs[DCCP_MIB_MAX];
-} __SNMP_MIB_ALIGN__;
+};
 
 DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
 #define DCCP_INC_STATS(field)      SNMP_INC_STATS(dccp_statistics, field)
@@ -223,7 +223,7 @@ static inline void dccp_csum_outgoing(struct sk_buff *skb)
        skb->csum = skb_checksum(skb, 0, (cov > skb->len)? skb->len : cov, 0);
 }
 
-extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);
+extern void dccp_v4_send_check(struct sock *sk, struct sk_buff *skb);
 
 extern int  dccp_retransmit_skb(struct sock *sk);
 
index 9ec717426024d0ab01a927653e4dd85134b72ef0..58f7bc1568503e26c755fa7122deb57ce53c832a 100644 (file)
@@ -415,7 +415,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
                if (!between48(DCCP_SKB_CB(skb)->dccpd_ack_seq,
                               dp->dccps_awl, dp->dccps_awh)) {
                        dccp_pr_debug("invalid ackno: S.AWL=%llu, "
-                                     "P.ackno=%llu, S.AWH=%llu \n",
+                                     "P.ackno=%llu, S.AWH=%llu\n",
                                      (unsigned long long)dp->dccps_awl,
                           (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
                                      (unsigned long long)dp->dccps_awh);
index 52ffa1cde15a07f597470a15d7fd5ad25bd1e695..d9b11ef8694c1732b609d21782141eca71dcfcce 100644 (file)
@@ -349,7 +349,7 @@ static inline __sum16 dccp_v4_csum_finish(struct sk_buff *skb,
        return csum_tcpudp_magic(src, dst, skb->len, IPPROTO_DCCP, skb->csum);
 }
 
-void dccp_v4_send_check(struct sock *sk, int unused, struct sk_buff *skb)
+void dccp_v4_send_check(struct sock *sk, struct sk_buff *skb)
 {
        const struct inet_sock *inet = inet_sk(sk);
        struct dccp_hdr *dh = dccp_hdr(skb);
index 3b11e41a2929e717ded1865c864a6f7b1b5fb7e0..091698899594388bbfb65678ce2ca8d1061283aa 100644 (file)
@@ -60,8 +60,7 @@ static inline __sum16 dccp_v6_csum_finish(struct sk_buff *skb,
        return csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_DCCP, skb->csum);
 }
 
-static inline void dccp_v6_send_check(struct sock *sk, int unused_value,
-                                     struct sk_buff *skb)
+static inline void dccp_v6_send_check(struct sock *sk, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct dccp_hdr *dh = dccp_hdr(skb);
@@ -293,7 +292,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
                                                         &ireq6->loc_addr,
                                                         &ireq6->rmt_addr);
                ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
-               err = ip6_xmit(sk, skb, &fl, opt, 0);
+               err = ip6_xmit(sk, skb, &fl, opt);
                err = net_xmit_eval(err);
        }
 
@@ -348,7 +347,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
        if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
                if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
                        skb_dst_set(skb, dst);
-                       ip6_xmit(ctl_sk, skb, &fl, NULL, 0);
+                       ip6_xmit(ctl_sk, skb, &fl, NULL);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS);
                        DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS);
                        return;
index fc3f436440b48980f01a05cb97f80960e4f5fd5a..aadbdb58758b754b2d712c6632b7457865f0a2cf 100644 (file)
@@ -129,14 +129,14 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
                        break;
                }
 
-               icsk->icsk_af_ops->send_check(sk, 0, skb);
+               icsk->icsk_af_ops->send_check(sk, skb);
 
                if (set_ack)
                        dccp_event_ack_sent(sk);
 
                DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 
-               err = icsk->icsk_af_ops->queue_xmit(skb, 0);
+               err = icsk->icsk_af_ops->queue_xmit(skb);
                return net_xmit_eval(err);
        }
        return -ENOBUFS;
@@ -195,15 +195,17 @@ EXPORT_SYMBOL_GPL(dccp_sync_mss);
 
 void dccp_write_space(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
+       struct socket_wq *wq;
 
-       if (sk_has_sleeper(sk))
-               wake_up_interruptible(sk->sk_sleep);
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible(&wq->wait);
        /* Should agree with poll, otherwise some programs break */
        if (sock_writeable(sk))
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
 
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 /**
@@ -225,7 +227,7 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay)
                dccp_pr_debug("delayed send by %d msec\n", delay);
                jiffdelay = msecs_to_jiffies(delay);
 
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
                sk->sk_write_pending++;
                release_sock(sk);
@@ -241,7 +243,7 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay)
                rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
        } while ((delay = rc) > 0);
 out:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return rc;
 
 do_error:
index a0e38d8018f55f9c7387136a3889d568d2bdfa92..b03ecf6b2bb052cf8c277c9d5ff3f5c3e96774ef 100644 (file)
@@ -312,7 +312,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        if (sk->sk_state == DCCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
index bbfeb5eae46a34d071972ab397f01d8d340cf070..1a9aa05d4dc4c399952cb9932d728768aa619e2d 100644 (file)
@@ -38,7 +38,7 @@ static int dccp_write_timeout(struct sock *sk)
 
        if (sk->sk_state == DCCP_REQUESTING || sk->sk_state == DCCP_PARTOPEN) {
                if (icsk->icsk_retransmits != 0)
-                       dst_negative_advice(&sk->sk_dst_cache, sk);
+                       dst_negative_advice(sk);
                retry_until = icsk->icsk_syn_retries ?
                            : sysctl_dccp_request_retries;
        } else {
@@ -63,7 +63,7 @@ static int dccp_write_timeout(struct sock *sk)
                           Golden words :-).
                   */
 
-                       dst_negative_advice(&sk->sk_dst_cache, sk);
+                       dst_negative_advice(sk);
                }
 
                retry_until = sysctl_dccp_retries2;
index 2b494fac9468d6816a677a80d362cb28ffe18b41..d6b93d19790f003b92935c1b1da7700e8d788787 100644 (file)
@@ -446,7 +446,7 @@ static void dn_destruct(struct sock *sk)
        skb_queue_purge(&scp->other_xmit_queue);
        skb_queue_purge(&scp->other_receive_queue);
 
-       dst_release(xchg(&sk->sk_dst_cache, NULL));
+       dst_release(rcu_dereference_check(sk->sk_dst_cache, 1));
 }
 
 static int dn_memory_pressure;
@@ -832,7 +832,7 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation)
        scp->segsize_loc = dst_metric(__sk_dst_get(sk), RTAX_ADVMSS);
        dn_send_conn_conf(sk, allocation);
 
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        for(;;) {
                release_sock(sk);
                if (scp->state == DN_CC)
@@ -850,9 +850,9 @@ static int dn_confirm_accept(struct sock *sk, long *timeo, gfp_t allocation)
                err = -EAGAIN;
                if (!*timeo)
                        break;
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (err == 0) {
                sk->sk_socket->state = SS_CONNECTED;
        } else if (scp->state != DN_CC) {
@@ -873,7 +873,7 @@ static int dn_wait_run(struct sock *sk, long *timeo)
        if (!*timeo)
                return -EALREADY;
 
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        for(;;) {
                release_sock(sk);
                if (scp->state == DN_CI || scp->state == DN_CC)
@@ -891,9 +891,9 @@ static int dn_wait_run(struct sock *sk, long *timeo)
                err = -ETIMEDOUT;
                if (!*timeo)
                        break;
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
 out:
        if (err == 0) {
                sk->sk_socket->state = SS_CONNECTED;
@@ -1040,7 +1040,7 @@ static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
        struct sk_buff *skb = NULL;
        int err = 0;
 
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        for(;;) {
                release_sock(sk);
                skb = skb_dequeue(&sk->sk_receive_queue);
@@ -1060,9 +1060,9 @@ static struct sk_buff *dn_wait_for_connect(struct sock *sk, long *timeo)
                err = -EAGAIN;
                if (!*timeo)
                        break;
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
 
        return skb == NULL ? ERR_PTR(err) : skb;
 }
@@ -1105,7 +1105,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
        release_sock(sk);
 
        dst = skb_dst(skb);
-       dst_release(xchg(&newsk->sk_dst_cache, dst));
+       sk_dst_set(newsk, dst);
        skb_dst_set(skb, NULL);
 
        DN_SK(newsk)->state        = DN_CR;
@@ -1746,11 +1746,11 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
                        goto out;
                }
 
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
                sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target));
                clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
        }
 
        skb_queue_walk_safe(queue, skb, n) {
@@ -1956,7 +1956,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
        }
 
        if ((flags & MSG_TRYHARD) && sk->sk_dst_cache)
-               dst_negative_advice(&sk->sk_dst_cache, sk);
+               dst_negative_advice(sk);
 
        mss = scp->segsize_rem;
        fctype = scp->services_rem & NSP_FC_MASK;
@@ -2003,12 +2003,12 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
                                goto out;
                        }
 
-                       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+                       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                        set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
                        sk_wait_event(sk, &timeo,
                                      !dn_queue_too_long(scp, queue, flags));
                        clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
-                       finish_wait(sk->sk_sleep, &wait);
+                       finish_wait(sk_sleep(sk), &wait);
                        continue;
                }
 
index cead68eb254c1370928ae37078a4df8b36fcd5a7..4c409b46aa35c0bb13bc0b99cec4f43dd2da0690 100644 (file)
@@ -350,7 +350,7 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de
        if (dn_db->dev->type == ARPHRD_ETHER) {
                if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {
                        dn_dn2eth(mac_addr, ifa1->ifa_local);
-                       dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);
+                       dev_mc_del(dev, mac_addr);
                }
        }
 
@@ -381,7 +381,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
        if (dev->type == ARPHRD_ETHER) {
                if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
                        dn_dn2eth(mac_addr, ifa->ifa_local);
-                       dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
+                       dev_mc_add(dev, mac_addr);
                }
        }
 
@@ -1001,9 +1001,9 @@ static int dn_eth_up(struct net_device *dev)
        struct dn_dev *dn_db = dev->dn_ptr;
 
        if (dn_db->parms.forwarding == 0)
-               dev_mc_add(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
+               dev_mc_add(dev, dn_rt_all_end_mcast);
        else
-               dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
+               dev_mc_add(dev, dn_rt_all_rt_mcast);
 
        dn_db->use_long = 1;
 
@@ -1015,9 +1015,9 @@ static void dn_eth_down(struct net_device *dev)
        struct dn_dev *dn_db = dev->dn_ptr;
 
        if (dn_db->parms.forwarding == 0)
-               dev_mc_delete(dev, dn_rt_all_end_mcast, ETH_ALEN, 0);
+               dev_mc_del(dev, dn_rt_all_end_mcast);
        else
-               dev_mc_delete(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
+               dev_mc_del(dev, dn_rt_all_rt_mcast);
 }
 
 static void dn_dev_set_timer(struct net_device *dev);
@@ -1220,17 +1220,14 @@ void dn_dev_down(struct net_device *dev)
 
 void dn_dev_init_pkt(struct sk_buff *skb)
 {
-       return;
 }
 
 void dn_dev_veri_pkt(struct sk_buff *skb)
 {
-       return;
 }
 
 void dn_dev_hello(struct sk_buff *skb)
 {
-       return;
 }
 
 void dn_dev_devices_off(void)
index deb723dba44b62d8aca89aa15d9ea332001f004a..0363bb95cc7db606d45dd08bac34340ba48a3a84 100644 (file)
@@ -266,7 +266,8 @@ static int dn_long_output(struct sk_buff *skb)
 
        skb_reset_network_header(skb);
 
-       return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
+                      neigh->dev, dn_neigh_output_packet);
 }
 
 static int dn_short_output(struct sk_buff *skb)
@@ -305,7 +306,8 @@ static int dn_short_output(struct sk_buff *skb)
 
        skb_reset_network_header(skb);
 
-       return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
+                      neigh->dev, dn_neigh_output_packet);
 }
 
 /*
@@ -347,7 +349,8 @@ static int dn_phase3_output(struct sk_buff *skb)
 
        skb_reset_network_header(skb);
 
-       return NF_HOOK(PF_DECnet, NF_DN_POST_ROUTING, skb, NULL, neigh->dev, dn_neigh_output_packet);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_POST_ROUTING, skb, NULL,
+                      neigh->dev, dn_neigh_output_packet);
 }
 
 /*
index 25a37299bc65c0fd8652c886758a372c1bdcf66a..b430549e2b917301320b26d91fd95dacbd305fb9 100644 (file)
@@ -810,7 +810,8 @@ free_out:
 
 int dn_nsp_rx(struct sk_buff *skb)
 {
-       return NF_HOOK(PF_DECnet, NF_DN_LOCAL_IN, skb, skb->dev, NULL, dn_nsp_rx_packet);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN, skb, skb->dev, NULL,
+                      dn_nsp_rx_packet);
 }
 
 /*
index 70ebe74027d558750218c8bc9974d0a02f2de3c8..812e6dff60675d5971b03d2d4b834ac530121e82 100644 (file)
@@ -264,7 +264,6 @@ static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst)
 
 static void dn_dst_link_failure(struct sk_buff *skb)
 {
-       return;
 }
 
 static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
@@ -518,7 +517,8 @@ static int dn_route_rx_long(struct sk_buff *skb)
        ptr++;
        cb->hops = *ptr++; /* Visit Count */
 
-       return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, skb, skb->dev, NULL,
+                      dn_route_rx_packet);
 
 drop_it:
        kfree_skb(skb);
@@ -544,7 +544,8 @@ static int dn_route_rx_short(struct sk_buff *skb)
        ptr += 2;
        cb->hops = *ptr & 0x3f;
 
-       return NF_HOOK(PF_DECnet, NF_DN_PRE_ROUTING, skb, skb->dev, NULL, dn_route_rx_packet);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_PRE_ROUTING, skb, skb->dev, NULL,
+                      dn_route_rx_packet);
 
 drop_it:
        kfree_skb(skb);
@@ -646,16 +647,24 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
 
                switch(flags & DN_RT_CNTL_MSK) {
                        case DN_RT_PKT_HELO:
-                               return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_route_ptp_hello);
+                               return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO,
+                                              skb, skb->dev, NULL,
+                                              dn_route_ptp_hello);
 
                        case DN_RT_PKT_L1RT:
                        case DN_RT_PKT_L2RT:
-                               return NF_HOOK(PF_DECnet, NF_DN_ROUTE, skb, skb->dev, NULL, dn_route_discard);
+                               return NF_HOOK(NFPROTO_DECNET, NF_DN_ROUTE,
+                                              skb, skb->dev, NULL,
+                                              dn_route_discard);
                        case DN_RT_PKT_ERTH:
-                               return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_router_hello);
+                               return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO,
+                                              skb, skb->dev, NULL,
+                                              dn_neigh_router_hello);
 
                        case DN_RT_PKT_EEDH:
-                               return NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_endnode_hello);
+                               return NF_HOOK(NFPROTO_DECNET, NF_DN_HELLO,
+                                              skb, skb->dev, NULL,
+                                              dn_neigh_endnode_hello);
                }
        } else {
                if (dn->parms.state != DN_DEV_S_RU)
@@ -704,7 +713,8 @@ static int dn_output(struct sk_buff *skb)
        cb->rt_flags |= DN_RT_F_IE;
        cb->hops = 0;
 
-       return NF_HOOK(PF_DECnet, NF_DN_LOCAL_OUT, skb, NULL, dev, neigh->output);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_OUT, skb, NULL, dev,
+                      neigh->output);
 
 error:
        if (net_ratelimit())
@@ -753,7 +763,8 @@ static int dn_forward(struct sk_buff *skb)
        if (rt->rt_flags & RTCF_DOREDIRECT)
                cb->rt_flags |= DN_RT_F_IE;
 
-       return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
+       return NF_HOOK(NFPROTO_DECNET, NF_DN_FORWARD, skb, dev, skb->dev,
+                      neigh->output);
 
 drop:
        kfree_skb(skb);
index 7466c546f2860d85ad51fc5b821f6775aa1d9012..48fdf10be7a1634a78114cd3a4e7d05b0902f585 100644 (file)
@@ -196,7 +196,6 @@ static int dn_fib_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
 {
        struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
 
-       frh->family = AF_DECnet;
        frh->dst_len = r->dst_len;
        frh->src_len = r->src_len;
        frh->tos = 0;
@@ -212,29 +211,12 @@ nla_put_failure:
        return -ENOBUFS;
 }
 
-static u32 dn_fib_rule_default_pref(struct fib_rules_ops *ops)
-{
-       struct list_head *pos;
-       struct fib_rule *rule;
-
-       if (!list_empty(&dn_fib_rules_ops->rules_list)) {
-               pos = dn_fib_rules_ops->rules_list.next;
-               if (pos->next != &dn_fib_rules_ops->rules_list) {
-                       rule = list_entry(pos->next, struct fib_rule, list);
-                       if (rule->pref)
-                               return rule->pref - 1;
-               }
-       }
-
-       return 0;
-}
-
 static void dn_fib_rule_flush_cache(struct fib_rules_ops *ops)
 {
        dn_rt_cache_flush(-1);
 }
 
-static struct fib_rules_ops dn_fib_rules_ops_template = {
+static const struct fib_rules_ops __net_initdata dn_fib_rules_ops_template = {
        .family         = AF_DECnet,
        .rule_size      = sizeof(struct dn_fib_rule),
        .addr_size      = sizeof(u16),
@@ -243,7 +225,7 @@ static struct fib_rules_ops dn_fib_rules_ops_template = {
        .configure      = dn_fib_rule_configure,
        .compare        = dn_fib_rule_compare,
        .fill           = dn_fib_rule_fill,
-       .default_pref   = dn_fib_rule_default_pref,
+       .default_pref   = fib_default_rule_pref,
        .flush_cache    = dn_fib_rule_flush_cache,
        .nlgroup        = RTNLGRP_DECnet_RULE,
        .policy         = dn_fib_rule_policy,
index 2175e6d5cc8d4dcab16e06c069d9016f4880be18..8fdca56bb08f33817645ae55f179fbe6a8ad9c1e 100644 (file)
@@ -67,7 +67,7 @@ static int dsa_slave_open(struct net_device *dev)
                return -ENETDOWN;
 
        if (compare_ether_addr(dev->dev_addr, master->dev_addr)) {
-               err = dev_unicast_add(master, dev->dev_addr);
+               err = dev_uc_add(master, dev->dev_addr);
                if (err < 0)
                        goto out;
        }
@@ -90,7 +90,7 @@ clear_allmulti:
                dev_set_allmulti(master, -1);
 del_unicast:
        if (compare_ether_addr(dev->dev_addr, master->dev_addr))
-               dev_unicast_delete(master, dev->dev_addr);
+               dev_uc_del(master, dev->dev_addr);
 out:
        return err;
 }
@@ -101,14 +101,14 @@ static int dsa_slave_close(struct net_device *dev)
        struct net_device *master = p->parent->dst->master_netdev;
 
        dev_mc_unsync(master, dev);
-       dev_unicast_unsync(master, dev);
+       dev_uc_unsync(master, dev);
        if (dev->flags & IFF_ALLMULTI)
                dev_set_allmulti(master, -1);
        if (dev->flags & IFF_PROMISC)
                dev_set_promiscuity(master, -1);
 
        if (compare_ether_addr(dev->dev_addr, master->dev_addr))
-               dev_unicast_delete(master, dev->dev_addr);
+               dev_uc_del(master, dev->dev_addr);
 
        return 0;
 }
@@ -130,7 +130,7 @@ static void dsa_slave_set_rx_mode(struct net_device *dev)
        struct net_device *master = p->parent->dst->master_netdev;
 
        dev_mc_sync(master, dev);
-       dev_unicast_sync(master, dev);
+       dev_uc_sync(master, dev);
 }
 
 static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
@@ -147,13 +147,13 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
                goto out;
 
        if (compare_ether_addr(addr->sa_data, master->dev_addr)) {
-               err = dev_unicast_add(master, addr->sa_data);
+               err = dev_uc_add(master, addr->sa_data);
                if (err < 0)
                        return err;
        }
 
        if (compare_ether_addr(dev->dev_addr, master->dev_addr))
-               dev_unicast_delete(master, dev->dev_addr);
+               dev_uc_del(master, dev->dev_addr);
 
 out:
        memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
index 205a1c12f3c0475f4c15bd59064e21c3be7b93e9..61ec0329316c1353fb5f59f3e1e24d0cb397a19e 100644 (file)
@@ -136,7 +136,7 @@ int eth_rebuild_header(struct sk_buff *skb)
        default:
                printk(KERN_DEBUG
                       "%s: unable to resolve type %X addresses.\n",
-                      dev->name, (int)eth->h_proto);
+                      dev->name, ntohs(eth->h_proto));
 
                memcpy(eth->h_source, dev->dev_addr, ETH_ALEN);
                break;
@@ -162,7 +162,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
 
        skb->dev = dev;
        skb_reset_mac_header(skb);
-       skb_pull(skb, ETH_HLEN);
+       skb_pull_inline(skb, ETH_HLEN);
        eth = eth_hdr(skb);
 
        if (unlikely(is_multicast_ether_addr(eth->h_dest))) {
index 0c94a1ac29464247e2dfdd6c4ac14c1dbed3bf79..8e3a1fd938ab3c2f18a8f9884598858b2020cd88 100644 (file)
@@ -250,6 +250,20 @@ config IP_MROUTE
          <file:Documentation/networking/multicast.txt>. If you haven't heard
          about it, you don't need it.
 
+config IP_MROUTE_MULTIPLE_TABLES
+       bool "IP: multicast policy routing"
+       depends on IP_MROUTE && IP_ADVANCED_ROUTER
+       select FIB_RULES
+       help
+         Normally, a multicast router runs a userspace daemon and decides
+         what to do with a multicast packet based on the source and
+         destination addresses. If you say Y here, the multicast router
+         will also be able to take interfaces and packet marks into
+         account and run multiple instances of userspace daemons
+         simultaneously, each one handling a single table.
+
+         If unsure, say N.
+
 config IP_PIMSM_V1
        bool "IP: PIM-SM version 1 support"
        depends on IP_MROUTE
@@ -587,9 +601,15 @@ choice
        config DEFAULT_HTCP
                bool "Htcp" if TCP_CONG_HTCP=y
 
+       config DEFAULT_HYBLA
+               bool "Hybla" if TCP_CONG_HYBLA=y
+
        config DEFAULT_VEGAS
                bool "Vegas" if TCP_CONG_VEGAS=y
 
+       config DEFAULT_VENO
+               bool "Veno" if TCP_CONG_VENO=y
+
        config DEFAULT_WESTWOOD
                bool "Westwood" if TCP_CONG_WESTWOOD=y
 
@@ -610,8 +630,10 @@ config DEFAULT_TCP_CONG
        default "bic" if DEFAULT_BIC
        default "cubic" if DEFAULT_CUBIC
        default "htcp" if DEFAULT_HTCP
+       default "hybla" if DEFAULT_HYBLA
        default "vegas" if DEFAULT_VEGAS
        default "westwood" if DEFAULT_WESTWOOD
+       default "veno" if DEFAULT_VENO
        default "reno" if DEFAULT_RENO
        default "cubic"
 
index f71357422380b640153b004968e7cf2b0d9a5444..551ce564b035592f54f1d6330d98454570bf3afd 100644 (file)
@@ -154,7 +154,7 @@ void inet_sock_destruct(struct sock *sk)
        WARN_ON(sk->sk_forward_alloc);
 
        kfree(inet->opt);
-       dst_release(sk->sk_dst_cache);
+       dst_release(rcu_dereference_check(sk->sk_dst_cache, 1));
        sk_refcnt_debug_dec(sk);
 }
 EXPORT_SYMBOL(inet_sock_destruct);
@@ -419,6 +419,8 @@ int inet_release(struct socket *sock)
        if (sk) {
                long timeout;
 
+               sock_rps_reset_flow(sk);
+
                /* Applications forget to leave groups before exiting */
                ip_mc_drop_socket(sk);
 
@@ -546,7 +548,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
 {
        DEFINE_WAIT(wait);
 
-       prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
        /* Basic assumption: if someone sets sk->sk_err, he _must_
         * change state of the socket from TCP_SYN_*.
@@ -559,9 +561,9 @@ static long inet_wait_for_connect(struct sock *sk, long timeo)
                lock_sock(sk);
                if (signal_pending(current) || !timeo)
                        break;
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return timeo;
 }
 
@@ -720,6 +722,8 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 {
        struct sock *sk = sock->sk;
 
+       sock_rps_record_flow(sk);
+
        /* We may need to bind the socket. */
        if (!inet_sk(sk)->inet_num && inet_autobind(sk))
                return -EAGAIN;
@@ -728,12 +732,13 @@ int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 }
 EXPORT_SYMBOL(inet_sendmsg);
 
-
 static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
                             size_t size, int flags)
 {
        struct sock *sk = sock->sk;
 
+       sock_rps_record_flow(sk);
+
        /* We may need to bind the socket. */
        if (!inet_sk(sk)->inet_num && inet_autobind(sk))
                return -EAGAIN;
@@ -743,6 +748,22 @@ static ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset,
        return sock_no_sendpage(sock, page, offset, size, flags);
 }
 
+int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+                size_t size, int flags)
+{
+       struct sock *sk = sock->sk;
+       int addr_len = 0;
+       int err;
+
+       sock_rps_record_flow(sk);
+
+       err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
+                                  flags & ~MSG_DONTWAIT, &addr_len);
+       if (err >= 0)
+               msg->msg_namelen = addr_len;
+       return err;
+}
+EXPORT_SYMBOL(inet_recvmsg);
 
 int inet_shutdown(struct socket *sock, int how)
 {
@@ -872,7 +893,7 @@ const struct proto_ops inet_stream_ops = {
        .setsockopt        = sock_common_setsockopt,
        .getsockopt        = sock_common_getsockopt,
        .sendmsg           = tcp_sendmsg,
-       .recvmsg           = sock_common_recvmsg,
+       .recvmsg           = inet_recvmsg,
        .mmap              = sock_no_mmap,
        .sendpage          = tcp_sendpage,
        .splice_read       = tcp_splice_read,
@@ -899,7 +920,7 @@ const struct proto_ops inet_dgram_ops = {
        .setsockopt        = sock_common_setsockopt,
        .getsockopt        = sock_common_getsockopt,
        .sendmsg           = inet_sendmsg,
-       .recvmsg           = sock_common_recvmsg,
+       .recvmsg           = inet_recvmsg,
        .mmap              = sock_no_mmap,
        .sendpage          = inet_sendpage,
 #ifdef CONFIG_COMPAT
@@ -929,7 +950,7 @@ static const struct proto_ops inet_sockraw_ops = {
        .setsockopt        = sock_common_setsockopt,
        .getsockopt        = sock_common_getsockopt,
        .sendmsg           = inet_sendmsg,
-       .recvmsg           = sock_common_recvmsg,
+       .recvmsg           = inet_recvmsg,
        .mmap              = sock_no_mmap,
        .sendpage          = inet_sendpage,
 #ifdef CONFIG_COMPAT
@@ -1302,8 +1323,8 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
        if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
                goto out_unlock;
 
-       id = ntohl(*(u32 *)&iph->id);
-       flush = (u16)((ntohl(*(u32 *)iph) ^ skb_gro_len(skb)) | (id ^ IP_DF));
+       id = ntohl(*(__be32 *)&iph->id);
+       flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id ^ IP_DF));
        id >>= 16;
 
        for (p = *head; p; p = p->next) {
@@ -1316,8 +1337,8 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
 
                if ((iph->protocol ^ iph2->protocol) |
                    (iph->tos ^ iph2->tos) |
-                   (iph->saddr ^ iph2->saddr) |
-                   (iph->daddr ^ iph2->daddr)) {
+                   ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) |
+                   ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) {
                        NAPI_GRO_CB(p)->same_flow = 0;
                        continue;
                }
@@ -1407,10 +1428,10 @@ EXPORT_SYMBOL_GPL(snmp_fold_field);
 int snmp_mib_init(void __percpu *ptr[2], size_t mibsize)
 {
        BUG_ON(ptr == NULL);
-       ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
+       ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long));
        if (!ptr[0])
                goto err0;
-       ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
+       ptr[1] = __alloc_percpu(mibsize, __alignof__(unsigned long));
        if (!ptr[1])
                goto err1;
        return 0;
@@ -1552,9 +1573,13 @@ static int __init inet_init(void)
 
        BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));
 
+       sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
+       if (!sysctl_local_reserved_ports)
+               goto out;
+
        rc = proto_register(&tcp_prot, 1);
        if (rc)
-               goto out;
+               goto out_free_reserved_ports;
 
        rc = proto_register(&udp_prot, 1);
        if (rc)
@@ -1653,6 +1678,8 @@ out_unregister_udp_proto:
        proto_unregister(&udp_prot);
 out_unregister_tcp_proto:
        proto_unregister(&tcp_prot);
+out_free_reserved_ports:
+       kfree(sysctl_local_reserved_ports);
        goto out;
 }
 
index 80769f1f9fab8d529bf5de1d1141a9108fe8f256..f094b75810db5fd44f29e14e4ff3b244441bdee1 100644 (file)
@@ -854,7 +854,7 @@ static int arp_process(struct sk_buff *skb)
        }
 
        if (arp->ar_op == htons(ARPOP_REQUEST) &&
-           ip_route_input(skb, tip, sip, 0, dev) == 0) {
+           ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {
 
                rt = skb_rtable(skb);
                addr_type = rt->rt_type;
index c97cd9ff697ee1cba4f373333190126c57970f28..3a92a76ae41d6265f957396e9ca9fd190d62b892 100644 (file)
@@ -290,8 +290,6 @@ void cipso_v4_cache_invalidate(void)
                cipso_v4_cache[iter].size = 0;
                spin_unlock_bh(&cipso_v4_cache[iter].lock);
        }
-
-       return;
 }
 
 /**
index 90e3d6379a42ae369ceeba06c783978858e96e71..382bc768ed565cc79bc79c8c71fa0588d2a7a78b 100644 (file)
@@ -1096,10 +1096,10 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
        case NETDEV_DOWN:
                ip_mc_down(in_dev);
                break;
-       case NETDEV_BONDING_OLDTYPE:
+       case NETDEV_PRE_TYPE_CHANGE:
                ip_mc_unmap(in_dev);
                break;
-       case NETDEV_BONDING_NEWTYPE:
+       case NETDEV_POST_TYPE_CHANGE:
                ip_mc_remap(in_dev);
                break;
        case NETDEV_CHANGEMTU:
index ca2d07b1c7064ec40cdda0f0a950b1082f568f7a..76daeb5ff5642e656622f0da906f73a32d603643 100644 (file)
@@ -213,7 +213,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
 {
        struct fib4_rule *rule4 = (struct fib4_rule *) rule;
 
-       frh->family = AF_INET;
        frh->dst_len = rule4->dst_len;
        frh->src_len = rule4->src_len;
        frh->tos = rule4->tos;
@@ -234,23 +233,6 @@ nla_put_failure:
        return -ENOBUFS;
 }
 
-static u32 fib4_rule_default_pref(struct fib_rules_ops *ops)
-{
-       struct list_head *pos;
-       struct fib_rule *rule;
-
-       if (!list_empty(&ops->rules_list)) {
-               pos = ops->rules_list.next;
-               if (pos->next != &ops->rules_list) {
-                       rule = list_entry(pos->next, struct fib_rule, list);
-                       if (rule->pref)
-                               return rule->pref - 1;
-               }
-       }
-
-       return 0;
-}
-
 static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
 {
        return nla_total_size(4) /* dst */
@@ -263,7 +245,7 @@ static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
        rt_cache_flush(ops->fro_net, -1);
 }
 
-static struct fib_rules_ops fib4_rules_ops_template = {
+static const struct fib_rules_ops __net_initdata fib4_rules_ops_template = {
        .family         = AF_INET,
        .rule_size      = sizeof(struct fib4_rule),
        .addr_size      = sizeof(u32),
@@ -272,7 +254,7 @@ static struct fib_rules_ops fib4_rules_ops_template = {
        .configure      = fib4_rule_configure,
        .compare        = fib4_rule_compare,
        .fill           = fib4_rule_fill,
-       .default_pref   = fib4_rule_default_pref,
+       .default_pref   = fib_default_rule_pref,
        .nlmsg_payload  = fib4_rule_nlmsg_payload,
        .flush_cache    = fib4_rule_flush_cache,
        .nlgroup        = RTNLGRP_IPV4_RULE,
index c98f115fb0fde6d97136695075fa45c04976c4be..79d057a939ba6404d4e7553008a2613815a9b049 100644 (file)
@@ -1022,8 +1022,6 @@ static void trie_rebalance(struct trie *t, struct tnode *tn)
 
        rcu_assign_pointer(t->trie, (struct node *)tn);
        tnode_free_flush();
-
-       return;
 }
 
 /* only used from updater-side */
index ac4dec1327354020b35f7404f5f47f4d463aba3f..d65e9215bcd77c2b15d6facdc0d75a67310c68f2 100644 (file)
@@ -331,9 +331,10 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
        if (ip_append_data(sk, icmp_glue_bits, icmp_param,
                           icmp_param->data_len+icmp_param->head_len,
                           icmp_param->head_len,
-                          ipc, rt, MSG_DONTWAIT) < 0)
+                          ipc, rt, MSG_DONTWAIT) < 0) {
+               ICMP_INC_STATS_BH(sock_net(sk), ICMP_MIB_OUTERRORS);
                ip_flush_pending_frames(sk);
-       else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
+       else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
                struct icmphdr *icmph = icmp_hdr(skb);
                __wsum csum = 0;
                struct sk_buff *skb1;
@@ -586,20 +587,20 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
                        err = __ip_route_output_key(net, &rt2, &fl);
                else {
                        struct flowi fl2 = {};
-                       struct dst_entry *odst;
+                       unsigned long orefdst;
 
                        fl2.fl4_dst = fl.fl4_src;
                        if (ip_route_output_key(net, &rt2, &fl2))
                                goto relookup_failed;
 
                        /* Ugh! */
-                       odst = skb_dst(skb_in);
+                       orefdst = skb_in->_skb_refdst; /* save old refdst */
                        err = ip_route_input(skb_in, fl.fl4_dst, fl.fl4_src,
                                             RT_TOS(tos), rt2->u.dst.dev);
 
                        dst_release(&rt2->u.dst);
                        rt2 = skb_rtable(skb_in);
-                       skb_dst_set(skb_in, odst);
+                       skb_in->_skb_refdst = orefdst; /* restore old refdst */
                }
 
                if (err)
index 15d3eeda92f5c7876698dac44048ff1c4bbc09b7..5fff865a4fa745c02cf93e65323f3316ae8299d0 100644 (file)
@@ -998,7 +998,7 @@ static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr)
           --ANK
           */
        if (arp_mc_map(addr, buf, dev, 0) == 0)
-               dev_mc_add(dev, buf, dev->addr_len, 0);
+               dev_mc_add(dev, buf);
 }
 
 /*
@@ -1011,7 +1011,7 @@ static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr)
        struct net_device *dev = in_dev->dev;
 
        if (arp_mc_map(addr, buf, dev, 0) == 0)
-               dev_mc_delete(dev, buf, dev->addr_len, 0);
+               dev_mc_del(dev, buf);
 }
 
 #ifdef CONFIG_IP_MULTICAST
index 8da6429269dddd922f9c3fb4eda2b86a7bffe0d2..70eb3507c40645a028d0ecd0421911f10f0a541d 100644 (file)
@@ -37,6 +37,9 @@ struct local_ports sysctl_local_ports __read_mostly = {
        .range = { 32768, 61000 },
 };
 
+unsigned long *sysctl_local_reserved_ports;
+EXPORT_SYMBOL(sysctl_local_reserved_ports);
+
 void inet_get_local_port_range(int *low, int *high)
 {
        unsigned seq;
@@ -108,6 +111,8 @@ again:
 
                smallest_size = -1;
                do {
+                       if (inet_is_reserved_local_port(rover))
+                               goto next_nolock;
                        head = &hashinfo->bhash[inet_bhashfn(net, rover,
                                        hashinfo->bhash_size)];
                        spin_lock(&head->lock);
@@ -130,6 +135,7 @@ again:
                        break;
                next:
                        spin_unlock(&head->lock);
+               next_nolock:
                        if (++rover > high)
                                rover = low;
                } while (--remaining > 0);
@@ -234,7 +240,7 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
         * having to remove and re-insert us on the wait queue.
         */
        for (;;) {
-               prepare_to_wait_exclusive(sk->sk_sleep, &wait,
+               prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                          TASK_INTERRUPTIBLE);
                release_sock(sk);
                if (reqsk_queue_empty(&icsk->icsk_accept_queue))
@@ -253,7 +259,7 @@ static int inet_csk_wait_for_connect(struct sock *sk, long timeo)
                if (!timeo)
                        break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return err;
 }
 
index 2b79377b468dd0b06d69b0c6b5842f52ba52db07..d3e160a88219d5d45c759bff91d2da54a03939bc 100644 (file)
@@ -456,6 +456,8 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
                local_bh_disable();
                for (i = 1; i <= remaining; i++) {
                        port = low + (i + offset) % remaining;
+                       if (inet_is_reserved_local_port(port))
+                               continue;
                        head = &hinfo->bhash[inet_bhashfn(net, port,
                                        hinfo->bhash_size)];
                        spin_lock(&head->lock);
index af10942b326c4f51cdd49c61411a009e2d80a026..56cdf68a074c3d27cf9c85c03ac86b6803147d22 100644 (file)
@@ -112,8 +112,8 @@ int ip_forward(struct sk_buff *skb)
 
        skb->priority = rt_tos2priority(iph->tos);
 
-       return NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, rt->u.dst.dev,
-                      ip_forward_finish);
+       return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev,
+                      rt->u.dst.dev, ip_forward_finish);
 
 sr_failed:
        /*
index fe381d12ecdd4227e785ff54f6e0b97162914f55..32618e11076d49776d3e017ac162fcc0837489b5 100644 (file)
@@ -502,7 +502,6 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
        t->err_time = jiffies;
 out:
        rcu_read_unlock();
-       return;
 }
 
 static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
@@ -538,7 +537,6 @@ static int ipgre_rcv(struct sk_buff *skb)
        struct ip_tunnel *tunnel;
        int    offset = 4;
        __be16 gre_proto;
-       unsigned int len;
 
        if (!pskb_may_pull(skb, 16))
                goto drop_nolock;
@@ -629,8 +627,6 @@ static int ipgre_rcv(struct sk_buff *skb)
                        tunnel->i_seqno = seqno + 1;
                }
 
-               len = skb->len;
-
                /* Warning: All skb pointers will be invalidated! */
                if (tunnel->dev->type == ARPHRD_ETHER) {
                        if (!pskb_may_pull(skb, ETH_HLEN)) {
@@ -644,11 +640,7 @@ static int ipgre_rcv(struct sk_buff *skb)
                        skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
                }
 
-               stats->rx_packets++;
-               stats->rx_bytes += len;
-               skb->dev = tunnel->dev;
-               skb_dst_drop(skb);
-               nf_reset(skb);
+               skb_tunnel_rx(skb, tunnel->dev);
 
                skb_reset_network_header(skb);
                ipgre_ecn_decapsulate(iph, skb);
index f8ab7a380d4a64b12696eeab5c5f23ab5ca332db..d930dc5e4d85a752ddb7af15b482b47108b62241 100644 (file)
@@ -266,7 +266,7 @@ int ip_local_deliver(struct sk_buff *skb)
                        return 0;
        }
 
-       return NF_HOOK(PF_INET, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
+       return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
                       ip_local_deliver_finish);
 }
 
@@ -331,8 +331,8 @@ static int ip_rcv_finish(struct sk_buff *skb)
         *      how the packet travels inside Linux networking.
         */
        if (skb_dst(skb) == NULL) {
-               int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
-                                        skb->dev);
+               int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
+                                              iph->tos, skb->dev);
                if (unlikely(err)) {
                        if (err == -EHOSTUNREACH)
                                IP_INC_STATS_BH(dev_net(skb->dev),
@@ -444,7 +444,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
        /* Must drop socket now because of tproxy. */
        skb_orphan(skb);
 
-       return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL,
+       return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,
                       ip_rcv_finish);
 
 inhdr_error:
index 4c09a31fd140c115a6f9cb4469d3f62aa10e56ae..ba9836c488ed915388e4c9d38b842bef8b241dda 100644 (file)
@@ -238,7 +238,6 @@ void ip_options_fragment(struct sk_buff * skb)
        opt->rr_needaddr = 0;
        opt->ts_needaddr = 0;
        opt->ts_needtime = 0;
-       return;
 }
 
 /*
@@ -601,6 +600,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
        unsigned char *optptr = skb_network_header(skb) + opt->srr;
        struct rtable *rt = skb_rtable(skb);
        struct rtable *rt2;
+       unsigned long orefdst;
        int err;
 
        if (!opt->srr)
@@ -624,16 +624,16 @@ int ip_options_rcv_srr(struct sk_buff *skb)
                }
                memcpy(&nexthop, &optptr[srrptr-1], 4);
 
-               rt = skb_rtable(skb);
+               orefdst = skb->_skb_refdst;
                skb_dst_set(skb, NULL);
                err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
                rt2 = skb_rtable(skb);
                if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
-                       ip_rt_put(rt2);
-                       skb_dst_set(skb, &rt->u.dst);
+                       skb_dst_drop(skb);
+                       skb->_skb_refdst = orefdst;
                        return -EINVAL;
                }
-               ip_rt_put(rt);
+               refdst_drop(orefdst);
                if (rt2->rt_type != RTN_LOCAL)
                        break;
                /* Superfast 8) loopback forward */
index d1bcc9f21d4fb57fc53670f046bcedfe3a98bef0..9a4a6c96cb0d634414691da197bf9e337fe18f81 100644 (file)
@@ -96,8 +96,8 @@ int __ip_local_out(struct sk_buff *skb)
 
        iph->tot_len = htons(skb->len);
        ip_send_check(iph);
-       return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
-                      dst_output);
+       return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
+                      skb_dst(skb)->dev, dst_output);
 }
 
 int ip_local_out(struct sk_buff *skb)
@@ -272,8 +272,8 @@ int ip_mc_output(struct sk_buff *skb)
                   ) {
                        struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
                        if (newskb)
-                               NF_HOOK(PF_INET, NF_INET_POST_ROUTING, newskb,
-                                       NULL, newskb->dev,
+                               NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING,
+                                       newskb, NULL, newskb->dev,
                                        ip_dev_loopback_xmit);
                }
 
@@ -288,12 +288,12 @@ int ip_mc_output(struct sk_buff *skb)
        if (rt->rt_flags&RTCF_BROADCAST) {
                struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
                if (newskb)
-                       NF_HOOK(PF_INET, NF_INET_POST_ROUTING, newskb, NULL,
-                               newskb->dev, ip_dev_loopback_xmit);
+                       NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, newskb,
+                               NULL, newskb->dev, ip_dev_loopback_xmit);
        }
 
-       return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
-                           ip_finish_output,
+       return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL,
+                           skb->dev, ip_finish_output,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
 
@@ -306,22 +306,24 @@ int ip_output(struct sk_buff *skb)
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
 
-       return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, NULL, dev,
+       return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,
                            ip_finish_output,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
 
-int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
+int ip_queue_xmit(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
        struct inet_sock *inet = inet_sk(sk);
        struct ip_options *opt = inet->opt;
        struct rtable *rt;
        struct iphdr *iph;
+       int res;
 
        /* Skip all of this if the packet is already routed,
         * f.e. by something like SCTP.
         */
+       rcu_read_lock();
        rt = skb_rtable(skb);
        if (rt != NULL)
                goto packet_routed;
@@ -359,7 +361,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
                }
                sk_setup_caps(sk, &rt->u.dst);
        }
-       skb_dst_set(skb, dst_clone(&rt->u.dst));
+       skb_dst_set_noref(skb, &rt->u.dst);
 
 packet_routed:
        if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
@@ -370,7 +372,7 @@ packet_routed:
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
        *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
-       if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
+       if (ip_dont_fragment(sk, &rt->u.dst) && !skb->local_df)
                iph->frag_off = htons(IP_DF);
        else
                iph->frag_off = 0;
@@ -391,9 +393,12 @@ packet_routed:
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
 
-       return ip_local_out(skb);
+       res = ip_local_out(skb);
+       rcu_read_unlock();
+       return res;
 
 no_route:
+       rcu_read_unlock();
        IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
        kfree_skb(skb);
        return -EHOSTUNREACH;
@@ -469,6 +474,10 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
        hlen = iph->ihl * 4;
        mtu = dst_mtu(&rt->u.dst) - hlen;       /* Size of data space */
+#ifdef CONFIG_BRIDGE_NETFILTER
+       if (skb->nf_bridge)
+               mtu -= nf_bridge_mtu_reduction(skb);
+#endif
        IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE;
 
        /* When frag_list is given, use it. First, check its validity:
index 1e64dabbd232ea41bdbf6825b9358dc18b741931..ce231780a2b14ef4e15a33baad4b0c887e96df16 100644 (file)
@@ -287,12 +287,8 @@ int ip_ra_control(struct sock *sk, unsigned char on,
 void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
                   __be16 port, u32 info, u8 *payload)
 {
-       struct inet_sock *inet = inet_sk(sk);
        struct sock_exterr_skb *serr;
 
-       if (!inet->recverr)
-               return;
-
        skb = skb_clone(skb, GFP_ATOMIC);
        if (!skb)
                return;
@@ -958,6 +954,22 @@ e_inval:
        return -EINVAL;
 }
 
+/**
+ * ip_queue_rcv_skb - Queue an skb into sock receive queue
+ * @sk: socket
+ * @skb: buffer
+ *
+ * Queues an skb into socket receive queue. If IP_CMSG_PKTINFO option
+ * is not set, we drop skb dst entry now, while dst cache line is hot.
+ */
+int ip_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       if (!(inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO))
+               skb_dst_drop(skb);
+       return sock_queue_rcv_skb(sk, skb);
+}
+EXPORT_SYMBOL(ip_queue_rcv_skb);
+
 int ip_setsockopt(struct sock *sk, int level,
                int optname, char __user *optval, unsigned int optlen)
 {
index 067ce9e043dc2e6d5013681815e6da46ef8cc060..b9d84e800cf4385b9d0bf51fe8aae78989d295b4 100644 (file)
@@ -976,7 +976,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
        /* Is it a reply for the device we are configuring? */
        if (b->xid != ic_dev_xid) {
                if (net_ratelimit())
-                       printk(KERN_ERR "DHCP/BOOTP: Ignoring delayed packet \n");
+                       printk(KERN_ERR "DHCP/BOOTP: Ignoring delayed packet\n");
                goto drop_unlock;
        }
 
index 0b27b14dcc9d65e6545327ef98a3ece61419214f..7fd636711037ae9be434f4b091e040a70843ef69 100644 (file)
@@ -374,11 +374,8 @@ static int ipip_rcv(struct sk_buff *skb)
                skb->protocol = htons(ETH_P_IP);
                skb->pkt_type = PACKET_HOST;
 
-               tunnel->dev->stats.rx_packets++;
-               tunnel->dev->stats.rx_bytes += skb->len;
-               skb->dev = tunnel->dev;
-               skb_dst_drop(skb);
-               nf_reset(skb);
+               skb_tunnel_rx(skb, tunnel->dev);
+
                ipip_ecn_decapsulate(iph, skb);
                netif_rx(skb);
                rcu_read_unlock();
index 82aa9c9e4edb7512330c40947899f6c7a1573d73..45889103b3e2a6e2dc76e5731f8ef2a7e9c821e0 100644 (file)
 #include <net/ipip.h>
 #include <net/checksum.h>
 #include <net/netlink.h>
+#include <net/fib_rules.h>
 
 #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
 #define CONFIG_IP_PIMSM        1
 #endif
 
+struct mr_table {
+       struct list_head        list;
+#ifdef CONFIG_NET_NS
+       struct net              *net;
+#endif
+       u32                     id;
+       struct sock             *mroute_sk;
+       struct timer_list       ipmr_expire_timer;
+       struct list_head        mfc_unres_queue;
+       struct list_head        mfc_cache_array[MFC_LINES];
+       struct vif_device       vif_table[MAXVIFS];
+       int                     maxvif;
+       atomic_t                cache_resolve_queue_len;
+       int                     mroute_do_assert;
+       int                     mroute_do_pim;
+#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
+       int                     mroute_reg_vif_num;
+#endif
+};
+
+struct ipmr_rule {
+       struct fib_rule         common;
+};
+
+struct ipmr_result {
+       struct mr_table         *mrt;
+};
+
 /* Big lock, protecting vif table, mrt cache and mroute socket state.
    Note that the changes are semaphored via rtnl_lock.
  */
@@ -78,9 +107,7 @@ static DEFINE_RWLOCK(mrt_lock);
  *     Multicast router control variables
  */
 
-#define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL)
-
-static struct mfc_cache *mfc_unres_queue;              /* Queue of unresolved entries */
+#define VIF_EXISTS(_mrt, _idx) ((_mrt)->vif_table[_idx].dev != NULL)
 
 /* Special spinlock for queue of unresolved entries */
 static DEFINE_SPINLOCK(mfc_unres_lock);
@@ -95,12 +122,215 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
 
 static struct kmem_cache *mrt_cachep __read_mostly;
 
-static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
-static int ipmr_cache_report(struct net *net,
+static struct mr_table *ipmr_new_table(struct net *net, u32 id);
+static int ip_mr_forward(struct net *net, struct mr_table *mrt,
+                        struct sk_buff *skb, struct mfc_cache *cache,
+                        int local);
+static int ipmr_cache_report(struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert);
-static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
+static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                             struct mfc_cache *c, struct rtmsg *rtm);
+static void ipmr_expire_process(unsigned long arg);
+
+#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
+#define ipmr_for_each_table(mrt, net) \
+       list_for_each_entry_rcu(mrt, &net->ipv4.mr_tables, list)
+
+static struct mr_table *ipmr_get_table(struct net *net, u32 id)
+{
+       struct mr_table *mrt;
+
+       ipmr_for_each_table(mrt, net) {
+               if (mrt->id == id)
+                       return mrt;
+       }
+       return NULL;
+}
+
+static int ipmr_fib_lookup(struct net *net, struct flowi *flp,
+                          struct mr_table **mrt)
+{
+       struct ipmr_result res;
+       struct fib_lookup_arg arg = { .result = &res, };
+       int err;
+
+       err = fib_rules_lookup(net->ipv4.mr_rules_ops, flp, 0, &arg);
+       if (err < 0)
+               return err;
+       *mrt = res.mrt;
+       return 0;
+}
+
+static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
+                           int flags, struct fib_lookup_arg *arg)
+{
+       struct ipmr_result *res = arg->result;
+       struct mr_table *mrt;
 
-static struct timer_list ipmr_expire_timer;
+       switch (rule->action) {
+       case FR_ACT_TO_TBL:
+               break;
+       case FR_ACT_UNREACHABLE:
+               return -ENETUNREACH;
+       case FR_ACT_PROHIBIT:
+               return -EACCES;
+       case FR_ACT_BLACKHOLE:
+       default:
+               return -EINVAL;
+       }
+
+       mrt = ipmr_get_table(rule->fr_net, rule->table);
+       if (mrt == NULL)
+               return -EAGAIN;
+       res->mrt = mrt;
+       return 0;
+}
+
+static int ipmr_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
+{
+       return 1;
+}
+
+static const struct nla_policy ipmr_rule_policy[FRA_MAX + 1] = {
+       FRA_GENERIC_POLICY,
+};
+
+static int ipmr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+                              struct fib_rule_hdr *frh, struct nlattr **tb)
+{
+       return 0;
+}
+
+static int ipmr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
+                            struct nlattr **tb)
+{
+       return 1;
+}
+
+static int ipmr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
+                         struct fib_rule_hdr *frh)
+{
+       frh->dst_len = 0;
+       frh->src_len = 0;
+       frh->tos     = 0;
+       return 0;
+}
+
+static const struct fib_rules_ops __net_initdata ipmr_rules_ops_template = {
+       .family         = RTNL_FAMILY_IPMR,
+       .rule_size      = sizeof(struct ipmr_rule),
+       .addr_size      = sizeof(u32),
+       .action         = ipmr_rule_action,
+       .match          = ipmr_rule_match,
+       .configure      = ipmr_rule_configure,
+       .compare        = ipmr_rule_compare,
+       .default_pref   = fib_default_rule_pref,
+       .fill           = ipmr_rule_fill,
+       .nlgroup        = RTNLGRP_IPV4_RULE,
+       .policy         = ipmr_rule_policy,
+       .owner          = THIS_MODULE,
+};
+
+static int __net_init ipmr_rules_init(struct net *net)
+{
+       struct fib_rules_ops *ops;
+       struct mr_table *mrt;
+       int err;
+
+       ops = fib_rules_register(&ipmr_rules_ops_template, net);
+       if (IS_ERR(ops))
+               return PTR_ERR(ops);
+
+       INIT_LIST_HEAD(&net->ipv4.mr_tables);
+
+       mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
+       if (mrt == NULL) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       err = fib_default_rule_add(ops, 0x7fff, RT_TABLE_DEFAULT, 0);
+       if (err < 0)
+               goto err2;
+
+       net->ipv4.mr_rules_ops = ops;
+       return 0;
+
+err2:
+       kfree(mrt);
+err1:
+       fib_rules_unregister(ops);
+       return err;
+}
+
+static void __net_exit ipmr_rules_exit(struct net *net)
+{
+       struct mr_table *mrt, *next;
+
+       list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list)
+               kfree(mrt);
+       fib_rules_unregister(net->ipv4.mr_rules_ops);
+}
+#else
+#define ipmr_for_each_table(mrt, net) \
+       for (mrt = net->ipv4.mrt; mrt; mrt = NULL)
+
+static struct mr_table *ipmr_get_table(struct net *net, u32 id)
+{
+       return net->ipv4.mrt;
+}
+
+static int ipmr_fib_lookup(struct net *net, struct flowi *flp,
+                          struct mr_table **mrt)
+{
+       *mrt = net->ipv4.mrt;
+       return 0;
+}
+
+static int __net_init ipmr_rules_init(struct net *net)
+{
+       net->ipv4.mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
+       return net->ipv4.mrt ? 0 : -ENOMEM;
+}
+
+static void __net_exit ipmr_rules_exit(struct net *net)
+{
+       kfree(net->ipv4.mrt);
+}
+#endif
+
+static struct mr_table *ipmr_new_table(struct net *net, u32 id)
+{
+       struct mr_table *mrt;
+       unsigned int i;
+
+       mrt = ipmr_get_table(net, id);
+       if (mrt != NULL)
+               return mrt;
+
+       mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
+       if (mrt == NULL)
+               return NULL;
+       write_pnet(&mrt->net, net);
+       mrt->id = id;
+
+       /* Forwarding cache */
+       for (i = 0; i < MFC_LINES; i++)
+               INIT_LIST_HEAD(&mrt->mfc_cache_array[i]);
+
+       INIT_LIST_HEAD(&mrt->mfc_unres_queue);
+
+       setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
+                   (unsigned long)mrt);
+
+#ifdef CONFIG_IP_PIMSM
+       mrt->mroute_reg_vif_num = -1;
+#endif
+#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
+       list_add_tail_rcu(&mrt->list, &net->ipv4.mr_tables);
+#endif
+       return mrt;
+}
 
 /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
 
@@ -201,12 +431,22 @@ failure:
 static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct net *net = dev_net(dev);
+       struct mr_table *mrt;
+       struct flowi fl = {
+               .oif            = dev->ifindex,
+               .iif            = skb->skb_iif,
+               .mark           = skb->mark,
+       };
+       int err;
+
+       err = ipmr_fib_lookup(net, &fl, &mrt);
+       if (err < 0)
+               return err;
 
        read_lock(&mrt_lock);
        dev->stats.tx_bytes += skb->len;
        dev->stats.tx_packets++;
-       ipmr_cache_report(net, skb, net->ipv4.mroute_reg_vif_num,
-                         IGMPMSG_WHOLEPKT);
+       ipmr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, IGMPMSG_WHOLEPKT);
        read_unlock(&mrt_lock);
        kfree_skb(skb);
        return NETDEV_TX_OK;
@@ -226,12 +466,18 @@ static void reg_vif_setup(struct net_device *dev)
        dev->features           |= NETIF_F_NETNS_LOCAL;
 }
 
-static struct net_device *ipmr_reg_vif(struct net *net)
+static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
 {
        struct net_device *dev;
        struct in_device *in_dev;
+       char name[IFNAMSIZ];
+
+       if (mrt->id == RT_TABLE_DEFAULT)
+               sprintf(name, "pimreg");
+       else
+               sprintf(name, "pimreg%u", mrt->id);
 
-       dev = alloc_netdev(0, "pimreg", reg_vif_setup);
+       dev = alloc_netdev(0, name, reg_vif_setup);
 
        if (dev == NULL)
                return NULL;
@@ -276,17 +522,17 @@ failure:
  *     @notify: Set to 1, if the caller is a notifier_call
  */
 
-static int vif_delete(struct net *net, int vifi, int notify,
+static int vif_delete(struct mr_table *mrt, int vifi, int notify,
                      struct list_head *head)
 {
        struct vif_device *v;
        struct net_device *dev;
        struct in_device *in_dev;
 
-       if (vifi < 0 || vifi >= net->ipv4.maxvif)
+       if (vifi < 0 || vifi >= mrt->maxvif)
                return -EADDRNOTAVAIL;
 
-       v = &net->ipv4.vif_table[vifi];
+       v = &mrt->vif_table[vifi];
 
        write_lock_bh(&mrt_lock);
        dev = v->dev;
@@ -298,17 +544,17 @@ static int vif_delete(struct net *net, int vifi, int notify,
        }
 
 #ifdef CONFIG_IP_PIMSM
-       if (vifi == net->ipv4.mroute_reg_vif_num)
-               net->ipv4.mroute_reg_vif_num = -1;
+       if (vifi == mrt->mroute_reg_vif_num)
+               mrt->mroute_reg_vif_num = -1;
 #endif
 
-       if (vifi+1 == net->ipv4.maxvif) {
+       if (vifi+1 == mrt->maxvif) {
                int tmp;
                for (tmp=vifi-1; tmp>=0; tmp--) {
-                       if (VIF_EXISTS(net, tmp))
+                       if (VIF_EXISTS(mrt, tmp))
                                break;
                }
-               net->ipv4.maxvif = tmp+1;
+               mrt->maxvif = tmp+1;
        }
 
        write_unlock_bh(&mrt_lock);
@@ -329,7 +575,6 @@ static int vif_delete(struct net *net, int vifi, int notify,
 
 static inline void ipmr_cache_free(struct mfc_cache *c)
 {
-       release_net(mfc_net(c));
        kmem_cache_free(mrt_cachep, c);
 }
 
@@ -337,13 +582,13 @@ static inline void ipmr_cache_free(struct mfc_cache *c)
    and reporting error to netlink readers.
  */
 
-static void ipmr_destroy_unres(struct mfc_cache *c)
+static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
 {
+       struct net *net = read_pnet(&mrt->net);
        struct sk_buff *skb;
        struct nlmsgerr *e;
-       struct net *net = mfc_net(c);
 
-       atomic_dec(&net->ipv4.cache_resolve_queue_len);
+       atomic_dec(&mrt->cache_resolve_queue_len);
 
        while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
                if (ip_hdr(skb)->version == 0) {
@@ -364,42 +609,40 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
 }
 
 
-/* Single timer process for all the unresolved queue. */
+/* Timer process for the unresolved queue. */
 
-static void ipmr_expire_process(unsigned long dummy)
+static void ipmr_expire_process(unsigned long arg)
 {
+       struct mr_table *mrt = (struct mr_table *)arg;
        unsigned long now;
        unsigned long expires;
-       struct mfc_cache *c, **cp;
+       struct mfc_cache *c, *next;
 
        if (!spin_trylock(&mfc_unres_lock)) {
-               mod_timer(&ipmr_expire_timer, jiffies+HZ/10);
+               mod_timer(&mrt->ipmr_expire_timer, jiffies+HZ/10);
                return;
        }
 
-       if (mfc_unres_queue == NULL)
+       if (list_empty(&mrt->mfc_unres_queue))
                goto out;
 
        now = jiffies;
        expires = 10*HZ;
-       cp = &mfc_unres_queue;
 
-       while ((c=*cp) != NULL) {
+       list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
                if (time_after(c->mfc_un.unres.expires, now)) {
                        unsigned long interval = c->mfc_un.unres.expires - now;
                        if (interval < expires)
                                expires = interval;
-                       cp = &c->next;
                        continue;
                }
 
-               *cp = c->next;
-
-               ipmr_destroy_unres(c);
+               list_del(&c->list);
+               ipmr_destroy_unres(mrt, c);
        }
 
-       if (mfc_unres_queue != NULL)
-               mod_timer(&ipmr_expire_timer, jiffies + expires);
+       if (!list_empty(&mrt->mfc_unres_queue))
+               mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
 
 out:
        spin_unlock(&mfc_unres_lock);
@@ -407,17 +650,17 @@ out:
 
 /* Fill oifs list. It is called under write locked mrt_lock. */
 
-static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
+static void ipmr_update_thresholds(struct mr_table *mrt, struct mfc_cache *cache,
+                                  unsigned char *ttls)
 {
        int vifi;
-       struct net *net = mfc_net(cache);
 
        cache->mfc_un.res.minvif = MAXVIFS;
        cache->mfc_un.res.maxvif = 0;
        memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
 
-       for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
-               if (VIF_EXISTS(net, vifi) &&
+       for (vifi = 0; vifi < mrt->maxvif; vifi++) {
+               if (VIF_EXISTS(mrt, vifi) &&
                    ttls[vifi] && ttls[vifi] < 255) {
                        cache->mfc_un.res.ttls[vifi] = ttls[vifi];
                        if (cache->mfc_un.res.minvif > vifi)
@@ -428,16 +671,17 @@ static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
        }
 }
 
-static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
+static int vif_add(struct net *net, struct mr_table *mrt,
+                  struct vifctl *vifc, int mrtsock)
 {
        int vifi = vifc->vifc_vifi;
-       struct vif_device *v = &net->ipv4.vif_table[vifi];
+       struct vif_device *v = &mrt->vif_table[vifi];
        struct net_device *dev;
        struct in_device *in_dev;
        int err;
 
        /* Is vif busy ? */
-       if (VIF_EXISTS(net, vifi))
+       if (VIF_EXISTS(mrt, vifi))
                return -EADDRINUSE;
 
        switch (vifc->vifc_flags) {
@@ -447,9 +691,9 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
                 * Special Purpose VIF in PIM
                 * All the packets will be sent to the daemon
                 */
-               if (net->ipv4.mroute_reg_vif_num >= 0)
+               if (mrt->mroute_reg_vif_num >= 0)
                        return -EADDRINUSE;
-               dev = ipmr_reg_vif(net);
+               dev = ipmr_reg_vif(net, mrt);
                if (!dev)
                        return -ENOBUFS;
                err = dev_set_allmulti(dev, 1);
@@ -525,49 +769,47 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
        v->dev = dev;
 #ifdef CONFIG_IP_PIMSM
        if (v->flags&VIFF_REGISTER)
-               net->ipv4.mroute_reg_vif_num = vifi;
+               mrt->mroute_reg_vif_num = vifi;
 #endif
-       if (vifi+1 > net->ipv4.maxvif)
-               net->ipv4.maxvif = vifi+1;
+       if (vifi+1 > mrt->maxvif)
+               mrt->maxvif = vifi+1;
        write_unlock_bh(&mrt_lock);
        return 0;
 }
 
-static struct mfc_cache *ipmr_cache_find(struct net *net,
+static struct mfc_cache *ipmr_cache_find(struct mr_table *mrt,
                                         __be32 origin,
                                         __be32 mcastgrp)
 {
        int line = MFC_HASH(mcastgrp, origin);
        struct mfc_cache *c;
 
-       for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
-               if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp)
-                       break;
+       list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
+               if (c->mfc_origin == origin && c->mfc_mcastgrp == mcastgrp)
+                       return c;
        }
-       return c;
+       return NULL;
 }
 
 /*
  *     Allocate a multicast cache entry
  */
-static struct mfc_cache *ipmr_cache_alloc(struct net *net)
+static struct mfc_cache *ipmr_cache_alloc(void)
 {
        struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
        if (c == NULL)
                return NULL;
        c->mfc_un.res.minvif = MAXVIFS;
-       mfc_net_set(c, net);
        return c;
 }
 
-static struct mfc_cache *ipmr_cache_alloc_unres(struct net *net)
+static struct mfc_cache *ipmr_cache_alloc_unres(void)
 {
        struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
        if (c == NULL)
                return NULL;
        skb_queue_head_init(&c->mfc_un.unres.unresolved);
        c->mfc_un.unres.expires = jiffies + 10*HZ;
-       mfc_net_set(c, net);
        return c;
 }
 
@@ -575,7 +817,8 @@ static struct mfc_cache *ipmr_cache_alloc_unres(struct net *net)
  *     A cache entry has gone into a resolved state from queued
  */
 
-static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
+static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
+                              struct mfc_cache *uc, struct mfc_cache *c)
 {
        struct sk_buff *skb;
        struct nlmsgerr *e;
@@ -588,7 +831,7 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
                if (ip_hdr(skb)->version == 0) {
                        struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
 
-                       if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
+                       if (__ipmr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
                                nlh->nlmsg_len = (skb_tail_pointer(skb) -
                                                  (u8 *)nlh);
                        } else {
@@ -600,9 +843,9 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
                                memset(&e->msg, 0, sizeof(e->msg));
                        }
 
-                       rtnl_unicast(skb, mfc_net(c), NETLINK_CB(skb).pid);
+                       rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
                } else
-                       ip_mr_forward(skb, c, 0);
+                       ip_mr_forward(net, mrt, skb, c, 0);
        }
 }
 
@@ -613,7 +856,7 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
  *     Called under mrt_lock.
  */
 
-static int ipmr_cache_report(struct net *net,
+static int ipmr_cache_report(struct mr_table *mrt,
                             struct sk_buff *pkt, vifi_t vifi, int assert)
 {
        struct sk_buff *skb;
@@ -646,7 +889,7 @@ static int ipmr_cache_report(struct net *net,
                memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
                msg->im_msgtype = IGMPMSG_WHOLEPKT;
                msg->im_mbz = 0;
-               msg->im_vif = net->ipv4.mroute_reg_vif_num;
+               msg->im_vif = mrt->mroute_reg_vif_num;
                ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
                ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
                                             sizeof(struct iphdr));
@@ -678,7 +921,7 @@ static int ipmr_cache_report(struct net *net,
        skb->transport_header = skb->network_header;
        }
 
-       if (net->ipv4.mroute_sk == NULL) {
+       if (mrt->mroute_sk == NULL) {
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -686,7 +929,7 @@ static int ipmr_cache_report(struct net *net,
        /*
         *      Deliver to mrouted
         */
-       ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
+       ret = sock_queue_rcv_skb(mrt->mroute_sk, skb);
        if (ret < 0) {
                if (net_ratelimit())
                        printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
@@ -701,27 +944,29 @@ static int ipmr_cache_report(struct net *net,
  */
 
 static int
-ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
+ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
 {
+       bool found = false;
        int err;
        struct mfc_cache *c;
        const struct iphdr *iph = ip_hdr(skb);
 
        spin_lock_bh(&mfc_unres_lock);
-       for (c=mfc_unres_queue; c; c=c->next) {
-               if (net_eq(mfc_net(c), net) &&
-                   c->mfc_mcastgrp == iph->daddr &&
-                   c->mfc_origin == iph->saddr)
+       list_for_each_entry(c, &mrt->mfc_unres_queue, list) {
+               if (c->mfc_mcastgrp == iph->daddr &&
+                   c->mfc_origin == iph->saddr) {
+                       found = true;
                        break;
+               }
        }
 
-       if (c == NULL) {
+       if (!found) {
                /*
                 *      Create a new entry if allowable
                 */
 
-               if (atomic_read(&net->ipv4.cache_resolve_queue_len) >= 10 ||
-                   (c = ipmr_cache_alloc_unres(net)) == NULL) {
+               if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
+                   (c = ipmr_cache_alloc_unres()) == NULL) {
                        spin_unlock_bh(&mfc_unres_lock);
 
                        kfree_skb(skb);
@@ -738,7 +983,7 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
                /*
                 *      Reflect first query at mrouted.
                 */
-               err = ipmr_cache_report(net, skb, vifi, IGMPMSG_NOCACHE);
+               err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE);
                if (err < 0) {
                        /* If the report failed throw the cache entry
                           out - Brad Parker
@@ -750,12 +995,11 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
                        return err;
                }
 
-               atomic_inc(&net->ipv4.cache_resolve_queue_len);
-               c->next = mfc_unres_queue;
-               mfc_unres_queue = c;
+               atomic_inc(&mrt->cache_resolve_queue_len);
+               list_add(&c->list, &mrt->mfc_unres_queue);
 
-               if (atomic_read(&net->ipv4.cache_resolve_queue_len) == 1)
-                       mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
+               if (atomic_read(&mrt->cache_resolve_queue_len) == 1)
+                       mod_timer(&mrt->ipmr_expire_timer, c->mfc_un.unres.expires);
        }
 
        /*
@@ -777,19 +1021,18 @@ ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
  *     MFC cache manipulation by user space mroute daemon
  */
 
-static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
+static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc)
 {
        int line;
-       struct mfc_cache *c, **cp;
+       struct mfc_cache *c, *next;
 
        line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
 
-       for (cp = &net->ipv4.mfc_cache_array[line];
-            (c = *cp) != NULL; cp = &c->next) {
+       list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[line], list) {
                if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
                    c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
                        write_lock_bh(&mrt_lock);
-                       *cp = c->next;
+                       list_del(&c->list);
                        write_unlock_bh(&mrt_lock);
 
                        ipmr_cache_free(c);
@@ -799,27 +1042,30 @@ static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
        return -ENOENT;
 }
 
-static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
+static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
+                       struct mfcctl *mfc, int mrtsock)
 {
+       bool found = false;
        int line;
-       struct mfc_cache *uc, *c, **cp;
+       struct mfc_cache *uc, *c;
 
        if (mfc->mfcc_parent >= MAXVIFS)
                return -ENFILE;
 
        line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
 
-       for (cp = &net->ipv4.mfc_cache_array[line];
-            (c = *cp) != NULL; cp = &c->next) {
+       list_for_each_entry(c, &mrt->mfc_cache_array[line], list) {
                if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
-                   c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
+                   c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
+                       found = true;
                        break;
+               }
        }
 
-       if (c != NULL) {
+       if (found) {
                write_lock_bh(&mrt_lock);
                c->mfc_parent = mfc->mfcc_parent;
-               ipmr_update_thresholds(c, mfc->mfcc_ttls);
+               ipmr_update_thresholds(mrt, c, mfc->mfcc_ttls);
                if (!mrtsock)
                        c->mfc_flags |= MFC_STATIC;
                write_unlock_bh(&mrt_lock);
@@ -829,43 +1075,42 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
        if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
                return -EINVAL;
 
-       c = ipmr_cache_alloc(net);
+       c = ipmr_cache_alloc();
        if (c == NULL)
                return -ENOMEM;
 
        c->mfc_origin = mfc->mfcc_origin.s_addr;
        c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
        c->mfc_parent = mfc->mfcc_parent;
-       ipmr_update_thresholds(c, mfc->mfcc_ttls);
+       ipmr_update_thresholds(mrt, c, mfc->mfcc_ttls);
        if (!mrtsock)
                c->mfc_flags |= MFC_STATIC;
 
        write_lock_bh(&mrt_lock);
-       c->next = net->ipv4.mfc_cache_array[line];
-       net->ipv4.mfc_cache_array[line] = c;
+       list_add(&c->list, &mrt->mfc_cache_array[line]);
        write_unlock_bh(&mrt_lock);
 
        /*
         *      Check to see if we resolved a queued list. If so we
         *      need to send on the frames and tidy up.
         */
+       found = false;
        spin_lock_bh(&mfc_unres_lock);
-       for (cp = &mfc_unres_queue; (uc=*cp) != NULL;
-            cp = &uc->next) {
-               if (net_eq(mfc_net(uc), net) &&
-                   uc->mfc_origin == c->mfc_origin &&
+       list_for_each_entry(uc, &mrt->mfc_unres_queue, list) {
+               if (uc->mfc_origin == c->mfc_origin &&
                    uc->mfc_mcastgrp == c->mfc_mcastgrp) {
-                       *cp = uc->next;
-                       atomic_dec(&net->ipv4.cache_resolve_queue_len);
+                       list_del(&uc->list);
+                       atomic_dec(&mrt->cache_resolve_queue_len);
+                       found = true;
                        break;
                }
        }
-       if (mfc_unres_queue == NULL)
-               del_timer(&ipmr_expire_timer);
+       if (list_empty(&mrt->mfc_unres_queue))
+               del_timer(&mrt->ipmr_expire_timer);
        spin_unlock_bh(&mfc_unres_lock);
 
-       if (uc) {
-               ipmr_cache_resolve(uc, c);
+       if (found) {
+               ipmr_cache_resolve(net, mrt, uc, c);
                ipmr_cache_free(uc);
        }
        return 0;
@@ -875,53 +1120,41 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
  *     Close the multicast socket, and clear the vif tables etc
  */
 
-static void mroute_clean_tables(struct net *net)
+static void mroute_clean_tables(struct mr_table *mrt)
 {
        int i;
        LIST_HEAD(list);
+       struct mfc_cache *c, *next;
 
        /*
         *      Shut down all active vif entries
         */
-       for (i = 0; i < net->ipv4.maxvif; i++) {
-               if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
-                       vif_delete(net, i, 0, &list);
+       for (i = 0; i < mrt->maxvif; i++) {
+               if (!(mrt->vif_table[i].flags&VIFF_STATIC))
+                       vif_delete(mrt, i, 0, &list);
        }
        unregister_netdevice_many(&list);
 
        /*
         *      Wipe the cache
         */
-       for (i=0; i<MFC_LINES; i++) {
-               struct mfc_cache *c, **cp;
-
-               cp = &net->ipv4.mfc_cache_array[i];
-               while ((c = *cp) != NULL) {
-                       if (c->mfc_flags&MFC_STATIC) {
-                               cp = &c->next;
+       for (i = 0; i < MFC_LINES; i++) {
+               list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
+                       if (c->mfc_flags&MFC_STATIC)
                                continue;
-                       }
                        write_lock_bh(&mrt_lock);
-                       *cp = c->next;
+                       list_del(&c->list);
                        write_unlock_bh(&mrt_lock);
 
                        ipmr_cache_free(c);
                }
        }
 
-       if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
-               struct mfc_cache *c, **cp;
-
+       if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
                spin_lock_bh(&mfc_unres_lock);
-               cp = &mfc_unres_queue;
-               while ((c = *cp) != NULL) {
-                       if (!net_eq(mfc_net(c), net)) {
-                               cp = &c->next;
-                               continue;
-                       }
-                       *cp = c->next;
-
-                       ipmr_destroy_unres(c);
+               list_for_each_entry_safe(c, next, &mrt->mfc_unres_queue, list) {
+                       list_del(&c->list);
+                       ipmr_destroy_unres(mrt, c);
                }
                spin_unlock_bh(&mfc_unres_lock);
        }
@@ -930,16 +1163,19 @@ static void mroute_clean_tables(struct net *net)
 static void mrtsock_destruct(struct sock *sk)
 {
        struct net *net = sock_net(sk);
+       struct mr_table *mrt;
 
        rtnl_lock();
-       if (sk == net->ipv4.mroute_sk) {
-               IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
+       ipmr_for_each_table(mrt, net) {
+               if (sk == mrt->mroute_sk) {
+                       IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
 
-               write_lock_bh(&mrt_lock);
-               net->ipv4.mroute_sk = NULL;
-               write_unlock_bh(&mrt_lock);
+                       write_lock_bh(&mrt_lock);
+                       mrt->mroute_sk = NULL;
+                       write_unlock_bh(&mrt_lock);
 
-               mroute_clean_tables(net);
+                       mroute_clean_tables(mrt);
+               }
        }
        rtnl_unlock();
 }
@@ -957,9 +1193,14 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
        struct vifctl vif;
        struct mfcctl mfc;
        struct net *net = sock_net(sk);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
 
        if (optname != MRT_INIT) {
-               if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
+               if (sk != mrt->mroute_sk && !capable(CAP_NET_ADMIN))
                        return -EACCES;
        }
 
@@ -972,7 +1213,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                        return -ENOPROTOOPT;
 
                rtnl_lock();
-               if (net->ipv4.mroute_sk) {
+               if (mrt->mroute_sk) {
                        rtnl_unlock();
                        return -EADDRINUSE;
                }
@@ -980,7 +1221,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                ret = ip_ra_control(sk, 1, mrtsock_destruct);
                if (ret == 0) {
                        write_lock_bh(&mrt_lock);
-                       net->ipv4.mroute_sk = sk;
+                       mrt->mroute_sk = sk;
                        write_unlock_bh(&mrt_lock);
 
                        IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
@@ -988,7 +1229,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                rtnl_unlock();
                return ret;
        case MRT_DONE:
-               if (sk != net->ipv4.mroute_sk)
+               if (sk != mrt->mroute_sk)
                        return -EACCES;
                return ip_ra_control(sk, 0, NULL);
        case MRT_ADD_VIF:
@@ -1001,9 +1242,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                        return -ENFILE;
                rtnl_lock();
                if (optname == MRT_ADD_VIF) {
-                       ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
+                       ret = vif_add(net, mrt, &vif, sk == mrt->mroute_sk);
                } else {
-                       ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
+                       ret = vif_delete(mrt, vif.vifc_vifi, 0, NULL);
                }
                rtnl_unlock();
                return ret;
@@ -1020,9 +1261,9 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                        return -EFAULT;
                rtnl_lock();
                if (optname == MRT_DEL_MFC)
-                       ret = ipmr_mfc_delete(net, &mfc);
+                       ret = ipmr_mfc_delete(mrt, &mfc);
                else
-                       ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
+                       ret = ipmr_mfc_add(net, mrt, &mfc, sk == mrt->mroute_sk);
                rtnl_unlock();
                return ret;
                /*
@@ -1033,7 +1274,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
                int v;
                if (get_user(v,(int __user *)optval))
                        return -EFAULT;
-               net->ipv4.mroute_do_assert = (v) ? 1 : 0;
+               mrt->mroute_do_assert = (v) ? 1 : 0;
                return 0;
        }
 #ifdef CONFIG_IP_PIMSM
@@ -1047,13 +1288,34 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
 
                rtnl_lock();
                ret = 0;
-               if (v != net->ipv4.mroute_do_pim) {
-                       net->ipv4.mroute_do_pim = v;
-                       net->ipv4.mroute_do_assert = v;
+               if (v != mrt->mroute_do_pim) {
+                       mrt->mroute_do_pim = v;
+                       mrt->mroute_do_assert = v;
                }
                rtnl_unlock();
                return ret;
        }
+#endif
+#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
+       case MRT_TABLE:
+       {
+               u32 v;
+
+               if (optlen != sizeof(u32))
+                       return -EINVAL;
+               if (get_user(v, (u32 __user *)optval))
+                       return -EFAULT;
+               if (sk == mrt->mroute_sk)
+                       return -EBUSY;
+
+               rtnl_lock();
+               ret = 0;
+               if (!ipmr_new_table(net, v))
+                       ret = -ENOMEM;
+               raw_sk(sk)->ipmr_table = v;
+               rtnl_unlock();
+               return ret;
+       }
 #endif
        /*
         *      Spurious command, or MRT_VERSION which you cannot
@@ -1073,6 +1335,11 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
        int olr;
        int val;
        struct net *net = sock_net(sk);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
 
        if (optname != MRT_VERSION &&
 #ifdef CONFIG_IP_PIMSM
@@ -1094,10 +1361,10 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
                val = 0x0305;
 #ifdef CONFIG_IP_PIMSM
        else if (optname == MRT_PIM)
-               val = net->ipv4.mroute_do_pim;
+               val = mrt->mroute_do_pim;
 #endif
        else
-               val = net->ipv4.mroute_do_assert;
+               val = mrt->mroute_do_assert;
        if (copy_to_user(optval, &val, olr))
                return -EFAULT;
        return 0;
@@ -1114,16 +1381,21 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
        struct vif_device *vif;
        struct mfc_cache *c;
        struct net *net = sock_net(sk);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
 
        switch (cmd) {
        case SIOCGETVIFCNT:
                if (copy_from_user(&vr, arg, sizeof(vr)))
                        return -EFAULT;
-               if (vr.vifi >= net->ipv4.maxvif)
+               if (vr.vifi >= mrt->maxvif)
                        return -EINVAL;
                read_lock(&mrt_lock);
-               vif = &net->ipv4.vif_table[vr.vifi];
-               if (VIF_EXISTS(net, vr.vifi)) {
+               vif = &mrt->vif_table[vr.vifi];
+               if (VIF_EXISTS(mrt, vr.vifi)) {
                        vr.icount = vif->pkt_in;
                        vr.ocount = vif->pkt_out;
                        vr.ibytes = vif->bytes_in;
@@ -1141,7 +1413,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
                        return -EFAULT;
 
                read_lock(&mrt_lock);
-               c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
+               c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
                if (c) {
                        sr.pktcnt = c->mfc_un.res.pkt;
                        sr.bytecnt = c->mfc_un.res.bytes;
@@ -1164,16 +1436,20 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
 {
        struct net_device *dev = ptr;
        struct net *net = dev_net(dev);
+       struct mr_table *mrt;
        struct vif_device *v;
        int ct;
        LIST_HEAD(list);
 
        if (event != NETDEV_UNREGISTER)
                return NOTIFY_DONE;
-       v = &net->ipv4.vif_table[0];
-       for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
-               if (v->dev == dev)
-                       vif_delete(net, ct, 1, &list);
+
+       ipmr_for_each_table(mrt, net) {
+               v = &mrt->vif_table[0];
+               for (ct = 0; ct < mrt->maxvif; ct++, v++) {
+                       if (v->dev == dev)
+                               vif_delete(mrt, ct, 1, &list);
+               }
        }
        unregister_netdevice_many(&list);
        return NOTIFY_DONE;
@@ -1232,11 +1508,11 @@ static inline int ipmr_forward_finish(struct sk_buff *skb)
  *     Processing handlers for ipmr_forward
  */
 
-static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
+static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
+                           struct sk_buff *skb, struct mfc_cache *c, int vifi)
 {
-       struct net *net = mfc_net(c);
        const struct iphdr *iph = ip_hdr(skb);
-       struct vif_device *vif = &net->ipv4.vif_table[vifi];
+       struct vif_device *vif = &mrt->vif_table[vifi];
        struct net_device *dev;
        struct rtable *rt;
        int    encap = 0;
@@ -1250,7 +1526,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
                vif->bytes_out += skb->len;
                vif->dev->stats.tx_bytes += skb->len;
                vif->dev->stats.tx_packets++;
-               ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
+               ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
                goto out_free;
        }
 #endif
@@ -1324,21 +1600,20 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
         * not mrouter) cannot join to more than one interface - it will
         * result in receiving multiple packets.
         */
-       NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
+       NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev, dev,
                ipmr_forward_finish);
        return;
 
 out_free:
        kfree_skb(skb);
-       return;
 }
 
-static int ipmr_find_vif(struct net_device *dev)
+static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev)
 {
-       struct net *net = dev_net(dev);
        int ct;
-       for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
-               if (net->ipv4.vif_table[ct].dev == dev)
+
+       for (ct = mrt->maxvif-1; ct >= 0; ct--) {
+               if (mrt->vif_table[ct].dev == dev)
                        break;
        }
        return ct;
@@ -1346,11 +1621,12 @@ static int ipmr_find_vif(struct net_device *dev)
 
 /* "local" means that we should preserve one skb (for local delivery) */
 
-static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
+static int ip_mr_forward(struct net *net, struct mr_table *mrt,
+                        struct sk_buff *skb, struct mfc_cache *cache,
+                        int local)
 {
        int psend = -1;
        int vif, ct;
-       struct net *net = mfc_net(cache);
 
        vif = cache->mfc_parent;
        cache->mfc_un.res.pkt++;
@@ -1359,7 +1635,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
        /*
         * Wrong interface: drop packet and (maybe) send PIM assert.
         */
-       if (net->ipv4.vif_table[vif].dev != skb->dev) {
+       if (mrt->vif_table[vif].dev != skb->dev) {
                int true_vifi;
 
                if (skb_rtable(skb)->fl.iif == 0) {
@@ -1378,26 +1654,26 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
                }
 
                cache->mfc_un.res.wrong_if++;
-               true_vifi = ipmr_find_vif(skb->dev);
+               true_vifi = ipmr_find_vif(mrt, skb->dev);
 
-               if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
+               if (true_vifi >= 0 && mrt->mroute_do_assert &&
                    /* pimsm uses asserts, when switching from RPT to SPT,
                       so that we cannot check that packet arrived on an oif.
                       It is bad, but otherwise we would need to move pretty
                       large chunk of pimd to kernel. Ough... --ANK
                     */
-                   (net->ipv4.mroute_do_pim ||
+                   (mrt->mroute_do_pim ||
                     cache->mfc_un.res.ttls[true_vifi] < 255) &&
                    time_after(jiffies,
                               cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
                        cache->mfc_un.res.last_assert = jiffies;
-                       ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
+                       ipmr_cache_report(mrt, skb, true_vifi, IGMPMSG_WRONGVIF);
                }
                goto dont_forward;
        }
 
-       net->ipv4.vif_table[vif].pkt_in++;
-       net->ipv4.vif_table[vif].bytes_in += skb->len;
+       mrt->vif_table[vif].pkt_in++;
+       mrt->vif_table[vif].bytes_in += skb->len;
 
        /*
         *      Forward the frame
@@ -1407,7 +1683,8 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
                        if (psend != -1) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                                if (skb2)
-                                       ipmr_queue_xmit(skb2, cache, psend);
+                                       ipmr_queue_xmit(net, mrt, skb2, cache,
+                                                       psend);
                        }
                        psend = ct;
                }
@@ -1416,9 +1693,9 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
                if (local) {
                        struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                        if (skb2)
-                               ipmr_queue_xmit(skb2, cache, psend);
+                               ipmr_queue_xmit(net, mrt, skb2, cache, psend);
                } else {
-                       ipmr_queue_xmit(skb, cache, psend);
+                       ipmr_queue_xmit(net, mrt, skb, cache, psend);
                        return 0;
                }
        }
@@ -1439,6 +1716,8 @@ int ip_mr_input(struct sk_buff *skb)
        struct mfc_cache *cache;
        struct net *net = dev_net(skb->dev);
        int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
+       struct mr_table *mrt;
+       int err;
 
        /* Packet is looped back after forward, it should not be
           forwarded second time, but still can be delivered locally.
@@ -1446,6 +1725,10 @@ int ip_mr_input(struct sk_buff *skb)
        if (IPCB(skb)->flags&IPSKB_FORWARDED)
                goto dont_forward;
 
+       err = ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt);
+       if (err < 0)
+               return err;
+
        if (!local) {
                    if (IPCB(skb)->opt.router_alert) {
                            if (ip_call_ra_chain(skb))
@@ -1458,9 +1741,9 @@ int ip_mr_input(struct sk_buff *skb)
                               that we can forward NO IGMP messages.
                             */
                            read_lock(&mrt_lock);
-                           if (net->ipv4.mroute_sk) {
+                           if (mrt->mroute_sk) {
                                    nf_reset(skb);
-                                   raw_rcv(net->ipv4.mroute_sk, skb);
+                                   raw_rcv(mrt->mroute_sk, skb);
                                    read_unlock(&mrt_lock);
                                    return 0;
                            }
@@ -1469,7 +1752,7 @@ int ip_mr_input(struct sk_buff *skb)
        }
 
        read_lock(&mrt_lock);
-       cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
+       cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
 
        /*
         *      No usable cache entry
@@ -1487,19 +1770,19 @@ int ip_mr_input(struct sk_buff *skb)
                        skb = skb2;
                }
 
-               vif = ipmr_find_vif(skb->dev);
+               vif = ipmr_find_vif(mrt, skb->dev);
                if (vif >= 0) {
-                       int err = ipmr_cache_unresolved(net, vif, skb);
+                       int err2 = ipmr_cache_unresolved(mrt, vif, skb);
                        read_unlock(&mrt_lock);
 
-                       return err;
+                       return err2;
                }
                read_unlock(&mrt_lock);
                kfree_skb(skb);
                return -ENODEV;
        }
 
-       ip_mr_forward(skb, cache, local);
+       ip_mr_forward(net, mrt, skb, cache, local);
 
        read_unlock(&mrt_lock);
 
@@ -1516,11 +1799,11 @@ dont_forward:
 }
 
 #ifdef CONFIG_IP_PIMSM
-static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
+static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
+                    unsigned int pimlen)
 {
        struct net_device *reg_dev = NULL;
        struct iphdr *encap;
-       struct net *net = dev_net(skb->dev);
 
        encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
        /*
@@ -1535,8 +1818,8 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
                return 1;
 
        read_lock(&mrt_lock);
-       if (net->ipv4.mroute_reg_vif_num >= 0)
-               reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
+       if (mrt->mroute_reg_vif_num >= 0)
+               reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
        if (reg_dev)
                dev_hold(reg_dev);
        read_unlock(&mrt_lock);
@@ -1547,14 +1830,12 @@ static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
        skb->mac_header = skb->network_header;
        skb_pull(skb, (u8*)encap - skb->data);
        skb_reset_network_header(skb);
-       skb->dev = reg_dev;
        skb->protocol = htons(ETH_P_IP);
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
-       skb_dst_drop(skb);
-       reg_dev->stats.rx_bytes += skb->len;
-       reg_dev->stats.rx_packets++;
-       nf_reset(skb);
+
+       skb_tunnel_rx(skb, reg_dev);
+
        netif_rx(skb);
        dev_put(reg_dev);
 
@@ -1571,17 +1852,21 @@ int pim_rcv_v1(struct sk_buff * skb)
 {
        struct igmphdr *pim;
        struct net *net = dev_net(skb->dev);
+       struct mr_table *mrt;
 
        if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
                goto drop;
 
        pim = igmp_hdr(skb);
 
-       if (!net->ipv4.mroute_do_pim ||
+       if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0)
+               goto drop;
+
+       if (!mrt->mroute_do_pim ||
            pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
                goto drop;
 
-       if (__pim_rcv(skb, sizeof(*pim))) {
+       if (__pim_rcv(mrt, skb, sizeof(*pim))) {
 drop:
                kfree_skb(skb);
        }
@@ -1593,6 +1878,8 @@ drop:
 static int pim_rcv(struct sk_buff * skb)
 {
        struct pimreghdr *pim;
+       struct net *net = dev_net(skb->dev);
+       struct mr_table *mrt;
 
        if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
                goto drop;
@@ -1604,7 +1891,10 @@ static int pim_rcv(struct sk_buff * skb)
             csum_fold(skb_checksum(skb, 0, skb->len, 0))))
                goto drop;
 
-       if (__pim_rcv(skb, sizeof(*pim))) {
+       if (ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt) < 0)
+               goto drop;
+
+       if (__pim_rcv(mrt, skb, sizeof(*pim))) {
 drop:
                kfree_skb(skb);
        }
@@ -1612,12 +1902,11 @@ drop:
 }
 #endif
 
-static int
-ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
+static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                             struct mfc_cache *c, struct rtmsg *rtm)
 {
        int ct;
        struct rtnexthop *nhp;
-       struct net *net = mfc_net(c);
        u8 *b = skb_tail_pointer(skb);
        struct rtattr *mp_head;
 
@@ -1625,19 +1914,19 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
        if (c->mfc_parent > MAXVIFS)
                return -ENOENT;
 
-       if (VIF_EXISTS(net, c->mfc_parent))
-               RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex);
+       if (VIF_EXISTS(mrt, c->mfc_parent))
+               RTA_PUT(skb, RTA_IIF, 4, &mrt->vif_table[c->mfc_parent].dev->ifindex);
 
        mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
 
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
-               if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
+               if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
                        if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
                                goto rtattr_failure;
                        nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
                        nhp->rtnh_flags = 0;
                        nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
-                       nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
+                       nhp->rtnh_ifindex = mrt->vif_table[ct].dev->ifindex;
                        nhp->rtnh_len = sizeof(*nhp);
                }
        }
@@ -1655,11 +1944,16 @@ int ipmr_get_route(struct net *net,
                   struct sk_buff *skb, struct rtmsg *rtm, int nowait)
 {
        int err;
+       struct mr_table *mrt;
        struct mfc_cache *cache;
        struct rtable *rt = skb_rtable(skb);
 
+       mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return -ENOENT;
+
        read_lock(&mrt_lock);
-       cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
+       cache = ipmr_cache_find(mrt, rt->rt_src, rt->rt_dst);
 
        if (cache == NULL) {
                struct sk_buff *skb2;
@@ -1673,7 +1967,7 @@ int ipmr_get_route(struct net *net,
                }
 
                dev = skb->dev;
-               if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
+               if (dev == NULL || (vif = ipmr_find_vif(mrt, dev)) < 0) {
                        read_unlock(&mrt_lock);
                        return -ENODEV;
                }
@@ -1690,24 +1984,107 @@ int ipmr_get_route(struct net *net,
                iph->saddr = rt->rt_src;
                iph->daddr = rt->rt_dst;
                iph->version = 0;
-               err = ipmr_cache_unresolved(net, vif, skb2);
+               err = ipmr_cache_unresolved(mrt, vif, skb2);
                read_unlock(&mrt_lock);
                return err;
        }
 
        if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
                cache->mfc_flags |= MFC_NOTIFY;
-       err = ipmr_fill_mroute(skb, cache, rtm);
+       err = __ipmr_fill_mroute(mrt, skb, cache, rtm);
        read_unlock(&mrt_lock);
        return err;
 }
 
+static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
+                           u32 pid, u32 seq, struct mfc_cache *c)
+{
+       struct nlmsghdr *nlh;
+       struct rtmsg *rtm;
+
+       nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI);
+       if (nlh == NULL)
+               return -EMSGSIZE;
+
+       rtm = nlmsg_data(nlh);
+       rtm->rtm_family   = RTNL_FAMILY_IPMR;
+       rtm->rtm_dst_len  = 32;
+       rtm->rtm_src_len  = 32;
+       rtm->rtm_tos      = 0;
+       rtm->rtm_table    = mrt->id;
+       NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
+       rtm->rtm_type     = RTN_MULTICAST;
+       rtm->rtm_scope    = RT_SCOPE_UNIVERSE;
+       rtm->rtm_protocol = RTPROT_UNSPEC;
+       rtm->rtm_flags    = 0;
+
+       NLA_PUT_BE32(skb, RTA_SRC, c->mfc_origin);
+       NLA_PUT_BE32(skb, RTA_DST, c->mfc_mcastgrp);
+
+       if (__ipmr_fill_mroute(mrt, skb, c, rtm) < 0)
+               goto nla_put_failure;
+
+       return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+       nlmsg_cancel(skb, nlh);
+       return -EMSGSIZE;
+}
+
+static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct net *net = sock_net(skb->sk);
+       struct mr_table *mrt;
+       struct mfc_cache *mfc;
+       unsigned int t = 0, s_t;
+       unsigned int h = 0, s_h;
+       unsigned int e = 0, s_e;
+
+       s_t = cb->args[0];
+       s_h = cb->args[1];
+       s_e = cb->args[2];
+
+       read_lock(&mrt_lock);
+       ipmr_for_each_table(mrt, net) {
+               if (t < s_t)
+                       goto next_table;
+               if (t > s_t)
+                       s_h = 0;
+               for (h = s_h; h < MFC_LINES; h++) {
+                       list_for_each_entry(mfc, &mrt->mfc_cache_array[h], list) {
+                               if (e < s_e)
+                                       goto next_entry;
+                               if (ipmr_fill_mroute(mrt, skb,
+                                                    NETLINK_CB(cb->skb).pid,
+                                                    cb->nlh->nlmsg_seq,
+                                                    mfc) < 0)
+                                       goto done;
+next_entry:
+                               e++;
+                       }
+                       e = s_e = 0;
+               }
+               s_h = 0;
+next_table:
+               t++;
+       }
+done:
+       read_unlock(&mrt_lock);
+
+       cb->args[2] = e;
+       cb->args[1] = h;
+       cb->args[0] = t;
+
+       return skb->len;
+}
+
 #ifdef CONFIG_PROC_FS
 /*
  *     The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
  */
 struct ipmr_vif_iter {
        struct seq_net_private p;
+       struct mr_table *mrt;
        int ct;
 };
 
@@ -1715,11 +2092,13 @@ static struct vif_device *ipmr_vif_seq_idx(struct net *net,
                                           struct ipmr_vif_iter *iter,
                                           loff_t pos)
 {
-       for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
-               if (!VIF_EXISTS(net, iter->ct))
+       struct mr_table *mrt = iter->mrt;
+
+       for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
+               if (!VIF_EXISTS(mrt, iter->ct))
                        continue;
                if (pos-- == 0)
-                       return &net->ipv4.vif_table[iter->ct];
+                       return &mrt->vif_table[iter->ct];
        }
        return NULL;
 }
@@ -1727,7 +2106,15 @@ static struct vif_device *ipmr_vif_seq_idx(struct net *net,
 static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(mrt_lock)
 {
+       struct ipmr_vif_iter *iter = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr_table *mrt;
+
+       mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return ERR_PTR(-ENOENT);
+
+       iter->mrt = mrt;
 
        read_lock(&mrt_lock);
        return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
@@ -1738,15 +2125,16 @@ static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct ipmr_vif_iter *iter = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr_table *mrt = iter->mrt;
 
        ++*pos;
        if (v == SEQ_START_TOKEN)
                return ipmr_vif_seq_idx(net, iter, 0);
 
-       while (++iter->ct < net->ipv4.maxvif) {
-               if (!VIF_EXISTS(net, iter->ct))
+       while (++iter->ct < mrt->maxvif) {
+               if (!VIF_EXISTS(mrt, iter->ct))
                        continue;
-               return &net->ipv4.vif_table[iter->ct];
+               return &mrt->vif_table[iter->ct];
        }
        return NULL;
 }
@@ -1759,7 +2147,8 @@ static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
 
 static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
 {
-       struct net *net = seq_file_net(seq);
+       struct ipmr_vif_iter *iter = seq->private;
+       struct mr_table *mrt = iter->mrt;
 
        if (v == SEQ_START_TOKEN) {
                seq_puts(seq,
@@ -1770,7 +2159,7 @@ static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
 
                seq_printf(seq,
                           "%2Zd %-10s %8ld %7ld  %8ld %7ld %05X %08X %08X\n",
-                          vif - net->ipv4.vif_table,
+                          vif - mrt->vif_table,
                           name, vif->bytes_in, vif->pkt_in,
                           vif->bytes_out, vif->pkt_out,
                           vif->flags, vif->local, vif->remote);
@@ -1801,7 +2190,8 @@ static const struct file_operations ipmr_vif_fops = {
 
 struct ipmr_mfc_iter {
        struct seq_net_private p;
-       struct mfc_cache **cache;
+       struct mr_table *mrt;
+       struct list_head *cache;
        int ct;
 };
 
@@ -1809,22 +2199,22 @@ struct ipmr_mfc_iter {
 static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
                                          struct ipmr_mfc_iter *it, loff_t pos)
 {
+       struct mr_table *mrt = it->mrt;
        struct mfc_cache *mfc;
 
-       it->cache = net->ipv4.mfc_cache_array;
        read_lock(&mrt_lock);
-       for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
-               for (mfc = net->ipv4.mfc_cache_array[it->ct];
-                    mfc; mfc = mfc->next)
+       for (it->ct = 0; it->ct < MFC_LINES; it->ct++) {
+               it->cache = &mrt->mfc_cache_array[it->ct];
+               list_for_each_entry(mfc, it->cache, list)
                        if (pos-- == 0)
                                return mfc;
+       }
        read_unlock(&mrt_lock);
 
-       it->cache = &mfc_unres_queue;
        spin_lock_bh(&mfc_unres_lock);
-       for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
-               if (net_eq(mfc_net(mfc), net) &&
-                   pos-- == 0)
+       it->cache = &mrt->mfc_unres_queue;
+       list_for_each_entry(mfc, it->cache, list)
+               if (pos-- == 0)
                        return mfc;
        spin_unlock_bh(&mfc_unres_lock);
 
@@ -1837,7 +2227,13 @@ static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
 {
        struct ipmr_mfc_iter *it = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr_table *mrt;
 
+       mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
+       if (mrt == NULL)
+               return ERR_PTR(-ENOENT);
+
+       it->mrt = mrt;
        it->cache = NULL;
        it->ct = 0;
        return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
@@ -1849,37 +2245,36 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct mfc_cache *mfc = v;
        struct ipmr_mfc_iter *it = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr_table *mrt = it->mrt;
 
        ++*pos;
 
        if (v == SEQ_START_TOKEN)
                return ipmr_mfc_seq_idx(net, seq->private, 0);
 
-       if (mfc->next)
-               return mfc->next;
+       if (mfc->list.next != it->cache)
+               return list_entry(mfc->list.next, struct mfc_cache, list);
 
-       if (it->cache == &mfc_unres_queue)
+       if (it->cache == &mrt->mfc_unres_queue)
                goto end_of_list;
 
-       BUG_ON(it->cache != net->ipv4.mfc_cache_array);
+       BUG_ON(it->cache != &mrt->mfc_cache_array[it->ct]);
 
        while (++it->ct < MFC_LINES) {
-               mfc = net->ipv4.mfc_cache_array[it->ct];
-               if (mfc)
-                       return mfc;
+               it->cache = &mrt->mfc_cache_array[it->ct];
+               if (list_empty(it->cache))
+                       continue;
+               return list_first_entry(it->cache, struct mfc_cache, list);
        }
 
        /* exhausted cache_array, show unresolved */
        read_unlock(&mrt_lock);
-       it->cache = &mfc_unres_queue;
+       it->cache = &mrt->mfc_unres_queue;
        it->ct = 0;
 
        spin_lock_bh(&mfc_unres_lock);
-       mfc = mfc_unres_queue;
-       while (mfc && !net_eq(mfc_net(mfc), net))
-               mfc = mfc->next;
-       if (mfc)
-               return mfc;
+       if (!list_empty(it->cache))
+               return list_first_entry(it->cache, struct mfc_cache, list);
 
  end_of_list:
        spin_unlock_bh(&mfc_unres_lock);
@@ -1891,18 +2286,17 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
 {
        struct ipmr_mfc_iter *it = seq->private;
-       struct net *net = seq_file_net(seq);
+       struct mr_table *mrt = it->mrt;
 
-       if (it->cache == &mfc_unres_queue)
+       if (it->cache == &mrt->mfc_unres_queue)
                spin_unlock_bh(&mfc_unres_lock);
-       else if (it->cache == net->ipv4.mfc_cache_array)
+       else if (it->cache == &mrt->mfc_cache_array[it->ct])
                read_unlock(&mrt_lock);
 }
 
 static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
 {
        int n;
-       struct net *net = seq_file_net(seq);
 
        if (v == SEQ_START_TOKEN) {
                seq_puts(seq,
@@ -1910,20 +2304,21 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
        } else {
                const struct mfc_cache *mfc = v;
                const struct ipmr_mfc_iter *it = seq->private;
+               const struct mr_table *mrt = it->mrt;
 
-               seq_printf(seq, "%08lX %08lX %-3hd",
-                          (unsigned long) mfc->mfc_mcastgrp,
-                          (unsigned long) mfc->mfc_origin,
+               seq_printf(seq, "%08X %08X %-3hd",
+                          (__force u32) mfc->mfc_mcastgrp,
+                          (__force u32) mfc->mfc_origin,
                           mfc->mfc_parent);
 
-               if (it->cache != &mfc_unres_queue) {
+               if (it->cache != &mrt->mfc_unres_queue) {
                        seq_printf(seq, " %8lu %8lu %8lu",
                                   mfc->mfc_un.res.pkt,
                                   mfc->mfc_un.res.bytes,
                                   mfc->mfc_un.res.wrong_if);
                        for (n = mfc->mfc_un.res.minvif;
                             n < mfc->mfc_un.res.maxvif; n++ ) {
-                               if (VIF_EXISTS(net, n) &&
+                               if (VIF_EXISTS(mrt, n) &&
                                    mfc->mfc_un.res.ttls[n] < 255)
                                        seq_printf(seq,
                                           " %2d:%-3d",
@@ -1975,27 +2370,11 @@ static const struct net_protocol pim_protocol = {
  */
 static int __net_init ipmr_net_init(struct net *net)
 {
-       int err = 0;
+       int err;
 
-       net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
-                                     GFP_KERNEL);
-       if (!net->ipv4.vif_table) {
-               err = -ENOMEM;
+       err = ipmr_rules_init(net);
+       if (err < 0)
                goto fail;
-       }
-
-       /* Forwarding cache */
-       net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
-                                           sizeof(struct mfc_cache *),
-                                           GFP_KERNEL);
-       if (!net->ipv4.mfc_cache_array) {
-               err = -ENOMEM;
-               goto fail_mfc_cache;
-       }
-
-#ifdef CONFIG_IP_PIMSM
-       net->ipv4.mroute_reg_vif_num = -1;
-#endif
 
 #ifdef CONFIG_PROC_FS
        err = -ENOMEM;
@@ -2010,10 +2389,8 @@ static int __net_init ipmr_net_init(struct net *net)
 proc_cache_fail:
        proc_net_remove(net, "ip_mr_vif");
 proc_vif_fail:
-       kfree(net->ipv4.mfc_cache_array);
+       ipmr_rules_exit(net);
 #endif
-fail_mfc_cache:
-       kfree(net->ipv4.vif_table);
 fail:
        return err;
 }
@@ -2024,8 +2401,7 @@ static void __net_exit ipmr_net_exit(struct net *net)
        proc_net_remove(net, "ip_mr_cache");
        proc_net_remove(net, "ip_mr_vif");
 #endif
-       kfree(net->ipv4.mfc_cache_array);
-       kfree(net->ipv4.vif_table);
+       ipmr_rules_exit(net);
 }
 
 static struct pernet_operations ipmr_net_ops = {
@@ -2048,7 +2424,6 @@ int __init ip_mr_init(void)
        if (err)
                goto reg_pernet_fail;
 
-       setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
        err = register_netdevice_notifier(&ip_mr_notifier);
        if (err)
                goto reg_notif_fail;
@@ -2059,6 +2434,7 @@ int __init ip_mr_init(void)
                goto add_proto_fail;
        }
 #endif
+       rtnl_register(RTNL_FAMILY_IPMR, RTM_GETROUTE, NULL, ipmr_rtm_dumproute);
        return 0;
 
 #ifdef CONFIG_IP_PIMSM_V2
@@ -2066,7 +2442,6 @@ add_proto_fail:
        unregister_netdevice_notifier(&ip_mr_notifier);
 #endif
 reg_notif_fail:
-       del_timer(&ipmr_expire_timer);
        unregister_pernet_subsys(&ipmr_net_ops);
 reg_pernet_fail:
        kmem_cache_destroy(mrt_cachep);
index 82fb43c5c59ef9cf058646516521406437b70b87..07de855e2175ea1f40760c84388388d4676f30b0 100644 (file)
@@ -17,7 +17,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
        const struct iphdr *iph = ip_hdr(skb);
        struct rtable *rt;
        struct flowi fl = {};
-       struct dst_entry *odst;
+       unsigned long orefdst;
        unsigned int hh_len;
        unsigned int type;
 
@@ -51,14 +51,14 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
                if (ip_route_output_key(net, &rt, &fl) != 0)
                        return -1;
 
-               odst = skb_dst(skb);
+               orefdst = skb->_skb_refdst;
                if (ip_route_input(skb, iph->daddr, iph->saddr,
                                   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
                        dst_release(&rt->u.dst);
                        return -1;
                }
                dst_release(&rt->u.dst);
-               dst_release(odst);
+               refdst_drop(orefdst);
        }
 
        if (skb_dst(skb)->error)
index f07d77f6575144e68eb79819a851021db84ab647..1ac01b1286219475cde625bb921887fc3645d7a3 100644 (file)
@@ -49,12 +49,7 @@ MODULE_DESCRIPTION("arptables core");
 #endif
 
 #ifdef CONFIG_NETFILTER_DEBUG
-#define ARP_NF_ASSERT(x)                                       \
-do {                                                           \
-       if (!(x))                                               \
-               printk("ARP_NF_ASSERT: %s:%s:%u\n",             \
-                      __func__, __FILE__, __LINE__);   \
-} while(0)
+#define ARP_NF_ASSERT(x)       WARN_ON(!(x))
 #else
 #define ARP_NF_ASSERT(x)
 #endif
@@ -224,10 +219,10 @@ static inline int arp_checkentry(const struct arpt_arp *arp)
 }
 
 static unsigned int
-arpt_error(struct sk_buff *skb, const struct xt_target_param *par)
+arpt_error(struct sk_buff *skb, const struct xt_action_param *par)
 {
        if (net_ratelimit())
-               printk("arp_tables: error: '%s'\n",
+               pr_err("arp_tables: error: '%s'\n",
                       (const char *)par->targinfo);
 
        return NF_DROP;
@@ -260,12 +255,11 @@ unsigned int arpt_do_table(struct sk_buff *skb,
        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
        unsigned int verdict = NF_DROP;
        const struct arphdr *arp;
-       bool hotdrop = false;
        struct arpt_entry *e, *back;
        const char *indev, *outdev;
        void *table_base;
        const struct xt_table_info *private;
-       struct xt_target_param tgpar;
+       struct xt_action_param acpar;
 
        if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
                return NF_DROP;
@@ -280,10 +274,11 @@ unsigned int arpt_do_table(struct sk_buff *skb,
        e = get_entry(table_base, private->hook_entry[hook]);
        back = get_entry(table_base, private->underflow[hook]);
 
-       tgpar.in      = in;
-       tgpar.out     = out;
-       tgpar.hooknum = hook;
-       tgpar.family  = NFPROTO_ARP;
+       acpar.in      = in;
+       acpar.out     = out;
+       acpar.hooknum = hook;
+       acpar.family  = NFPROTO_ARP;
+       acpar.hotdrop = false;
 
        arp = arp_hdr(skb);
        do {
@@ -333,9 +328,9 @@ unsigned int arpt_do_table(struct sk_buff *skb,
                /* Targets which reenter must return
                 * abs. verdicts
                 */
-               tgpar.target   = t->u.kernel.target;
-               tgpar.targinfo = t->data;
-               verdict = t->u.kernel.target->target(skb, &tgpar);
+               acpar.target   = t->u.kernel.target;
+               acpar.targinfo = t->data;
+               verdict = t->u.kernel.target->target(skb, &acpar);
 
                /* Target might have changed stuff. */
                arp = arp_hdr(skb);
@@ -345,10 +340,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
                else
                        /* Verdict */
                        break;
-       } while (!hotdrop);
+       } while (!acpar.hotdrop);
        xt_info_rdunlock_bh();
 
-       if (hotdrop)
+       if (acpar.hotdrop)
                return NF_DROP;
        else
                return verdict;
@@ -390,7 +385,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo,
                        int visited = e->comefrom & (1 << hook);
 
                        if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
-                               printk("arptables: loop hook %u pos %u %08X.\n",
+                               pr_notice("arptables: loop hook %u pos %u %08X.\n",
                                       hook, pos, e->comefrom);
                                return 0;
                        }
@@ -523,13 +518,11 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size)
                return ret;
 
        t = arpt_get_target(e);
-       target = try_then_request_module(xt_find_target(NFPROTO_ARP,
-                                                       t->u.user.name,
-                                                       t->u.user.revision),
-                                        "arpt_%s", t->u.user.name);
-       if (IS_ERR(target) || !target) {
+       target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
+                                       t->u.user.revision);
+       if (IS_ERR(target)) {
                duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
-               ret = target ? PTR_ERR(target) : -ENOENT;
+               ret = PTR_ERR(target);
                goto out;
        }
        t->u.kernel.target = target;
@@ -651,6 +644,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0,
                if (ret != 0)
                        break;
                ++i;
+               if (strcmp(arpt_get_target(iter)->u.user.name,
+                   XT_ERROR_TARGET) == 0)
+                       ++newinfo->stacksize;
        }
        duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);
        if (ret != 0)
@@ -1252,14 +1248,12 @@ check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
        entry_offset = (void *)e - (void *)base;
 
        t = compat_arpt_get_target(e);
-       target = try_then_request_module(xt_find_target(NFPROTO_ARP,
-                                                       t->u.user.name,
-                                                       t->u.user.revision),
-                                        "arpt_%s", t->u.user.name);
-       if (IS_ERR(target) || !target) {
+       target = xt_request_find_target(NFPROTO_ARP, t->u.user.name,
+                                       t->u.user.revision);
+       if (IS_ERR(target)) {
                duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
                         t->u.user.name);
-               ret = target ? PTR_ERR(target) : -ENOENT;
+               ret = PTR_ERR(target);
                goto out;
        }
        t->u.kernel.target = target;
@@ -1778,8 +1772,7 @@ struct xt_table *arpt_register_table(struct net *net,
 {
        int ret;
        struct xt_table_info *newinfo;
-       struct xt_table_info bootstrap
-               = { 0, 0, 0, { 0 }, { 0 }, { } };
+       struct xt_table_info bootstrap = {0};
        void *loc_cpu_entry;
        struct xt_table *new_table;
 
@@ -1830,22 +1823,23 @@ void arpt_unregister_table(struct xt_table *table)
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct xt_target arpt_standard_target __read_mostly = {
-       .name           = ARPT_STANDARD_TARGET,
-       .targetsize     = sizeof(int),
-       .family         = NFPROTO_ARP,
+static struct xt_target arpt_builtin_tg[] __read_mostly = {
+       {
+               .name             = ARPT_STANDARD_TARGET,
+               .targetsize       = sizeof(int),
+               .family           = NFPROTO_ARP,
 #ifdef CONFIG_COMPAT
-       .compatsize     = sizeof(compat_int_t),
-       .compat_from_user = compat_standard_from_user,
-       .compat_to_user = compat_standard_to_user,
+               .compatsize       = sizeof(compat_int_t),
+               .compat_from_user = compat_standard_from_user,
+               .compat_to_user   = compat_standard_to_user,
 #endif
-};
-
-static struct xt_target arpt_error_target __read_mostly = {
-       .name           = ARPT_ERROR_TARGET,
-       .target         = arpt_error,
-       .targetsize     = ARPT_FUNCTION_MAXNAMELEN,
-       .family         = NFPROTO_ARP,
+       },
+       {
+               .name             = ARPT_ERROR_TARGET,
+               .target           = arpt_error,
+               .targetsize       = ARPT_FUNCTION_MAXNAMELEN,
+               .family           = NFPROTO_ARP,
+       },
 };
 
 static struct nf_sockopt_ops arpt_sockopts = {
@@ -1889,12 +1883,9 @@ static int __init arp_tables_init(void)
                goto err1;
 
        /* Noone else will be downing sem now, so we won't sleep */
-       ret = xt_register_target(&arpt_standard_target);
+       ret = xt_register_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
        if (ret < 0)
                goto err2;
-       ret = xt_register_target(&arpt_error_target);
-       if (ret < 0)
-               goto err3;
 
        /* Register setsockopt */
        ret = nf_register_sockopt(&arpt_sockopts);
@@ -1905,9 +1896,7 @@ static int __init arp_tables_init(void)
        return 0;
 
 err4:
-       xt_unregister_target(&arpt_error_target);
-err3:
-       xt_unregister_target(&arpt_standard_target);
+       xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
 err2:
        unregister_pernet_subsys(&arp_tables_net_ops);
 err1:
@@ -1917,8 +1906,7 @@ err1:
 static void __exit arp_tables_fini(void)
 {
        nf_unregister_sockopt(&arpt_sockopts);
-       xt_unregister_target(&arpt_error_target);
-       xt_unregister_target(&arpt_standard_target);
+       xt_unregister_targets(arpt_builtin_tg, ARRAY_SIZE(arpt_builtin_tg));
        unregister_pernet_subsys(&arp_tables_net_ops);
 }
 
index b0d5b1d0a7693726cf07bf521c559f0e45c20c5b..e1be7dd1171b368eb4a0e1593abc9b8b2294838a 100644 (file)
@@ -9,7 +9,7 @@ MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
 static unsigned int
-target(struct sk_buff *skb, const struct xt_target_param *par)
+target(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct arpt_mangle *mangle = par->targinfo;
        const struct arphdr *arp;
@@ -54,7 +54,7 @@ target(struct sk_buff *skb, const struct xt_target_param *par)
        return mangle->target;
 }
 
-static bool checkentry(const struct xt_tgchk_param *par)
+static int checkentry(const struct xt_tgchk_param *par)
 {
        const struct arpt_mangle *mangle = par->targinfo;
 
index e2787048aa0a4f9008cb8389e89baaaa45717fce..a4e5fc5df4bfd31aef2ed606fe475e7cfc15559d 100644 (file)
@@ -161,8 +161,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
                break;
 
        case IPQ_COPY_PACKET:
-               if ((entry->skb->ip_summed == CHECKSUM_PARTIAL ||
-                    entry->skb->ip_summed == CHECKSUM_COMPLETE) &&
+               if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
                    (*errp = skb_checksum_help(entry->skb))) {
                        read_unlock_bh(&queue_lock);
                        return NULL;
@@ -462,7 +461,6 @@ __ipq_rcv_skb(struct sk_buff *skb)
 
        if (flags & NLM_F_ACK)
                netlink_ack(skb, nlh, 0);
-       return;
 }
 
 static void
index b29c66df8d1fe12803feca71162a1123643c8422..63958f3394a5d0fbe67e675ee72a10b9d27446cd 100644 (file)
@@ -39,24 +39,19 @@ MODULE_DESCRIPTION("IPv4 packet filter");
 /*#define DEBUG_IP_FIREWALL_USER*/
 
 #ifdef DEBUG_IP_FIREWALL
-#define dprintf(format, args...)  printk(format , ## args)
+#define dprintf(format, args...) pr_info(format , ## args)
 #else
 #define dprintf(format, args...)
 #endif
 
 #ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
+#define duprintf(format, args...) pr_info(format , ## args)
 #else
 #define duprintf(format, args...)
 #endif
 
 #ifdef CONFIG_NETFILTER_DEBUG
-#define IP_NF_ASSERT(x)                                                \
-do {                                                           \
-       if (!(x))                                               \
-               printk("IP_NF_ASSERT: %s:%s:%u\n",              \
-                      __func__, __FILE__, __LINE__);   \
-} while(0)
+#define IP_NF_ASSERT(x)                WARN_ON(!(x))
 #else
 #define IP_NF_ASSERT(x)
 #endif
@@ -165,30 +160,14 @@ ip_checkentry(const struct ipt_ip *ip)
 }
 
 static unsigned int
-ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
+ipt_error(struct sk_buff *skb, const struct xt_action_param *par)
 {
        if (net_ratelimit())
-               printk("ip_tables: error: `%s'\n",
-                      (const char *)par->targinfo);
+               pr_info("error: `%s'\n", (const char *)par->targinfo);
 
        return NF_DROP;
 }
 
-/* Performance critical - called for every packet */
-static inline bool
-do_match(const struct ipt_entry_match *m, const struct sk_buff *skb,
-        struct xt_match_param *par)
-{
-       par->match     = m->u.kernel.match;
-       par->matchinfo = m->data;
-
-       /* Stop iteration if it doesn't match */
-       if (!m->u.kernel.match->match(skb, par))
-               return true;
-       else
-               return false;
-}
-
 /* Performance critical */
 static inline struct ipt_entry *
 get_entry(const void *base, unsigned int offset)
@@ -322,19 +301,16 @@ ipt_do_table(struct sk_buff *skb,
             const struct net_device *out,
             struct xt_table *table)
 {
-#define tb_comefrom ((struct ipt_entry *)table_base)->comefrom
-
        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
        const struct iphdr *ip;
-       bool hotdrop = false;
        /* Initializing verdict to NF_DROP keeps gcc happy. */
        unsigned int verdict = NF_DROP;
        const char *indev, *outdev;
        const void *table_base;
-       struct ipt_entry *e, *back;
+       struct ipt_entry *e, **jumpstack;
+       unsigned int *stackptr, origptr, cpu;
        const struct xt_table_info *private;
-       struct xt_match_param mtpar;
-       struct xt_target_param tgpar;
+       struct xt_action_param acpar;
 
        /* Initialization */
        ip = ip_hdr(skb);
@@ -346,40 +322,47 @@ ipt_do_table(struct sk_buff *skb,
         * things we don't know, ie. tcp syn flag or ports).  If the
         * rule is also a fragment-specific rule, non-fragments won't
         * match it. */
-       mtpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
-       mtpar.thoff   = ip_hdrlen(skb);
-       mtpar.hotdrop = &hotdrop;
-       mtpar.in      = tgpar.in  = in;
-       mtpar.out     = tgpar.out = out;
-       mtpar.family  = tgpar.family = NFPROTO_IPV4;
-       mtpar.hooknum = tgpar.hooknum = hook;
+       acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
+       acpar.thoff   = ip_hdrlen(skb);
+       acpar.hotdrop = false;
+       acpar.in      = in;
+       acpar.out     = out;
+       acpar.family  = NFPROTO_IPV4;
+       acpar.hooknum = hook;
 
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
        xt_info_rdlock_bh();
        private = table->private;
-       table_base = private->entries[smp_processor_id()];
+       cpu        = smp_processor_id();
+       table_base = private->entries[cpu];
+       jumpstack  = (struct ipt_entry **)private->jumpstack[cpu];
+       stackptr   = &private->stackptr[cpu];
+       origptr    = *stackptr;
 
        e = get_entry(table_base, private->hook_entry[hook]);
 
-       /* For return from builtin chain */
-       back = get_entry(table_base, private->underflow[hook]);
+       pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n",
+                table->name, hook, origptr,
+                get_entry(table_base, private->underflow[hook]));
 
        do {
                const struct ipt_entry_target *t;
                const struct xt_entry_match *ematch;
 
                IP_NF_ASSERT(e);
-               IP_NF_ASSERT(back);
                if (!ip_packet_match(ip, indev, outdev,
-                   &e->ip, mtpar.fragoff)) {
+                   &e->ip, acpar.fragoff)) {
  no_match:
                        e = ipt_next_entry(e);
                        continue;
                }
 
-               xt_ematch_foreach(ematch, e)
-                       if (do_match(ematch, skb, &mtpar) != 0)
+               xt_ematch_foreach(ematch, e) {
+                       acpar.match     = ematch->u.kernel.match;
+                       acpar.matchinfo = ematch->data;
+                       if (!acpar.match->match(skb, &acpar))
                                goto no_match;
+               }
 
                ADD_COUNTER(e->counters, ntohs(ip->tot_len), 1);
 
@@ -404,41 +387,38 @@ ipt_do_table(struct sk_buff *skb,
                                        verdict = (unsigned)(-v) - 1;
                                        break;
                                }
-                               e = back;
-                               back = get_entry(table_base, back->comefrom);
+                               if (*stackptr == 0) {
+                                       e = get_entry(table_base,
+                                           private->underflow[hook]);
+                                       pr_debug("Underflow (this is normal) "
+                                                "to %p\n", e);
+                               } else {
+                                       e = jumpstack[--*stackptr];
+                                       pr_debug("Pulled %p out from pos %u\n",
+                                                e, *stackptr);
+                                       e = ipt_next_entry(e);
+                               }
                                continue;
                        }
                        if (table_base + v != ipt_next_entry(e) &&
                            !(e->ip.flags & IPT_F_GOTO)) {
-                               /* Save old back ptr in next entry */
-                               struct ipt_entry *next = ipt_next_entry(e);
-                               next->comefrom = (void *)back - table_base;
-                               /* set back pointer to next entry */
-                               back = next;
+                               if (*stackptr >= private->stacksize) {
+                                       verdict = NF_DROP;
+                                       break;
+                               }
+                               jumpstack[(*stackptr)++] = e;
+                               pr_debug("Pushed %p into pos %u\n",
+                                        e, *stackptr - 1);
                        }
 
                        e = get_entry(table_base, v);
                        continue;
                }
 
-               /* Targets which reenter must return
-                  abs. verdicts */
-               tgpar.target   = t->u.kernel.target;
-               tgpar.targinfo = t->data;
-
+               acpar.target   = t->u.kernel.target;
+               acpar.targinfo = t->data;
 
-#ifdef CONFIG_NETFILTER_DEBUG
-               tb_comefrom = 0xeeeeeeec;
-#endif
-               verdict = t->u.kernel.target->target(skb, &tgpar);
-#ifdef CONFIG_NETFILTER_DEBUG
-               if (tb_comefrom != 0xeeeeeeec && verdict == IPT_CONTINUE) {
-                       printk("Target %s reentered!\n",
-                              t->u.kernel.target->name);
-                       verdict = NF_DROP;
-               }
-               tb_comefrom = 0x57acc001;
-#endif
+               verdict = t->u.kernel.target->target(skb, &acpar);
                /* Target might have changed stuff. */
                ip = ip_hdr(skb);
                if (verdict == IPT_CONTINUE)
@@ -446,18 +426,18 @@ ipt_do_table(struct sk_buff *skb,
                else
                        /* Verdict */
                        break;
-       } while (!hotdrop);
+       } while (!acpar.hotdrop);
        xt_info_rdunlock_bh();
-
+       pr_debug("Exiting %s; resetting sp from %u to %u\n",
+                __func__, *stackptr, origptr);
+       *stackptr = origptr;
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
 #else
-       if (hotdrop)
+       if (acpar.hotdrop)
                return NF_DROP;
        else return verdict;
 #endif
-
-#undef tb_comefrom
 }
 
 /* Figures out from what hook each rule can be called: returns 0 if
@@ -486,7 +466,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
                        int visited = e->comefrom & (1 << hook);
 
                        if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
-                               printk("iptables: loop hook %u pos %u %08X.\n",
+                               pr_err("iptables: loop hook %u pos %u %08X.\n",
                                       hook, pos, e->comefrom);
                                return 0;
                        }
@@ -591,7 +571,7 @@ check_entry(const struct ipt_entry *e, const char *name)
        const struct ipt_entry_target *t;
 
        if (!ip_checkentry(&e->ip)) {
-               duprintf("ip_tables: ip check failed %p %s.\n", e, name);
+               duprintf("ip check failed %p %s.\n", e, par->match->name);
                return -EINVAL;
        }
 
@@ -618,8 +598,7 @@ check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
        ret = xt_check_match(par, m->u.match_size - sizeof(*m),
              ip->proto, ip->invflags & IPT_INV_PROTO);
        if (ret < 0) {
-               duprintf("ip_tables: check failed for `%s'.\n",
-                        par.match->name);
+               duprintf("check failed for `%s'.\n", par->match->name);
                return ret;
        }
        return 0;
@@ -631,12 +610,11 @@ find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par)
        struct xt_match *match;
        int ret;
 
-       match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
-                                                     m->u.user.revision),
-                                       "ipt_%s", m->u.user.name);
-       if (IS_ERR(match) || !match) {
+       match = xt_request_find_match(NFPROTO_IPV4, m->u.user.name,
+                                     m->u.user.revision);
+       if (IS_ERR(match)) {
                duprintf("find_check_match: `%s' not found\n", m->u.user.name);
-               return match ? PTR_ERR(match) : -ENOENT;
+               return PTR_ERR(match);
        }
        m->u.kernel.match = match;
 
@@ -667,7 +645,7 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name)
        ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
              e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
        if (ret < 0) {
-               duprintf("ip_tables: check failed for `%s'.\n",
+               duprintf("check failed for `%s'.\n",
                         t->u.kernel.target->name);
                return ret;
        }
@@ -703,13 +681,11 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
        }
 
        t = ipt_get_target(e);
-       target = try_then_request_module(xt_find_target(AF_INET,
-                                                       t->u.user.name,
-                                                       t->u.user.revision),
-                                        "ipt_%s", t->u.user.name);
-       if (IS_ERR(target) || !target) {
+       target = xt_request_find_target(NFPROTO_IPV4, t->u.user.name,
+                                       t->u.user.revision);
+       if (IS_ERR(target)) {
                duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
-               ret = target ? PTR_ERR(target) : -ENOENT;
+               ret = PTR_ERR(target);
                goto cleanup_matches;
        }
        t->u.kernel.target = target;
@@ -843,6 +819,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
                if (ret != 0)
                        return ret;
                ++i;
+               if (strcmp(ipt_get_target(iter)->u.user.name,
+                   XT_ERROR_TARGET) == 0)
+                       ++newinfo->stacksize;
        }
 
        if (i != repl->num_entries) {
@@ -1311,7 +1290,7 @@ do_replace(struct net *net, const void __user *user, unsigned int len)
        if (ret != 0)
                goto free_newinfo;
 
-       duprintf("ip_tables: Translated table\n");
+       duprintf("Translated table\n");
 
        ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
                           tmp.num_counters, tmp.counters);
@@ -1476,13 +1455,12 @@ compat_find_calc_match(struct ipt_entry_match *m,
 {
        struct xt_match *match;
 
-       match = try_then_request_module(xt_find_match(AF_INET, m->u.user.name,
-                                                     m->u.user.revision),
-                                       "ipt_%s", m->u.user.name);
-       if (IS_ERR(match) || !match) {
+       match = xt_request_find_match(NFPROTO_IPV4, m->u.user.name,
+                                     m->u.user.revision);
+       if (IS_ERR(match)) {
                duprintf("compat_check_calc_match: `%s' not found\n",
                         m->u.user.name);
-               return match ? PTR_ERR(match) : -ENOENT;
+               return PTR_ERR(match);
        }
        m->u.kernel.match = match;
        *size += xt_compat_match_offset(match);
@@ -1549,14 +1527,12 @@ check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
        }
 
        t = compat_ipt_get_target(e);
-       target = try_then_request_module(xt_find_target(AF_INET,
-                                                       t->u.user.name,
-                                                       t->u.user.revision),
-                                        "ipt_%s", t->u.user.name);
-       if (IS_ERR(target) || !target) {
+       target = xt_request_find_target(NFPROTO_IPV4, t->u.user.name,
+                                       t->u.user.revision);
+       if (IS_ERR(target)) {
                duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
                         t->u.user.name);
-               ret = target ? PTR_ERR(target) : -ENOENT;
+               ret = PTR_ERR(target);
                goto release_matches;
        }
        t->u.kernel.target = target;
@@ -2094,8 +2070,7 @@ struct xt_table *ipt_register_table(struct net *net,
 {
        int ret;
        struct xt_table_info *newinfo;
-       struct xt_table_info bootstrap
-               = { 0, 0, 0, { 0 }, { 0 }, { } };
+       struct xt_table_info bootstrap = {0};
        void *loc_cpu_entry;
        struct xt_table *new_table;
 
@@ -2157,7 +2132,7 @@ icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
 }
 
 static bool
-icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
+icmp_match(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct icmphdr *ic;
        struct icmphdr _icmph;
@@ -2173,7 +2148,7 @@ icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
                 * can't.  Hence, no choice but to drop.
                 */
                duprintf("Dropping evil ICMP tinygram.\n");
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -2184,31 +2159,31 @@ icmp_match(const struct sk_buff *skb, const struct xt_match_param *par)
                                    !!(icmpinfo->invflags&IPT_ICMP_INV));
 }
 
-static bool icmp_checkentry(const struct xt_mtchk_param *par)
+static int icmp_checkentry(const struct xt_mtchk_param *par)
 {
        const struct ipt_icmp *icmpinfo = par->matchinfo;
 
        /* Must specify no unknown invflags */
-       return !(icmpinfo->invflags & ~IPT_ICMP_INV);
+       return (icmpinfo->invflags & ~IPT_ICMP_INV) ? -EINVAL : 0;
 }
 
-/* The built-in targets: standard (NULL) and error. */
-static struct xt_target ipt_standard_target __read_mostly = {
-       .name           = IPT_STANDARD_TARGET,
-       .targetsize     = sizeof(int),
-       .family         = NFPROTO_IPV4,
+static struct xt_target ipt_builtin_tg[] __read_mostly = {
+       {
+               .name             = IPT_STANDARD_TARGET,
+               .targetsize       = sizeof(int),
+               .family           = NFPROTO_IPV4,
 #ifdef CONFIG_COMPAT
-       .compatsize     = sizeof(compat_int_t),
-       .compat_from_user = compat_standard_from_user,
-       .compat_to_user = compat_standard_to_user,
+               .compatsize       = sizeof(compat_int_t),
+               .compat_from_user = compat_standard_from_user,
+               .compat_to_user   = compat_standard_to_user,
 #endif
-};
-
-static struct xt_target ipt_error_target __read_mostly = {
-       .name           = IPT_ERROR_TARGET,
-       .target         = ipt_error,
-       .targetsize     = IPT_FUNCTION_MAXNAMELEN,
-       .family         = NFPROTO_IPV4,
+       },
+       {
+               .name             = IPT_ERROR_TARGET,
+               .target           = ipt_error,
+               .targetsize       = IPT_FUNCTION_MAXNAMELEN,
+               .family           = NFPROTO_IPV4,
+       },
 };
 
 static struct nf_sockopt_ops ipt_sockopts = {
@@ -2228,13 +2203,15 @@ static struct nf_sockopt_ops ipt_sockopts = {
        .owner          = THIS_MODULE,
 };
 
-static struct xt_match icmp_matchstruct __read_mostly = {
-       .name           = "icmp",
-       .match          = icmp_match,
-       .matchsize      = sizeof(struct ipt_icmp),
-       .checkentry     = icmp_checkentry,
-       .proto          = IPPROTO_ICMP,
-       .family         = NFPROTO_IPV4,
+static struct xt_match ipt_builtin_mt[] __read_mostly = {
+       {
+               .name       = "icmp",
+               .match      = icmp_match,
+               .matchsize  = sizeof(struct ipt_icmp),
+               .checkentry = icmp_checkentry,
+               .proto      = IPPROTO_ICMP,
+               .family     = NFPROTO_IPV4,
+       },
 };
 
 static int __net_init ip_tables_net_init(struct net *net)
@@ -2261,13 +2238,10 @@ static int __init ip_tables_init(void)
                goto err1;
 
        /* Noone else will be downing sem now, so we won't sleep */
-       ret = xt_register_target(&ipt_standard_target);
+       ret = xt_register_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
        if (ret < 0)
                goto err2;
-       ret = xt_register_target(&ipt_error_target);
-       if (ret < 0)
-               goto err3;
-       ret = xt_register_match(&icmp_matchstruct);
+       ret = xt_register_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
        if (ret < 0)
                goto err4;
 
@@ -2276,15 +2250,13 @@ static int __init ip_tables_init(void)
        if (ret < 0)
                goto err5;
 
-       printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
+       pr_info("(C) 2000-2006 Netfilter Core Team\n");
        return 0;
 
 err5:
-       xt_unregister_match(&icmp_matchstruct);
+       xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
 err4:
-       xt_unregister_target(&ipt_error_target);
-err3:
-       xt_unregister_target(&ipt_standard_target);
+       xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
 err2:
        unregister_pernet_subsys(&ip_tables_net_ops);
 err1:
@@ -2295,10 +2267,8 @@ static void __exit ip_tables_fini(void)
 {
        nf_unregister_sockopt(&ipt_sockopts);
 
-       xt_unregister_match(&icmp_matchstruct);
-       xt_unregister_target(&ipt_error_target);
-       xt_unregister_target(&ipt_standard_target);
-
+       xt_unregister_matches(ipt_builtin_mt, ARRAY_SIZE(ipt_builtin_mt));
+       xt_unregister_targets(ipt_builtin_tg, ARRAY_SIZE(ipt_builtin_tg));
        unregister_pernet_subsys(&ip_tables_net_ops);
 }
 
index ab828400ed7160c146f8dc058edf9b17dc81ab96..f91c94b9a7900017b3589598a26c3491ef6a2407 100644 (file)
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/jhash.h>
@@ -88,7 +89,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
                list_del(&c->list);
                write_unlock_bh(&clusterip_lock);
 
-               dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0);
+               dev_mc_del(c->dev, c->clustermac);
                dev_put(c->dev);
 
                /* In case anyone still accesses the file, the open/close
@@ -239,8 +240,7 @@ clusterip_hashfn(const struct sk_buff *skb,
                break;
        default:
                if (net_ratelimit())
-                       printk(KERN_NOTICE "CLUSTERIP: unknown protocol `%u'\n",
-                               iph->protocol);
+                       pr_info("unknown protocol %u\n", iph->protocol);
                sport = dport = 0;
        }
 
@@ -262,7 +262,7 @@ clusterip_hashfn(const struct sk_buff *skb,
                hashval = 0;
                /* This cannot happen, unless the check function wasn't called
                 * at rule load time */
-               printk("CLUSTERIP: unknown mode `%u'\n", config->hash_mode);
+               pr_info("unknown mode %u\n", config->hash_mode);
                BUG();
                break;
        }
@@ -282,7 +282,7 @@ clusterip_responsible(const struct clusterip_config *config, u_int32_t hash)
  ***********************************************************************/
 
 static unsigned int
-clusterip_tg(struct sk_buff *skb, const struct xt_target_param *par)
+clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
        struct nf_conn *ct;
@@ -295,7 +295,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_target_param *par)
 
        ct = nf_ct_get(skb, &ctinfo);
        if (ct == NULL) {
-               printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
+               pr_info("no conntrack!\n");
                        /* FIXME: need to drop invalid ones, since replies
                         * to outgoing connections of other nodes will be
                         * marked as INVALID */
@@ -348,25 +348,24 @@ clusterip_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool clusterip_tg_check(const struct xt_tgchk_param *par)
+static int clusterip_tg_check(const struct xt_tgchk_param *par)
 {
        struct ipt_clusterip_tgt_info *cipinfo = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
-
        struct clusterip_config *config;
+       int ret;
 
        if (cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP &&
            cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT &&
            cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
-               printk(KERN_WARNING "CLUSTERIP: unknown mode `%u'\n",
-                       cipinfo->hash_mode);
-               return false;
+               pr_info("unknown mode %u\n", cipinfo->hash_mode);
+               return -EINVAL;
 
        }
        if (e->ip.dmsk.s_addr != htonl(0xffffffff) ||
            e->ip.dst.s_addr == 0) {
-               printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
-               return false;
+               pr_info("Please specify destination IP\n");
+               return -EINVAL;
        }
 
        /* FIXME: further sanity checks */
@@ -374,41 +373,41 @@ static bool clusterip_tg_check(const struct xt_tgchk_param *par)
        config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
        if (!config) {
                if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
-                       printk(KERN_WARNING "CLUSTERIP: no config found for %pI4, need 'new'\n", &e->ip.dst.s_addr);
-                       return false;
+                       pr_info("no config found for %pI4, need 'new'\n",
+                               &e->ip.dst.s_addr);
+                       return -EINVAL;
                } else {
                        struct net_device *dev;
 
                        if (e->ip.iniface[0] == '\0') {
-                               printk(KERN_WARNING "CLUSTERIP: Please specify an interface name\n");
-                               return false;
+                               pr_info("Please specify an interface name\n");
+                               return -EINVAL;
                        }
 
                        dev = dev_get_by_name(&init_net, e->ip.iniface);
                        if (!dev) {
-                               printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface);
-                               return false;
+                               pr_info("no such interface %s\n",
+                                       e->ip.iniface);
+                               return -ENOENT;
                        }
 
                        config = clusterip_config_init(cipinfo,
                                                        e->ip.dst.s_addr, dev);
                        if (!config) {
-                               printk(KERN_WARNING "CLUSTERIP: cannot allocate config\n");
+                               pr_info("cannot allocate config\n");
                                dev_put(dev);
-                               return false;
+                               return -ENOMEM;
                        }
-                       dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0);
+                       dev_mc_add(config->dev, config->clustermac);
                }
        }
        cipinfo->config = config;
 
-       if (nf_ct_l3proto_try_module_get(par->target->family) < 0) {
-               printk(KERN_WARNING "can't load conntrack support for "
-                                   "proto=%u\n", par->target->family);
-               return false;
-       }
-
-       return true;
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
 }
 
 /* drop reference count of cluster config when rule is deleted */
@@ -422,7 +421,7 @@ static void clusterip_tg_destroy(const struct xt_tgdtor_param *par)
 
        clusterip_config_put(cipinfo->config);
 
-       nf_ct_l3proto_module_put(par->target->family);
+       nf_ct_l3proto_module_put(par->family);
 }
 
 #ifdef CONFIG_COMPAT
@@ -479,8 +478,8 @@ static void arp_print(struct arp_payload *payload)
        }
        hbuffer[--k]='\0';
 
-       printk("src %pI4@%s, dst %pI4\n",
-               &payload->src_ip, hbuffer, &payload->dst_ip);
+       pr_debug("src %pI4@%s, dst %pI4\n",
+                &payload->src_ip, hbuffer, &payload->dst_ip);
 }
 #endif
 
@@ -519,7 +518,7 @@ arp_mangle(unsigned int hook,
         * this wouldn't work, since we didn't subscribe the mcast group on
         * other interfaces */
        if (c->dev != out) {
-               pr_debug("CLUSTERIP: not mangling arp reply on different "
+               pr_debug("not mangling arp reply on different "
                         "interface: cip'%s'-skb'%s'\n",
                         c->dev->name, out->name);
                clusterip_config_put(c);
@@ -530,7 +529,7 @@ arp_mangle(unsigned int hook,
        memcpy(payload->src_hw, c->clustermac, arp->ar_hln);
 
 #ifdef DEBUG
-       pr_debug(KERN_DEBUG "CLUSTERIP mangled arp reply: ");
+       pr_debug("mangled arp reply: ");
        arp_print(payload);
 #endif
 
@@ -601,7 +600,8 @@ static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos)
 
 static void clusterip_seq_stop(struct seq_file *s, void *v)
 {
-       kfree(v);
+       if (!IS_ERR(v))
+               kfree(v);
 }
 
 static int clusterip_seq_show(struct seq_file *s, void *v)
@@ -706,13 +706,13 @@ static int __init clusterip_tg_init(void)
 #ifdef CONFIG_PROC_FS
        clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", init_net.proc_net);
        if (!clusterip_procdir) {
-               printk(KERN_ERR "CLUSTERIP: Unable to proc dir entry\n");
+               pr_err("Unable to proc dir entry\n");
                ret = -ENOMEM;
                goto cleanup_hook;
        }
 #endif /* CONFIG_PROC_FS */
 
-       printk(KERN_NOTICE "ClusterIP Version %s loaded successfully\n",
+       pr_info("ClusterIP Version %s loaded successfully\n",
                CLUSTERIP_VERSION);
        return 0;
 
@@ -727,8 +727,7 @@ cleanup_target:
 
 static void __exit clusterip_tg_exit(void)
 {
-       printk(KERN_NOTICE "ClusterIP Version %s unloading\n",
-               CLUSTERIP_VERSION);
+       pr_info("ClusterIP Version %s unloading\n", CLUSTERIP_VERSION);
 #ifdef CONFIG_PROC_FS
        remove_proc_entry(clusterip_procdir->name, clusterip_procdir->parent);
 #endif
index ea5cea2415c133f3386a68c9b6c1eca1492e2a1e..4bf3dc49ad1ea84d59815cb9a46aa3cd3fd374b5 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -77,7 +77,7 @@ set_ect_tcp(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
 }
 
 static unsigned int
-ecn_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ecn_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ipt_ECN_info *einfo = par->targinfo;
 
@@ -93,28 +93,25 @@ ecn_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool ecn_tg_check(const struct xt_tgchk_param *par)
+static int ecn_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_ECN_info *einfo = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
 
        if (einfo->operation & IPT_ECN_OP_MASK) {
-               printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
-                       einfo->operation);
-               return false;
+               pr_info("unsupported ECN operation %x\n", einfo->operation);
+               return -EINVAL;
        }
        if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
-               printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
-                       einfo->ip_ect);
-               return false;
+               pr_info("new ECT codepoint %x out of mask\n", einfo->ip_ect);
+               return -EINVAL;
        }
        if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) &&
            (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
-               printk(KERN_WARNING "ECN: cannot use TCP operations on a "
-                      "non-tcp rule\n");
-               return false;
+               pr_info("cannot use TCP operations on a non-tcp rule\n");
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target ecn_tg_reg __read_mostly = {
index ee128efa1c8d73bbc9b0244d1b44ff2693e5a4f4..5234f4f3499ad87e06c9d1bfab14e27d35b77fe6 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/skbuff.h>
@@ -367,7 +367,7 @@ static struct nf_loginfo default_loginfo = {
        .type   = NF_LOG_TYPE_LOG,
        .u = {
                .log = {
-                       .level    = 0,
+                       .level    = 5,
                        .logflags = NF_LOG_MASK,
                },
        },
@@ -425,7 +425,7 @@ ipt_log_packet(u_int8_t pf,
 }
 
 static unsigned int
-log_tg(struct sk_buff *skb, const struct xt_target_param *par)
+log_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ipt_log_info *loginfo = par->targinfo;
        struct nf_loginfo li;
@@ -439,20 +439,19 @@ log_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool log_tg_check(const struct xt_tgchk_param *par)
+static int log_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_log_info *loginfo = par->targinfo;
 
        if (loginfo->level >= 8) {
-               pr_debug("LOG: level %u >= 8\n", loginfo->level);
-               return false;
+               pr_debug("level %u >= 8\n", loginfo->level);
+               return -EINVAL;
        }
        if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
-               pr_debug("LOG: prefix term %i\n",
-                        loginfo->prefix[sizeof(loginfo->prefix)-1]);
-               return false;
+               pr_debug("prefix is not null-terminated\n");
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target log_tg_reg __read_mostly = {
index 650b54042b01f2138bdc7621504224a7cefd80a6..d2ed9dc74ebc3c029e134295f4ed490f27af0ef6 100644 (file)
@@ -8,7 +8,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/types.h>
 #include <linux/inetdevice.h>
 #include <linux/ip.h>
@@ -28,23 +28,23 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
 MODULE_DESCRIPTION("Xtables: automatic-address SNAT");
 
 /* FIXME: Multiple targets. --RR */
-static bool masquerade_tg_check(const struct xt_tgchk_param *par)
+static int masquerade_tg_check(const struct xt_tgchk_param *par)
 {
        const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
        if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
-               pr_debug("masquerade_check: bad MAP_IPS.\n");
-               return false;
+               pr_debug("bad MAP_IPS.\n");
+               return -EINVAL;
        }
        if (mr->rangesize != 1) {
-               pr_debug("masquerade_check: bad rangesize %u\n", mr->rangesize);
-               return false;
+               pr_debug("bad rangesize %u\n", mr->rangesize);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static unsigned int
-masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par)
+masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct nf_conn *ct;
        struct nf_conn_nat *nat;
@@ -72,7 +72,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_target_param *par)
        rt = skb_rtable(skb);
        newsrc = inet_select_addr(par->out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
        if (!newsrc) {
-               printk("MASQUERADE: %s ate my IP address\n", par->out->name);
+               pr_info("%s ate my IP address\n", par->out->name);
                return NF_DROP;
        }
 
index 7c29582d4ec8cfcf84cf7d49eff6e03d1000c9d3..f43867d1697f2b6c262030672ed7411af5b2b2a4 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/ip.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -22,23 +22,23 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
 MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv4 subnets");
 
-static bool netmap_tg_check(const struct xt_tgchk_param *par)
+static int netmap_tg_check(const struct xt_tgchk_param *par)
 {
        const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
        if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
-               pr_debug("NETMAP:check: bad MAP_IPS.\n");
-               return false;
+               pr_debug("bad MAP_IPS.\n");
+               return -EINVAL;
        }
        if (mr->rangesize != 1) {
-               pr_debug("NETMAP:check: bad rangesize %u.\n", mr->rangesize);
-               return false;
+               pr_debug("bad rangesize %u.\n", mr->rangesize);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static unsigned int
-netmap_tg(struct sk_buff *skb, const struct xt_target_param *par)
+netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
index 698e5e78685b18139180c8807ad28f619c43e0fd..18a0656505a02046099219b0563a1617bce321dd 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/timer.h>
@@ -26,23 +26,23 @@ MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
 MODULE_DESCRIPTION("Xtables: Connection redirection to localhost");
 
 /* FIXME: Take multiple ranges --RR */
-static bool redirect_tg_check(const struct xt_tgchk_param *par)
+static int redirect_tg_check(const struct xt_tgchk_param *par)
 {
        const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
        if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
-               pr_debug("redirect_check: bad MAP_IPS.\n");
-               return false;
+               pr_debug("bad MAP_IPS.\n");
+               return -EINVAL;
        }
        if (mr->rangesize != 1) {
-               pr_debug("redirect_check: bad rangesize %u.\n", mr->rangesize);
-               return false;
+               pr_debug("bad rangesize %u.\n", mr->rangesize);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static unsigned int
-redirect_tg(struct sk_buff *skb, const struct xt_target_param *par)
+redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
index a0e8bcf041592cac88b9a623cb001e22cd0b55cd..f5f4a888e4ec71243f2d6589507355f28273c5e9 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
@@ -136,13 +136,10 @@ static inline void send_unreach(struct sk_buff *skb_in, int code)
 }
 
 static unsigned int
-reject_tg(struct sk_buff *skb, const struct xt_target_param *par)
+reject_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ipt_reject_info *reject = par->targinfo;
 
-       /* WARNING: This code causes reentry within iptables.
-          This means that the iptables jump stack is now crap.  We
-          must return an absolute verdict. --RR */
        switch (reject->with) {
        case IPT_ICMP_NET_UNREACHABLE:
                send_unreach(skb, ICMP_NET_UNREACH);
@@ -175,23 +172,23 @@ reject_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return NF_DROP;
 }
 
-static bool reject_tg_check(const struct xt_tgchk_param *par)
+static int reject_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_reject_info *rejinfo = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
 
        if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
-               printk("ipt_REJECT: ECHOREPLY no longer supported.\n");
-               return false;
+               pr_info("ECHOREPLY no longer supported.\n");
+               return -EINVAL;
        } else if (rejinfo->with == IPT_TCP_RESET) {
                /* Must specify that it's a TCP packet */
                if (e->ip.proto != IPPROTO_TCP ||
                    (e->ip.invflags & XT_INV_PROTO)) {
-                       printk("ipt_REJECT: TCP_RESET invalid for non-tcp\n");
-                       return false;
+                       pr_info("TCP_RESET invalid for non-tcp\n");
+                       return -EINVAL;
                }
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target reject_tg_reg __read_mostly = {
index 0dbe697f164fd38487a6a8a09e56d83cc00a2352..446e0f467a17eed968b7a9cba12b001b05de1154 100644 (file)
@@ -29,7 +29,7 @@
  *   Specify, after how many hundredths of a second the queue should be
  *   flushed even if it is not full yet.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/socket.h>
@@ -57,8 +57,6 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
 #define ULOG_NL_EVENT          111             /* Harald's favorite number */
 #define ULOG_MAXNLGROUPS       32              /* numer of nlgroups */
 
-#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0)
-
 static unsigned int nlbufsiz = NLMSG_GOODSIZE;
 module_param(nlbufsiz, uint, 0400);
 MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
@@ -91,12 +89,12 @@ static void ulog_send(unsigned int nlgroupnum)
        ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
 
        if (timer_pending(&ub->timer)) {
-               pr_debug("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+               pr_debug("ulog_send: timer was pending, deleting\n");
                del_timer(&ub->timer);
        }
 
        if (!ub->skb) {
-               pr_debug("ipt_ULOG: ulog_send: nothing to send\n");
+               pr_debug("ulog_send: nothing to send\n");
                return;
        }
 
@@ -105,7 +103,7 @@ static void ulog_send(unsigned int nlgroupnum)
                ub->lastnlh->nlmsg_type = NLMSG_DONE;
 
        NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1;
-       pr_debug("ipt_ULOG: throwing %d packets to netlink group %u\n",
+       pr_debug("throwing %d packets to netlink group %u\n",
                 ub->qlen, nlgroupnum + 1);
        netlink_broadcast(nflognl, ub->skb, 0, nlgroupnum + 1, GFP_ATOMIC);
 
@@ -118,7 +116,7 @@ static void ulog_send(unsigned int nlgroupnum)
 /* timer function to flush queue in flushtimeout time */
 static void ulog_timer(unsigned long data)
 {
-       pr_debug("ipt_ULOG: timer function called, calling ulog_send\n");
+       pr_debug("timer function called, calling ulog_send\n");
 
        /* lock to protect against somebody modifying our structure
         * from ipt_ulog_target at the same time */
@@ -139,7 +137,7 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size)
        n = max(size, nlbufsiz);
        skb = alloc_skb(n, GFP_ATOMIC);
        if (!skb) {
-               PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n", n);
+               pr_debug("cannot alloc whole buffer %ub!\n", n);
 
                if (n > size) {
                        /* try to allocate only as much as we need for
@@ -147,8 +145,7 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size)
 
                        skb = alloc_skb(size, GFP_ATOMIC);
                        if (!skb)
-                               PRINTR("ipt_ULOG: can't even allocate %ub\n",
-                                      size);
+                               pr_debug("cannot even allocate %ub\n", size);
                }
        }
 
@@ -199,8 +196,7 @@ static void ipt_ulog_packet(unsigned int hooknum,
                        goto alloc_failure;
        }
 
-       pr_debug("ipt_ULOG: qlen %d, qthreshold %Zu\n", ub->qlen,
-                loginfo->qthreshold);
+       pr_debug("qlen %d, qthreshold %Zu\n", ub->qlen, loginfo->qthreshold);
 
        /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
        nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT,
@@ -273,16 +269,14 @@ static void ipt_ulog_packet(unsigned int hooknum,
        return;
 
 nlmsg_failure:
-       PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
-
+       pr_debug("error during NLMSG_PUT\n");
 alloc_failure:
-       PRINTR("ipt_ULOG: Error building netlink message\n");
-
+       pr_debug("Error building netlink message\n");
        spin_unlock_bh(&ulog_lock);
 }
 
 static unsigned int
-ulog_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ulog_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        ipt_ulog_packet(par->hooknum, skb, par->in, par->out,
                        par->targinfo, NULL);
@@ -314,21 +308,20 @@ static void ipt_logfn(u_int8_t pf,
        ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
 }
 
-static bool ulog_tg_check(const struct xt_tgchk_param *par)
+static int ulog_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_ulog_info *loginfo = par->targinfo;
 
        if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
-               pr_debug("ipt_ULOG: prefix term %i\n",
-                        loginfo->prefix[sizeof(loginfo->prefix) - 1]);
-               return false;
+               pr_debug("prefix not null-terminated\n");
+               return -EINVAL;
        }
        if (loginfo->qthreshold > ULOG_MAX_QLEN) {
-               pr_debug("ipt_ULOG: queue threshold %Zu > MAX_QLEN\n",
+               pr_debug("queue threshold %Zu > MAX_QLEN\n",
                         loginfo->qthreshold);
-               return false;
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 #ifdef CONFIG_COMPAT
@@ -390,10 +383,10 @@ static int __init ulog_tg_init(void)
 {
        int ret, i;
 
-       pr_debug("ipt_ULOG: init module\n");
+       pr_debug("init module\n");
 
        if (nlbufsiz > 128*1024) {
-               printk("Netlink buffer has to be <= 128kB\n");
+               pr_warning("Netlink buffer has to be <= 128kB\n");
                return -EINVAL;
        }
 
@@ -423,7 +416,7 @@ static void __exit ulog_tg_exit(void)
        ulog_buff_t *ub;
        int i;
 
-       pr_debug("ipt_ULOG: cleanup_module\n");
+       pr_debug("cleanup_module\n");
 
        if (nflog)
                nf_log_unregister(&ipt_ulog_logger);
index 3b216be3bc9fbcf940d00dff5c8d428ec229fe59..db8bff0fb86dc711f1d422ba188a41f85a33d32f 100644 (file)
@@ -8,7 +8,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -30,7 +30,7 @@ static inline bool match_type(struct net *net, const struct net_device *dev,
 }
 
 static bool
-addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
+addrtype_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct net *net = dev_net(par->in ? par->in : par->out);
        const struct ipt_addrtype_info *info = par->matchinfo;
@@ -48,7 +48,7 @@ addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
 }
 
 static bool
-addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
+addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct net *net = dev_net(par->in ? par->in : par->out);
        const struct ipt_addrtype_info_v1 *info = par->matchinfo;
@@ -70,34 +70,34 @@ addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
        return ret;
 }
 
-static bool addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
+static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
 {
        struct ipt_addrtype_info_v1 *info = par->matchinfo;
 
        if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN &&
            info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
-               printk(KERN_ERR "ipt_addrtype: both incoming and outgoing "
-                               "interface limitation cannot be selected\n");
-               return false;
+               pr_info("both incoming and outgoing "
+                       "interface limitation cannot be selected\n");
+               return -EINVAL;
        }
 
        if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
            (1 << NF_INET_LOCAL_IN)) &&
            info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) {
-               printk(KERN_ERR "ipt_addrtype: output interface limitation "
-                               "not valid in PRE_ROUTING and INPUT\n");
-               return false;
+               pr_info("output interface limitation "
+                       "not valid in PREROUTING and INPUT\n");
+               return -EINVAL;
        }
 
        if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
            (1 << NF_INET_LOCAL_OUT)) &&
            info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) {
-               printk(KERN_ERR "ipt_addrtype: input interface limitation "
-                               "not valid in POST_ROUTING and OUTPUT\n");
-               return false;
+               pr_info("input interface limitation "
+                       "not valid in POSTROUTING and OUTPUT\n");
+               return -EINVAL;
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match addrtype_mt_reg[] __read_mostly = {
index 0104c0b399de5ca3efc6ba58ff8ada6aa8b6de43..14a2aa8b8a142502095e4da8a034eae6e78a8313 100644 (file)
@@ -5,7 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -18,25 +18,19 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yon Uriarte <yon@astaro.de>");
 MODULE_DESCRIPTION("Xtables: IPv4 IPsec-AH SPI match");
 
-#ifdef DEBUG_CONNTRACK
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline bool
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
 {
        bool r;
-       duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
-               min,spi,max);
+       pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n",
+                invert ? '!' : ' ', min, spi, max);
        r=(spi >= min && spi <= max) ^ invert;
-       duprintf(" result %s\n",r? "PASS" : "FAILED");
+       pr_debug(" result %s\n", r ? "PASS" : "FAILED");
        return r;
 }
 
-static bool ah_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool ah_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ip_auth_hdr _ahdr;
        const struct ip_auth_hdr *ah;
@@ -51,8 +45,8 @@ static bool ah_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                /* We've been asked to examine this packet, and we
                 * can't.  Hence, no choice but to drop.
                 */
-               duprintf("Dropping evil AH tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil AH tinygram.\n");
+               par->hotdrop = true;
                return 0;
        }
 
@@ -61,16 +55,16 @@ static bool ah_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                         !!(ahinfo->invflags & IPT_AH_INV_SPI));
 }
 
-static bool ah_mt_check(const struct xt_mtchk_param *par)
+static int ah_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ipt_ah *ahinfo = par->matchinfo;
 
        /* Must specify no unknown invflags */
        if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
-               duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags);
-               return false;
+               pr_debug("unknown flags %X\n", ahinfo->invflags);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match ah_mt_reg __read_mostly = {
index 2a1e56b71908b35e0ea1ad290c8226d714bb7a16..af6e9c778345ff802916cc7fa0078cbd79735c81 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <net/ip.h>
@@ -67,7 +67,7 @@ static inline bool match_tcp(const struct sk_buff *skb,
        return true;
 }
 
-static bool ecn_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ipt_ecn_info *info = par->matchinfo;
 
@@ -78,32 +78,31 @@ static bool ecn_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
                if (ip_hdr(skb)->protocol != IPPROTO_TCP)
                        return false;
-               if (!match_tcp(skb, info, par->hotdrop))
+               if (!match_tcp(skb, info, &par->hotdrop))
                        return false;
        }
 
        return true;
 }
 
-static bool ecn_mt_check(const struct xt_mtchk_param *par)
+static int ecn_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ipt_ecn_info *info = par->matchinfo;
        const struct ipt_ip *ip = par->entryinfo;
 
        if (info->operation & IPT_ECN_OP_MATCH_MASK)
-               return false;
+               return -EINVAL;
 
        if (info->invert & IPT_ECN_OP_MATCH_MASK)
-               return false;
+               return -EINVAL;
 
        if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) &&
            ip->proto != IPPROTO_TCP) {
-               printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
-                      " non-tcp packets\n");
-               return false;
+               pr_info("cannot match TCP bits in rule for non-tcp packets\n");
+               return -EINVAL;
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match ecn_mt_reg __read_mostly = {
index 55392466daa49fd455a4c28d6b168c388db2eff2..c37641e819f2e9025854b95edc8de145831cb70a 100644 (file)
@@ -89,7 +89,7 @@ static int __init iptable_filter_init(void)
        int ret;
 
        if (forward < 0 || forward > NF_MAX_VERDICT) {
-               printk("iptables forward must be 0 or 1\n");
+               pr_err("iptables forward must be 0 or 1\n");
                return -EINVAL;
        }
 
index 2bb1f87051c4762b896aa9669969742b04859133..5a03c02af999a45ac7d3f9e403ea1c2d38bc0c5a 100644 (file)
@@ -382,32 +382,32 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
 
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4);
        if (ret < 0) {
-               printk("nf_conntrack_ipv4: can't register tcp.\n");
+               pr_err("nf_conntrack_ipv4: can't register tcp.\n");
                goto cleanup_sockopt;
        }
 
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4);
        if (ret < 0) {
-               printk("nf_conntrack_ipv4: can't register udp.\n");
+               pr_err("nf_conntrack_ipv4: can't register udp.\n");
                goto cleanup_tcp;
        }
 
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp);
        if (ret < 0) {
-               printk("nf_conntrack_ipv4: can't register icmp.\n");
+               pr_err("nf_conntrack_ipv4: can't register icmp.\n");
                goto cleanup_udp;
        }
 
        ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
        if (ret < 0) {
-               printk("nf_conntrack_ipv4: can't register ipv4\n");
+               pr_err("nf_conntrack_ipv4: can't register ipv4\n");
                goto cleanup_icmp;
        }
 
        ret = nf_register_hooks(ipv4_conntrack_ops,
                                ARRAY_SIZE(ipv4_conntrack_ops));
        if (ret < 0) {
-               printk("nf_conntrack_ipv4: can't register hooks.\n");
+               pr_err("nf_conntrack_ipv4: can't register hooks.\n");
                goto cleanup_ipv4;
        }
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
index 2fb7b76da94fafed76c19f9a0fe8396ae5bbf321..244f7cb08d681d35f9a08744ca449ce90f5b8972 100644 (file)
@@ -336,12 +336,12 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
        const struct ip_conntrack_stat *st = v;
 
        if (v == SEQ_START_TOKEN) {
-               seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
+               seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart\n");
                return 0;
        }
 
        seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
-                       "%08x %08x %08x %08x %08x  %08x %08x %08x \n",
+                       "%08x %08x %08x %08x %08x  %08x %08x %08x %08x\n",
                   nr_conntracks,
                   st->searched,
                   st->found,
@@ -358,7 +358,8 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 
                   st->expect_new,
                   st->expect_create,
-                  st->expect_delete
+                  st->expect_delete,
+                  st->search_restart
                );
        return 0;
 }
index 7e8e6fc754133526abf86638b176e2c9e4d005e0..5045196d853c7878050161ea5e43e1aac26eff83 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/tcp.h>
 #include <net/tcp.h>
 
@@ -44,7 +43,7 @@ static int set_addr(struct sk_buff *skb,
                                              addroff, sizeof(buf),
                                              (char *) &buf, sizeof(buf))) {
                        if (net_ratelimit())
-                               printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
+                               pr_notice("nf_nat_h323: nf_nat_mangle_tcp_packet"
                                       " error\n");
                        return -1;
                }
@@ -60,7 +59,7 @@ static int set_addr(struct sk_buff *skb,
                                              addroff, sizeof(buf),
                                              (char *) &buf, sizeof(buf))) {
                        if (net_ratelimit())
-                               printk("nf_nat_h323: nf_nat_mangle_udp_packet"
+                               pr_notice("nf_nat_h323: nf_nat_mangle_udp_packet"
                                       " error\n");
                        return -1;
                }
@@ -216,7 +215,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
        /* Run out of expectations */
        if (i >= H323_RTP_CHANNEL_MAX) {
                if (net_ratelimit())
-                       printk("nf_nat_h323: out of expectations\n");
+                       pr_notice("nf_nat_h323: out of expectations\n");
                return 0;
        }
 
@@ -235,7 +234,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 
        if (nated_port == 0) {  /* No port available */
                if (net_ratelimit())
-                       printk("nf_nat_h323: out of RTP ports\n");
+                       pr_notice("nf_nat_h323: out of RTP ports\n");
                return 0;
        }
 
@@ -292,7 +291,7 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
 
        if (nated_port == 0) {  /* No port available */
                if (net_ratelimit())
-                       printk("nf_nat_h323: out of TCP ports\n");
+                       pr_notice("nf_nat_h323: out of TCP ports\n");
                return 0;
        }
 
@@ -342,7 +341,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
 
        if (nated_port == 0) {  /* No port available */
                if (net_ratelimit())
-                       printk("nf_nat_q931: out of TCP ports\n");
+                       pr_notice("nf_nat_q931: out of TCP ports\n");
                return 0;
        }
 
@@ -426,7 +425,7 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 
        if (nated_port == 0) {  /* No port available */
                if (net_ratelimit())
-                       printk("nf_nat_ras: out of TCP ports\n");
+                       pr_notice("nf_nat_ras: out of TCP ports\n");
                return 0;
        }
 
@@ -508,7 +507,7 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
 
        if (nated_port == 0) {  /* No port available */
                if (net_ratelimit())
-                       printk("nf_nat_q931: out of TCP ports\n");
+                       pr_notice("nf_nat_q931: out of TCP ports\n");
                return 0;
        }
 
index 26de2c1f7fabd1a0e1b135fd487595311aa1793a..98ed78281aee15eae5da8b99105c3f2da36836bd 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 /* Everything about the rules for NAT. */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/netfilter.h>
@@ -38,7 +39,7 @@ static const struct xt_table nat_table = {
 
 /* Source NAT */
 static unsigned int
-ipt_snat_target(struct sk_buff *skb, const struct xt_target_param *par)
+ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
@@ -57,7 +58,7 @@ ipt_snat_target(struct sk_buff *skb, const struct xt_target_param *par)
 }
 
 static unsigned int
-ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par)
+ipt_dnat_target(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct nf_conn *ct;
        enum ip_conntrack_info ctinfo;
@@ -74,28 +75,28 @@ ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par)
        return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST);
 }
 
-static bool ipt_snat_checkentry(const struct xt_tgchk_param *par)
+static int ipt_snat_checkentry(const struct xt_tgchk_param *par)
 {
        const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
        /* Must be a valid range */
        if (mr->rangesize != 1) {
-               printk("SNAT: multiple ranges no longer supported\n");
-               return false;
+               pr_info("SNAT: multiple ranges no longer supported\n");
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
-static bool ipt_dnat_checkentry(const struct xt_tgchk_param *par)
+static int ipt_dnat_checkentry(const struct xt_tgchk_param *par)
 {
        const struct nf_nat_multi_range_compat *mr = par->targinfo;
 
        /* Must be a valid range */
        if (mr->rangesize != 1) {
-               printk("DNAT: multiple ranges no longer supported\n");
-               return false;
+               pr_info("DNAT: multiple ranges no longer supported\n");
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 unsigned int
index 4d85b6e55f2978f31cbe2aa85d2fbbf95d9bbdb4..1679e2c0963d9b83e34f1f8d6a34b7702a603e2c 100644 (file)
@@ -401,7 +401,7 @@ static unsigned char asn1_octets_decode(struct asn1_ctx *ctx,
        *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC);
        if (*octets == NULL) {
                if (net_ratelimit())
-                       printk("OOM in bsalg (%d)\n", __LINE__);
+                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                return 0;
        }
 
@@ -452,7 +452,7 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx,
        *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
        if (*oid == NULL) {
                if (net_ratelimit())
-                       printk("OOM in bsalg (%d)\n", __LINE__);
+                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                return 0;
        }
 
@@ -729,7 +729,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                        if (*obj == NULL) {
                                kfree(id);
                                if (net_ratelimit())
-                                       printk("OOM in bsalg (%d)\n", __LINE__);
+                                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                                return 0;
                        }
                        (*obj)->syntax.l[0] = l;
@@ -746,7 +746,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                                kfree(p);
                                kfree(id);
                                if (net_ratelimit())
-                                       printk("OOM in bsalg (%d)\n", __LINE__);
+                                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                                return 0;
                        }
                        memcpy((*obj)->syntax.c, p, len);
@@ -761,7 +761,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                        if (*obj == NULL) {
                                kfree(id);
                                if (net_ratelimit())
-                                       printk("OOM in bsalg (%d)\n", __LINE__);
+                                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                                return 0;
                        }
                        if (!asn1_null_decode(ctx, end)) {
@@ -782,7 +782,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                                kfree(lp);
                                kfree(id);
                                if (net_ratelimit())
-                                       printk("OOM in bsalg (%d)\n", __LINE__);
+                                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                                return 0;
                        }
                        memcpy((*obj)->syntax.ul, lp, len);
@@ -803,7 +803,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                                kfree(p);
                                kfree(id);
                                if (net_ratelimit())
-                                       printk("OOM in bsalg (%d)\n", __LINE__);
+                                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                                return 0;
                        }
                        memcpy((*obj)->syntax.uc, p, len);
@@ -821,7 +821,7 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx,
                        if (*obj == NULL) {
                                kfree(id);
                                if (net_ratelimit())
-                                       printk("OOM in bsalg (%d)\n", __LINE__);
+                                       pr_notice("OOM in bsalg (%d)\n", __LINE__);
                                return 0;
                        }
                        (*obj)->syntax.ul[0] = ul;
index c39c9cf6bee67f9f853f7a8f7c3faa00a440fbba..beb25819c9c9f66c0fa5a1a40c398e860f3e10a8 100644 (file)
@@ -138,9 +138,8 @@ nf_nat_fn(unsigned int hooknum,
                                ret = nf_nat_rule_find(skb, hooknum, in, out,
                                                       ct);
 
-                       if (ret != NF_ACCEPT) {
+                       if (ret != NF_ACCEPT)
                                return ret;
-                       }
                } else
                        pr_debug("Already setup manip %s for ct %p\n",
                                 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
@@ -294,12 +293,12 @@ static int __init nf_nat_standalone_init(void)
 #endif
        ret = nf_nat_rule_init();
        if (ret < 0) {
-               printk("nf_nat_init: can't setup rules.\n");
+               pr_err("nf_nat_init: can't setup rules.\n");
                goto cleanup_decode_session;
        }
        ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
        if (ret < 0) {
-               printk("nf_nat_init: can't register hooks.\n");
+               pr_err("nf_nat_init: can't register hooks.\n");
                goto cleanup_rule_init;
        }
        return ret;
index b096e81500aea2b86ffa6a2e0111d94307edf2a9..7274a43c7a12f08210d09a14bb677450f598e246 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/udp.h>
 
 #include <net/netfilter/nf_nat_helper.h>
index 4f1f337f4337836169f19536de6adf4ba7c23064..3dc9914c1dcee4f77faa26b97e5eb8ec3b4243b6 100644 (file)
@@ -251,6 +251,7 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPSackShiftFallback", LINUX_MIB_SACKSHIFTFALLBACK),
        SNMP_MIB_ITEM("TCPBacklogDrop", LINUX_MIB_TCPBACKLOGDROP),
        SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP),
+       SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
        SNMP_MIB_SENTINEL
 };
 
index cc6f097fbd5fb9a24ce0b80737f6973ee48e3b7a..2c7a1639388aea5e18223cc1ef0cc72312276792 100644 (file)
@@ -290,7 +290,7 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
        /* Charge it to the socket. */
 
-       if (sock_queue_rcv_skb(sk, skb) < 0) {
+       if (ip_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -381,8 +381,8 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length,
                icmp_out_count(net, ((struct icmphdr *)
                        skb_transport_header(skb))->type);
 
-       err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                     dst_output);
+       err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
+                     rt->u.dst.dev, dst_output);
        if (err > 0)
                err = net_xmit_errno(err);
        if (err)
index cb562fdd9b9a5342cee41f2cc642a8b4af9e30ce..560acc677ce485cce87a0161fa709f5e50b8e56f 100644 (file)
@@ -129,7 +129,6 @@ static int ip_rt_gc_elasticity __read_mostly        = 8;
 static int ip_rt_mtu_expires __read_mostly     = 10 * 60 * HZ;
 static int ip_rt_min_pmtu __read_mostly                = 512 + 20 + 20;
 static int ip_rt_min_advmss __read_mostly      = 256;
-static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ;
 static int rt_chain_length_max __read_mostly   = 20;
 
 static struct delayed_work expires_work;
@@ -258,10 +257,9 @@ static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
        (__raw_get_cpu_var(rt_cache_stat).field++)
 
 static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx,
-               int genid)
+                                  int genid)
 {
-       return jhash_3words((__force u32)(__be32)(daddr),
-                           (__force u32)(__be32)(saddr),
+       return jhash_3words((__force u32)daddr, (__force u32)saddr,
                            idx, genid)
                & rt_hash_mask;
 }
@@ -378,12 +376,13 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v)
                struct rtable *r = v;
                int len;
 
-               seq_printf(seq, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t"
-                             "%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
+               seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t"
+                             "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n",
                        r->u.dst.dev ? r->u.dst.dev->name : "*",
-                       (unsigned long)r->rt_dst, (unsigned long)r->rt_gateway,
+                       (__force u32)r->rt_dst,
+                       (__force u32)r->rt_gateway,
                        r->rt_flags, atomic_read(&r->u.dst.__refcnt),
-                       r->u.dst.__use, 0, (unsigned long)r->rt_src,
+                       r->u.dst.__use, 0, (__force u32)r->rt_src,
                        (dst_metric(&r->u.dst, RTAX_ADVMSS) ?
                             (int)dst_metric(&r->u.dst, RTAX_ADVMSS) + 40 : 0),
                        dst_metric(&r->u.dst, RTAX_WINDOW),
@@ -685,18 +684,17 @@ static inline bool rt_caching(const struct net *net)
 static inline bool compare_hash_inputs(const struct flowi *fl1,
                                        const struct flowi *fl2)
 {
-       return (__force u32)(((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
-               (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) |
+       return ((((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
+               ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
                (fl1->iif ^ fl2->iif)) == 0);
 }
 
 static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
 {
-       return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
-               (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) |
+       return (((__force u32)fl1->nl_u.ip4_u.daddr ^ (__force u32)fl2->nl_u.ip4_u.daddr) |
+               ((__force u32)fl1->nl_u.ip4_u.saddr ^ (__force u32)fl2->nl_u.ip4_u.saddr) |
                (fl1->mark ^ fl2->mark) |
-               (*(u16 *)&fl1->nl_u.ip4_u.tos ^
-                *(u16 *)&fl2->nl_u.ip4_u.tos) |
+               (*(u16 *)&fl1->nl_u.ip4_u.tos ^ *(u16 *)&fl2->nl_u.ip4_u.tos) |
                (fl1->oif ^ fl2->oif) |
                (fl1->iif ^ fl2->iif)) == 0;
 }
@@ -919,32 +917,11 @@ void rt_cache_flush_batch(void)
        rt_do_flush(!in_softirq());
 }
 
-/*
- * We change rt_genid and let gc do the cleanup
- */
-static void rt_secret_rebuild(unsigned long __net)
-{
-       struct net *net = (struct net *)__net;
-       rt_cache_invalidate(net);
-       mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval);
-}
-
-static void rt_secret_rebuild_oneshot(struct net *net)
-{
-       del_timer_sync(&net->ipv4.rt_secret_timer);
-       rt_cache_invalidate(net);
-       if (ip_rt_secret_interval)
-               mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval);
-}
-
 static void rt_emergency_hash_rebuild(struct net *net)
 {
-       if (net_ratelimit()) {
+       if (net_ratelimit())
                printk(KERN_WARNING "Route hash chain too long!\n");
-               printk(KERN_WARNING "Adjust your secret_interval!\n");
-       }
-
-       rt_secret_rebuild_oneshot(net);
+       rt_cache_invalidate(net);
 }
 
 /*
@@ -2300,8 +2277,8 @@ martian_source:
        goto e_inval;
 }
 
-int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
-                  u8 tos, struct net_device *dev)
+int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
+                          u8 tos, struct net_device *dev, bool noref)
 {
        struct rtable * rth;
        unsigned        hash;
@@ -2319,18 +2296,23 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        rcu_read_lock();
        for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
             rth = rcu_dereference(rth->u.dst.rt_next)) {
-               if (((rth->fl.fl4_dst ^ daddr) |
-                    (rth->fl.fl4_src ^ saddr) |
+               if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
+                    ((__force u32)rth->fl.fl4_src ^ (__force u32)saddr) |
                     (rth->fl.iif ^ iif) |
                     rth->fl.oif |
                     (rth->fl.fl4_tos ^ tos)) == 0 &&
                    rth->fl.mark == skb->mark &&
                    net_eq(dev_net(rth->u.dst.dev), net) &&
                    !rt_is_expired(rth)) {
-                       dst_use(&rth->u.dst, jiffies);
+                       if (noref) {
+                               dst_use_noref(&rth->u.dst, jiffies);
+                               skb_dst_set_noref(skb, &rth->u.dst);
+                       } else {
+                               dst_use(&rth->u.dst, jiffies);
+                               skb_dst_set(skb, &rth->u.dst);
+                       }
                        RT_CACHE_STAT_INC(in_hit);
                        rcu_read_unlock();
-                       skb_dst_set(skb, &rth->u.dst);
                        return 0;
                }
                RT_CACHE_STAT_INC(in_hlist_search);
@@ -2373,6 +2355,7 @@ skip_cache:
        }
        return ip_route_input_slow(skb, daddr, saddr, tos, dev);
 }
+EXPORT_SYMBOL(ip_route_input_common);
 
 static int __mkroute_output(struct rtable **result,
                            struct fib_result *res,
@@ -3056,7 +3039,7 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
                                continue;
                        if (rt_is_expired(rt))
                                continue;
-                       skb_dst_set(skb, dst_clone(&rt->u.dst));
+                       skb_dst_set_noref(skb, &rt->u.dst);
                        if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid,
                                         cb->nlh->nlmsg_seq, RTM_NEWROUTE,
                                         1, NLM_F_MULTI) <= 0) {
@@ -3102,48 +3085,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
        return -EINVAL;
 }
 
-static void rt_secret_reschedule(int old)
-{
-       struct net *net;
-       int new = ip_rt_secret_interval;
-       int diff = new - old;
-
-       if (!diff)
-               return;
-
-       rtnl_lock();
-       for_each_net(net) {
-               int deleted = del_timer_sync(&net->ipv4.rt_secret_timer);
-               long time;
-
-               if (!new)
-                       continue;
-
-               if (deleted) {
-                       time = net->ipv4.rt_secret_timer.expires - jiffies;
-
-                       if (time <= 0 || (time += diff) <= 0)
-                               time = 0;
-               } else
-                       time = new;
-
-               mod_timer(&net->ipv4.rt_secret_timer, jiffies + time);
-       }
-       rtnl_unlock();
-}
-
-static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
-                                         void __user *buffer, size_t *lenp,
-                                         loff_t *ppos)
-{
-       int old = ip_rt_secret_interval;
-       int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
-
-       rt_secret_reschedule(old);
-
-       return ret;
-}
-
 static ctl_table ipv4_route_table[] = {
        {
                .procname       = "gc_thresh",
@@ -3252,13 +3193,6 @@ static ctl_table ipv4_route_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
-       {
-               .procname       = "secret_interval",
-               .data           = &ip_rt_secret_interval,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = ipv4_sysctl_rt_secret_interval,
-       },
        { }
 };
 
@@ -3337,34 +3271,15 @@ static __net_initdata struct pernet_operations sysctl_route_ops = {
 };
 #endif
 
-
-static __net_init int rt_secret_timer_init(struct net *net)
+static __net_init int rt_genid_init(struct net *net)
 {
-       atomic_set(&net->ipv4.rt_genid,
-                       (int) ((num_physpages ^ (num_physpages>>8)) ^
-                       (jiffies ^ (jiffies >> 7))));
-
-       net->ipv4.rt_secret_timer.function = rt_secret_rebuild;
-       net->ipv4.rt_secret_timer.data = (unsigned long)net;
-       init_timer_deferrable(&net->ipv4.rt_secret_timer);
-
-       if (ip_rt_secret_interval) {
-               net->ipv4.rt_secret_timer.expires =
-                       jiffies + net_random() % ip_rt_secret_interval +
-                       ip_rt_secret_interval;
-               add_timer(&net->ipv4.rt_secret_timer);
-       }
+       get_random_bytes(&net->ipv4.rt_genid,
+                        sizeof(net->ipv4.rt_genid));
        return 0;
 }
 
-static __net_exit void rt_secret_timer_exit(struct net *net)
-{
-       del_timer_sync(&net->ipv4.rt_secret_timer);
-}
-
-static __net_initdata struct pernet_operations rt_secret_timer_ops = {
-       .init = rt_secret_timer_init,
-       .exit = rt_secret_timer_exit,
+static __net_initdata struct pernet_operations rt_genid_ops = {
+       .init = rt_genid_init,
 };
 
 
@@ -3425,9 +3340,6 @@ int __init ip_rt_init(void)
        schedule_delayed_work(&expires_work,
                net_random() % ip_rt_gc_interval + ip_rt_gc_interval);
 
-       if (register_pernet_subsys(&rt_secret_timer_ops))
-               printk(KERN_ERR "Unable to setup rt_secret_timer\n");
-
        if (ip_rt_proc_init())
                printk(KERN_ERR "Unable to create route proc files\n");
 #ifdef CONFIG_XFRM
@@ -3439,6 +3351,7 @@ int __init ip_rt_init(void)
 #ifdef CONFIG_SYSCTL
        register_pernet_subsys(&sysctl_route_ops);
 #endif
+       register_pernet_subsys(&rt_genid_ops);
        return rc;
 }
 
@@ -3454,5 +3367,4 @@ void __init ip_static_sysctl_init(void)
 #endif
 
 EXPORT_SYMBOL(__ip_select_ident);
-EXPORT_SYMBOL(ip_route_input);
 EXPORT_SYMBOL(ip_route_output_key);
index 1cd5c15174b8a0f286fd9d7a92100841dd341ecd..d96c1da4b17cf97790bb2a426abbe5eb4582356d 100644 (file)
@@ -299,6 +299,13 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = ipv4_local_port_range,
        },
+       {
+               .procname       = "ip_local_reserved_ports",
+               .data           = NULL, /* initialized in sysctl_ipv4_init */
+               .maxlen         = 65536,
+               .mode           = 0644,
+               .proc_handler   = proc_do_large_bitmap,
+       },
 #ifdef CONFIG_IP_MULTICAST
        {
                .procname       = "igmp_max_memberships",
@@ -736,6 +743,16 @@ static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
 static __init int sysctl_ipv4_init(void)
 {
        struct ctl_table_header *hdr;
+       struct ctl_table *i;
+
+       for (i = ipv4_table; i->procname; i++) {
+               if (strcmp(i->procname, "ip_local_reserved_ports") == 0) {
+                       i->data = sysctl_local_reserved_ports;
+                       break;
+               }
+       }
+       if (!i->procname)
+               return -EINVAL;
 
        hdr = register_sysctl_paths(net_ipv4_ctl_path, ipv4_table);
        if (hdr == NULL)
index 296150b2a62f11ac127177b6cdfaf73d1dfc4c6a..6596b4feeddc7879fc020606f53dabdc8608f3e8 100644 (file)
@@ -378,7 +378,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct sock *sk = sock->sk;
        struct tcp_sock *tp = tcp_sk(sk);
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        if (sk->sk_state == TCP_LISTEN)
                return inet_csk_listen_poll(sk);
 
@@ -2215,7 +2215,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
        default:
                /* fallthru */
                break;
-       };
+       }
 
        if (optlen < sizeof(int))
                return -EINVAL;
@@ -2298,7 +2298,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                        if (sock_flag(sk, SOCK_KEEPOPEN) &&
                            !((1 << sk->sk_state) &
                              (TCPF_CLOSE | TCPF_LISTEN))) {
-                               __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp;
+                               u32 elapsed = keepalive_time_elapsed(tp);
                                if (tp->keepalive_time > elapsed)
                                        elapsed = tp->keepalive_time - elapsed;
                                else
@@ -2721,7 +2721,7 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
        struct tcphdr *th2;
        unsigned int len;
        unsigned int thlen;
-       unsigned int flags;
+       __be32 flags;
        unsigned int mss = 1;
        unsigned int hlen;
        unsigned int off;
@@ -2771,10 +2771,10 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb)
 
 found:
        flush = NAPI_GRO_CB(p)->flush;
-       flush |= flags & TCP_FLAG_CWR;
-       flush |= (flags ^ tcp_flag_word(th2)) &
-                 ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH);
-       flush |= th->ack_seq ^ th2->ack_seq;
+       flush |= (__force int)(flags & TCP_FLAG_CWR);
+       flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
+                 ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH));
+       flush |= (__force int)(th->ack_seq ^ th2->ack_seq);
        for (i = sizeof(*th); i < thlen; i += 4)
                flush |= *(u32 *)((u8 *)th + i) ^
                         *(u32 *)((u8 *)th2 + i);
@@ -2795,8 +2795,9 @@ found:
 
 out_check_final:
        flush = len < mss;
-       flush |= flags & (TCP_FLAG_URG | TCP_FLAG_PSH | TCP_FLAG_RST |
-                         TCP_FLAG_SYN | TCP_FLAG_FIN);
+       flush |= (__force int)(flags & (TCP_FLAG_URG | TCP_FLAG_PSH |
+                                       TCP_FLAG_RST | TCP_FLAG_SYN |
+                                       TCP_FLAG_FIN));
 
        if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
                pp = head;
index f240f57b2199e0e7e801212742b152dae2060608..3e6dafcb1071663c2e0590da7c379b6b324bbe0f 100644 (file)
@@ -3710,7 +3710,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
        }
 
        if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
-               dst_confirm(sk->sk_dst_cache);
+               dst_confirm(__sk_dst_get(sk));
 
        return 1;
 
@@ -3845,12 +3845,13 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
                                        /* 16-bit multiple */
                                        opt_rx->cookie_plus = opsize;
                                        *hvpp = ptr;
+                                       break;
                                default:
                                        /* ignore option */
                                        break;
-                               };
+                               }
                                break;
-                       };
+                       }
 
                        ptr += opsize-2;
                        length -= opsize;
@@ -4319,7 +4320,7 @@ static void tcp_ofo_queue(struct sock *sk)
                }
 
                if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) {
-                       SOCK_DEBUG(sk, "ofo packet was already received \n");
+                       SOCK_DEBUG(sk, "ofo packet was already received\n");
                        __skb_unlink(skb, &tp->out_of_order_queue);
                        __kfree_skb(skb);
                        continue;
@@ -4367,6 +4368,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
        if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq)
                goto drop;
 
+       skb_dst_drop(skb);
        __skb_pull(skb, th->doff * 4);
 
        TCP_ECN_accept_cwr(tp, skb);
@@ -5833,7 +5835,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                        if (tp->snd_una == tp->write_seq) {
                                tcp_set_state(sk, TCP_FIN_WAIT2);
                                sk->sk_shutdown |= SEND_SHUTDOWN;
-                               dst_confirm(sk->sk_dst_cache);
+                               dst_confirm(__sk_dst_get(sk));
 
                                if (!sock_flag(sk, SOCK_DEAD))
                                        /* Wake up lingering close() */
index 3c23e70885f41b2eb486731b708867b2000c408e..202cf09c4cd4be9f8a556d2740a51ca4bba96e56 100644 (file)
@@ -519,26 +519,31 @@ out:
        sock_put(sk);
 }
 
-/* This routine computes an IPv4 TCP checksum. */
-void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
+static void __tcp_v4_send_check(struct sk_buff *skb,
+                               __be32 saddr, __be32 daddr)
 {
-       struct inet_sock *inet = inet_sk(sk);
        struct tcphdr *th = tcp_hdr(skb);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               th->check = ~tcp_v4_check(len, inet->inet_saddr,
-                                         inet->inet_daddr, 0);
+               th->check = ~tcp_v4_check(skb->len, saddr, daddr, 0);
                skb->csum_start = skb_transport_header(skb) - skb->head;
                skb->csum_offset = offsetof(struct tcphdr, check);
        } else {
-               th->check = tcp_v4_check(len, inet->inet_saddr,
-                                        inet->inet_daddr,
+               th->check = tcp_v4_check(skb->len, saddr, daddr,
                                         csum_partial(th,
                                                      th->doff << 2,
                                                      skb->csum));
        }
 }
 
+/* This routine computes an IPv4 TCP checksum. */
+void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb)
+{
+       struct inet_sock *inet = inet_sk(sk);
+
+       __tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr);
+}
+
 int tcp_v4_gso_send_check(struct sk_buff *skb)
 {
        const struct iphdr *iph;
@@ -551,10 +556,8 @@ int tcp_v4_gso_send_check(struct sk_buff *skb)
        th = tcp_hdr(skb);
 
        th->check = 0;
-       th->check = ~tcp_v4_check(skb->len, iph->saddr, iph->daddr, 0);
-       skb->csum_start = skb_transport_header(skb) - skb->head;
-       skb->csum_offset = offsetof(struct tcphdr, check);
        skb->ip_summed = CHECKSUM_PARTIAL;
+       __tcp_v4_send_check(skb, iph->saddr, iph->daddr);
        return 0;
 }
 
@@ -763,13 +766,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
        skb = tcp_make_synack(sk, dst, req, rvp);
 
        if (skb) {
-               struct tcphdr *th = tcp_hdr(skb);
-
-               th->check = tcp_v4_check(skb->len,
-                                        ireq->loc_addr,
-                                        ireq->rmt_addr,
-                                        csum_partial(th, skb->len,
-                                                     skb->csum));
+               __tcp_v4_send_check(skb, ireq->loc_addr, ireq->rmt_addr);
 
                err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
                                            ireq->rmt_addr,
@@ -894,7 +891,7 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr,
                                kfree(newkey);
                                return -ENOMEM;
                        }
-                       sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+                       sk_nocaps_add(sk, NETIF_F_GSO_MASK);
                }
                if (tcp_alloc_md5sig_pool(sk) == NULL) {
                        kfree(newkey);
@@ -1024,7 +1021,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
                        return -EINVAL;
 
                tp->md5sig_info = p;
-               sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+               sk_nocaps_add(sk, NETIF_F_GSO_MASK);
        }
 
        newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, sk->sk_allocation);
@@ -1289,8 +1286,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                        goto drop_and_release;
 
                /* Secret recipe starts with IP addresses */
-               *mess++ ^= daddr;
-               *mess++ ^= saddr;
+               *mess++ ^= (__force u32)daddr;
+               *mess++ ^= (__force u32)saddr;
 
                /* plus variable length Initiator Cookie */
                c = (u8 *)mess;
@@ -1465,7 +1462,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                if (newkey != NULL)
                        tcp_v4_md5_do_add(newsk, newinet->inet_daddr,
                                          newkey, key->keylen);
-               newsk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+               sk_nocaps_add(newsk, NETIF_F_GSO_MASK);
        }
 #endif
 
@@ -1675,6 +1672,8 @@ process:
 
        skb->dev = NULL;
 
+       sock_rps_save_rxhash(sk, skb->rxhash);
+
        bh_lock_sock_nested(sk);
        ret = 0;
        if (!sock_owned_by_user(sk)) {
index 5fabff9ac6d6b42596fcc96727598e087b455ceb..794c2e122a41f2fafc08e60282f32a5485c8e87b 100644 (file)
@@ -672,6 +672,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
        if (req->retrans < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
            TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
                inet_rsk(req)->acked = 1;
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP);
                return NULL;
        }
 
index 0dda86e72ad8b6d60e24d62128ccadf7ae65a0fe..b4ed957f201a6f3f2ebf8d5564edec567b6435a6 100644 (file)
@@ -350,6 +350,7 @@ static inline void TCP_ECN_send(struct sock *sk, struct sk_buff *skb,
  */
 static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
 {
+       skb->ip_summed = CHECKSUM_PARTIAL;
        skb->csum = 0;
 
        TCP_SKB_CB(skb)->flags = flags;
@@ -667,7 +668,6 @@ static unsigned tcp_synack_options(struct sock *sk,
        u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ?
                         xvp->cookie_plus :
                         0;
-       bool doing_ts = ireq->tstamp_ok;
 
 #ifdef CONFIG_TCP_MD5SIG
        *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
@@ -680,7 +680,7 @@ static unsigned tcp_synack_options(struct sock *sk,
                 * rather than TS in order to fit in better with old,
                 * buggy kernels, but that was deemed to be unnecessary.
                 */
-               doing_ts &= !ireq->sack_ok;
+               ireq->tstamp_ok &= !ireq->sack_ok;
        }
 #else
        *md5 = NULL;
@@ -695,7 +695,7 @@ static unsigned tcp_synack_options(struct sock *sk,
                opts->options |= OPTION_WSCALE;
                remaining -= TCPOLEN_WSCALE_ALIGNED;
        }
-       if (likely(doing_ts)) {
+       if (likely(ireq->tstamp_ok)) {
                opts->options |= OPTION_TS;
                opts->tsval = TCP_SKB_CB(skb)->when;
                opts->tsecr = req->ts_recent;
@@ -703,7 +703,7 @@ static unsigned tcp_synack_options(struct sock *sk,
        }
        if (likely(ireq->sack_ok)) {
                opts->options |= OPTION_SACK_ADVERTISE;
-               if (unlikely(!doing_ts))
+               if (unlikely(!ireq->tstamp_ok))
                        remaining -= TCPOLEN_SACKPERM_ALIGNED;
        }
 
@@ -711,7 +711,7 @@ static unsigned tcp_synack_options(struct sock *sk,
         * If the <SYN> options fit, the same options should fit now!
         */
        if (*md5 == NULL &&
-           doing_ts &&
+           ireq->tstamp_ok &&
            cookie_plus > TCPOLEN_COOKIE_BASE) {
                int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */
 
@@ -860,7 +860,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                        th->urg_ptr = htons(tp->snd_up - tcb->seq);
                        th->urg = 1;
                } else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) {
-                       th->urg_ptr = 0xFFFF;
+                       th->urg_ptr = htons(0xFFFF);
                        th->urg = 1;
                }
        }
@@ -872,13 +872,13 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
 #ifdef CONFIG_TCP_MD5SIG
        /* Calculate the MD5 hash, as we have all we need now */
        if (md5) {
-               sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+               sk_nocaps_add(sk, NETIF_F_GSO_MASK);
                tp->af_specific->calc_md5_hash(opts.hash_location,
                                               md5, sk, NULL, skb);
        }
 #endif
 
-       icsk->icsk_af_ops->send_check(sk, skb->len, skb);
+       icsk->icsk_af_ops->send_check(sk, skb);
 
        if (likely(tcb->flags & TCPCB_FLAG_ACK))
                tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
@@ -887,9 +887,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                tcp_event_data_sent(tp, skb, sk);
 
        if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
-               TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
+               TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS,
+                             tcp_skb_pcount(skb));
 
-       err = icsk->icsk_af_ops->queue_xmit(skb, 0);
+       err = icsk->icsk_af_ops->queue_xmit(skb);
        if (likely(err <= 0))
                return err;
 
@@ -2484,7 +2485,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
                        *tail-- ^= TCP_SKB_CB(skb)->seq + 1;
 
                        /* recommended */
-                       *tail-- ^= ((th->dest << 16) | th->source);
+                       *tail-- ^= (((__force u32)th->dest << 16) | (__force u32)th->source);
                        *tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */
 
                        sha_transform((__u32 *)&xvp->cookie_bakery[0],
@@ -2502,7 +2503,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        th->window = htons(min(req->rcv_wnd, 65535U));
        tcp_options_write((__be32 *)(th + 1), tp, &opts);
        th->doff = (tcp_header_size >> 2);
-       TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
+       TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, tcp_skb_pcount(skb));
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Okay, we have all we need - do the md5 hash if needed */
index 8a0ab2977f1fd8be8c4bf9f27d21efa9c214418e..440a5c6004f6ac8d1b2d8404d641d0a174b241b4 100644 (file)
@@ -172,14 +172,14 @@ static int tcp_write_timeout(struct sock *sk)
 
        if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
                if (icsk->icsk_retransmits)
-                       dst_negative_advice(&sk->sk_dst_cache, sk);
+                       dst_negative_advice(sk);
                retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
        } else {
                if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
                        /* Black hole detection */
                        tcp_mtu_probing(icsk, sk);
 
-                       dst_negative_advice(&sk->sk_dst_cache, sk);
+                       dst_negative_advice(sk);
                }
 
                retry_until = sysctl_tcp_retries2;
@@ -517,7 +517,7 @@ static void tcp_keepalive_timer (unsigned long data)
        struct sock *sk = (struct sock *) data;
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
-       __u32 elapsed;
+       u32 elapsed;
 
        /* Only process if socket is not in use. */
        bh_lock_sock(sk);
@@ -554,7 +554,7 @@ static void tcp_keepalive_timer (unsigned long data)
        if (tp->packets_out || tcp_send_head(sk))
                goto resched;
 
-       elapsed = tcp_time_stamp - tp->rcv_tstamp;
+       elapsed = keepalive_time_elapsed(tp);
 
        if (elapsed >= keepalive_time_when(tp)) {
                if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
index c36522a0f1130005f96bd11fc385c42d949c6e80..9de6a698f91d6ed861d8dd42c803a49222db7105 100644 (file)
@@ -233,7 +233,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
                         */
                        do {
                                if (low <= snum && snum <= high &&
-                                   !test_bit(snum >> udptable->log, bitmap))
+                                   !test_bit(snum >> udptable->log, bitmap) &&
+                                   !inet_is_reserved_local_port(snum))
                                        goto found;
                                snum += rand;
                        } while (snum != first);
@@ -307,13 +308,13 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr,
                                       unsigned int port)
 {
-       return jhash_1word(saddr, net_hash_mix(net)) ^ port;
+       return jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port;
 }
 
 int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
        unsigned int hash2_nulladdr =
-               udp4_portaddr_hash(sock_net(sk), INADDR_ANY, snum);
+               udp4_portaddr_hash(sock_net(sk), htonl(INADDR_ANY), snum);
        unsigned int hash2_partial =
                udp4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0);
 
@@ -466,14 +467,14 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
                                          daddr, hnum, dif,
                                          hslot2, slot2);
                if (!result) {
-                       hash2 = udp4_portaddr_hash(net, INADDR_ANY, hnum);
+                       hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum);
                        slot2 = hash2 & udptable->mask;
                        hslot2 = &udptable->hash2[slot2];
                        if (hslot->count < hslot2->count)
                                goto begin;
 
                        result = udp4_lib_lookup2(net, saddr, sport,
-                                                 INADDR_ANY, hnum, dif,
+                                                 htonl(INADDR_ANY), hnum, dif,
                                                  hslot2, slot2);
                }
                rcu_read_unlock();
@@ -1062,10 +1063,10 @@ static unsigned int first_packet_length(struct sock *sk)
        spin_unlock_bh(&rcvq->lock);
 
        if (!skb_queue_empty(&list_kill)) {
-               lock_sock(sk);
+               lock_sock_bh(sk);
                __skb_queue_purge(&list_kill);
                sk_mem_reclaim_partial(sk);
-               release_sock(sk);
+               unlock_sock_bh(sk);
        }
        return res;
 }
@@ -1196,10 +1197,10 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock(sk);
+       lock_sock_bh(sk);
        if (!skb_kill_datagram(sk, skb, flags))
                UDP_INC_STATS_USER(sock_net(sk), UDP_MIB_INERRORS, is_udplite);
-       release_sock(sk);
+       unlock_sock_bh(sk);
 
        if (noblock)
                return -EAGAIN;
@@ -1217,6 +1218,7 @@ int udp_disconnect(struct sock *sk, int flags)
        sk->sk_state = TCP_CLOSE;
        inet->inet_daddr = 0;
        inet->inet_dport = 0;
+       sock_rps_save_rxhash(sk, 0);
        sk->sk_bound_dev_if = 0;
        if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK))
                inet_reset_saddr(sk);
@@ -1258,8 +1260,12 @@ EXPORT_SYMBOL(udp_lib_unhash);
 
 static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-       int rc = sock_queue_rcv_skb(sk, skb);
+       int rc;
+
+       if (inet_sk(sk)->inet_daddr)
+               sock_rps_save_rxhash(sk, skb->rxhash);
 
+       rc = ip_queue_rcv_skb(sk, skb);
        if (rc < 0) {
                int is_udplite = IS_UDPLITE(sk);
 
@@ -1367,6 +1373,10 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
                        goto drop;
        }
 
+
+       if (sk_rcvqueues_full(sk, skb))
+               goto drop;
+
        rc = 0;
 
        bh_lock_sock(sk);
@@ -1615,9 +1625,9 @@ int udp_rcv(struct sk_buff *skb)
 
 void udp_destroy_sock(struct sock *sk)
 {
-       lock_sock(sk);
+       lock_sock_bh(sk);
        udp_flush_pending_frames(sk);
-       release_sock(sk);
+       unlock_sock_bh(sk);
 }
 
 /*
index c791bb63203f2895a629d26b4734e152d17295cd..ad8fbb871aa068cc9d299aa15580b06f45fc7187 100644 (file)
@@ -27,8 +27,8 @@ static inline int xfrm4_rcv_encap_finish(struct sk_buff *skb)
        if (skb_dst(skb) == NULL) {
                const struct iphdr *iph = ip_hdr(skb);
 
-               if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
-                                  skb->dev))
+               if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
+                                        iph->tos, skb->dev))
                        goto drop;
        }
        return dst_input(skb);
@@ -61,7 +61,7 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async)
        iph->tot_len = htons(skb->len);
        ip_send_check(iph);
 
-       NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
+       NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
                xfrm4_rcv_encap_finish);
        return 0;
 }
index c908bd99bcbae11e2f0c18b37363f8382d6a3544..571aa96a175c956fb81728030441309286b938c9 100644 (file)
@@ -86,7 +86,7 @@ static int xfrm4_output_finish(struct sk_buff *skb)
 
 int xfrm4_output(struct sk_buff *skb)
 {
-       return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb,
+       return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb,
                            NULL, skb_dst(skb)->dev, xfrm4_output_finish,
                            !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
index e4a1483fba7776b3df5a9008967f5dc5a7c4b558..1705476670ef7a05e83d91cb7072e951302a30e2 100644 (file)
@@ -59,27 +59,6 @@ static int xfrm4_get_saddr(struct net *net,
        return 0;
 }
 
-static struct dst_entry *
-__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
-{
-       struct dst_entry *dst;
-
-       read_lock_bh(&policy->lock);
-       for (dst = policy->bundles; dst; dst = dst->next) {
-               struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
-               if (xdst->u.rt.fl.oif == fl->oif &&     /*XXX*/
-                   xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
-                   xdst->u.rt.fl.fl4_src == fl->fl4_src &&
-                   xdst->u.rt.fl.fl4_tos == fl->fl4_tos &&
-                   xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) {
-                       dst_clone(dst);
-                       break;
-               }
-       }
-       read_unlock_bh(&policy->lock);
-       return dst;
-}
-
 static int xfrm4_get_tos(struct flowi *fl)
 {
        return fl->fl4_tos;
@@ -259,7 +238,6 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
        .dst_ops =              &xfrm4_dst_ops,
        .dst_lookup =           xfrm4_dst_lookup,
        .get_saddr =            xfrm4_get_saddr,
-       .find_bundle =          __xfrm4_find_bundle,
        .decode_session =       _decode_session4,
        .get_tos =              xfrm4_get_tos,
        .init_path =            xfrm4_init_path,
index a578096152ab8acf46f7fdb997403c7be9ebd5ef..36d7437ac054f221b2ddb09c68c0e9fc92ad70dc 100644 (file)
@@ -229,6 +229,20 @@ config IPV6_MROUTE
          Experimental support for IPv6 multicast forwarding.
          If unsure, say N.
 
+config IPV6_MROUTE_MULTIPLE_TABLES
+       bool "IPv6: multicast policy routing"
+       depends on IPV6_MROUTE
+       select FIB_RULES
+       help
+         Normally, a multicast router runs a userspace daemon and decides
+         what to do with a multicast packet based on the source and
+         destination addresses. If you say Y here, the multicast router
+         will also be able to take interfaces and packet marks into
+         account and run multiple instances of userspace daemons
+         simultaneously, each one handling a single table.
+
+         If unsure, say N.
+
 config IPV6_PIMSM_V2
        bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)"
        depends on IPV6_MROUTE
index 413054f02aab3dbfe5773f9a81b1589cd21d5027..e1a698df5706a9bcff5889e4b734ad66d6dbfb55 100644 (file)
@@ -82,7 +82,7 @@
 #include <linux/random.h>
 #endif
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <linux/proc_fs.h>
 #endif
 
 #define        INFINITY_LIFE_TIME      0xFFFFFFFF
-#define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b)))
+#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
+
+#define ADDRCONF_TIMER_FUZZ_MINUS      (HZ > 50 ? HZ/50 : 1)
+#define ADDRCONF_TIMER_FUZZ            (HZ / 4)
+#define ADDRCONF_TIMER_FUZZ_MAX                (HZ)
 
 #ifdef CONFIG_SYSCTL
 static void addrconf_sysctl_register(struct inet6_dev *idev);
@@ -127,8 +131,8 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
 /*
  *     Configured unicast address hash table
  */
-static struct inet6_ifaddr             *inet6_addr_lst[IN6_ADDR_HSIZE];
-static DEFINE_RWLOCK(addrconf_hash_lock);
+static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
+static DEFINE_SPINLOCK(addrconf_hash_lock);
 
 static void addrconf_verify(unsigned long);
 
@@ -138,8 +142,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock);
 static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
 
-static void addrconf_bonding_change(struct net_device *dev,
-                                   unsigned long event);
+static void addrconf_type_change(struct net_device *dev,
+                                unsigned long event);
 static int addrconf_ifdown(struct net_device *dev, int how);
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
@@ -152,8 +156,8 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
 
 static void inet6_prefix_notify(int event, struct inet6_dev *idev,
                                struct prefix_info *pinfo);
-static int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
-                             struct net_device *dev);
+static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
+                              struct net_device *dev);
 
 static ATOMIC_NOTIFIER_HEAD(inet6addr_chain);
 
@@ -250,8 +254,7 @@ static void addrconf_del_timer(struct inet6_ifaddr *ifp)
                __in6_ifa_put(ifp);
 }
 
-enum addrconf_timer_t
-{
+enum addrconf_timer_t {
        AC_NONE,
        AC_DAD,
        AC_RS,
@@ -271,7 +274,8 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
        case AC_RS:
                ifp->timer.function = addrconf_rs_timer;
                break;
-       default:;
+       default:
+               break;
        }
        ifp->timer.expires = jiffies + when;
        add_timer(&ifp->timer);
@@ -318,7 +322,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
 {
        struct net_device *dev = idev->dev;
 
-       WARN_ON(idev->addr_list != NULL);
+       WARN_ON(!list_empty(&idev->addr_list));
        WARN_ON(idev->mc_list != NULL);
 
 #ifdef NET_REFCNT_DEBUG
@@ -326,7 +330,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
 #endif
        dev_put(dev);
        if (!idev->dead) {
-               printk("Freeing alive inet6 device %p\n", idev);
+               pr_warning("Freeing alive inet6 device %p\n", idev);
                return;
        }
        snmp6_free_dev(idev);
@@ -351,6 +355,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 
        rwlock_init(&ndev->lock);
        ndev->dev = dev;
+       INIT_LIST_HEAD(&ndev->addr_list);
+
        memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
        ndev->cnf.mtu6 = dev->mtu;
        ndev->cnf.sysctl = NULL;
@@ -402,6 +408,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 #endif
 
 #ifdef CONFIG_IPV6_PRIVACY
+       INIT_LIST_HEAD(&ndev->tempaddr_list);
        setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
        if ((dev->flags&IFF_LOOPBACK) ||
            dev->type == ARPHRD_TUNNEL ||
@@ -439,8 +446,10 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev)
 
        ASSERT_RTNL();
 
-       if ((idev = __in6_dev_get(dev)) == NULL) {
-               if ((idev = ipv6_add_dev(dev)) == NULL)
+       idev = __in6_dev_get(dev);
+       if (!idev) {
+               idev = ipv6_add_dev(dev);
+               if (!idev)
                        return NULL;
        }
 
@@ -466,7 +475,8 @@ static void dev_forward_change(struct inet6_dev *idev)
                else
                        ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
        }
-       for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+
+       list_for_each_entry(ifa, &idev->addr_list, if_list) {
                if (ifa->flags&IFA_F_TENTATIVE)
                        continue;
                if (idev->cnf.forwarding)
@@ -523,12 +533,16 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
 }
 #endif
 
-/* Nobody refers to this ifaddr, destroy it */
+static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head)
+{
+       struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu);
+       kfree(ifp);
+}
 
+/* Nobody refers to this ifaddr, destroy it */
 void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
 {
-       WARN_ON(ifp->if_next != NULL);
-       WARN_ON(ifp->lst_next != NULL);
+       WARN_ON(!hlist_unhashed(&ifp->addr_lst));
 
 #ifdef NET_REFCNT_DEBUG
        printk(KERN_DEBUG "inet6_ifa_finish_destroy\n");
@@ -537,54 +551,46 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
        in6_dev_put(ifp->idev);
 
        if (del_timer(&ifp->timer))
-               printk("Timer is still running, when freeing ifa=%p\n", ifp);
+               pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
 
-       if (!ifp->dead) {
-               printk("Freeing alive inet6 address %p\n", ifp);
+       if (ifp->state != INET6_IFADDR_STATE_DEAD) {
+               pr_warning("Freeing alive inet6 address %p\n", ifp);
                return;
        }
        dst_release(&ifp->rt->u.dst);
 
-       kfree(ifp);
+       call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
 }
 
 static void
 ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
 {
-       struct inet6_ifaddr *ifa, **ifap;
+       struct list_head *p;
        int ifp_scope = ipv6_addr_src_scope(&ifp->addr);
 
        /*
         * Each device address list is sorted in order of scope -
         * global before linklocal.
         */
-       for (ifap = &idev->addr_list; (ifa = *ifap) != NULL;
-            ifap = &ifa->if_next) {
+       list_for_each(p, &idev->addr_list) {
+               struct inet6_ifaddr *ifa
+                       = list_entry(p, struct inet6_ifaddr, if_list);
                if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))
                        break;
        }
 
-       ifp->if_next = *ifap;
-       *ifap = ifp;
+       list_add_tail(&ifp->if_list, p);
 }
 
-/*
- *     Hash function taken from net_alias.c
- */
-static u8 ipv6_addr_hash(const struct in6_addr *addr)
+static u32 ipv6_addr_hash(const struct in6_addr *addr)
 {
-       __u32 word;
-
        /*
         * We perform the hash function over the last 64 bits of the address
         * This will include the IEEE address token on links that support it.
         */
-
-       word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]);
-       word ^= (word >> 16);
-       word ^= (word >> 8);
-
-       return ((word ^ (word >> 4)) & 0x0f);
+       return jhash_2words((__force u32)addr->s6_addr32[2],
+                           (__force u32)addr->s6_addr32[3], 0)
+               & (IN6_ADDR_HSIZE - 1);
 }
 
 /* On success it returns ifp with increased reference count */
@@ -595,7 +601,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
-       int hash;
+       unsigned int hash;
        int err = 0;
        int addr_type = ipv6_addr_type(addr);
 
@@ -616,7 +622,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out2;
        }
 
-       write_lock(&addrconf_hash_lock);
+       spin_lock(&addrconf_hash_lock);
 
        /* Ignore adding duplicate addresses on an interface */
        if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
@@ -642,7 +648,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ipv6_addr_copy(&ifa->addr, addr);
 
        spin_lock_init(&ifa->lock);
+       spin_lock_init(&ifa->state_lock);
        init_timer(&ifa->timer);
+       INIT_HLIST_NODE(&ifa->addr_lst);
        ifa->timer.data = (unsigned long) ifa;
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
@@ -669,10 +677,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        /* Add to big hash table */
        hash = ipv6_addr_hash(addr);
 
-       ifa->lst_next = inet6_addr_lst[hash];
-       inet6_addr_lst[hash] = ifa;
-       in6_ifa_hold(ifa);
-       write_unlock(&addrconf_hash_lock);
+       hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]);
+       spin_unlock(&addrconf_hash_lock);
 
        write_lock(&idev->lock);
        /* Add to inet6_dev unicast addr list. */
@@ -680,8 +686,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 
 #ifdef CONFIG_IPV6_PRIVACY
        if (ifa->flags&IFA_F_TEMPORARY) {
-               ifa->tmp_next = idev->tempaddr_list;
-               idev->tempaddr_list = ifa;
+               list_add(&ifa->tmp_list, &idev->tempaddr_list);
                in6_ifa_hold(ifa);
        }
 #endif
@@ -700,7 +705,7 @@ out2:
 
        return ifa;
 out:
-       write_unlock(&addrconf_hash_lock);
+       spin_unlock(&addrconf_hash_lock);
        goto out2;
 }
 
@@ -708,52 +713,44 @@ out:
 
 static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 {
-       struct inet6_ifaddr *ifa, **ifap;
+       struct inet6_ifaddr *ifa, *ifn;
        struct inet6_dev *idev = ifp->idev;
+       int state;
        int hash;
        int deleted = 0, onlink = 0;
        unsigned long expires = jiffies;
 
        hash = ipv6_addr_hash(&ifp->addr);
 
-       ifp->dead = 1;
+       spin_lock_bh(&ifp->state_lock);
+       state = ifp->state;
+       ifp->state = INET6_IFADDR_STATE_DEAD;
+       spin_unlock_bh(&ifp->state_lock);
 
-       write_lock_bh(&addrconf_hash_lock);
-       for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL;
-            ifap = &ifa->lst_next) {
-               if (ifa == ifp) {
-                       *ifap = ifa->lst_next;
-                       __in6_ifa_put(ifp);
-                       ifa->lst_next = NULL;
-                       break;
-               }
-       }
-       write_unlock_bh(&addrconf_hash_lock);
+       if (state == INET6_IFADDR_STATE_DEAD)
+               goto out;
+
+       spin_lock_bh(&addrconf_hash_lock);
+       hlist_del_init_rcu(&ifp->addr_lst);
+       spin_unlock_bh(&addrconf_hash_lock);
 
        write_lock_bh(&idev->lock);
 #ifdef CONFIG_IPV6_PRIVACY
        if (ifp->flags&IFA_F_TEMPORARY) {
-               for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL;
-                    ifap = &ifa->tmp_next) {
-                       if (ifa == ifp) {
-                               *ifap = ifa->tmp_next;
-                               if (ifp->ifpub) {
-                                       in6_ifa_put(ifp->ifpub);
-                                       ifp->ifpub = NULL;
-                               }
-                               __in6_ifa_put(ifp);
-                               ifa->tmp_next = NULL;
-                               break;
-                       }
+               list_del(&ifp->tmp_list);
+               if (ifp->ifpub) {
+                       in6_ifa_put(ifp->ifpub);
+                       ifp->ifpub = NULL;
                }
+               __in6_ifa_put(ifp);
        }
 #endif
 
-       for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) {
+       list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) {
                if (ifa == ifp) {
-                       *ifap = ifa->if_next;
+                       list_del_init(&ifp->if_list);
                        __in6_ifa_put(ifp);
-                       ifa->if_next = NULL;
+
                        if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
                                break;
                        deleted = 1;
@@ -786,7 +783,6 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
                                }
                        }
                }
-               ifap = &ifa->if_next;
        }
        write_unlock_bh(&idev->lock);
 
@@ -830,6 +826,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
                dst_release(&rt->u.dst);
        }
 
+out:
        in6_ifa_put(ifp);
 }
 
@@ -1165,7 +1162,7 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
                        continue;
 
                read_lock_bh(&idev->lock);
-               for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) {
+               list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
                        int i;
 
                        /*
@@ -1243,7 +1240,6 @@ try_nextdev:
        in6_ifa_put(hiscore->ifa);
        return 0;
 }
-
 EXPORT_SYMBOL(ipv6_dev_get_saddr);
 
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
@@ -1253,12 +1249,14 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
        int err = -EADDRNOTAVAIL;
 
        rcu_read_lock();
-       if ((idev = __in6_dev_get(dev)) != NULL) {
+       idev = __in6_dev_get(dev);
+       if (idev) {
                struct inet6_ifaddr *ifp;
 
                read_lock_bh(&idev->lock);
-               for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
-                       if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
+               list_for_each_entry(ifp, &idev->addr_list, if_list) {
+                       if (ifp->scope == IFA_LINK &&
+                           !(ifp->flags & banned_flags)) {
                                ipv6_addr_copy(addr, &ifp->addr);
                                err = 0;
                                break;
@@ -1276,7 +1274,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
        struct inet6_ifaddr *ifp;
 
        read_lock_bh(&idev->lock);
-       for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)
+       list_for_each_entry(ifp, &idev->addr_list, if_list)
                cnt++;
        read_unlock_bh(&idev->lock);
        return cnt;
@@ -1285,41 +1283,44 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
 int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
                  struct net_device *dev, int strict)
 {
-       struct inet6_ifaddr * ifp;
-       u8 hash = ipv6_addr_hash(addr);
+       struct inet6_ifaddr *ifp;
+       struct hlist_node *node;
+       unsigned int hash = ipv6_addr_hash(addr);
 
-       read_lock_bh(&addrconf_hash_lock);
-       for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+       rcu_read_lock_bh();
+       hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
                if (!net_eq(dev_net(ifp->idev->dev), net))
                        continue;
                if (ipv6_addr_equal(&ifp->addr, addr) &&
-                   !(ifp->flags&IFA_F_TENTATIVE)) {
-                       if (dev == NULL || ifp->idev->dev == dev ||
-                           !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))
-                               break;
+                   !(ifp->flags&IFA_F_TENTATIVE) &&
+                   (dev == NULL || ifp->idev->dev == dev ||
+                    !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
+                       rcu_read_unlock_bh();
+                       return 1;
                }
        }
-       read_unlock_bh(&addrconf_hash_lock);
-       return ifp != NULL;
+
+       rcu_read_unlock_bh();
+       return 0;
 }
 EXPORT_SYMBOL(ipv6_chk_addr);
 
-static
-int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
-                      struct net_device *dev)
+static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
+                              struct net_device *dev)
 {
-       struct inet6_ifaddr * ifp;
-       u8 hash = ipv6_addr_hash(addr);
+       unsigned int hash = ipv6_addr_hash(addr);
+       struct inet6_ifaddr *ifp;
+       struct hlist_node *node;
 
-       for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+       hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
                if (!net_eq(dev_net(ifp->idev->dev), net))
                        continue;
                if (ipv6_addr_equal(&ifp->addr, addr)) {
                        if (dev == NULL || ifp->idev->dev == dev)
-                               break;
+                               return true;
                }
        }
-       return ifp != NULL;
+       return false;
 }
 
 int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev)
@@ -1333,7 +1334,7 @@ int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev)
        idev = __in6_dev_get(dev);
        if (idev) {
                read_lock_bh(&idev->lock);
-               for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
+               list_for_each_entry(ifa, &idev->addr_list, if_list) {
                        onlink = ipv6_prefix_equal(addr, &ifa->addr,
                                                   ifa->prefix_len);
                        if (onlink)
@@ -1350,24 +1351,26 @@ EXPORT_SYMBOL(ipv6_chk_prefix);
 struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr,
                                     struct net_device *dev, int strict)
 {
-       struct inet6_ifaddr * ifp;
-       u8 hash = ipv6_addr_hash(addr);
+       struct inet6_ifaddr *ifp, *result = NULL;
+       unsigned int hash = ipv6_addr_hash(addr);
+       struct hlist_node *node;
 
-       read_lock_bh(&addrconf_hash_lock);
-       for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+       rcu_read_lock_bh();
+       hlist_for_each_entry_rcu_bh(ifp, node, &inet6_addr_lst[hash], addr_lst) {
                if (!net_eq(dev_net(ifp->idev->dev), net))
                        continue;
                if (ipv6_addr_equal(&ifp->addr, addr)) {
                        if (dev == NULL || ifp->idev->dev == dev ||
                            !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) {
+                               result = ifp;
                                in6_ifa_hold(ifp);
                                break;
                        }
                }
        }
-       read_unlock_bh(&addrconf_hash_lock);
+       rcu_read_unlock_bh();
 
-       return ifp;
+       return result;
 }
 
 /* Gets referenced address, destroys ifaddr */
@@ -1403,10 +1406,27 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
                ipv6_del_addr(ifp);
 }
 
+static int addrconf_dad_end(struct inet6_ifaddr *ifp)
+{
+       int err = -ENOENT;
+
+       spin_lock(&ifp->state_lock);
+       if (ifp->state == INET6_IFADDR_STATE_DAD) {
+               ifp->state = INET6_IFADDR_STATE_POSTDAD;
+               err = 0;
+       }
+       spin_unlock(&ifp->state_lock);
+
+       return err;
+}
+
 void addrconf_dad_failure(struct inet6_ifaddr *ifp)
 {
        struct inet6_dev *idev = ifp->idev;
 
+       if (addrconf_dad_end(ifp))
+               return;
+
        if (net_ratelimit())
                printk(KERN_INFO "%s: IPv6 duplicate address %pI6c detected!\n",
                        ifp->idev->dev->name, &ifp->addr);
@@ -1570,7 +1590,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
        struct inet6_ifaddr *ifp;
 
        read_lock_bh(&idev->lock);
-       for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+       list_for_each_entry(ifp, &idev->addr_list, if_list) {
                if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
                        memcpy(eui, ifp->addr.s6_addr+8, 8);
                        err = 0;
@@ -1738,7 +1758,8 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
 
        ASSERT_RTNL();
 
-       if ((idev = ipv6_find_idev(dev)) == NULL)
+       idev = ipv6_find_idev(dev);
+       if (!idev)
                return NULL;
 
        /* Add default multicast route */
@@ -1971,7 +1992,7 @@ ok:
 #ifdef CONFIG_IPV6_PRIVACY
                        read_lock_bh(&in6_dev->lock);
                        /* update all temporary addresses in the list */
-                       for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) {
+                       list_for_each_entry(ift, &in6_dev->tempaddr_list, tmp_list) {
                                /*
                                 * When adjusting the lifetimes of an existing
                                 * temporary address, only lower the lifetimes.
@@ -2174,7 +2195,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
                return -ENXIO;
 
        read_lock_bh(&idev->lock);
-       for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {
+       list_for_each_entry(ifp, &idev->addr_list, if_list) {
                if (ifp->prefix_len == plen &&
                    ipv6_addr_equal(pfx, &ifp->addr)) {
                        in6_ifa_hold(ifp);
@@ -2185,7 +2206,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
                        /* If the last address is deleted administratively,
                           disable IPv6 on this interface.
                         */
-                       if (idev->addr_list == NULL)
+                       if (list_empty(&idev->addr_list))
                                addrconf_ifdown(idev->dev, 1);
                        return 0;
                }
@@ -2446,7 +2467,8 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)
 
        ASSERT_RTNL();
 
-       if ((idev = addrconf_add_dev(dev)) == NULL) {
+       idev = addrconf_add_dev(dev);
+       if (!idev) {
                printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");
                return;
        }
@@ -2461,7 +2483,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
        int run_pending = 0;
        int err;
 
-       switch(event) {
+       switch (event) {
        case NETDEV_REGISTER:
                if (!idev && dev->mtu >= IPV6_MIN_MTU) {
                        idev = ipv6_add_dev(dev);
@@ -2469,6 +2491,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                return notifier_from_errno(-ENOMEM);
                }
                break;
+
        case NETDEV_UP:
        case NETDEV_CHANGE:
                if (dev->flags & IFF_SLAVE)
@@ -2498,10 +2521,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        }
 
                        if (idev) {
-                               if (idev->if_flags & IF_READY) {
+                               if (idev->if_flags & IF_READY)
                                        /* device is already configured. */
                                        break;
-                               }
                                idev->if_flags |= IF_READY;
                        }
 
@@ -2513,7 +2535,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        run_pending = 1;
                }
 
-               switch(dev->type) {
+               switch (dev->type) {
 #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
                case ARPHRD_SIT:
                        addrconf_sit_config(dev);
@@ -2530,25 +2552,30 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        addrconf_dev_config(dev);
                        break;
                }
+
                if (idev) {
                        if (run_pending)
                                addrconf_dad_run(idev);
 
-                       /* If the MTU changed during the interface down, when the
-                          interface up, the changed MTU must be reflected in the
-                          idev as well as routers.
+                       /*
+                        * If the MTU changed during the interface down,
+                        * when the interface up, the changed MTU must be
+                        * reflected in the idev as well as routers.
                         */
-                       if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) {
+                       if (idev->cnf.mtu6 != dev->mtu &&
+                           dev->mtu >= IPV6_MIN_MTU) {
                                rt6_mtu_change(dev, dev->mtu);
                                idev->cnf.mtu6 = dev->mtu;
                        }
                        idev->tstamp = jiffies;
                        inet6_ifinfo_notify(RTM_NEWLINK, idev);
-                       /* If the changed mtu during down is lower than IPV6_MIN_MTU
-                          stop IPv6 on this interface.
+
+                       /*
+                        * If the changed mtu during down is lower than
+                        * IPV6_MIN_MTU stop IPv6 on this interface.
                         */
                        if (dev->mtu < IPV6_MIN_MTU)
-                               addrconf_ifdown(dev, event != NETDEV_DOWN);
+                               addrconf_ifdown(dev, 1);
                }
                break;
 
@@ -2565,7 +2592,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                break;
                }
 
-               /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */
+               /*
+                * MTU falled under IPV6_MIN_MTU.
+                * Stop IPv6 on this interface.
+                */
 
        case NETDEV_DOWN:
        case NETDEV_UNREGISTER:
@@ -2585,9 +2615,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                return notifier_from_errno(err);
                }
                break;
-       case NETDEV_BONDING_OLDTYPE:
-       case NETDEV_BONDING_NEWTYPE:
-               addrconf_bonding_change(dev, event);
+
+       case NETDEV_PRE_TYPE_CHANGE:
+       case NETDEV_POST_TYPE_CHANGE:
+               addrconf_type_change(dev, event);
                break;
        }
 
@@ -2599,28 +2630,28 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
  */
 static struct notifier_block ipv6_dev_notf = {
        .notifier_call = addrconf_notify,
-       .priority = 0
 };
 
-static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
+static void addrconf_type_change(struct net_device *dev, unsigned long event)
 {
        struct inet6_dev *idev;
        ASSERT_RTNL();
 
        idev = __in6_dev_get(dev);
 
-       if (event == NETDEV_BONDING_NEWTYPE)
+       if (event == NETDEV_POST_TYPE_CHANGE)
                ipv6_mc_remap(idev);
-       else if (event == NETDEV_BONDING_OLDTYPE)
+       else if (event == NETDEV_PRE_TYPE_CHANGE)
                ipv6_mc_unmap(idev);
 }
 
 static int addrconf_ifdown(struct net_device *dev, int how)
 {
-       struct inet6_dev *idev;
-       struct inet6_ifaddr *ifa, *keep_list, **bifa;
        struct net *net = dev_net(dev);
-       int i;
+       struct inet6_dev *idev;
+       struct inet6_ifaddr *ifa;
+       LIST_HEAD(keep_list);
+       int state;
 
        ASSERT_RTNL();
 
@@ -2631,8 +2662,9 @@ static int addrconf_ifdown(struct net_device *dev, int how)
        if (idev == NULL)
                return -ENODEV;
 
-       /* Step 1: remove reference to ipv6 device from parent device.
-                  Do not dev_put!
+       /*
+        * Step 1: remove reference to ipv6 device from parent device.
+        *         Do not dev_put!
         */
        if (how) {
                idev->dead = 1;
@@ -2645,41 +2677,21 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        }
 
-       /* Step 2: clear hash table */
-       for (i=0; i<IN6_ADDR_HSIZE; i++) {
-               bifa = &inet6_addr_lst[i];
-
-               write_lock_bh(&addrconf_hash_lock);
-               while ((ifa = *bifa) != NULL) {
-                       if (ifa->idev == idev &&
-                           (how || !(ifa->flags&IFA_F_PERMANENT) ||
-                            ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
-                               *bifa = ifa->lst_next;
-                               ifa->lst_next = NULL;
-                               __in6_ifa_put(ifa);
-                               continue;
-                       }
-                       bifa = &ifa->lst_next;
-               }
-               write_unlock_bh(&addrconf_hash_lock);
-       }
-
        write_lock_bh(&idev->lock);
 
-       /* Step 3: clear flags for stateless addrconf */
+       /* Step 2: clear flags for stateless addrconf */
        if (!how)
                idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
 
-       /* Step 4: clear address list */
 #ifdef CONFIG_IPV6_PRIVACY
        if (how && del_timer(&idev->regen_timer))
                in6_dev_put(idev);
 
-       /* clear tempaddr list */
-       while ((ifa = idev->tempaddr_list) != NULL) {
-               idev->tempaddr_list = ifa->tmp_next;
-               ifa->tmp_next = NULL;
-               ifa->dead = 1;
+       /* Step 3: clear tempaddr list */
+       while (!list_empty(&idev->tempaddr_list)) {
+               ifa = list_first_entry(&idev->tempaddr_list,
+                                      struct inet6_ifaddr, tmp_list);
+               list_del(&ifa->tmp_list);
                write_unlock_bh(&idev->lock);
                spin_lock_bh(&ifa->lock);
 
@@ -2692,23 +2704,18 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                write_lock_bh(&idev->lock);
        }
 #endif
-       keep_list = NULL;
-       bifa = &keep_list;
-       while ((ifa = idev->addr_list) != NULL) {
-               idev->addr_list = ifa->if_next;
-               ifa->if_next = NULL;
 
+       while (!list_empty(&idev->addr_list)) {
+               ifa = list_first_entry(&idev->addr_list,
+                                      struct inet6_ifaddr, if_list);
                addrconf_del_timer(ifa);
 
                /* If just doing link down, and address is permanent
                   and not link-local, then retain it. */
-               if (how == 0 &&
+               if (!how &&
                    (ifa->flags&IFA_F_PERMANENT) &&
                    !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
-
-                       /* Move to holding list */
-                       *bifa = ifa;
-                       bifa = &ifa->if_next;
+                       list_move_tail(&ifa->if_list, &keep_list);
 
                        /* If not doing DAD on this address, just keep it. */
                        if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
@@ -2722,25 +2729,45 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
                        /* Flag it for later restoration when link comes up */
                        ifa->flags |= IFA_F_TENTATIVE;
+                       ifa->state = INET6_IFADDR_STATE_DAD;
+
+                       write_unlock_bh(&idev->lock);
+
                        in6_ifa_hold(ifa);
                } else {
-                       ifa->dead = 1;
+                       list_del(&ifa->if_list);
+
+                       /* clear hash table */
+                       spin_lock_bh(&addrconf_hash_lock);
+                       hlist_del_init_rcu(&ifa->addr_lst);
+                       spin_unlock_bh(&addrconf_hash_lock);
+
+                       write_unlock_bh(&idev->lock);
+                       spin_lock_bh(&ifa->state_lock);
+                       state = ifa->state;
+                       ifa->state = INET6_IFADDR_STATE_DEAD;
+                       spin_unlock_bh(&ifa->state_lock);
+
+                       if (state == INET6_IFADDR_STATE_DEAD)
+                               goto put_ifa;
                }
-               write_unlock_bh(&idev->lock);
 
                __ipv6_ifa_notify(RTM_DELADDR, ifa);
-               atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+               if (ifa->state == INET6_IFADDR_STATE_DEAD)
+                       atomic_notifier_call_chain(&inet6addr_chain,
+                                                  NETDEV_DOWN, ifa);
+
+put_ifa:
                in6_ifa_put(ifa);
 
                write_lock_bh(&idev->lock);
        }
 
-       idev->addr_list = keep_list;
+       list_splice(&keep_list, &idev->addr_list);
 
        write_unlock_bh(&idev->lock);
 
        /* Step 5: Discard multicast list */
-
        if (how)
                ipv6_mc_destroy_dev(idev);
        else
@@ -2748,8 +2775,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        idev->tstamp = jiffies;
 
-       /* Shot the device (if unregistered) */
-
+       /* Last: Shot the device (if unregistered) */
        if (how) {
                addrconf_sysctl_unregister(idev);
                neigh_parms_release(&nd_tbl, idev->nd_parms);
@@ -2827,10 +2853,10 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
        net_srandom(ifp->addr.s6_addr32[3]);
 
        read_lock_bh(&idev->lock);
-       if (ifp->dead)
+       spin_lock(&ifp->lock);
+       if (ifp->state == INET6_IFADDR_STATE_DEAD)
                goto out;
 
-       spin_lock(&ifp->lock);
        if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
            idev->cnf.accept_dad < 1 ||
            !(ifp->flags&IFA_F_TENTATIVE) ||
@@ -2860,12 +2886,12 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
         * Optimistic nodes can start receiving
         * Frames right away
         */
-       if(ifp->flags & IFA_F_OPTIMISTIC)
+       if (ifp->flags & IFA_F_OPTIMISTIC)
                ip6_ins_rt(ifp->rt);
 
        addrconf_dad_kick(ifp);
-       spin_unlock(&ifp->lock);
 out:
+       spin_unlock(&ifp->lock);
        read_unlock_bh(&idev->lock);
 }
 
@@ -2875,6 +2901,9 @@ static void addrconf_dad_timer(unsigned long data)
        struct inet6_dev *idev = ifp->idev;
        struct in6_addr mcaddr;
 
+       if (!ifp->probes && addrconf_dad_end(ifp))
+               goto out;
+
        read_lock(&idev->lock);
        if (idev->dead || !(idev->if_flags & IF_READY)) {
                read_unlock(&idev->lock);
@@ -2882,6 +2911,12 @@ static void addrconf_dad_timer(unsigned long data)
        }
 
        spin_lock(&ifp->lock);
+       if (ifp->state == INET6_IFADDR_STATE_DEAD) {
+               spin_unlock(&ifp->lock);
+               read_unlock(&idev->lock);
+               goto out;
+       }
+
        if (ifp->probes == 0) {
                /*
                 * DAD was successful
@@ -2910,7 +2945,7 @@ out:
 
 static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
 {
-       struct net_device *     dev = ifp->idev->dev;
+       struct net_device *dev = ifp->idev->dev;
 
        /*
         *      Configure the address for reception. Now it is valid.
@@ -2941,18 +2976,17 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
        }
 }
 
-static void addrconf_dad_run(struct inet6_dev *idev) {
+static void addrconf_dad_run(struct inet6_dev *idev)
+{
        struct inet6_ifaddr *ifp;
 
        read_lock_bh(&idev->lock);
-       for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) {
+       list_for_each_entry(ifp, &idev->addr_list, if_list) {
                spin_lock(&ifp->lock);
-               if (!(ifp->flags & IFA_F_TENTATIVE)) {
-                       spin_unlock(&ifp->lock);
-                       continue;
-               }
+               if (ifp->flags & IFA_F_TENTATIVE &&
+                   ifp->state == INET6_IFADDR_STATE_DAD)
+                       addrconf_dad_kick(ifp);
                spin_unlock(&ifp->lock);
-               addrconf_dad_kick(ifp);
        }
        read_unlock_bh(&idev->lock);
 }
@@ -2970,36 +3004,35 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
        struct net *net = seq_file_net(seq);
 
        for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
-               ifa = inet6_addr_lst[state->bucket];
-
-               while (ifa && !net_eq(dev_net(ifa->idev->dev), net))
-                       ifa = ifa->lst_next;
-               if (ifa)
-                       break;
+               struct hlist_node *n;
+               hlist_for_each_entry_rcu_bh(ifa, n, &inet6_addr_lst[state->bucket],
+                                        addr_lst)
+                       if (net_eq(dev_net(ifa->idev->dev), net))
+                               return ifa;
        }
-       return ifa;
+       return NULL;
 }
 
-static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa)
+static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,
+                                        struct inet6_ifaddr *ifa)
 {
        struct if6_iter_state *state = seq->private;
        struct net *net = seq_file_net(seq);
+       struct hlist_node *n = &ifa->addr_lst;
 
-       ifa = ifa->lst_next;
-try_again:
-       if (ifa) {
-               if (!net_eq(dev_net(ifa->idev->dev), net)) {
-                       ifa = ifa->lst_next;
-                       goto try_again;
-               }
-       }
+       hlist_for_each_entry_continue_rcu_bh(ifa, n, addr_lst)
+               if (net_eq(dev_net(ifa->idev->dev), net))
+                       return ifa;
 
-       if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) {
-               ifa = inet6_addr_lst[state->bucket];
-               goto try_again;
+       while (++state->bucket < IN6_ADDR_HSIZE) {
+               hlist_for_each_entry_rcu_bh(ifa, n,
+                                    &inet6_addr_lst[state->bucket], addr_lst) {
+                       if (net_eq(dev_net(ifa->idev->dev), net))
+                               return ifa;
+               }
        }
 
-       return ifa;
+       return NULL;
 }
 
 static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
@@ -3007,15 +3040,15 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
        struct inet6_ifaddr *ifa = if6_get_first(seq);
 
        if (ifa)
-               while(pos && (ifa = if6_get_next(seq, ifa)) != NULL)
+               while (pos && (ifa = if6_get_next(seq, ifa)) != NULL)
                        --pos;
        return pos ? NULL : ifa;
 }
 
 static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(addrconf_hash_lock)
+       __acquires(rcu_bh)
 {
-       read_lock_bh(&addrconf_hash_lock);
+       rcu_read_lock_bh();
        return if6_get_idx(seq, *pos);
 }
 
@@ -3029,9 +3062,9 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void if6_seq_stop(struct seq_file *seq, void *v)
-       __releases(addrconf_hash_lock)
+       __releases(rcu_bh)
 {
-       read_unlock_bh(&addrconf_hash_lock);
+       rcu_read_unlock_bh();
 }
 
 static int if6_seq_show(struct seq_file *seq, void *v)
@@ -3101,10 +3134,12 @@ void if6_proc_exit(void)
 int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
 {
        int ret = 0;
-       struct inet6_ifaddr * ifp;
-       u8 hash = ipv6_addr_hash(addr);
-       read_lock_bh(&addrconf_hash_lock);
-       for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
+       struct inet6_ifaddr *ifp = NULL;
+       struct hlist_node *n;
+       unsigned int hash = ipv6_addr_hash(addr);
+
+       rcu_read_lock_bh();
+       hlist_for_each_entry_rcu_bh(ifp, n, &inet6_addr_lst[hash], addr_lst) {
                if (!net_eq(dev_net(ifp->idev->dev), net))
                        continue;
                if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -3113,7 +3148,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
                        break;
                }
        }
-       read_unlock_bh(&addrconf_hash_lock);
+       rcu_read_unlock_bh();
        return ret;
 }
 #endif
@@ -3124,43 +3159,35 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
 
 static void addrconf_verify(unsigned long foo)
 {
+       unsigned long now, next, next_sec, next_sched;
        struct inet6_ifaddr *ifp;
-       unsigned long now, next;
+       struct hlist_node *node;
        int i;
 
-       spin_lock_bh(&addrconf_verify_lock);
+       rcu_read_lock_bh();
+       spin_lock(&addrconf_verify_lock);
        now = jiffies;
-       next = now + ADDR_CHECK_FREQUENCY;
+       next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
 
        del_timer(&addr_chk_timer);
 
-       for (i=0; i < IN6_ADDR_HSIZE; i++) {
-
+       for (i = 0; i < IN6_ADDR_HSIZE; i++) {
 restart:
-               read_lock(&addrconf_hash_lock);
-               for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
+               hlist_for_each_entry_rcu_bh(ifp, node,
+                                        &inet6_addr_lst[i], addr_lst) {
                        unsigned long age;
-#ifdef CONFIG_IPV6_PRIVACY
-                       unsigned long regen_advance;
-#endif
 
                        if (ifp->flags & IFA_F_PERMANENT)
                                continue;
 
                        spin_lock(&ifp->lock);
-                       age = (now - ifp->tstamp) / HZ;
-
-#ifdef CONFIG_IPV6_PRIVACY
-                       regen_advance = ifp->idev->cnf.regen_max_retry *
-                                       ifp->idev->cnf.dad_transmits *
-                                       ifp->idev->nd_parms->retrans_time / HZ;
-#endif
+                       /* We try to batch several events at once. */
+                       age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
 
                        if (ifp->valid_lft != INFINITY_LIFE_TIME &&
                            age >= ifp->valid_lft) {
                                spin_unlock(&ifp->lock);
                                in6_ifa_hold(ifp);
-                               read_unlock(&addrconf_hash_lock);
                                ipv6_del_addr(ifp);
                                goto restart;
                        } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
@@ -3182,7 +3209,6 @@ restart:
 
                                if (deprecate) {
                                        in6_ifa_hold(ifp);
-                                       read_unlock(&addrconf_hash_lock);
 
                                        ipv6_ifa_notify(0, ifp);
                                        in6_ifa_put(ifp);
@@ -3191,6 +3217,10 @@ restart:
 #ifdef CONFIG_IPV6_PRIVACY
                        } else if ((ifp->flags&IFA_F_TEMPORARY) &&
                                   !(ifp->flags&IFA_F_TENTATIVE)) {
+                               unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
+                                       ifp->idev->cnf.dad_transmits *
+                                       ifp->idev->nd_parms->retrans_time / HZ;
+
                                if (age >= ifp->prefered_lft - regen_advance) {
                                        struct inet6_ifaddr *ifpub = ifp->ifpub;
                                        if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
@@ -3200,7 +3230,7 @@ restart:
                                                in6_ifa_hold(ifp);
                                                in6_ifa_hold(ifpub);
                                                spin_unlock(&ifp->lock);
-                                               read_unlock(&addrconf_hash_lock);
+
                                                spin_lock(&ifpub->lock);
                                                ifpub->regen_count = 0;
                                                spin_unlock(&ifpub->lock);
@@ -3220,12 +3250,26 @@ restart:
                                spin_unlock(&ifp->lock);
                        }
                }
-               read_unlock(&addrconf_hash_lock);
        }
 
-       addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
+       next_sec = round_jiffies_up(next);
+       next_sched = next;
+
+       /* If rounded timeout is accurate enough, accept it. */
+       if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
+               next_sched = next_sec;
+
+       /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
+       if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
+               next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
+
+       ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
+             now, next, next_sec, next_sched));
+
+       addr_chk_timer.expires = next_sched;
        add_timer(&addr_chk_timer);
-       spin_unlock_bh(&addrconf_verify_lock);
+       spin_unlock(&addrconf_verify_lock);
+       rcu_read_unlock_bh();
 }
 
 static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local)
@@ -3515,8 +3559,7 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
        return nlmsg_end(skb, nlh);
 }
 
-enum addr_type_t
-{
+enum addr_type_t {
        UNICAST_ADDR,
        MULTICAST_ADDR,
        ANYCAST_ADDR,
@@ -3527,7 +3570,6 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
                          struct netlink_callback *cb, enum addr_type_t type,
                          int s_ip_idx, int *p_ip_idx)
 {
-       struct inet6_ifaddr *ifa;
        struct ifmcaddr6 *ifmca;
        struct ifacaddr6 *ifaca;
        int err = 1;
@@ -3535,11 +3577,12 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
 
        read_lock_bh(&idev->lock);
        switch (type) {
-       case UNICAST_ADDR:
+       case UNICAST_ADDR: {
+               struct inet6_ifaddr *ifa;
+
                /* unicast address incl. temp addr */
-               for (ifa = idev->addr_list; ifa;
-                    ifa = ifa->if_next, ip_idx++) {
-                       if (ip_idx < s_ip_idx)
+               list_for_each_entry(ifa, &idev->addr_list, if_list) {
+                       if (++ip_idx < s_ip_idx)
                                continue;
                        err = inet6_fill_ifaddr(skb, ifa,
                                                NETLINK_CB(cb->skb).pid,
@@ -3550,6 +3593,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
                                break;
                }
                break;
+       }
        case MULTICAST_ADDR:
                /* multicast address */
                for (ifmca = idev->mc_list; ifmca;
@@ -3614,7 +3658,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                        if (h > s_h || idx > s_idx)
                                s_ip_idx = 0;
                        ip_idx = 0;
-                       if ((idev = __in6_dev_get(dev)) == NULL)
+                       idev = __in6_dev_get(dev);
+                       if (!idev)
                                goto cont;
 
                        if (in6_dump_addrs(idev, skb, cb, type,
@@ -3681,12 +3726,14 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
        if (ifm->ifa_index)
                dev = __dev_get_by_index(net, ifm->ifa_index);
 
-       if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
+       ifa = ipv6_get_ifaddr(net, addr, dev, 1);
+       if (!ifa) {
                err = -EADDRNOTAVAIL;
                goto errout;
        }
 
-       if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) {
+       skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL);
+       if (!skb) {
                err = -ENOBUFS;
                goto errout_ifa;
        }
@@ -3811,7 +3858,7 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,
 static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
                             int bytes)
 {
-       switch(attrtype) {
+       switch (attrtype) {
        case IFLA_INET6_STATS:
                __snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
                break;
@@ -4047,7 +4094,9 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                        addrconf_leave_anycast(ifp);
                addrconf_leave_solict(ifp->idev, &ifp->addr);
                dst_hold(&ifp->rt->u.dst);
-               if (ip6_del_rt(ifp->rt))
+
+               if (ifp->state == INET6_IFADDR_STATE_DEAD &&
+                   ip6_del_rt(ifp->rt))
                        dst_free(&ifp->rt->u.dst);
                break;
        }
@@ -4163,211 +4212,211 @@ static struct addrconf_sysctl_table
        .sysctl_header = NULL,
        .addrconf_vars = {
                {
-                       .procname       =       "forwarding",
-                       .data           =       &ipv6_devconf.forwarding,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       addrconf_sysctl_forward,
+                       .procname       = "forwarding",
+                       .data           = &ipv6_devconf.forwarding,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = addrconf_sysctl_forward,
                },
                {
-                       .procname       =       "hop_limit",
-                       .data           =       &ipv6_devconf.hop_limit,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "hop_limit",
+                       .data           = &ipv6_devconf.hop_limit,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "mtu",
-                       .data           =       &ipv6_devconf.mtu6,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "mtu",
+                       .data           = &ipv6_devconf.mtu6,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "accept_ra",
-                       .data           =       &ipv6_devconf.accept_ra,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_ra",
+                       .data           = &ipv6_devconf.accept_ra,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "accept_redirects",
-                       .data           =       &ipv6_devconf.accept_redirects,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_redirects",
+                       .data           = &ipv6_devconf.accept_redirects,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "autoconf",
-                       .data           =       &ipv6_devconf.autoconf,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "autoconf",
+                       .data           = &ipv6_devconf.autoconf,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "dad_transmits",
-                       .data           =       &ipv6_devconf.dad_transmits,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "dad_transmits",
+                       .data           = &ipv6_devconf.dad_transmits,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "router_solicitations",
-                       .data           =       &ipv6_devconf.rtr_solicits,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "router_solicitations",
+                       .data           = &ipv6_devconf.rtr_solicits,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "router_solicitation_interval",
-                       .data           =       &ipv6_devconf.rtr_solicit_interval,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec_jiffies,
+                       .procname       = "router_solicitation_interval",
+                       .data           = &ipv6_devconf.rtr_solicit_interval,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec_jiffies,
                },
                {
-                       .procname       =       "router_solicitation_delay",
-                       .data           =       &ipv6_devconf.rtr_solicit_delay,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec_jiffies,
+                       .procname       = "router_solicitation_delay",
+                       .data           = &ipv6_devconf.rtr_solicit_delay,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec_jiffies,
                },
                {
-                       .procname       =       "force_mld_version",
-                       .data           =       &ipv6_devconf.force_mld_version,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "force_mld_version",
+                       .data           = &ipv6_devconf.force_mld_version,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
 #ifdef CONFIG_IPV6_PRIVACY
                {
-                       .procname       =       "use_tempaddr",
-                       .data           =       &ipv6_devconf.use_tempaddr,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "use_tempaddr",
+                       .data           = &ipv6_devconf.use_tempaddr,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "temp_valid_lft",
-                       .data           =       &ipv6_devconf.temp_valid_lft,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "temp_valid_lft",
+                       .data           = &ipv6_devconf.temp_valid_lft,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "temp_prefered_lft",
-                       .data           =       &ipv6_devconf.temp_prefered_lft,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "temp_prefered_lft",
+                       .data           = &ipv6_devconf.temp_prefered_lft,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "regen_max_retry",
-                       .data           =       &ipv6_devconf.regen_max_retry,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "regen_max_retry",
+                       .data           = &ipv6_devconf.regen_max_retry,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "max_desync_factor",
-                       .data           =       &ipv6_devconf.max_desync_factor,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "max_desync_factor",
+                       .data           = &ipv6_devconf.max_desync_factor,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
 #endif
                {
-                       .procname       =       "max_addresses",
-                       .data           =       &ipv6_devconf.max_addresses,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "max_addresses",
+                       .data           = &ipv6_devconf.max_addresses,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "accept_ra_defrtr",
-                       .data           =       &ipv6_devconf.accept_ra_defrtr,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_ra_defrtr",
+                       .data           = &ipv6_devconf.accept_ra_defrtr,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "accept_ra_pinfo",
-                       .data           =       &ipv6_devconf.accept_ra_pinfo,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_ra_pinfo",
+                       .data           = &ipv6_devconf.accept_ra_pinfo,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
 #ifdef CONFIG_IPV6_ROUTER_PREF
                {
-                       .procname       =       "accept_ra_rtr_pref",
-                       .data           =       &ipv6_devconf.accept_ra_rtr_pref,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_ra_rtr_pref",
+                       .data           = &ipv6_devconf.accept_ra_rtr_pref,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "router_probe_interval",
-                       .data           =       &ipv6_devconf.rtr_probe_interval,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec_jiffies,
+                       .procname       = "router_probe_interval",
+                       .data           = &ipv6_devconf.rtr_probe_interval,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec_jiffies,
                },
 #ifdef CONFIG_IPV6_ROUTE_INFO
                {
-                       .procname       =       "accept_ra_rt_info_max_plen",
-                       .data           =       &ipv6_devconf.accept_ra_rt_info_max_plen,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_ra_rt_info_max_plen",
+                       .data           = &ipv6_devconf.accept_ra_rt_info_max_plen,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
 #endif
 #endif
                {
-                       .procname       =       "proxy_ndp",
-                       .data           =       &ipv6_devconf.proxy_ndp,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "proxy_ndp",
+                       .data           = &ipv6_devconf.proxy_ndp,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
-                       .procname       =       "accept_source_route",
-                       .data           =       &ipv6_devconf.accept_source_route,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_source_route",
+                       .data           = &ipv6_devconf.accept_source_route,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
 #ifdef CONFIG_IPV6_OPTIMISTIC_DAD
                {
-                       .procname       =       "optimistic_dad",
-                       .data           =       &ipv6_devconf.optimistic_dad,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "optimistic_dad",
+                       .data           = &ipv6_devconf.optimistic_dad,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
 
                },
 #endif
 #ifdef CONFIG_IPV6_MROUTE
                {
-                       .procname       =       "mc_forwarding",
-                       .data           =       &ipv6_devconf.mc_forwarding,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0444,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "mc_forwarding",
+                       .data           = &ipv6_devconf.mc_forwarding,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0444,
+                       .proc_handler   = proc_dointvec,
                },
 #endif
                {
-                       .procname       =       "disable_ipv6",
-                       .data           =       &ipv6_devconf.disable_ipv6,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       addrconf_sysctl_disable,
+                       .procname       = "disable_ipv6",
+                       .data           = &ipv6_devconf.disable_ipv6,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = addrconf_sysctl_disable,
                },
                {
-                       .procname       =       "accept_dad",
-                       .data           =       &ipv6_devconf.accept_dad,
-                       .maxlen         =       sizeof(int),
-                       .mode           =       0644,
-                       .proc_handler   =       proc_dointvec,
+                       .procname       = "accept_dad",
+                       .data           = &ipv6_devconf.accept_dad,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec,
                },
                {
                        .procname       = "force_tllao",
@@ -4403,8 +4452,8 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,
        if (t == NULL)
                goto out;
 
-       for (i=0; t->addrconf_vars[i].data; i++) {
-               t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
+       for (i = 0; t->addrconf_vars[i].data; i++) {
+               t->addrconf_vars[i].data += (char *)p - (char *)&ipv6_devconf;
                t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
                t->addrconf_vars[i].extra2 = net;
        }
@@ -4541,14 +4590,12 @@ int register_inet6addr_notifier(struct notifier_block *nb)
 {
        return atomic_notifier_chain_register(&inet6addr_chain, nb);
 }
-
 EXPORT_SYMBOL(register_inet6addr_notifier);
 
 int unregister_inet6addr_notifier(struct notifier_block *nb)
 {
-       return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
+       return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
 }
-
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
 
 /*
@@ -4557,11 +4604,12 @@ EXPORT_SYMBOL(unregister_inet6addr_notifier);
 
 int __init addrconf_init(void)
 {
-       int err;
+       int i, err;
 
-       if ((err = ipv6_addr_label_init()) < 0) {
-               printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n",
-                       err);
+       err = ipv6_addr_label_init();
+       if (err < 0) {
+               printk(KERN_CRIT "IPv6 Addrconf:"
+                      " cannot initialize default policy table: %d.\n", err);
                return err;
        }
 
@@ -4592,6 +4640,9 @@ int __init addrconf_init(void)
        if (err)
                goto errlo;
 
+       for (i = 0; i < IN6_ADDR_HSIZE; i++)
+               INIT_HLIST_HEAD(&inet6_addr_lst[i]);
+
        register_netdevice_notifier(&ipv6_dev_notf);
 
        addrconf_verify(0);
@@ -4620,7 +4671,6 @@ errlo:
 
 void addrconf_cleanup(void)
 {
-       struct inet6_ifaddr *ifa;
        struct net_device *dev;
        int i;
 
@@ -4640,20 +4690,10 @@ void addrconf_cleanup(void)
        /*
         *      Check hash table.
         */
-       write_lock_bh(&addrconf_hash_lock);
-       for (i=0; i < IN6_ADDR_HSIZE; i++) {
-               for (ifa=inet6_addr_lst[i]; ifa; ) {
-                       struct inet6_ifaddr *bifa;
-
-                       bifa = ifa;
-                       ifa = ifa->lst_next;
-                       printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa);
-                       /* Do not free it; something is wrong.
-                          Now we can investigate it with debugger.
-                        */
-               }
-       }
-       write_unlock_bh(&addrconf_hash_lock);
+       spin_lock_bh(&addrconf_hash_lock);
+       for (i = 0; i < IN6_ADDR_HSIZE; i++)
+               WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
+       spin_unlock_bh(&addrconf_hash_lock);
 
        del_timer(&addr_chk_timer);
        rtnl_unlock();
index ae404c9a746c3fe088144b16aca92b84108a5b37..8c4348cb19505446e13471d09369610e41851146 100644 (file)
@@ -422,10 +422,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
            ifal->ifal_prefixlen > 128)
                return -EINVAL;
 
-       if (ifal->ifal_index &&
-           !__dev_get_by_index(net, ifal->ifal_index))
-               return -EINVAL;
-
        if (!tb[IFAL_ADDRESS])
                return -EINVAL;
 
@@ -441,6 +437,10 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        switch(nlh->nlmsg_type) {
        case RTM_NEWADDRLABEL:
+               if (ifal->ifal_index &&
+                   !__dev_get_by_index(net, ifal->ifal_index))
+                       return -EINVAL;
+
                err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
                                     ifal->ifal_index, label,
                                     nlh->nlmsg_flags & NLM_F_REPLACE);
index 3f9e86b15e0d867e1b85125b4521edbc0092054d..e733942dafe124c00a67380d1bbd5f6d6acaf824 100644 (file)
@@ -417,6 +417,9 @@ void inet6_destroy_sock(struct sock *sk)
        if ((skb = xchg(&np->pktoptions, NULL)) != NULL)
                kfree_skb(skb);
 
+       if ((skb = xchg(&np->rxpmtu, NULL)) != NULL)
+               kfree_skb(skb);
+
        /* Free flowlabels */
        fl6_free_socklist(sk);
 
index 61573885e4517abca63a36ae1f30999470ef2a32..712684687c9a9d8f25baca4ff07a86f0386820bd 100644 (file)
@@ -282,6 +282,45 @@ void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
                kfree_skb(skb);
 }
 
+void ipv6_local_rxpmtu(struct sock *sk, struct flowi *fl, u32 mtu)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6hdr *iph;
+       struct sk_buff *skb;
+       struct ip6_mtuinfo *mtu_info;
+
+       if (!np->rxopt.bits.rxpmtu)
+               return;
+
+       skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       skb_put(skb, sizeof(struct ipv6hdr));
+       skb_reset_network_header(skb);
+       iph = ipv6_hdr(skb);
+       ipv6_addr_copy(&iph->daddr, &fl->fl6_dst);
+
+       mtu_info = IP6CBMTU(skb);
+       if (!mtu_info) {
+               kfree_skb(skb);
+               return;
+       }
+
+       mtu_info->ip6m_mtu = mtu;
+       mtu_info->ip6m_addr.sin6_family = AF_INET6;
+       mtu_info->ip6m_addr.sin6_port = 0;
+       mtu_info->ip6m_addr.sin6_flowinfo = 0;
+       mtu_info->ip6m_addr.sin6_scope_id = fl->oif;
+       ipv6_addr_copy(&mtu_info->ip6m_addr.sin6_addr, &ipv6_hdr(skb)->daddr);
+
+       __skb_pull(skb, skb_tail_pointer(skb) - skb->data);
+       skb_reset_transport_header(skb);
+
+       skb = xchg(&np->rxpmtu, skb);
+       kfree_skb(skb);
+}
+
 /*
  *     Handle MSG_ERRQUEUE
  */
@@ -385,6 +424,54 @@ out:
        return err;
 }
 
+/*
+ *     Handle IPV6_RECVPATHMTU
+ */
+int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+       struct sk_buff *skb;
+       struct sockaddr_in6 *sin;
+       struct ip6_mtuinfo mtu_info;
+       int err;
+       int copied;
+
+       err = -EAGAIN;
+       skb = xchg(&np->rxpmtu, NULL);
+       if (skb == NULL)
+               goto out;
+
+       copied = skb->len;
+       if (copied > len) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto out_free_skb;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info));
+
+       sin = (struct sockaddr_in6 *)msg->msg_name;
+       if (sin) {
+               sin->sin6_family = AF_INET6;
+               sin->sin6_flowinfo = 0;
+               sin->sin6_port = 0;
+               sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id;
+               ipv6_addr_copy(&sin->sin6_addr, &mtu_info.ip6m_addr.sin6_addr);
+       }
+
+       put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info);
+
+       err = copied;
+
+out_free_skb:
+       kfree_skb(skb);
+out:
+       return err;
+}
 
 
 int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
@@ -501,7 +588,7 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
 int datagram_send_ctl(struct net *net,
                      struct msghdr *msg, struct flowi *fl,
                      struct ipv6_txoptions *opt,
-                     int *hlimit, int *tclass)
+                     int *hlimit, int *tclass, int *dontfrag)
 {
        struct in6_pktinfo *src_info;
        struct cmsghdr *cmsg;
@@ -739,6 +826,25 @@ int datagram_send_ctl(struct net *net,
                        err = 0;
                        *tclass = tc;
 
+                       break;
+                   }
+
+               case IPV6_DONTFRAG:
+                   {
+                       int df;
+
+                       err = -EINVAL;
+                       if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
+                               goto exit_f;
+                       }
+
+                       df = *(int *)CMSG_DATA(cmsg);
+                       if (df < 0 || df > 1)
+                               goto exit_f;
+
+                       err = 0;
+                       *dontfrag = df;
+
                        break;
                    }
                default:
index 5e463c43fcc27a3abdfaf257a0bae134819154ae..8e44f8f9c18846c8929e44b14e99c8825783916a 100644 (file)
@@ -208,7 +208,6 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
 {
        struct fib6_rule *rule6 = (struct fib6_rule *) rule;
 
-       frh->family = AF_INET6;
        frh->dst_len = rule6->dst.plen;
        frh->src_len = rule6->src.plen;
        frh->tos = rule6->tclass;
@@ -238,7 +237,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
               + nla_total_size(16); /* src */
 }
 
-static struct fib_rules_ops fib6_rules_ops_template = {
+static const struct fib_rules_ops __net_initdata fib6_rules_ops_template = {
        .family                 = AF_INET6,
        .rule_size              = sizeof(struct fib6_rule),
        .addr_size              = sizeof(struct in6_addr),
index 3330a4bd6157e86d9e951f0d7833531fd10b0872..ce7992982557d8cc28037bbb6388ede8f0e62d46 100644 (file)
@@ -481,8 +481,9 @@ route_done:
                              len + sizeof(struct icmp6hdr),
                              sizeof(struct icmp6hdr), hlimit,
                              np->tclass, NULL, &fl, (struct rt6_info*)dst,
-                             MSG_DONTWAIT);
+                             MSG_DONTWAIT, np->dontfrag);
        if (err) {
+               ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
                ip6_flush_pending_frames(sk);
                goto out_put;
        }
@@ -560,9 +561,11 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 
        err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr),
                                sizeof(struct icmp6hdr), hlimit, np->tclass, NULL, &fl,
-                               (struct rt6_info*)dst, MSG_DONTWAIT);
+                               (struct rt6_info*)dst, MSG_DONTWAIT,
+                               np->dontfrag);
 
        if (err) {
+               ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS);
                ip6_flush_pending_frames(sk);
                goto out_put;
        }
index 628db24bcf22bceff783384ea7779a87c4cb0ab7..0c5e3c3b7fd56d87222ec0c5a691f1e961a9f58b 100644 (file)
@@ -178,7 +178,7 @@ struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
        return dst;
 }
 
-int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
+int inet6_csk_xmit(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
        struct inet_sock *inet = inet_sk(sk);
@@ -234,7 +234,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
        /* Restore final destination back after routing done */
        ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
 
-       return ip6_xmit(sk, skb, &fl, np->opt, 0);
+       return ip6_xmit(sk, skb, &fl, np->opt);
 }
 
 EXPORT_SYMBOL_GPL(inet6_csk_xmit);
index 6b82e02158c6d9c80b2e26dce09497441eed92f3..92a122b7795d4c9d67049bc747f3875414f016ad 100644 (file)
@@ -128,12 +128,24 @@ static __inline__ u32 fib6_new_sernum(void)
 /*
  *     test bit
  */
+#if defined(__LITTLE_ENDIAN)
+# define BITOP_BE32_SWIZZLE    (0x1F & ~7)
+#else
+# define BITOP_BE32_SWIZZLE    0
+#endif
 
 static __inline__ __be32 addr_bit_set(void *token, int fn_bit)
 {
        __be32 *addr = token;
-
-       return htonl(1 << ((~fn_bit)&0x1F)) & addr[fn_bit>>5];
+       /*
+        * Here,
+        *      1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)
+        * is optimized version of
+        *      htonl(1 << ((~fn_bit)&0x1F))
+        * See include/asm-generic/bitops/le.h.
+        */
+       return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) &
+              addr[fn_bit >> 5];
 }
 
 static __inline__ struct fib6_node * node_alloc(void)
index 14e23216eb28c7332fc67afe6a855ee9a98936a4..13654686aeabae2eb832467c8f22d4ad41ea9d2f 100644 (file)
@@ -360,7 +360,8 @@ fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
                msg.msg_control = (void*)(fl->opt+1);
                flowi.oif = 0;
 
-               err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk, &junk);
+               err = datagram_send_ctl(net, &msg, &flowi, fl->opt, &junk,
+                                       &junk, &junk);
                if (err)
                        goto done;
                err = -EINVAL;
index 6aa7ee1295c2f5d7f467a71dcb74a0a8e029cef2..a83e9209cecc332dac210563fa70833658b1f371 100644 (file)
@@ -143,7 +143,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
        /* Must drop socket now because of tproxy. */
        skb_orphan(skb);
 
-       return NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,
+       return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL,
                       ip6_rcv_finish);
 err:
        IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INHDRERRORS);
@@ -236,7 +236,7 @@ discard:
 
 int ip6_input(struct sk_buff *skb)
 {
-       return NF_HOOK(PF_INET6, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
+       return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, skb, skb->dev, NULL,
                       ip6_input_finish);
 }
 
index 75d5ef830097fc99cbd7e0ccd36452ff45a6f806..cd963f64e27c882f39c25c2092aa9116b4568bbc 100644 (file)
@@ -67,8 +67,8 @@ int __ip6_local_out(struct sk_buff *skb)
                len = 0;
        ipv6_hdr(skb)->payload_len = htons(len);
 
-       return nf_hook(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb_dst(skb)->dev,
-                      dst_output);
+       return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
+                      skb_dst(skb)->dev, dst_output);
 }
 
 int ip6_local_out(struct sk_buff *skb)
@@ -83,22 +83,6 @@ int ip6_local_out(struct sk_buff *skb)
 }
 EXPORT_SYMBOL_GPL(ip6_local_out);
 
-static int ip6_output_finish(struct sk_buff *skb)
-{
-       struct dst_entry *dst = skb_dst(skb);
-
-       if (dst->hh)
-               return neigh_hh_output(dst->hh, skb);
-       else if (dst->neighbour)
-               return dst->neighbour->output(skb);
-
-       IP6_INC_STATS_BH(dev_net(dst->dev),
-                        ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
-       kfree_skb(skb);
-       return -EINVAL;
-
-}
-
 /* dev_loopback_xmit for use with netfilter. */
 static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
 {
@@ -112,8 +96,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
        return 0;
 }
 
-
-static int ip6_output2(struct sk_buff *skb)
+static int ip6_finish_output2(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
        struct net_device *dev = dst->dev;
@@ -125,7 +108,7 @@ static int ip6_output2(struct sk_buff *skb)
                struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
 
                if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) &&
-                   ((mroute6_socket(dev_net(dev)) &&
+                   ((mroute6_socket(dev_net(dev), skb) &&
                     !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
                     ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
                                         &ipv6_hdr(skb)->saddr))) {
@@ -135,8 +118,8 @@ static int ip6_output2(struct sk_buff *skb)
                           is not supported in any case.
                         */
                        if (newskb)
-                               NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, newskb,
-                                       NULL, newskb->dev,
+                               NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
+                                       newskb, NULL, newskb->dev,
                                        ip6_dev_loopback_xmit);
 
                        if (ipv6_hdr(skb)->hop_limit == 0) {
@@ -151,8 +134,15 @@ static int ip6_output2(struct sk_buff *skb)
                                skb->len);
        }
 
-       return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
-                      ip6_output_finish);
+       if (dst->hh)
+               return neigh_hh_output(dst->hh, skb);
+       else if (dst->neighbour)
+               return dst->neighbour->output(skb);
+
+       IP6_INC_STATS_BH(dev_net(dst->dev),
+                        ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
+       kfree_skb(skb);
+       return -EINVAL;
 }
 
 static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
@@ -163,29 +153,37 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
               skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
 }
 
+static int ip6_finish_output(struct sk_buff *skb)
+{
+       if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
+           dst_allfrag(skb_dst(skb)))
+               return ip6_fragment(skb, ip6_finish_output2);
+       else
+               return ip6_finish_output2(skb);
+}
+
 int ip6_output(struct sk_buff *skb)
 {
+       struct net_device *dev = skb_dst(skb)->dev;
        struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
        if (unlikely(idev->cnf.disable_ipv6)) {
-               IP6_INC_STATS(dev_net(skb_dst(skb)->dev), idev,
+               IP6_INC_STATS(dev_net(dev), idev,
                              IPSTATS_MIB_OUTDISCARDS);
                kfree_skb(skb);
                return 0;
        }
 
-       if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
-                               dst_allfrag(skb_dst(skb)))
-               return ip6_fragment(skb, ip6_output2);
-       else
-               return ip6_output2(skb);
+       return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev,
+                           ip6_finish_output,
+                           !(IP6CB(skb)->flags & IP6SKB_REROUTED));
 }
 
 /*
- *     xmit an sk_buff (used by TCP)
+ *     xmit an sk_buff (used by TCP, SCTP and DCCP)
  */
 
 int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
-            struct ipv6_txoptions *opt, int ipfragok)
+            struct ipv6_txoptions *opt)
 {
        struct net *net = sock_net(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -218,8 +216,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
                        }
                        kfree_skb(skb);
                        skb = skb2;
-                       if (sk)
-                               skb_set_owner_w(skb, sk);
+                       skb_set_owner_w(skb, sk);
                }
                if (opt->opt_flen)
                        ipv6_push_frag_opts(skb, opt, &proto);
@@ -231,10 +228,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
        skb_reset_network_header(skb);
        hdr = ipv6_hdr(skb);
 
-       /* Allow local fragmentation. */
-       if (ipfragok)
-               skb->local_df = 1;
-
        /*
         *      Fill in the IPv6 header
         */
@@ -261,8 +254,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
        if ((skb->len <= mtu) || skb->local_df || skb_is_gso(skb)) {
                IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
                              IPSTATS_MIB_OUT, skb->len);
-               return NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
-                               dst_output);
+               return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
+                              dst->dev, dst_output);
        }
 
        if (net_ratelimit())
@@ -538,7 +531,7 @@ int ip6_forward(struct sk_buff *skb)
        hdr->hop_limit--;
 
        IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
-       return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
+       return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev,
                       ip6_forward_finish);
 
 error:
@@ -1109,7 +1102,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
        int offset, int len, int odd, struct sk_buff *skb),
        void *from, int length, int transhdrlen,
        int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi *fl,
-       struct rt6_info *rt, unsigned int flags)
+       struct rt6_info *rt, unsigned int flags, int dontfrag)
 {
        struct inet_sock *inet = inet_sk(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -1223,15 +1216,23 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
         */
 
        inet->cork.length += length;
-       if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
-           (rt->u.dst.dev->features & NETIF_F_UFO)) {
+       if (length > mtu) {
+               int proto = sk->sk_protocol;
+               if (dontfrag && (proto == IPPROTO_UDP || proto == IPPROTO_RAW)){
+                       ipv6_local_rxpmtu(sk, fl, mtu-exthdrlen);
+                       return -EMSGSIZE;
+               }
 
-               err = ip6_ufo_append_data(sk, getfrag, from, length, hh_len,
-                                         fragheaderlen, transhdrlen, mtu,
-                                         flags);
-               if (err)
-                       goto error;
-               return 0;
+               if (proto == IPPROTO_UDP &&
+                   (rt->u.dst.dev->features & NETIF_F_UFO)) {
+
+                       err = ip6_ufo_append_data(sk, getfrag, from, length,
+                                                 hh_len, fragheaderlen,
+                                                 transhdrlen, mtu, flags);
+                       if (err)
+                               goto error;
+                       return 0;
+               }
        }
 
        if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
index 2599870747ec88e82101fde1c1d42eb393c01898..8f39893d808153993dcecf2326dd453dd2b630b9 100644 (file)
@@ -723,14 +723,10 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
                skb->protocol = htons(protocol);
                skb->pkt_type = PACKET_HOST;
                memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
-               skb->dev = t->dev;
-               skb_dst_drop(skb);
-               nf_reset(skb);
 
-               dscp_ecn_decapsulate(t, ipv6h, skb);
+               skb_tunnel_rx(skb, t->dev);
 
-               t->dev->stats.rx_packets++;
-               t->dev->stats.rx_bytes += skb->len;
+               dscp_ecn_decapsulate(t, ipv6h, skb);
                netif_rx(skb);
                rcu_read_unlock();
                return 0;
index 3e333268db897eeeee23895e3dc764f82f401391..bd9e7d3e9c8e2fe4779dc42e63273972e5e76cfc 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/if_arp.h>
 #include <net/checksum.h>
 #include <net/netlink.h>
+#include <net/fib_rules.h>
 
 #include <net/ipv6.h>
 #include <net/ip6_route.h>
 #include <linux/netfilter_ipv6.h>
 #include <net/ip6_checksum.h>
 
+struct mr6_table {
+       struct list_head        list;
+#ifdef CONFIG_NET_NS
+       struct net              *net;
+#endif
+       u32                     id;
+       struct sock             *mroute6_sk;
+       struct timer_list       ipmr_expire_timer;
+       struct list_head        mfc6_unres_queue;
+       struct list_head        mfc6_cache_array[MFC6_LINES];
+       struct mif_device       vif6_table[MAXMIFS];
+       int                     maxvif;
+       atomic_t                cache_resolve_queue_len;
+       int                     mroute_do_assert;
+       int                     mroute_do_pim;
+#ifdef CONFIG_IPV6_PIMSM_V2
+       int                     mroute_reg_vif_num;
+#endif
+};
+
+struct ip6mr_rule {
+       struct fib_rule         common;
+};
+
+struct ip6mr_result {
+       struct mr6_table        *mrt;
+};
+
 /* Big lock, protecting vif table, mrt cache and mroute socket state.
    Note that the changes are semaphored via rtnl_lock.
  */
@@ -61,9 +90,7 @@ static DEFINE_RWLOCK(mrt_lock);
  *     Multicast router control variables
  */
 
-#define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL)
-
-static struct mfc6_cache *mfc_unres_queue;             /* Queue of unresolved entries */
+#define MIF_EXISTS(_mrt, _idx) ((_mrt)->vif6_table[_idx].dev != NULL)
 
 /* Special spinlock for queue of unresolved entries */
 static DEFINE_SPINLOCK(mfc_unres_lock);
@@ -78,20 +105,233 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
 
 static struct kmem_cache *mrt_cachep __read_mostly;
 
-static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache);
-static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt,
+static struct mr6_table *ip6mr_new_table(struct net *net, u32 id);
+static void ip6mr_free_table(struct mr6_table *mrt);
+
+static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
+                         struct sk_buff *skb, struct mfc6_cache *cache);
+static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
                              mifi_t mifi, int assert);
-static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
-static void mroute_clean_tables(struct net *net);
+static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
+                              struct mfc6_cache *c, struct rtmsg *rtm);
+static int ip6mr_rtm_dumproute(struct sk_buff *skb,
+                              struct netlink_callback *cb);
+static void mroute_clean_tables(struct mr6_table *mrt);
+static void ipmr_expire_process(unsigned long arg);
+
+#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+#define ip6mr_for_each_table(mrt, met) \
+       list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
+
+static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
+{
+       struct mr6_table *mrt;
+
+       ip6mr_for_each_table(mrt, net) {
+               if (mrt->id == id)
+                       return mrt;
+       }
+       return NULL;
+}
+
+static int ip6mr_fib_lookup(struct net *net, struct flowi *flp,
+                           struct mr6_table **mrt)
+{
+       struct ip6mr_result res;
+       struct fib_lookup_arg arg = { .result = &res, };
+       int err;
+
+       err = fib_rules_lookup(net->ipv6.mr6_rules_ops, flp, 0, &arg);
+       if (err < 0)
+               return err;
+       *mrt = res.mrt;
+       return 0;
+}
+
+static int ip6mr_rule_action(struct fib_rule *rule, struct flowi *flp,
+                            int flags, struct fib_lookup_arg *arg)
+{
+       struct ip6mr_result *res = arg->result;
+       struct mr6_table *mrt;
+
+       switch (rule->action) {
+       case FR_ACT_TO_TBL:
+               break;
+       case FR_ACT_UNREACHABLE:
+               return -ENETUNREACH;
+       case FR_ACT_PROHIBIT:
+               return -EACCES;
+       case FR_ACT_BLACKHOLE:
+       default:
+               return -EINVAL;
+       }
+
+       mrt = ip6mr_get_table(rule->fr_net, rule->table);
+       if (mrt == NULL)
+               return -EAGAIN;
+       res->mrt = mrt;
+       return 0;
+}
+
+static int ip6mr_rule_match(struct fib_rule *rule, struct flowi *flp, int flags)
+{
+       return 1;
+}
+
+static const struct nla_policy ip6mr_rule_policy[FRA_MAX + 1] = {
+       FRA_GENERIC_POLICY,
+};
+
+static int ip6mr_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
+                               struct fib_rule_hdr *frh, struct nlattr **tb)
+{
+       return 0;
+}
+
+static int ip6mr_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
+                             struct nlattr **tb)
+{
+       return 1;
+}
+
+static int ip6mr_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
+                          struct fib_rule_hdr *frh)
+{
+       frh->dst_len = 0;
+       frh->src_len = 0;
+       frh->tos     = 0;
+       return 0;
+}
+
+static const struct fib_rules_ops __net_initdata ip6mr_rules_ops_template = {
+       .family         = RTNL_FAMILY_IP6MR,
+       .rule_size      = sizeof(struct ip6mr_rule),
+       .addr_size      = sizeof(struct in6_addr),
+       .action         = ip6mr_rule_action,
+       .match          = ip6mr_rule_match,
+       .configure      = ip6mr_rule_configure,
+       .compare        = ip6mr_rule_compare,
+       .default_pref   = fib_default_rule_pref,
+       .fill           = ip6mr_rule_fill,
+       .nlgroup        = RTNLGRP_IPV6_RULE,
+       .policy         = ip6mr_rule_policy,
+       .owner          = THIS_MODULE,
+};
+
+static int __net_init ip6mr_rules_init(struct net *net)
+{
+       struct fib_rules_ops *ops;
+       struct mr6_table *mrt;
+       int err;
+
+       ops = fib_rules_register(&ip6mr_rules_ops_template, net);
+       if (IS_ERR(ops))
+               return PTR_ERR(ops);
+
+       INIT_LIST_HEAD(&net->ipv6.mr6_tables);
+
+       mrt = ip6mr_new_table(net, RT6_TABLE_DFLT);
+       if (mrt == NULL) {
+               err = -ENOMEM;
+               goto err1;
+       }
+
+       err = fib_default_rule_add(ops, 0x7fff, RT6_TABLE_DFLT, 0);
+       if (err < 0)
+               goto err2;
+
+       net->ipv6.mr6_rules_ops = ops;
+       return 0;
+
+err2:
+       kfree(mrt);
+err1:
+       fib_rules_unregister(ops);
+       return err;
+}
+
+static void __net_exit ip6mr_rules_exit(struct net *net)
+{
+       struct mr6_table *mrt, *next;
+
+       list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list)
+               ip6mr_free_table(mrt);
+       fib_rules_unregister(net->ipv6.mr6_rules_ops);
+}
+#else
+#define ip6mr_for_each_table(mrt, net) \
+       for (mrt = net->ipv6.mrt6; mrt; mrt = NULL)
+
+static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
+{
+       return net->ipv6.mrt6;
+}
+
+static int ip6mr_fib_lookup(struct net *net, struct flowi *flp,
+                           struct mr6_table **mrt)
+{
+       *mrt = net->ipv6.mrt6;
+       return 0;
+}
+
+static int __net_init ip6mr_rules_init(struct net *net)
+{
+       net->ipv6.mrt6 = ip6mr_new_table(net, RT6_TABLE_DFLT);
+       return net->ipv6.mrt6 ? 0 : -ENOMEM;
+}
 
-static struct timer_list ipmr_expire_timer;
+static void __net_exit ip6mr_rules_exit(struct net *net)
+{
+       ip6mr_free_table(net->ipv6.mrt6);
+}
+#endif
+
+static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
+{
+       struct mr6_table *mrt;
+       unsigned int i;
+
+       mrt = ip6mr_get_table(net, id);
+       if (mrt != NULL)
+               return mrt;
+
+       mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
+       if (mrt == NULL)
+               return NULL;
+       mrt->id = id;
+       write_pnet(&mrt->net, net);
+
+       /* Forwarding cache */
+       for (i = 0; i < MFC6_LINES; i++)
+               INIT_LIST_HEAD(&mrt->mfc6_cache_array[i]);
+
+       INIT_LIST_HEAD(&mrt->mfc6_unres_queue);
 
+       setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
+                   (unsigned long)mrt);
+
+#ifdef CONFIG_IPV6_PIMSM_V2
+       mrt->mroute_reg_vif_num = -1;
+#endif
+#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+       list_add_tail_rcu(&mrt->list, &net->ipv6.mr6_tables);
+#endif
+       return mrt;
+}
+
+static void ip6mr_free_table(struct mr6_table *mrt)
+{
+       del_timer(&mrt->ipmr_expire_timer);
+       mroute_clean_tables(mrt);
+       kfree(mrt);
+}
 
 #ifdef CONFIG_PROC_FS
 
 struct ipmr_mfc_iter {
        struct seq_net_private p;
-       struct mfc6_cache **cache;
+       struct mr6_table *mrt;
+       struct list_head *cache;
        int ct;
 };
 
@@ -99,22 +339,22 @@ struct ipmr_mfc_iter {
 static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
                                           struct ipmr_mfc_iter *it, loff_t pos)
 {
+       struct mr6_table *mrt = it->mrt;
        struct mfc6_cache *mfc;
 
-       it->cache = net->ipv6.mfc6_cache_array;
        read_lock(&mrt_lock);
-       for (it->ct = 0; it->ct < MFC6_LINES; it->ct++)
-               for (mfc = net->ipv6.mfc6_cache_array[it->ct];
-                    mfc; mfc = mfc->next)
+       for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) {
+               it->cache = &mrt->mfc6_cache_array[it->ct];
+               list_for_each_entry(mfc, it->cache, list)
                        if (pos-- == 0)
                                return mfc;
+       }
        read_unlock(&mrt_lock);
 
-       it->cache = &mfc_unres_queue;
        spin_lock_bh(&mfc_unres_lock);
-       for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
-               if (net_eq(mfc6_net(mfc), net) &&
-                   pos-- == 0)
+       it->cache = &mrt->mfc6_unres_queue;
+       list_for_each_entry(mfc, it->cache, list)
+               if (pos-- == 0)
                        return mfc;
        spin_unlock_bh(&mfc_unres_lock);
 
@@ -122,15 +362,13 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net,
        return NULL;
 }
 
-
-
-
 /*
  *     The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif
  */
 
 struct ipmr_vif_iter {
        struct seq_net_private p;
+       struct mr6_table *mrt;
        int ct;
 };
 
@@ -138,11 +376,13 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
                                            struct ipmr_vif_iter *iter,
                                            loff_t pos)
 {
-       for (iter->ct = 0; iter->ct < net->ipv6.maxvif; ++iter->ct) {
-               if (!MIF_EXISTS(net, iter->ct))
+       struct mr6_table *mrt = iter->mrt;
+
+       for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
+               if (!MIF_EXISTS(mrt, iter->ct))
                        continue;
                if (pos-- == 0)
-                       return &net->ipv6.vif6_table[iter->ct];
+                       return &mrt->vif6_table[iter->ct];
        }
        return NULL;
 }
@@ -150,7 +390,15 @@ static struct mif_device *ip6mr_vif_seq_idx(struct net *net,
 static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(mrt_lock)
 {
+       struct ipmr_vif_iter *iter = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr6_table *mrt;
+
+       mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return ERR_PTR(-ENOENT);
+
+       iter->mrt = mrt;
 
        read_lock(&mrt_lock);
        return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1)
@@ -161,15 +409,16 @@ static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
        struct ipmr_vif_iter *iter = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr6_table *mrt = iter->mrt;
 
        ++*pos;
        if (v == SEQ_START_TOKEN)
                return ip6mr_vif_seq_idx(net, iter, 0);
 
-       while (++iter->ct < net->ipv6.maxvif) {
-               if (!MIF_EXISTS(net, iter->ct))
+       while (++iter->ct < mrt->maxvif) {
+               if (!MIF_EXISTS(mrt, iter->ct))
                        continue;
-               return &net->ipv6.vif6_table[iter->ct];
+               return &mrt->vif6_table[iter->ct];
        }
        return NULL;
 }
@@ -182,7 +431,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v)
 
 static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
 {
-       struct net *net = seq_file_net(seq);
+       struct ipmr_vif_iter *iter = seq->private;
+       struct mr6_table *mrt = iter->mrt;
 
        if (v == SEQ_START_TOKEN) {
                seq_puts(seq,
@@ -193,7 +443,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v)
 
                seq_printf(seq,
                           "%2td %-10s %8ld %7ld  %8ld %7ld %05X\n",
-                          vif - net->ipv6.vif6_table,
+                          vif - mrt->vif6_table,
                           name, vif->bytes_in, vif->pkt_in,
                           vif->bytes_out, vif->pkt_out,
                           vif->flags);
@@ -224,8 +474,15 @@ static const struct file_operations ip6mr_vif_fops = {
 
 static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
 {
+       struct ipmr_mfc_iter *it = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr6_table *mrt;
 
+       mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return ERR_PTR(-ENOENT);
+
+       it->mrt = mrt;
        return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
                : SEQ_START_TOKEN;
 }
@@ -235,35 +492,36 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        struct mfc6_cache *mfc = v;
        struct ipmr_mfc_iter *it = seq->private;
        struct net *net = seq_file_net(seq);
+       struct mr6_table *mrt = it->mrt;
 
        ++*pos;
 
        if (v == SEQ_START_TOKEN)
                return ipmr_mfc_seq_idx(net, seq->private, 0);
 
-       if (mfc->next)
-               return mfc->next;
+       if (mfc->list.next != it->cache)
+               return list_entry(mfc->list.next, struct mfc6_cache, list);
 
-       if (it->cache == &mfc_unres_queue)
+       if (it->cache == &mrt->mfc6_unres_queue)
                goto end_of_list;
 
-       BUG_ON(it->cache != net->ipv6.mfc6_cache_array);
+       BUG_ON(it->cache != &mrt->mfc6_cache_array[it->ct]);
 
        while (++it->ct < MFC6_LINES) {
-               mfc = net->ipv6.mfc6_cache_array[it->ct];
-               if (mfc)
-                       return mfc;
+               it->cache = &mrt->mfc6_cache_array[it->ct];
+               if (list_empty(it->cache))
+                       continue;
+               return list_first_entry(it->cache, struct mfc6_cache, list);
        }
 
        /* exhausted cache_array, show unresolved */
        read_unlock(&mrt_lock);
-       it->cache = &mfc_unres_queue;
+       it->cache = &mrt->mfc6_unres_queue;
        it->ct = 0;
 
        spin_lock_bh(&mfc_unres_lock);
-       mfc = mfc_unres_queue;
-       if (mfc)
-               return mfc;
+       if (!list_empty(it->cache))
+               return list_first_entry(it->cache, struct mfc6_cache, list);
 
  end_of_list:
        spin_unlock_bh(&mfc_unres_lock);
@@ -275,18 +533,17 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
 {
        struct ipmr_mfc_iter *it = seq->private;
-       struct net *net = seq_file_net(seq);
+       struct mr6_table *mrt = it->mrt;
 
-       if (it->cache == &mfc_unres_queue)
+       if (it->cache == &mrt->mfc6_unres_queue)
                spin_unlock_bh(&mfc_unres_lock);
-       else if (it->cache == net->ipv6.mfc6_cache_array)
+       else if (it->cache == mrt->mfc6_cache_array)
                read_unlock(&mrt_lock);
 }
 
 static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
 {
        int n;
-       struct net *net = seq_file_net(seq);
 
        if (v == SEQ_START_TOKEN) {
                seq_puts(seq,
@@ -296,19 +553,20 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
        } else {
                const struct mfc6_cache *mfc = v;
                const struct ipmr_mfc_iter *it = seq->private;
+               struct mr6_table *mrt = it->mrt;
 
                seq_printf(seq, "%pI6 %pI6 %-3hd",
                           &mfc->mf6c_mcastgrp, &mfc->mf6c_origin,
                           mfc->mf6c_parent);
 
-               if (it->cache != &mfc_unres_queue) {
+               if (it->cache != &mrt->mfc6_unres_queue) {
                        seq_printf(seq, " %8lu %8lu %8lu",
                                   mfc->mfc_un.res.pkt,
                                   mfc->mfc_un.res.bytes,
                                   mfc->mfc_un.res.wrong_if);
                        for (n = mfc->mfc_un.res.minvif;
                             n < mfc->mfc_un.res.maxvif; n++) {
-                               if (MIF_EXISTS(net, n) &&
+                               if (MIF_EXISTS(mrt, n) &&
                                    mfc->mfc_un.res.ttls[n] < 255)
                                        seq_printf(seq,
                                                   " %2d:%-3d",
@@ -355,7 +613,12 @@ static int pim6_rcv(struct sk_buff *skb)
        struct ipv6hdr   *encap;
        struct net_device  *reg_dev = NULL;
        struct net *net = dev_net(skb->dev);
-       int reg_vif_num = net->ipv6.mroute_reg_vif_num;
+       struct mr6_table *mrt;
+       struct flowi fl = {
+               .iif    = skb->dev->ifindex,
+               .mark   = skb->mark,
+       };
+       int reg_vif_num;
 
        if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
                goto drop;
@@ -378,9 +641,13 @@ static int pim6_rcv(struct sk_buff *skb)
            ntohs(encap->payload_len) + sizeof(*pim) > skb->len)
                goto drop;
 
+       if (ip6mr_fib_lookup(net, &fl, &mrt) < 0)
+               goto drop;
+       reg_vif_num = mrt->mroute_reg_vif_num;
+
        read_lock(&mrt_lock);
        if (reg_vif_num >= 0)
-               reg_dev = net->ipv6.vif6_table[reg_vif_num].dev;
+               reg_dev = mrt->vif6_table[reg_vif_num].dev;
        if (reg_dev)
                dev_hold(reg_dev);
        read_unlock(&mrt_lock);
@@ -391,14 +658,12 @@ static int pim6_rcv(struct sk_buff *skb)
        skb->mac_header = skb->network_header;
        skb_pull(skb, (u8 *)encap - skb->data);
        skb_reset_network_header(skb);
-       skb->dev = reg_dev;
        skb->protocol = htons(ETH_P_IPV6);
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
-       skb_dst_drop(skb);
-       reg_dev->stats.rx_bytes += skb->len;
-       reg_dev->stats.rx_packets++;
-       nf_reset(skb);
+
+       skb_tunnel_rx(skb, reg_dev);
+
        netif_rx(skb);
        dev_put(reg_dev);
        return 0;
@@ -417,12 +682,22 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
                                      struct net_device *dev)
 {
        struct net *net = dev_net(dev);
+       struct mr6_table *mrt;
+       struct flowi fl = {
+               .oif            = dev->ifindex,
+               .iif            = skb->skb_iif,
+               .mark           = skb->mark,
+       };
+       int err;
+
+       err = ip6mr_fib_lookup(net, &fl, &mrt);
+       if (err < 0)
+               return err;
 
        read_lock(&mrt_lock);
        dev->stats.tx_bytes += skb->len;
        dev->stats.tx_packets++;
-       ip6mr_cache_report(net, skb, net->ipv6.mroute_reg_vif_num,
-                          MRT6MSG_WHOLEPKT);
+       ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT);
        read_unlock(&mrt_lock);
        kfree_skb(skb);
        return NETDEV_TX_OK;
@@ -442,11 +717,17 @@ static void reg_vif_setup(struct net_device *dev)
        dev->features           |= NETIF_F_NETNS_LOCAL;
 }
 
-static struct net_device *ip6mr_reg_vif(struct net *net)
+static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
 {
        struct net_device *dev;
+       char name[IFNAMSIZ];
+
+       if (mrt->id == RT6_TABLE_DFLT)
+               sprintf(name, "pim6reg");
+       else
+               sprintf(name, "pim6reg%u", mrt->id);
 
-       dev = alloc_netdev(0, "pim6reg", reg_vif_setup);
+       dev = alloc_netdev(0, name, reg_vif_setup);
        if (dev == NULL)
                return NULL;
 
@@ -478,15 +759,16 @@ failure:
  *     Delete a VIF entry
  */
 
-static int mif6_delete(struct net *net, int vifi, struct list_head *head)
+static int mif6_delete(struct mr6_table *mrt, int vifi, struct list_head *head)
 {
        struct mif_device *v;
        struct net_device *dev;
        struct inet6_dev *in6_dev;
-       if (vifi < 0 || vifi >= net->ipv6.maxvif)
+
+       if (vifi < 0 || vifi >= mrt->maxvif)
                return -EADDRNOTAVAIL;
 
-       v = &net->ipv6.vif6_table[vifi];
+       v = &mrt->vif6_table[vifi];
 
        write_lock_bh(&mrt_lock);
        dev = v->dev;
@@ -498,17 +780,17 @@ static int mif6_delete(struct net *net, int vifi, struct list_head *head)
        }
 
 #ifdef CONFIG_IPV6_PIMSM_V2
-       if (vifi == net->ipv6.mroute_reg_vif_num)
-               net->ipv6.mroute_reg_vif_num = -1;
+       if (vifi == mrt->mroute_reg_vif_num)
+               mrt->mroute_reg_vif_num = -1;
 #endif
 
-       if (vifi + 1 == net->ipv6.maxvif) {
+       if (vifi + 1 == mrt->maxvif) {
                int tmp;
                for (tmp = vifi - 1; tmp >= 0; tmp--) {
-                       if (MIF_EXISTS(net, tmp))
+                       if (MIF_EXISTS(mrt, tmp))
                                break;
                }
-               net->ipv6.maxvif = tmp + 1;
+               mrt->maxvif = tmp + 1;
        }
 
        write_unlock_bh(&mrt_lock);
@@ -528,7 +810,6 @@ static int mif6_delete(struct net *net, int vifi, struct list_head *head)
 
 static inline void ip6mr_cache_free(struct mfc6_cache *c)
 {
-       release_net(mfc6_net(c));
        kmem_cache_free(mrt_cachep, c);
 }
 
@@ -536,12 +817,12 @@ static inline void ip6mr_cache_free(struct mfc6_cache *c)
    and reporting error to netlink readers.
  */
 
-static void ip6mr_destroy_unres(struct mfc6_cache *c)
+static void ip6mr_destroy_unres(struct mr6_table *mrt, struct mfc6_cache *c)
 {
+       struct net *net = read_pnet(&mrt->net);
        struct sk_buff *skb;
-       struct net *net = mfc6_net(c);
 
-       atomic_dec(&net->ipv6.cache_resolve_queue_len);
+       atomic_dec(&mrt->cache_resolve_queue_len);
 
        while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) {
                if (ipv6_hdr(skb)->version == 0) {
@@ -559,60 +840,59 @@ static void ip6mr_destroy_unres(struct mfc6_cache *c)
 }
 
 
-/* Single timer process for all the unresolved queue. */
+/* Timer process for all the unresolved queue. */
 
-static void ipmr_do_expire_process(unsigned long dummy)
+static void ipmr_do_expire_process(struct mr6_table *mrt)
 {
        unsigned long now = jiffies;
        unsigned long expires = 10 * HZ;
-       struct mfc6_cache *c, **cp;
-
-       cp = &mfc_unres_queue;
+       struct mfc6_cache *c, *next;
 
-       while ((c = *cp) != NULL) {
+       list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
                if (time_after(c->mfc_un.unres.expires, now)) {
                        /* not yet... */
                        unsigned long interval = c->mfc_un.unres.expires - now;
                        if (interval < expires)
                                expires = interval;
-                       cp = &c->next;
                        continue;
                }
 
-               *cp = c->next;
-               ip6mr_destroy_unres(c);
+               list_del(&c->list);
+               ip6mr_destroy_unres(mrt, c);
        }
 
-       if (mfc_unres_queue != NULL)
-               mod_timer(&ipmr_expire_timer, jiffies + expires);
+       if (!list_empty(&mrt->mfc6_unres_queue))
+               mod_timer(&mrt->ipmr_expire_timer, jiffies + expires);
 }
 
-static void ipmr_expire_process(unsigned long dummy)
+static void ipmr_expire_process(unsigned long arg)
 {
+       struct mr6_table *mrt = (struct mr6_table *)arg;
+
        if (!spin_trylock(&mfc_unres_lock)) {
-               mod_timer(&ipmr_expire_timer, jiffies + 1);
+               mod_timer(&mrt->ipmr_expire_timer, jiffies + 1);
                return;
        }
 
-       if (mfc_unres_queue != NULL)
-               ipmr_do_expire_process(dummy);
+       if (!list_empty(&mrt->mfc6_unres_queue))
+               ipmr_do_expire_process(mrt);
 
        spin_unlock(&mfc_unres_lock);
 }
 
 /* Fill oifs list. It is called under write locked mrt_lock. */
 
-static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls)
+static void ip6mr_update_thresholds(struct mr6_table *mrt, struct mfc6_cache *cache,
+                                   unsigned char *ttls)
 {
        int vifi;
-       struct net *net = mfc6_net(cache);
 
        cache->mfc_un.res.minvif = MAXMIFS;
        cache->mfc_un.res.maxvif = 0;
        memset(cache->mfc_un.res.ttls, 255, MAXMIFS);
 
-       for (vifi = 0; vifi < net->ipv6.maxvif; vifi++) {
-               if (MIF_EXISTS(net, vifi) &&
+       for (vifi = 0; vifi < mrt->maxvif; vifi++) {
+               if (MIF_EXISTS(mrt, vifi) &&
                    ttls[vifi] && ttls[vifi] < 255) {
                        cache->mfc_un.res.ttls[vifi] = ttls[vifi];
                        if (cache->mfc_un.res.minvif > vifi)
@@ -623,16 +903,17 @@ static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttl
        }
 }
 
-static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
+static int mif6_add(struct net *net, struct mr6_table *mrt,
+                   struct mif6ctl *vifc, int mrtsock)
 {
        int vifi = vifc->mif6c_mifi;
-       struct mif_device *v = &net->ipv6.vif6_table[vifi];
+       struct mif_device *v = &mrt->vif6_table[vifi];
        struct net_device *dev;
        struct inet6_dev *in6_dev;
        int err;
 
        /* Is vif busy ? */
-       if (MIF_EXISTS(net, vifi))
+       if (MIF_EXISTS(mrt, vifi))
                return -EADDRINUSE;
 
        switch (vifc->mif6c_flags) {
@@ -642,9 +923,9 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
                 * Special Purpose VIF in PIM
                 * All the packets will be sent to the daemon
                 */
-               if (net->ipv6.mroute_reg_vif_num >= 0)
+               if (mrt->mroute_reg_vif_num >= 0)
                        return -EADDRINUSE;
-               dev = ip6mr_reg_vif(net);
+               dev = ip6mr_reg_vif(net, mrt);
                if (!dev)
                        return -ENOBUFS;
                err = dev_set_allmulti(dev, 1);
@@ -694,50 +975,48 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
        v->dev = dev;
 #ifdef CONFIG_IPV6_PIMSM_V2
        if (v->flags & MIFF_REGISTER)
-               net->ipv6.mroute_reg_vif_num = vifi;
+               mrt->mroute_reg_vif_num = vifi;
 #endif
-       if (vifi + 1 > net->ipv6.maxvif)
-               net->ipv6.maxvif = vifi + 1;
+       if (vifi + 1 > mrt->maxvif)
+               mrt->maxvif = vifi + 1;
        write_unlock_bh(&mrt_lock);
        return 0;
 }
 
-static struct mfc6_cache *ip6mr_cache_find(struct net *net,
+static struct mfc6_cache *ip6mr_cache_find(struct mr6_table *mrt,
                                           struct in6_addr *origin,
                                           struct in6_addr *mcastgrp)
 {
        int line = MFC6_HASH(mcastgrp, origin);
        struct mfc6_cache *c;
 
-       for (c = net->ipv6.mfc6_cache_array[line]; c; c = c->next) {
+       list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
                if (ipv6_addr_equal(&c->mf6c_origin, origin) &&
                    ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp))
-                       break;
+                       return c;
        }
-       return c;
+       return NULL;
 }
 
 /*
  *     Allocate a multicast cache entry
  */
-static struct mfc6_cache *ip6mr_cache_alloc(struct net *net)
+static struct mfc6_cache *ip6mr_cache_alloc(void)
 {
        struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
        if (c == NULL)
                return NULL;
        c->mfc_un.res.minvif = MAXMIFS;
-       mfc6_net_set(c, net);
        return c;
 }
 
-static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
+static struct mfc6_cache *ip6mr_cache_alloc_unres(void)
 {
        struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
        if (c == NULL)
                return NULL;
        skb_queue_head_init(&c->mfc_un.unres.unresolved);
        c->mfc_un.unres.expires = jiffies + 10 * HZ;
-       mfc6_net_set(c, net);
        return c;
 }
 
@@ -745,7 +1024,8 @@ static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net)
  *     A cache entry has gone into a resolved state from queued
  */
 
-static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
+static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
+                               struct mfc6_cache *uc, struct mfc6_cache *c)
 {
        struct sk_buff *skb;
 
@@ -758,7 +1038,7 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
                        int err;
                        struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr));
 
-                       if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
+                       if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) {
                                nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh;
                        } else {
                                nlh->nlmsg_type = NLMSG_ERROR;
@@ -766,9 +1046,9 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
                                skb_trim(skb, nlh->nlmsg_len);
                                ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE;
                        }
-                       err = rtnl_unicast(skb, mfc6_net(uc), NETLINK_CB(skb).pid);
+                       err = rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
                } else
-                       ip6_mr_forward(skb, c);
+                       ip6_mr_forward(net, mrt, skb, c);
        }
 }
 
@@ -779,8 +1059,8 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c)
  *     Called under mrt_lock.
  */
 
-static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
-                             int assert)
+static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
+                             mifi_t mifi, int assert)
 {
        struct sk_buff *skb;
        struct mrt6msg *msg;
@@ -816,7 +1096,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
                msg = (struct mrt6msg *)skb_transport_header(skb);
                msg->im6_mbz = 0;
                msg->im6_msgtype = MRT6MSG_WHOLEPKT;
-               msg->im6_mif = net->ipv6.mroute_reg_vif_num;
+               msg->im6_mif = mrt->mroute_reg_vif_num;
                msg->im6_pad = 0;
                ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr);
                ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr);
@@ -851,7 +1131,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
-       if (net->ipv6.mroute6_sk == NULL) {
+       if (mrt->mroute6_sk == NULL) {
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -859,7 +1139,7 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
        /*
         *      Deliver to user space multicast routing algorithms
         */
-       ret = sock_queue_rcv_skb(net->ipv6.mroute6_sk, skb);
+       ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
        if (ret < 0) {
                if (net_ratelimit())
                        printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n");
@@ -874,26 +1154,28 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
  */
 
 static int
-ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
+ip6mr_cache_unresolved(struct mr6_table *mrt, mifi_t mifi, struct sk_buff *skb)
 {
+       bool found = false;
        int err;
        struct mfc6_cache *c;
 
        spin_lock_bh(&mfc_unres_lock);
-       for (c = mfc_unres_queue; c; c = c->next) {
-               if (net_eq(mfc6_net(c), net) &&
-                   ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
-                   ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr))
+       list_for_each_entry(c, &mrt->mfc6_unres_queue, list) {
+               if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) &&
+                   ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) {
+                       found = true;
                        break;
+               }
        }
 
-       if (c == NULL) {
+       if (!found) {
                /*
                 *      Create a new entry if allowable
                 */
 
-               if (atomic_read(&net->ipv6.cache_resolve_queue_len) >= 10 ||
-                   (c = ip6mr_cache_alloc_unres(net)) == NULL) {
+               if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
+                   (c = ip6mr_cache_alloc_unres()) == NULL) {
                        spin_unlock_bh(&mfc_unres_lock);
 
                        kfree_skb(skb);
@@ -910,7 +1192,7 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
                /*
                 *      Reflect first query at pim6sd
                 */
-               err = ip6mr_cache_report(net, skb, mifi, MRT6MSG_NOCACHE);
+               err = ip6mr_cache_report(mrt, skb, mifi, MRT6MSG_NOCACHE);
                if (err < 0) {
                        /* If the report failed throw the cache entry
                           out - Brad Parker
@@ -922,11 +1204,10 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
                        return err;
                }
 
-               atomic_inc(&net->ipv6.cache_resolve_queue_len);
-               c->next = mfc_unres_queue;
-               mfc_unres_queue = c;
+               atomic_inc(&mrt->cache_resolve_queue_len);
+               list_add(&c->list, &mrt->mfc6_unres_queue);
 
-               ipmr_do_expire_process(1);
+               ipmr_do_expire_process(mrt);
        }
 
        /*
@@ -948,19 +1229,18 @@ ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb)
  *     MFC6 cache manipulation by user space
  */
 
-static int ip6mr_mfc_delete(struct net *net, struct mf6cctl *mfc)
+static int ip6mr_mfc_delete(struct mr6_table *mrt, struct mf6cctl *mfc)
 {
        int line;
-       struct mfc6_cache *c, **cp;
+       struct mfc6_cache *c, *next;
 
        line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
 
-       for (cp = &net->ipv6.mfc6_cache_array[line];
-            (c = *cp) != NULL; cp = &c->next) {
+       list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[line], list) {
                if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
                    ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
                        write_lock_bh(&mrt_lock);
-                       *cp = c->next;
+                       list_del(&c->list);
                        write_unlock_bh(&mrt_lock);
 
                        ip6mr_cache_free(c);
@@ -975,6 +1255,7 @@ static int ip6mr_device_event(struct notifier_block *this,
 {
        struct net_device *dev = ptr;
        struct net *net = dev_net(dev);
+       struct mr6_table *mrt;
        struct mif_device *v;
        int ct;
        LIST_HEAD(list);
@@ -982,10 +1263,12 @@ static int ip6mr_device_event(struct notifier_block *this,
        if (event != NETDEV_UNREGISTER)
                return NOTIFY_DONE;
 
-       v = &net->ipv6.vif6_table[0];
-       for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) {
-               if (v->dev == dev)
-                       mif6_delete(net, ct, &list);
+       ip6mr_for_each_table(mrt, net) {
+               v = &mrt->vif6_table[0];
+               for (ct = 0; ct < mrt->maxvif; ct++, v++) {
+                       if (v->dev == dev)
+                               mif6_delete(mrt, ct, &list);
+               }
        }
        unregister_netdevice_many(&list);
 
@@ -1002,26 +1285,11 @@ static struct notifier_block ip6_mr_notifier = {
 
 static int __net_init ip6mr_net_init(struct net *net)
 {
-       int err = 0;
-       net->ipv6.vif6_table = kcalloc(MAXMIFS, sizeof(struct mif_device),
-                                      GFP_KERNEL);
-       if (!net->ipv6.vif6_table) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       /* Forwarding cache */
-       net->ipv6.mfc6_cache_array = kcalloc(MFC6_LINES,
-                                            sizeof(struct mfc6_cache *),
-                                            GFP_KERNEL);
-       if (!net->ipv6.mfc6_cache_array) {
-               err = -ENOMEM;
-               goto fail_mfc6_cache;
-       }
+       int err;
 
-#ifdef CONFIG_IPV6_PIMSM_V2
-       net->ipv6.mroute_reg_vif_num = -1;
-#endif
+       err = ip6mr_rules_init(net);
+       if (err < 0)
+               goto fail;
 
 #ifdef CONFIG_PROC_FS
        err = -ENOMEM;
@@ -1030,16 +1298,15 @@ static int __net_init ip6mr_net_init(struct net *net)
        if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops))
                goto proc_cache_fail;
 #endif
+
        return 0;
 
 #ifdef CONFIG_PROC_FS
 proc_cache_fail:
        proc_net_remove(net, "ip6_mr_vif");
 proc_vif_fail:
-       kfree(net->ipv6.mfc6_cache_array);
+       ip6mr_rules_exit(net);
 #endif
-fail_mfc6_cache:
-       kfree(net->ipv6.vif6_table);
 fail:
        return err;
 }
@@ -1050,9 +1317,7 @@ static void __net_exit ip6mr_net_exit(struct net *net)
        proc_net_remove(net, "ip6_mr_cache");
        proc_net_remove(net, "ip6_mr_vif");
 #endif
-       mroute_clean_tables(net);
-       kfree(net->ipv6.mfc6_cache_array);
-       kfree(net->ipv6.vif6_table);
+       ip6mr_rules_exit(net);
 }
 
 static struct pernet_operations ip6mr_net_ops = {
@@ -1075,7 +1340,6 @@ int __init ip6_mr_init(void)
        if (err)
                goto reg_pernet_fail;
 
-       setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
        err = register_netdevice_notifier(&ip6_mr_notifier);
        if (err)
                goto reg_notif_fail;
@@ -1086,13 +1350,13 @@ int __init ip6_mr_init(void)
                goto add_proto_fail;
        }
 #endif
+       rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL, ip6mr_rtm_dumproute);
        return 0;
 #ifdef CONFIG_IPV6_PIMSM_V2
 add_proto_fail:
        unregister_netdevice_notifier(&ip6_mr_notifier);
 #endif
 reg_notif_fail:
-       del_timer(&ipmr_expire_timer);
        unregister_pernet_subsys(&ip6mr_net_ops);
 reg_pernet_fail:
        kmem_cache_destroy(mrt_cachep);
@@ -1102,15 +1366,16 @@ reg_pernet_fail:
 void ip6_mr_cleanup(void)
 {
        unregister_netdevice_notifier(&ip6_mr_notifier);
-       del_timer(&ipmr_expire_timer);
        unregister_pernet_subsys(&ip6mr_net_ops);
        kmem_cache_destroy(mrt_cachep);
 }
 
-static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
+static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
+                        struct mf6cctl *mfc, int mrtsock)
 {
+       bool found = false;
        int line;
-       struct mfc6_cache *uc, *c, **cp;
+       struct mfc6_cache *uc, *c;
        unsigned char ttls[MAXMIFS];
        int i;
 
@@ -1126,17 +1391,18 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
 
        line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr);
 
-       for (cp = &net->ipv6.mfc6_cache_array[line];
-            (c = *cp) != NULL; cp = &c->next) {
+       list_for_each_entry(c, &mrt->mfc6_cache_array[line], list) {
                if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) &&
-                   ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr))
+                   ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) {
+                       found = true;
                        break;
+               }
        }
 
-       if (c != NULL) {
+       if (found) {
                write_lock_bh(&mrt_lock);
                c->mf6c_parent = mfc->mf6cc_parent;
-               ip6mr_update_thresholds(c, ttls);
+               ip6mr_update_thresholds(mrt, c, ttls);
                if (!mrtsock)
                        c->mfc_flags |= MFC_STATIC;
                write_unlock_bh(&mrt_lock);
@@ -1146,43 +1412,42 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
        if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr))
                return -EINVAL;
 
-       c = ip6mr_cache_alloc(net);
+       c = ip6mr_cache_alloc();
        if (c == NULL)
                return -ENOMEM;
 
        c->mf6c_origin = mfc->mf6cc_origin.sin6_addr;
        c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr;
        c->mf6c_parent = mfc->mf6cc_parent;
-       ip6mr_update_thresholds(c, ttls);
+       ip6mr_update_thresholds(mrt, c, ttls);
        if (!mrtsock)
                c->mfc_flags |= MFC_STATIC;
 
        write_lock_bh(&mrt_lock);
-       c->next = net->ipv6.mfc6_cache_array[line];
-       net->ipv6.mfc6_cache_array[line] = c;
+       list_add(&c->list, &mrt->mfc6_cache_array[line]);
        write_unlock_bh(&mrt_lock);
 
        /*
         *      Check to see if we resolved a queued list. If so we
         *      need to send on the frames and tidy up.
         */
+       found = false;
        spin_lock_bh(&mfc_unres_lock);
-       for (cp = &mfc_unres_queue; (uc = *cp) != NULL;
-            cp = &uc->next) {
-               if (net_eq(mfc6_net(uc), net) &&
-                   ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
+       list_for_each_entry(uc, &mrt->mfc6_unres_queue, list) {
+               if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) &&
                    ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) {
-                       *cp = uc->next;
-                       atomic_dec(&net->ipv6.cache_resolve_queue_len);
+                       list_del(&uc->list);
+                       atomic_dec(&mrt->cache_resolve_queue_len);
+                       found = true;
                        break;
                }
        }
-       if (mfc_unres_queue == NULL)
-               del_timer(&ipmr_expire_timer);
+       if (list_empty(&mrt->mfc6_unres_queue))
+               del_timer(&mrt->ipmr_expire_timer);
        spin_unlock_bh(&mfc_unres_lock);
 
-       if (uc) {
-               ip6mr_cache_resolve(uc, c);
+       if (found) {
+               ip6mr_cache_resolve(net, mrt, uc, c);
                ip6mr_cache_free(uc);
        }
        return 0;
@@ -1192,17 +1457,18 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
  *     Close the multicast socket, and clear the vif tables etc
  */
 
-static void mroute_clean_tables(struct net *net)
+static void mroute_clean_tables(struct mr6_table *mrt)
 {
        int i;
        LIST_HEAD(list);
+       struct mfc6_cache *c, *next;
 
        /*
         *      Shut down all active vif entries
         */
-       for (i = 0; i < net->ipv6.maxvif; i++) {
-               if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC))
-                       mif6_delete(net, i, &list);
+       for (i = 0; i < mrt->maxvif; i++) {
+               if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
+                       mif6_delete(mrt, i, &list);
        }
        unregister_netdevice_many(&list);
 
@@ -1210,48 +1476,36 @@ static void mroute_clean_tables(struct net *net)
         *      Wipe the cache
         */
        for (i = 0; i < MFC6_LINES; i++) {
-               struct mfc6_cache *c, **cp;
-
-               cp = &net->ipv6.mfc6_cache_array[i];
-               while ((c = *cp) != NULL) {
-                       if (c->mfc_flags & MFC_STATIC) {
-                               cp = &c->next;
+               list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
+                       if (c->mfc_flags & MFC_STATIC)
                                continue;
-                       }
                        write_lock_bh(&mrt_lock);
-                       *cp = c->next;
+                       list_del(&c->list);
                        write_unlock_bh(&mrt_lock);
 
                        ip6mr_cache_free(c);
                }
        }
 
-       if (atomic_read(&net->ipv6.cache_resolve_queue_len) != 0) {
-               struct mfc6_cache *c, **cp;
-
+       if (atomic_read(&mrt->cache_resolve_queue_len) != 0) {
                spin_lock_bh(&mfc_unres_lock);
-               cp = &mfc_unres_queue;
-               while ((c = *cp) != NULL) {
-                       if (!net_eq(mfc6_net(c), net)) {
-                               cp = &c->next;
-                               continue;
-                       }
-                       *cp = c->next;
-                       ip6mr_destroy_unres(c);
+               list_for_each_entry_safe(c, next, &mrt->mfc6_unres_queue, list) {
+                       list_del(&c->list);
+                       ip6mr_destroy_unres(mrt, c);
                }
                spin_unlock_bh(&mfc_unres_lock);
        }
 }
 
-static int ip6mr_sk_init(struct sock *sk)
+static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
 {
        int err = 0;
        struct net *net = sock_net(sk);
 
        rtnl_lock();
        write_lock_bh(&mrt_lock);
-       if (likely(net->ipv6.mroute6_sk == NULL)) {
-               net->ipv6.mroute6_sk = sk;
+       if (likely(mrt->mroute6_sk == NULL)) {
+               mrt->mroute6_sk = sk;
                net->ipv6.devconf_all->mc_forwarding++;
        }
        else
@@ -1265,24 +1519,43 @@ static int ip6mr_sk_init(struct sock *sk)
 
 int ip6mr_sk_done(struct sock *sk)
 {
-       int err = 0;
+       int err = -EACCES;
        struct net *net = sock_net(sk);
+       struct mr6_table *mrt;
 
        rtnl_lock();
-       if (sk == net->ipv6.mroute6_sk) {
-               write_lock_bh(&mrt_lock);
-               net->ipv6.mroute6_sk = NULL;
-               net->ipv6.devconf_all->mc_forwarding--;
-               write_unlock_bh(&mrt_lock);
+       ip6mr_for_each_table(mrt, net) {
+               if (sk == mrt->mroute6_sk) {
+                       write_lock_bh(&mrt_lock);
+                       mrt->mroute6_sk = NULL;
+                       net->ipv6.devconf_all->mc_forwarding--;
+                       write_unlock_bh(&mrt_lock);
 
-               mroute_clean_tables(net);
-       } else
-               err = -EACCES;
+                       mroute_clean_tables(mrt);
+                       err = 0;
+                       break;
+               }
+       }
        rtnl_unlock();
 
        return err;
 }
 
+struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
+{
+       struct mr6_table *mrt;
+       struct flowi fl = {
+               .iif    = skb->skb_iif,
+               .oif    = skb->dev->ifindex,
+               .mark   = skb->mark,
+       };
+
+       if (ip6mr_fib_lookup(net, &fl, &mrt) < 0)
+               return NULL;
+
+       return mrt->mroute6_sk;
+}
+
 /*
  *     Socket options and virtual interface manipulation. The whole
  *     virtual interface system is a complete heap, but unfortunately
@@ -1297,9 +1570,14 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
        struct mf6cctl mfc;
        mifi_t mifi;
        struct net *net = sock_net(sk);
+       struct mr6_table *mrt;
+
+       mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return -ENOENT;
 
        if (optname != MRT6_INIT) {
-               if (sk != net->ipv6.mroute6_sk && !capable(CAP_NET_ADMIN))
+               if (sk != mrt->mroute6_sk && !capable(CAP_NET_ADMIN))
                        return -EACCES;
        }
 
@@ -1311,7 +1589,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                if (optlen < sizeof(int))
                        return -EINVAL;
 
-               return ip6mr_sk_init(sk);
+               return ip6mr_sk_init(mrt, sk);
 
        case MRT6_DONE:
                return ip6mr_sk_done(sk);
@@ -1324,7 +1602,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                if (vif.mif6c_mifi >= MAXMIFS)
                        return -ENFILE;
                rtnl_lock();
-               ret = mif6_add(net, &vif, sk == net->ipv6.mroute6_sk);
+               ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
                rtnl_unlock();
                return ret;
 
@@ -1334,7 +1612,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
                        return -EFAULT;
                rtnl_lock();
-               ret = mif6_delete(net, mifi, NULL);
+               ret = mif6_delete(mrt, mifi, NULL);
                rtnl_unlock();
                return ret;
 
@@ -1350,10 +1628,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                        return -EFAULT;
                rtnl_lock();
                if (optname == MRT6_DEL_MFC)
-                       ret = ip6mr_mfc_delete(net, &mfc);
+                       ret = ip6mr_mfc_delete(mrt, &mfc);
                else
-                       ret = ip6mr_mfc_add(net, &mfc,
-                                           sk == net->ipv6.mroute6_sk);
+                       ret = ip6mr_mfc_add(net, mrt, &mfc, sk == mrt->mroute6_sk);
                rtnl_unlock();
                return ret;
 
@@ -1365,7 +1642,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                int v;
                if (get_user(v, (int __user *)optval))
                        return -EFAULT;
-               net->ipv6.mroute_do_assert = !!v;
+               mrt->mroute_do_assert = !!v;
                return 0;
        }
 
@@ -1378,14 +1655,35 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
                v = !!v;
                rtnl_lock();
                ret = 0;
-               if (v != net->ipv6.mroute_do_pim) {
-                       net->ipv6.mroute_do_pim = v;
-                       net->ipv6.mroute_do_assert = v;
+               if (v != mrt->mroute_do_pim) {
+                       mrt->mroute_do_pim = v;
+                       mrt->mroute_do_assert = v;
                }
                rtnl_unlock();
                return ret;
        }
 
+#endif
+#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
+       case MRT6_TABLE:
+       {
+               u32 v;
+
+               if (optlen != sizeof(u32))
+                       return -EINVAL;
+               if (get_user(v, (u32 __user *)optval))
+                       return -EFAULT;
+               if (sk == mrt->mroute6_sk)
+                       return -EBUSY;
+
+               rtnl_lock();
+               ret = 0;
+               if (!ip6mr_new_table(net, v))
+                       ret = -ENOMEM;
+               raw6_sk(sk)->ip6mr_table = v;
+               rtnl_unlock();
+               return ret;
+       }
 #endif
        /*
         *      Spurious command, or MRT6_VERSION which you cannot
@@ -1406,6 +1704,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
        int olr;
        int val;
        struct net *net = sock_net(sk);
+       struct mr6_table *mrt;
+
+       mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return -ENOENT;
 
        switch (optname) {
        case MRT6_VERSION:
@@ -1413,11 +1716,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval,
                break;
 #ifdef CONFIG_IPV6_PIMSM_V2
        case MRT6_PIM:
-               val = net->ipv6.mroute_do_pim;
+               val = mrt->mroute_do_pim;
                break;
 #endif
        case MRT6_ASSERT:
-               val = net->ipv6.mroute_do_assert;
+               val = mrt->mroute_do_assert;
                break;
        default:
                return -ENOPROTOOPT;
@@ -1448,16 +1751,21 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
        struct mif_device *vif;
        struct mfc6_cache *c;
        struct net *net = sock_net(sk);
+       struct mr6_table *mrt;
+
+       mrt = ip6mr_get_table(net, raw6_sk(sk)->ip6mr_table ? : RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return -ENOENT;
 
        switch (cmd) {
        case SIOCGETMIFCNT_IN6:
                if (copy_from_user(&vr, arg, sizeof(vr)))
                        return -EFAULT;
-               if (vr.mifi >= net->ipv6.maxvif)
+               if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
                read_lock(&mrt_lock);
-               vif = &net->ipv6.vif6_table[vr.mifi];
-               if (MIF_EXISTS(net, vr.mifi)) {
+               vif = &mrt->vif6_table[vr.mifi];
+               if (MIF_EXISTS(mrt, vr.mifi)) {
                        vr.icount = vif->pkt_in;
                        vr.ocount = vif->pkt_out;
                        vr.ibytes = vif->bytes_in;
@@ -1475,7 +1783,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
                        return -EFAULT;
 
                read_lock(&mrt_lock);
-               c = ip6mr_cache_find(net, &sr.src.sin6_addr, &sr.grp.sin6_addr);
+               c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
                if (c) {
                        sr.pktcnt = c->mfc_un.res.pkt;
                        sr.bytecnt = c->mfc_un.res.bytes;
@@ -1505,11 +1813,11 @@ static inline int ip6mr_forward2_finish(struct sk_buff *skb)
  *     Processing handlers for ip6mr_forward
  */
 
-static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
+static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
+                         struct sk_buff *skb, struct mfc6_cache *c, int vifi)
 {
        struct ipv6hdr *ipv6h;
-       struct net *net = mfc6_net(c);
-       struct mif_device *vif = &net->ipv6.vif6_table[vifi];
+       struct mif_device *vif = &mrt->vif6_table[vifi];
        struct net_device *dev;
        struct dst_entry *dst;
        struct flowi fl;
@@ -1523,7 +1831,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
                vif->bytes_out += skb->len;
                vif->dev->stats.tx_bytes += skb->len;
                vif->dev->stats.tx_packets++;
-               ip6mr_cache_report(net, skb, vifi, MRT6MSG_WHOLEPKT);
+               ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
                goto out_free;
        }
 #endif
@@ -1570,7 +1878,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
 
        IP6CB(skb)->flags |= IP6SKB_FORWARDED;
 
-       return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev,
+       return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
                       ip6mr_forward2_finish);
 
 out_free:
@@ -1578,22 +1886,22 @@ out_free:
        return 0;
 }
 
-static int ip6mr_find_vif(struct net_device *dev)
+static int ip6mr_find_vif(struct mr6_table *mrt, struct net_device *dev)
 {
-       struct net *net = dev_net(dev);
        int ct;
-       for (ct = net->ipv6.maxvif - 1; ct >= 0; ct--) {
-               if (net->ipv6.vif6_table[ct].dev == dev)
+
+       for (ct = mrt->maxvif - 1; ct >= 0; ct--) {
+               if (mrt->vif6_table[ct].dev == dev)
                        break;
        }
        return ct;
 }
 
-static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
+static int ip6_mr_forward(struct net *net, struct mr6_table *mrt,
+                         struct sk_buff *skb, struct mfc6_cache *cache)
 {
        int psend = -1;
        int vif, ct;
-       struct net *net = mfc6_net(cache);
 
        vif = cache->mf6c_parent;
        cache->mfc_un.res.pkt++;
@@ -1602,30 +1910,30 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
        /*
         * Wrong interface: drop packet and (maybe) send PIM assert.
         */
-       if (net->ipv6.vif6_table[vif].dev != skb->dev) {
+       if (mrt->vif6_table[vif].dev != skb->dev) {
                int true_vifi;
 
                cache->mfc_un.res.wrong_if++;
-               true_vifi = ip6mr_find_vif(skb->dev);
+               true_vifi = ip6mr_find_vif(mrt, skb->dev);
 
-               if (true_vifi >= 0 && net->ipv6.mroute_do_assert &&
+               if (true_vifi >= 0 && mrt->mroute_do_assert &&
                    /* pimsm uses asserts, when switching from RPT to SPT,
                       so that we cannot check that packet arrived on an oif.
                       It is bad, but otherwise we would need to move pretty
                       large chunk of pimd to kernel. Ough... --ANK
                     */
-                   (net->ipv6.mroute_do_pim ||
+                   (mrt->mroute_do_pim ||
                     cache->mfc_un.res.ttls[true_vifi] < 255) &&
                    time_after(jiffies,
                               cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
                        cache->mfc_un.res.last_assert = jiffies;
-                       ip6mr_cache_report(net, skb, true_vifi, MRT6MSG_WRONGMIF);
+                       ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
                }
                goto dont_forward;
        }
 
-       net->ipv6.vif6_table[vif].pkt_in++;
-       net->ipv6.vif6_table[vif].bytes_in += skb->len;
+       mrt->vif6_table[vif].pkt_in++;
+       mrt->vif6_table[vif].bytes_in += skb->len;
 
        /*
         *      Forward the frame
@@ -1635,13 +1943,13 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache)
                        if (psend != -1) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
                                if (skb2)
-                                       ip6mr_forward2(skb2, cache, psend);
+                                       ip6mr_forward2(net, mrt, skb2, cache, psend);
                        }
                        psend = ct;
                }
        }
        if (psend != -1) {
-               ip6mr_forward2(skb, cache, psend);
+               ip6mr_forward2(net, mrt, skb, cache, psend);
                return 0;
        }
 
@@ -1659,9 +1967,19 @@ int ip6_mr_input(struct sk_buff *skb)
 {
        struct mfc6_cache *cache;
        struct net *net = dev_net(skb->dev);
+       struct mr6_table *mrt;
+       struct flowi fl = {
+               .iif    = skb->dev->ifindex,
+               .mark   = skb->mark,
+       };
+       int err;
+
+       err = ip6mr_fib_lookup(net, &fl, &mrt);
+       if (err < 0)
+               return err;
 
        read_lock(&mrt_lock);
-       cache = ip6mr_cache_find(net,
+       cache = ip6mr_cache_find(mrt,
                                 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr);
 
        /*
@@ -1670,9 +1988,9 @@ int ip6_mr_input(struct sk_buff *skb)
        if (cache == NULL) {
                int vif;
 
-               vif = ip6mr_find_vif(skb->dev);
+               vif = ip6mr_find_vif(mrt, skb->dev);
                if (vif >= 0) {
-                       int err = ip6mr_cache_unresolved(net, vif, skb);
+                       int err = ip6mr_cache_unresolved(mrt, vif, skb);
                        read_unlock(&mrt_lock);
 
                        return err;
@@ -1682,7 +2000,7 @@ int ip6_mr_input(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       ip6_mr_forward(skb, cache);
+       ip6_mr_forward(net, mrt, skb, cache);
 
        read_unlock(&mrt_lock);
 
@@ -1690,12 +2008,11 @@ int ip6_mr_input(struct sk_buff *skb)
 }
 
 
-static int
-ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
+static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
+                              struct mfc6_cache *c, struct rtmsg *rtm)
 {
        int ct;
        struct rtnexthop *nhp;
-       struct net *net = mfc6_net(c);
        u8 *b = skb_tail_pointer(skb);
        struct rtattr *mp_head;
 
@@ -1703,19 +2020,19 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
        if (c->mf6c_parent > MAXMIFS)
                return -ENOENT;
 
-       if (MIF_EXISTS(net, c->mf6c_parent))
-               RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex);
+       if (MIF_EXISTS(mrt, c->mf6c_parent))
+               RTA_PUT(skb, RTA_IIF, 4, &mrt->vif6_table[c->mf6c_parent].dev->ifindex);
 
        mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
 
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
-               if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
+               if (MIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
                        if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
                                goto rtattr_failure;
                        nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
                        nhp->rtnh_flags = 0;
                        nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
-                       nhp->rtnh_ifindex = net->ipv6.vif6_table[ct].dev->ifindex;
+                       nhp->rtnh_ifindex = mrt->vif6_table[ct].dev->ifindex;
                        nhp->rtnh_len = sizeof(*nhp);
                }
        }
@@ -1733,11 +2050,16 @@ int ip6mr_get_route(struct net *net,
                    struct sk_buff *skb, struct rtmsg *rtm, int nowait)
 {
        int err;
+       struct mr6_table *mrt;
        struct mfc6_cache *cache;
        struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
 
+       mrt = ip6mr_get_table(net, RT6_TABLE_DFLT);
+       if (mrt == NULL)
+               return -ENOENT;
+
        read_lock(&mrt_lock);
-       cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
+       cache = ip6mr_cache_find(mrt, &rt->rt6i_src.addr, &rt->rt6i_dst.addr);
 
        if (!cache) {
                struct sk_buff *skb2;
@@ -1751,7 +2073,7 @@ int ip6mr_get_route(struct net *net,
                }
 
                dev = skb->dev;
-               if (dev == NULL || (vif = ip6mr_find_vif(dev)) < 0) {
+               if (dev == NULL || (vif = ip6mr_find_vif(mrt, dev)) < 0) {
                        read_unlock(&mrt_lock);
                        return -ENODEV;
                }
@@ -1780,7 +2102,7 @@ int ip6mr_get_route(struct net *net,
                ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr);
                ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr);
 
-               err = ip6mr_cache_unresolved(net, vif, skb2);
+               err = ip6mr_cache_unresolved(mrt, vif, skb2);
                read_unlock(&mrt_lock);
 
                return err;
@@ -1789,8 +2111,88 @@ int ip6mr_get_route(struct net *net,
        if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
                cache->mfc_flags |= MFC_NOTIFY;
 
-       err = ip6mr_fill_mroute(skb, cache, rtm);
+       err = __ip6mr_fill_mroute(mrt, skb, cache, rtm);
        read_unlock(&mrt_lock);
        return err;
 }
 
+static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
+                            u32 pid, u32 seq, struct mfc6_cache *c)
+{
+       struct nlmsghdr *nlh;
+       struct rtmsg *rtm;
+
+       nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI);
+       if (nlh == NULL)
+               return -EMSGSIZE;
+
+       rtm = nlmsg_data(nlh);
+       rtm->rtm_family   = RTNL_FAMILY_IPMR;
+       rtm->rtm_dst_len  = 128;
+       rtm->rtm_src_len  = 128;
+       rtm->rtm_tos      = 0;
+       rtm->rtm_table    = mrt->id;
+       NLA_PUT_U32(skb, RTA_TABLE, mrt->id);
+       rtm->rtm_scope    = RT_SCOPE_UNIVERSE;
+       rtm->rtm_protocol = RTPROT_UNSPEC;
+       rtm->rtm_flags    = 0;
+
+       NLA_PUT(skb, RTA_SRC, 16, &c->mf6c_origin);
+       NLA_PUT(skb, RTA_DST, 16, &c->mf6c_mcastgrp);
+
+       if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0)
+               goto nla_put_failure;
+
+       return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+       nlmsg_cancel(skb, nlh);
+       return -EMSGSIZE;
+}
+
+static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct net *net = sock_net(skb->sk);
+       struct mr6_table *mrt;
+       struct mfc6_cache *mfc;
+       unsigned int t = 0, s_t;
+       unsigned int h = 0, s_h;
+       unsigned int e = 0, s_e;
+
+       s_t = cb->args[0];
+       s_h = cb->args[1];
+       s_e = cb->args[2];
+
+       read_lock(&mrt_lock);
+       ip6mr_for_each_table(mrt, net) {
+               if (t < s_t)
+                       goto next_table;
+               if (t > s_t)
+                       s_h = 0;
+               for (h = s_h; h < MFC6_LINES; h++) {
+                       list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) {
+                               if (e < s_e)
+                                       goto next_entry;
+                               if (ip6mr_fill_mroute(mrt, skb,
+                                                     NETLINK_CB(cb->skb).pid,
+                                                     cb->nlh->nlmsg_seq,
+                                                     mfc) < 0)
+                                       goto done;
+next_entry:
+                               e++;
+                       }
+                       e = s_e = 0;
+               }
+               s_h = 0;
+next_table:
+               t++;
+       }
+done:
+       read_unlock(&mrt_lock);
+
+       cb->args[2] = e;
+       cb->args[1] = h;
+       cb->args[0] = t;
+
+       return skb->len;
+}
index 33f60fca7aa775e36082c65171a10e10a4ec49bb..bd43f0152c21d5e7f5dca9b609a735d1a0573bac 100644 (file)
@@ -114,9 +114,9 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
                }
                opt = xchg(&inet6_sk(sk)->opt, opt);
        } else {
-               write_lock(&sk->sk_dst_lock);
+               spin_lock(&sk->sk_dst_lock);
                opt = xchg(&inet6_sk(sk)->opt, opt);
-               write_unlock(&sk->sk_dst_lock);
+               spin_unlock(&sk->sk_dst_lock);
        }
        sk_dst_reset(sk);
 
@@ -337,6 +337,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                retv = 0;
                break;
 
+       case IPV6_RECVPATHMTU:
+               if (optlen < sizeof(int))
+                       goto e_inval;
+               np->rxopt.bits.rxpmtu = valbool;
+               retv = 0;
+               break;
+
        case IPV6_HOPOPTS:
        case IPV6_RTHDRDSTOPTS:
        case IPV6_RTHDR:
@@ -451,7 +458,8 @@ sticky_done:
                msg.msg_controllen = optlen;
                msg.msg_control = (void*)(opt+1);
 
-               retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk);
+               retv = datagram_send_ctl(net, &msg, &fl, opt, &junk, &junk,
+                                        &junk);
                if (retv)
                        goto done;
 update:
@@ -767,6 +775,17 @@ pref_skip_coa:
 
                break;
            }
+       case IPV6_MINHOPCOUNT:
+               if (optlen < sizeof(int))
+                       goto e_inval;
+               if (val < 0 || val > 255)
+                       goto e_inval;
+               np->min_hopcount = val;
+               break;
+       case IPV6_DONTFRAG:
+               np->dontfrag = valbool;
+               retv = 0;
+               break;
        }
 
        release_sock(sk);
@@ -971,14 +990,13 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
        case IPV6_MTU:
        {
                struct dst_entry *dst;
+
                val = 0;
-               lock_sock(sk);
-               dst = sk_dst_get(sk);
-               if (dst) {
+               rcu_read_lock();
+               dst = __sk_dst_get(sk);
+               if (dst)
                        val = dst_mtu(dst);
-                       dst_release(dst);
-               }
-               release_sock(sk);
+               rcu_read_unlock();
                if (!val)
                        return -ENOTCONN;
                break;
@@ -1056,6 +1074,38 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                val = np->rxopt.bits.rxflow;
                break;
 
+       case IPV6_RECVPATHMTU:
+               val = np->rxopt.bits.rxpmtu;
+               break;
+
+       case IPV6_PATHMTU:
+       {
+               struct dst_entry *dst;
+               struct ip6_mtuinfo mtuinfo;
+
+               if (len < sizeof(mtuinfo))
+                       return -EINVAL;
+
+               len = sizeof(mtuinfo);
+               memset(&mtuinfo, 0, sizeof(mtuinfo));
+
+               rcu_read_lock();
+               dst = __sk_dst_get(sk);
+               if (dst)
+                       mtuinfo.ip6m_mtu = dst_mtu(dst);
+               rcu_read_unlock();
+               if (!mtuinfo.ip6m_mtu)
+                       return -ENOTCONN;
+
+               if (put_user(len, optlen))
+                       return -EFAULT;
+               if (copy_to_user(optval, &mtuinfo, len))
+                       return -EFAULT;
+
+               return 0;
+               break;
+       }
+
        case IPV6_UNICAST_HOPS:
        case IPV6_MULTICAST_HOPS:
        {
@@ -1066,12 +1116,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                else
                        val = np->mcast_hops;
 
-               dst = sk_dst_get(sk);
-               if (dst) {
-                       if (val < 0)
+               if (val < 0) {
+                       rcu_read_lock();
+                       dst = __sk_dst_get(sk);
+                       if (dst)
                                val = ip6_dst_hoplimit(dst);
-                       dst_release(dst);
+                       rcu_read_unlock();
                }
+
                if (val < 0)
                        val = sock_net(sk)->ipv6.devconf_all->hop_limit;
                break;
@@ -1115,6 +1167,14 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                        val |= IPV6_PREFER_SRC_HOME;
                break;
 
+       case IPV6_MINHOPCOUNT:
+               val = np->min_hopcount;
+               break;
+
+       case IPV6_DONTFRAG:
+               val = np->dontfrag;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
index c483ab9fd67b494286f2dfd7574fed4fa91792a3..59f1881968c70aad15b0296cf6400c6b0b3e49cb 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
+#include <net/mld.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
 #define MDBG(x)
 #endif
 
-/*
- *  These header formats should be in a separate include file, but icmpv6.h
- *  doesn't have in6_addr defined in all cases, there is no __u128, and no
- *  other files reference these.
- *
- *                     +-DLS 4/14/03
- */
-
-/* Multicast Listener Discovery version 2 headers */
-
-struct mld2_grec {
-       __u8            grec_type;
-       __u8            grec_auxwords;
-       __be16          grec_nsrcs;
-       struct in6_addr grec_mca;
-       struct in6_addr grec_src[0];
-};
-
-struct mld2_report {
-       __u8    type;
-       __u8    resv1;
-       __sum16 csum;
-       __be16  resv2;
-       __be16  ngrec;
-       struct mld2_grec grec[0];
-};
-
-struct mld2_query {
-       __u8 type;
-       __u8 code;
-       __sum16 csum;
-       __be16 mrc;
-       __be16 resv1;
-       struct in6_addr mca;
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8 qrv:3,
-            suppress:1,
-            resv2:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       __u8 resv2:4,
-            suppress:1,
-            qrv:3;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
-       __u8 qqic;
-       __be16 nsrcs;
-       struct in6_addr srcs[0];
+/* Ensure that we have struct in6_addr aligned on 32bit word. */
+static void *__mld2_query_bugs[] __attribute__((__unused__)) = {
+       BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4),
+       BUILD_BUG_ON_NULL(offsetof(struct mld2_report, mld2r_grec) % 4),
+       BUILD_BUG_ON_NULL(offsetof(struct mld2_grec, grec_mca) % 4)
 };
 
 static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
@@ -157,14 +115,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
                ((idev)->mc_v1_seen && \
                time_before(jiffies, (idev)->mc_v1_seen)))
 
-#define MLDV2_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value))
-#define MLDV2_EXP(thresh, nbmant, nbexp, value) \
-       ((value) < (thresh) ? (value) : \
-       ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
-       (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
-
-#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
-
 #define IPV6_MLD_MAX_MSF       64
 
 int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
@@ -715,7 +665,7 @@ static void igmp6_group_added(struct ifmcaddr6 *mc)
        if (!(mc->mca_flags&MAF_LOADED)) {
                mc->mca_flags |= MAF_LOADED;
                if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
-                       dev_mc_add(dev, buf, dev->addr_len, 0);
+                       dev_mc_add(dev, buf);
        }
        spin_unlock_bh(&mc->mca_lock);
 
@@ -741,7 +691,7 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)
        if (mc->mca_flags&MAF_LOADED) {
                mc->mca_flags &= ~MAF_LOADED;
                if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
-                       dev_mc_delete(dev, buf, dev->addr_len, 0);
+                       dev_mc_del(dev, buf);
        }
 
        if (mc->mca_flags & MAF_NOREPORT)
@@ -1161,7 +1111,7 @@ int igmp6_event_query(struct sk_buff *skb)
        struct in6_addr *group;
        unsigned long max_delay;
        struct inet6_dev *idev;
-       struct icmp6hdr *hdr;
+       struct mld_msg *mld;
        int group_type;
        int mark = 0;
        int len;
@@ -1182,8 +1132,8 @@ int igmp6_event_query(struct sk_buff *skb)
        if (idev == NULL)
                return 0;
 
-       hdr = icmp6_hdr(skb);
-       group = (struct in6_addr *) (hdr + 1);
+       mld = (struct mld_msg *)icmp6_hdr(skb);
+       group = &mld->mld_mca;
        group_type = ipv6_addr_type(group);
 
        if (group_type != IPV6_ADDR_ANY &&
@@ -1197,7 +1147,7 @@ int igmp6_event_query(struct sk_buff *skb)
                /* MLDv1 router present */
 
                /* Translate milliseconds to jiffies */
-               max_delay = (ntohs(hdr->icmp6_maxdelay)*HZ)/1000;
+               max_delay = (ntohs(mld->mld_maxdelay)*HZ)/1000;
 
                switchback = (idev->mc_qrv + 1) * max_delay;
                idev->mc_v1_seen = jiffies + switchback;
@@ -1216,14 +1166,14 @@ int igmp6_event_query(struct sk_buff *skb)
                        return -EINVAL;
                }
                mlh2 = (struct mld2_query *)skb_transport_header(skb);
-               max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000;
+               max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
                if (!max_delay)
                        max_delay = 1;
                idev->mc_maxdelay = max_delay;
-               if (mlh2->qrv)
-                       idev->mc_qrv = mlh2->qrv;
+               if (mlh2->mld2q_qrv)
+                       idev->mc_qrv = mlh2->mld2q_qrv;
                if (group_type == IPV6_ADDR_ANY) { /* general query */
-                       if (mlh2->nsrcs) {
+                       if (mlh2->mld2q_nsrcs) {
                                in6_dev_put(idev);
                                return -EINVAL; /* no sources allowed */
                        }
@@ -1232,9 +1182,9 @@ int igmp6_event_query(struct sk_buff *skb)
                        return 0;
                }
                /* mark sources to include, if group & source-specific */
-               if (mlh2->nsrcs != 0) {
+               if (mlh2->mld2q_nsrcs != 0) {
                        if (!pskb_may_pull(skb, srcs_offset +
-                           ntohs(mlh2->nsrcs) * sizeof(struct in6_addr))) {
+                           ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
                                in6_dev_put(idev);
                                return -EINVAL;
                        }
@@ -1270,7 +1220,7 @@ int igmp6_event_query(struct sk_buff *skb)
                                        ma->mca_flags &= ~MAF_GSQUERY;
                        }
                        if (!(ma->mca_flags & MAF_GSQUERY) ||
-                           mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs))
+                           mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs))
                                igmp6_group_queried(ma, max_delay);
                        spin_unlock_bh(&ma->mca_lock);
                        break;
@@ -1286,9 +1236,8 @@ int igmp6_event_query(struct sk_buff *skb)
 int igmp6_event_report(struct sk_buff *skb)
 {
        struct ifmcaddr6 *ma;
-       struct in6_addr *addrp;
        struct inet6_dev *idev;
-       struct icmp6hdr *hdr;
+       struct mld_msg *mld;
        int addr_type;
 
        /* Our own report looped back. Ignore it. */
@@ -1300,10 +1249,10 @@ int igmp6_event_report(struct sk_buff *skb)
            skb->pkt_type != PACKET_BROADCAST)
                return 0;
 
-       if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
+       if (!pskb_may_pull(skb, sizeof(*mld) - sizeof(struct icmp6hdr)))
                return -EINVAL;
 
-       hdr = icmp6_hdr(skb);
+       mld = (struct mld_msg *)icmp6_hdr(skb);
 
        /* Drop reports with not link local source */
        addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr);
@@ -1311,8 +1260,6 @@ int igmp6_event_report(struct sk_buff *skb)
            !(addr_type&IPV6_ADDR_LINKLOCAL))
                return -EINVAL;
 
-       addrp = (struct in6_addr *) (hdr + 1);
-
        idev = in6_dev_get(skb->dev);
        if (idev == NULL)
                return -ENODEV;
@@ -1323,7 +1270,7 @@ int igmp6_event_report(struct sk_buff *skb)
 
        read_lock_bh(&idev->lock);
        for (ma = idev->mc_list; ma; ma=ma->next) {
-               if (ipv6_addr_equal(&ma->mca_addr, addrp)) {
+               if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) {
                        spin_lock(&ma->mca_lock);
                        if (del_timer(&ma->mca_timer))
                                atomic_dec(&ma->mca_refcnt);
@@ -1432,11 +1379,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
        skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data);
        skb_put(skb, sizeof(*pmr));
        pmr = (struct mld2_report *)skb_transport_header(skb);
-       pmr->type = ICMPV6_MLD2_REPORT;
-       pmr->resv1 = 0;
-       pmr->csum = 0;
-       pmr->resv2 = 0;
-       pmr->ngrec = 0;
+       pmr->mld2r_type = ICMPV6_MLD2_REPORT;
+       pmr->mld2r_resv1 = 0;
+       pmr->mld2r_cksum = 0;
+       pmr->mld2r_resv2 = 0;
+       pmr->mld2r_ngrec = 0;
        return skb;
 }
 
@@ -1458,9 +1405,10 @@ static void mld_sendpack(struct sk_buff *skb)
        mldlen = skb->tail - skb->transport_header;
        pip6->payload_len = htons(payload_len);
 
-       pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
-               IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
-                                            mldlen, 0));
+       pmr->mld2r_cksum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
+                                          IPPROTO_ICMPV6,
+                                          csum_partial(skb_transport_header(skb),
+                                                       mldlen, 0));
 
        dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
 
@@ -1480,7 +1428,7 @@ static void mld_sendpack(struct sk_buff *skb)
 
        payload_len = skb->len;
 
-       err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
+       err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
                      dst_output);
 out:
        if (!err) {
@@ -1521,7 +1469,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        pgr->grec_nsrcs = 0;
        pgr->grec_mca = pmc->mca_addr;  /* structure copy */
        pmr = (struct mld2_report *)skb_transport_header(skb);
-       pmr->ngrec = htons(ntohs(pmr->ngrec)+1);
+       pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1);
        *ppgr = pgr;
        return skb;
 }
@@ -1557,7 +1505,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 
        /* EX and TO_EX get a fresh packet, if needed */
        if (truncate) {
-               if (pmr && pmr->ngrec &&
+               if (pmr && pmr->mld2r_ngrec &&
                    AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
                        if (skb)
                                mld_sendpack(skb);
@@ -1770,9 +1718,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
        struct sock *sk = net->ipv6.igmp_sk;
        struct inet6_dev *idev;
        struct sk_buff *skb;
-       struct icmp6hdr *hdr;
+       struct mld_msg *hdr;
        const struct in6_addr *snd_addr, *saddr;
-       struct in6_addr *addrp;
        struct in6_addr addr_buf;
        int err, len, payload_len, full_len;
        u8 ra[8] = { IPPROTO_ICMPV6, 0,
@@ -1820,16 +1767,14 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 
        memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
 
-       hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
-       memset(hdr, 0, sizeof(struct icmp6hdr));
-       hdr->icmp6_type = type;
+       hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg));
+       memset(hdr, 0, sizeof(struct mld_msg));
+       hdr->mld_type = type;
+       ipv6_addr_copy(&hdr->mld_mca, addr);
 
-       addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
-       ipv6_addr_copy(addrp, addr);
-
-       hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len,
-                                          IPPROTO_ICMPV6,
-                                          csum_partial(hdr, len, 0));
+       hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len,
+                                        IPPROTO_ICMPV6,
+                                        csum_partial(hdr, len, 0));
 
        idev = in6_dev_get(skb->dev);
 
@@ -1848,7 +1793,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
                goto err_out;
 
        skb_dst_set(skb, dst);
-       err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
+       err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
                      dst_output);
 out:
        if (!err) {
index da0a4d2adc69ac531eba98783de78f8b570d4717..0abdc242ddb76029cc2f6a52bed1bbdea2189364 100644 (file)
@@ -536,7 +536,7 @@ void ndisc_send_skb(struct sk_buff *skb,
        idev = in6_dev_get(dst->dev);
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
 
-       err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
+       err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
                      dst_output);
        if (!err) {
                ICMP6MSGOUT_INC_STATS(net, idev, type);
@@ -890,8 +890,6 @@ out:
                in6_ifa_put(ifp);
        else
                in6_dev_put(idev);
-
-       return;
 }
 
 static void ndisc_recv_na(struct sk_buff *skb)
@@ -1618,7 +1616,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
        skb_dst_set(buff, dst);
        idev = in6_dev_get(dst->dev);
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
-       err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
+       err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
                      dst_output);
        if (!err) {
                ICMP6MSGOUT_INC_STATS(net, idev, NDISC_REDIRECT);
index d5ed92b143469488f475816a1ebb08a5c1803558..a74951c039b6abdcc8844202b082eefd15da7da1 100644 (file)
@@ -25,20 +25,6 @@ int ip6_route_me_harder(struct sk_buff *skb)
        };
 
        dst = ip6_route_output(net, skb->sk, &fl);
-
-#ifdef CONFIG_XFRM
-       if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
-           xfrm_decode_session(skb, &fl, AF_INET6) == 0) {
-               struct dst_entry *dst2 = skb_dst(skb);
-
-               if (xfrm_lookup(net, &dst2, &fl, skb->sk, 0)) {
-                       skb_dst_set(skb, NULL);
-                       return -1;
-               }
-               skb_dst_set(skb, dst2);
-       }
-#endif
-
        if (dst->error) {
                IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
                LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
@@ -50,6 +36,17 @@ int ip6_route_me_harder(struct sk_buff *skb)
        skb_dst_drop(skb);
 
        skb_dst_set(skb, dst);
+
+#ifdef CONFIG_XFRM
+       if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
+           xfrm_decode_session(skb, &fl, AF_INET6) == 0) {
+               skb_dst_set(skb, NULL);
+               if (xfrm_lookup(net, &dst, &fl, skb->sk, 0))
+                       return -1;
+               skb_dst_set(skb, dst);
+       }
+#endif
+
        return 0;
 }
 EXPORT_SYMBOL(ip6_route_me_harder);
index 6a68a74d14a3a451775ae2f046518b5d119d8f3e..8c201743d96d3fe8366603fc29d071c773c07166 100644 (file)
@@ -162,8 +162,7 @@ ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
                break;
 
        case IPQ_COPY_PACKET:
-               if ((entry->skb->ip_summed == CHECKSUM_PARTIAL ||
-                    entry->skb->ip_summed == CHECKSUM_COMPLETE) &&
+               if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
                    (*errp = skb_checksum_help(entry->skb))) {
                        read_unlock_bh(&queue_lock);
                        return NULL;
@@ -463,7 +462,6 @@ __ipq_rcv_skb(struct sk_buff *skb)
 
        if (flags & NLM_F_ACK)
                netlink_ack(skb, nlh, 0);
-       return;
 }
 
 static void
index 9210e312edf1d41a62cf336ec3287329060f3fa9..6f517bd8369254ae73d0ac9888792326dd610352 100644 (file)
@@ -40,24 +40,19 @@ MODULE_DESCRIPTION("IPv6 packet filter");
 /*#define DEBUG_IP_FIREWALL_USER*/
 
 #ifdef DEBUG_IP_FIREWALL
-#define dprintf(format, args...)  printk(format , ## args)
+#define dprintf(format, args...) pr_info(format , ## args)
 #else
 #define dprintf(format, args...)
 #endif
 
 #ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
+#define duprintf(format, args...) pr_info(format , ## args)
 #else
 #define duprintf(format, args...)
 #endif
 
 #ifdef CONFIG_NETFILTER_DEBUG
-#define IP_NF_ASSERT(x)                                                \
-do {                                                           \
-       if (!(x))                                               \
-               printk("IP_NF_ASSERT: %s:%s:%u\n",              \
-                      __func__, __FILE__, __LINE__);   \
-} while(0)
+#define IP_NF_ASSERT(x)        WARN_ON(!(x))
 #else
 #define IP_NF_ASSERT(x)
 #endif
@@ -197,30 +192,14 @@ ip6_checkentry(const struct ip6t_ip6 *ipv6)
 }
 
 static unsigned int
-ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
+ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
 {
        if (net_ratelimit())
-               printk("ip6_tables: error: `%s'\n",
-                      (const char *)par->targinfo);
+               pr_info("error: `%s'\n", (const char *)par->targinfo);
 
        return NF_DROP;
 }
 
-/* Performance critical - called for every packet */
-static inline bool
-do_match(const struct ip6t_entry_match *m, const struct sk_buff *skb,
-        struct xt_match_param *par)
-{
-       par->match     = m->u.kernel.match;
-       par->matchinfo = m->data;
-
-       /* Stop iteration if it doesn't match */
-       if (!m->u.kernel.match->match(skb, par))
-               return true;
-       else
-               return false;
-}
-
 static inline struct ip6t_entry *
 get_entry(const void *base, unsigned int offset)
 {
@@ -352,18 +331,15 @@ ip6t_do_table(struct sk_buff *skb,
              const struct net_device *out,
              struct xt_table *table)
 {
-#define tb_comefrom ((struct ip6t_entry *)table_base)->comefrom
-
        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
-       bool hotdrop = false;
        /* Initializing verdict to NF_DROP keeps gcc happy. */
        unsigned int verdict = NF_DROP;
        const char *indev, *outdev;
        const void *table_base;
-       struct ip6t_entry *e, *back;
+       struct ip6t_entry *e, **jumpstack;
+       unsigned int *stackptr, origptr, cpu;
        const struct xt_table_info *private;
-       struct xt_match_param mtpar;
-       struct xt_target_param tgpar;
+       struct xt_action_param acpar;
 
        /* Initialization */
        indev = in ? in->name : nulldevname;
@@ -374,39 +350,42 @@ ip6t_do_table(struct sk_buff *skb,
         * things we don't know, ie. tcp syn flag or ports).  If the
         * rule is also a fragment-specific rule, non-fragments won't
         * match it. */
-       mtpar.hotdrop = &hotdrop;
-       mtpar.in      = tgpar.in  = in;
-       mtpar.out     = tgpar.out = out;
-       mtpar.family  = tgpar.family = NFPROTO_IPV6;
-       mtpar.hooknum = tgpar.hooknum = hook;
+       acpar.hotdrop = false;
+       acpar.in      = in;
+       acpar.out     = out;
+       acpar.family  = NFPROTO_IPV6;
+       acpar.hooknum = hook;
 
        IP_NF_ASSERT(table->valid_hooks & (1 << hook));
 
        xt_info_rdlock_bh();
        private = table->private;
-       table_base = private->entries[smp_processor_id()];
+       cpu        = smp_processor_id();
+       table_base = private->entries[cpu];
+       jumpstack  = (struct ip6t_entry **)private->jumpstack[cpu];
+       stackptr   = &private->stackptr[cpu];
+       origptr    = *stackptr;
 
        e = get_entry(table_base, private->hook_entry[hook]);
 
-       /* For return from builtin chain */
-       back = get_entry(table_base, private->underflow[hook]);
-
        do {
                const struct ip6t_entry_target *t;
                const struct xt_entry_match *ematch;
 
                IP_NF_ASSERT(e);
-               IP_NF_ASSERT(back);
                if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
-                   &mtpar.thoff, &mtpar.fragoff, &hotdrop)) {
+                   &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
  no_match:
                        e = ip6t_next_entry(e);
                        continue;
                }
 
-               xt_ematch_foreach(ematch, e)
-                       if (do_match(ematch, skb, &mtpar) != 0)
+               xt_ematch_foreach(ematch, e) {
+                       acpar.match     = ematch->u.kernel.match;
+                       acpar.matchinfo = ematch->data;
+                       if (!acpar.match->match(skb, &acpar))
                                goto no_match;
+               }
 
                ADD_COUNTER(e->counters,
                            ntohs(ipv6_hdr(skb)->payload_len) +
@@ -433,62 +412,47 @@ ip6t_do_table(struct sk_buff *skb,
                                        verdict = (unsigned)(-v) - 1;
                                        break;
                                }
-                               e = back;
-                               back = get_entry(table_base, back->comefrom);
+                               if (*stackptr == 0)
+                                       e = get_entry(table_base,
+                                           private->underflow[hook]);
+                               else
+                                       e = ip6t_next_entry(jumpstack[--*stackptr]);
                                continue;
                        }
                        if (table_base + v != ip6t_next_entry(e) &&
                            !(e->ipv6.flags & IP6T_F_GOTO)) {
-                               /* Save old back ptr in next entry */
-                               struct ip6t_entry *next = ip6t_next_entry(e);
-                               next->comefrom = (void *)back - table_base;
-                               /* set back pointer to next entry */
-                               back = next;
+                               if (*stackptr >= private->stacksize) {
+                                       verdict = NF_DROP;
+                                       break;
+                               }
+                               jumpstack[(*stackptr)++] = e;
                        }
 
                        e = get_entry(table_base, v);
                        continue;
                }
 
-               /* Targets which reenter must return
-                  abs. verdicts */
-               tgpar.target   = t->u.kernel.target;
-               tgpar.targinfo = t->data;
-
-#ifdef CONFIG_NETFILTER_DEBUG
-               tb_comefrom = 0xeeeeeeec;
-#endif
-               verdict = t->u.kernel.target->target(skb, &tgpar);
+               acpar.target   = t->u.kernel.target;
+               acpar.targinfo = t->data;
 
-#ifdef CONFIG_NETFILTER_DEBUG
-               if (tb_comefrom != 0xeeeeeeec && verdict == IP6T_CONTINUE) {
-                       printk("Target %s reentered!\n",
-                              t->u.kernel.target->name);
-                       verdict = NF_DROP;
-               }
-               tb_comefrom = 0x57acc001;
-#endif
+               verdict = t->u.kernel.target->target(skb, &acpar);
                if (verdict == IP6T_CONTINUE)
                        e = ip6t_next_entry(e);
                else
                        /* Verdict */
                        break;
-       } while (!hotdrop);
+       } while (!acpar.hotdrop);
 
-#ifdef CONFIG_NETFILTER_DEBUG
-       tb_comefrom = NETFILTER_LINK_POISON;
-#endif
        xt_info_rdunlock_bh();
+       *stackptr = origptr;
 
 #ifdef DEBUG_ALLOW_ALL
        return NF_ACCEPT;
 #else
-       if (hotdrop)
+       if (acpar.hotdrop)
                return NF_DROP;
        else return verdict;
 #endif
-
-#undef tb_comefrom
 }
 
 /* Figures out from what hook each rule can be called: returns 0 if
@@ -517,7 +481,7 @@ mark_source_chains(const struct xt_table_info *newinfo,
                        int visited = e->comefrom & (1 << hook);
 
                        if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
-                               printk("iptables: loop hook %u pos %u %08X.\n",
+                               pr_err("iptables: loop hook %u pos %u %08X.\n",
                                       hook, pos, e->comefrom);
                                return 0;
                        }
@@ -661,12 +625,11 @@ find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par)
        struct xt_match *match;
        int ret;
 
-       match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
-                                                     m->u.user.revision),
-                                       "ip6t_%s", m->u.user.name);
-       if (IS_ERR(match) || !match) {
+       match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
+                                     m->u.user.revision);
+       if (IS_ERR(match)) {
                duprintf("find_check_match: `%s' not found\n", m->u.user.name);
-               return match ? PTR_ERR(match) : -ENOENT;
+               return PTR_ERR(match);
        }
        m->u.kernel.match = match;
 
@@ -734,13 +697,11 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
        }
 
        t = ip6t_get_target(e);
-       target = try_then_request_module(xt_find_target(AF_INET6,
-                                                       t->u.user.name,
-                                                       t->u.user.revision),
-                                        "ip6t_%s", t->u.user.name);
-       if (IS_ERR(target) || !target) {
+       target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
+                                       t->u.user.revision);
+       if (IS_ERR(target)) {
                duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
-               ret = target ? PTR_ERR(target) : -ENOENT;
+               ret = PTR_ERR(target);
                goto cleanup_matches;
        }
        t->u.kernel.target = target;
@@ -873,6 +834,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
                if (ret != 0)
                        return ret;
                ++i;
+               if (strcmp(ip6t_get_target(iter)->u.user.name,
+                   XT_ERROR_TARGET) == 0)
+                       ++newinfo->stacksize;
        }
 
        if (i != repl->num_entries) {
@@ -1509,13 +1473,12 @@ compat_find_calc_match(struct ip6t_entry_match *m,
 {
        struct xt_match *match;
 
-       match = try_then_request_module(xt_find_match(AF_INET6, m->u.user.name,
-                                                     m->u.user.revision),
-                                       "ip6t_%s", m->u.user.name);
-       if (IS_ERR(match) || !match) {
+       match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
+                                     m->u.user.revision);
+       if (IS_ERR(match)) {
                duprintf("compat_check_calc_match: `%s' not found\n",
                         m->u.user.name);
-               return match ? PTR_ERR(match) : -ENOENT;
+               return PTR_ERR(match);
        }
        m->u.kernel.match = match;
        *size += xt_compat_match_offset(match);
@@ -1582,14 +1545,12 @@ check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
        }
 
        t = compat_ip6t_get_target(e);
-       target = try_then_request_module(xt_find_target(AF_INET6,
-                                                       t->u.user.name,
-                                                       t->u.user.revision),
-                                        "ip6t_%s", t->u.user.name);
-       if (IS_ERR(target) || !target) {
+       target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
+                                       t->u.user.revision);
+       if (IS_ERR(target)) {
                duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
                         t->u.user.name);
-               ret = target ? PTR_ERR(target) : -ENOENT;
+               ret = PTR_ERR(target);
                goto release_matches;
        }
        t->u.kernel.target = target;
@@ -2127,8 +2088,7 @@ struct xt_table *ip6t_register_table(struct net *net,
 {
        int ret;
        struct xt_table_info *newinfo;
-       struct xt_table_info bootstrap
-               = { 0, 0, 0, { 0 }, { 0 }, { } };
+       struct xt_table_info bootstrap = {0};
        void *loc_cpu_entry;
        struct xt_table *new_table;
 
@@ -2188,7 +2148,7 @@ icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
 }
 
 static bool
-icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
+icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct icmp6hdr *ic;
        struct icmp6hdr _icmph;
@@ -2204,7 +2164,7 @@ icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
                 * can't.  Hence, no choice but to drop.
                 */
                duprintf("Dropping evil ICMP tinygram.\n");
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -2216,31 +2176,32 @@ icmp6_match(const struct sk_buff *skb, const struct xt_match_param *par)
 }
 
 /* Called when user tries to insert an entry of this type. */
-static bool icmp6_checkentry(const struct xt_mtchk_param *par)
+static int icmp6_checkentry(const struct xt_mtchk_param *par)
 {
        const struct ip6t_icmp *icmpinfo = par->matchinfo;
 
        /* Must specify no unknown invflags */
-       return !(icmpinfo->invflags & ~IP6T_ICMP_INV);
+       return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
 }
 
 /* The built-in targets: standard (NULL) and error. */
-static struct xt_target ip6t_standard_target __read_mostly = {
-       .name           = IP6T_STANDARD_TARGET,
-       .targetsize     = sizeof(int),
-       .family         = NFPROTO_IPV6,
+static struct xt_target ip6t_builtin_tg[] __read_mostly = {
+       {
+               .name             = IP6T_STANDARD_TARGET,
+               .targetsize       = sizeof(int),
+               .family           = NFPROTO_IPV6,
 #ifdef CONFIG_COMPAT
-       .compatsize     = sizeof(compat_int_t),
-       .compat_from_user = compat_standard_from_user,
-       .compat_to_user = compat_standard_to_user,
+               .compatsize       = sizeof(compat_int_t),
+               .compat_from_user = compat_standard_from_user,
+               .compat_to_user   = compat_standard_to_user,
 #endif
-};
-
-static struct xt_target ip6t_error_target __read_mostly = {
-       .name           = IP6T_ERROR_TARGET,
-       .target         = ip6t_error,
-       .targetsize     = IP6T_FUNCTION_MAXNAMELEN,
-       .family         = NFPROTO_IPV6,
+       },
+       {
+               .name             = IP6T_ERROR_TARGET,
+               .target           = ip6t_error,
+               .targetsize       = IP6T_FUNCTION_MAXNAMELEN,
+               .family           = NFPROTO_IPV6,
+       },
 };
 
 static struct nf_sockopt_ops ip6t_sockopts = {
@@ -2260,13 +2221,15 @@ static struct nf_sockopt_ops ip6t_sockopts = {
        .owner          = THIS_MODULE,
 };
 
-static struct xt_match icmp6_matchstruct __read_mostly = {
-       .name           = "icmp6",
-       .match          = icmp6_match,
-       .matchsize      = sizeof(struct ip6t_icmp),
-       .checkentry     = icmp6_checkentry,
-       .proto          = IPPROTO_ICMPV6,
-       .family         = NFPROTO_IPV6,
+static struct xt_match ip6t_builtin_mt[] __read_mostly = {
+       {
+               .name       = "icmp6",
+               .match      = icmp6_match,
+               .matchsize  = sizeof(struct ip6t_icmp),
+               .checkentry = icmp6_checkentry,
+               .proto      = IPPROTO_ICMPV6,
+               .family     = NFPROTO_IPV6,
+       },
 };
 
 static int __net_init ip6_tables_net_init(struct net *net)
@@ -2293,13 +2256,10 @@ static int __init ip6_tables_init(void)
                goto err1;
 
        /* Noone else will be downing sem now, so we won't sleep */
-       ret = xt_register_target(&ip6t_standard_target);
+       ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
        if (ret < 0)
                goto err2;
-       ret = xt_register_target(&ip6t_error_target);
-       if (ret < 0)
-               goto err3;
-       ret = xt_register_match(&icmp6_matchstruct);
+       ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
        if (ret < 0)
                goto err4;
 
@@ -2308,15 +2268,13 @@ static int __init ip6_tables_init(void)
        if (ret < 0)
                goto err5;
 
-       printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
+       pr_info("(C) 2000-2006 Netfilter Core Team\n");
        return 0;
 
 err5:
-       xt_unregister_match(&icmp6_matchstruct);
+       xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
 err4:
-       xt_unregister_target(&ip6t_error_target);
-err3:
-       xt_unregister_target(&ip6t_standard_target);
+       xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
 err2:
        unregister_pernet_subsys(&ip6_tables_net_ops);
 err1:
@@ -2327,10 +2285,8 @@ static void __exit ip6_tables_fini(void)
 {
        nf_unregister_sockopt(&ip6t_sockopts);
 
-       xt_unregister_match(&icmp6_matchstruct);
-       xt_unregister_target(&ip6t_error_target);
-       xt_unregister_target(&ip6t_standard_target);
-
+       xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
+       xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
        unregister_pernet_subsys(&ip6_tables_net_ops);
 }
 
index b285fdf19050c83da61fe5c24011f475847dcfd6..af4ee11f206609861708443150ae20abbc8e64b6 100644 (file)
@@ -9,9 +9,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/ip.h>
@@ -378,7 +377,7 @@ static struct nf_loginfo default_loginfo = {
        .type   = NF_LOG_TYPE_LOG,
        .u = {
                .log = {
-                       .level    = 0,
+                       .level    = 5,
                        .logflags = NF_LOG_MASK,
                },
        },
@@ -437,7 +436,7 @@ ip6t_log_packet(u_int8_t pf,
 }
 
 static unsigned int
-log_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+log_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ip6t_log_info *loginfo = par->targinfo;
        struct nf_loginfo li;
@@ -452,20 +451,19 @@ log_tg6(struct sk_buff *skb, const struct xt_target_param *par)
 }
 
 
-static bool log_tg6_check(const struct xt_tgchk_param *par)
+static int log_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_log_info *loginfo = par->targinfo;
 
        if (loginfo->level >= 8) {
-               pr_debug("LOG: level %u >= 8\n", loginfo->level);
-               return false;
+               pr_debug("level %u >= 8\n", loginfo->level);
+               return -EINVAL;
        }
        if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
-               pr_debug("LOG: prefix term %i\n",
-                        loginfo->prefix[sizeof(loginfo->prefix)-1]);
-               return false;
+               pr_debug("prefix not null-terminated\n");
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target log_tg6_reg __read_mostly = {
index 39b50c3768e8b5c22f293e72c465d4b2aeea2bf2..47d2277137585648f57711618fe9b573ec83a1ff 100644 (file)
@@ -14,6 +14,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/gfp.h>
 #include <linux/module.h>
@@ -50,7 +51,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
 
        if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
            (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
-               pr_debug("ip6t_REJECT: addr is not unicast.\n");
+               pr_debug("addr is not unicast.\n");
                return;
        }
 
@@ -58,7 +59,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
        tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto);
 
        if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
-               pr_debug("ip6t_REJECT: Can't get TCP header.\n");
+               pr_debug("Cannot get TCP header.\n");
                return;
        }
 
@@ -66,7 +67,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
 
        /* IP header checks: fragment, too short. */
        if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
-               pr_debug("ip6t_REJECT: proto(%d) != IPPROTO_TCP, "
+               pr_debug("proto(%d) != IPPROTO_TCP, "
                         "or too short. otcplen = %d\n",
                         proto, otcplen);
                return;
@@ -77,14 +78,14 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
 
        /* No RST for RST. */
        if (otcph.rst) {
-               pr_debug("ip6t_REJECT: RST is set\n");
+               pr_debug("RST is set\n");
                return;
        }
 
        /* Check checksum. */
        if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
                            skb_checksum(oldskb, tcphoff, otcplen, 0))) {
-               pr_debug("ip6t_REJECT: TCP checksum is invalid\n");
+               pr_debug("TCP checksum is invalid\n");
                return;
        }
 
@@ -108,7 +109,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
 
        if (!nskb) {
                if (net_ratelimit())
-                       printk("ip6t_REJECT: Can't alloc skb\n");
+                       pr_debug("cannot alloc skb\n");
                dst_release(dst);
                return;
        }
@@ -174,15 +175,12 @@ send_unreach(struct net *net, struct sk_buff *skb_in, unsigned char code,
 }
 
 static unsigned int
-reject_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+reject_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct ip6t_reject_info *reject = par->targinfo;
        struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
 
        pr_debug("%s: medium point\n", __func__);
-       /* WARNING: This code causes reentry within ip6tables.
-          This means that the ip6tables jump stack is now crap.  We
-          must return an absolute verdict. --RR */
        switch (reject->with) {
        case IP6T_ICMP6_NO_ROUTE:
                send_unreach(net, skb, ICMPV6_NOROUTE, par->hooknum);
@@ -207,30 +205,30 @@ reject_tg6(struct sk_buff *skb, const struct xt_target_param *par)
                break;
        default:
                if (net_ratelimit())
-                       printk(KERN_WARNING "ip6t_REJECT: case %u not handled yet\n", reject->with);
+                       pr_info("case %u not handled yet\n", reject->with);
                break;
        }
 
        return NF_DROP;
 }
 
-static bool reject_tg6_check(const struct xt_tgchk_param *par)
+static int reject_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_reject_info *rejinfo = par->targinfo;
        const struct ip6t_entry *e = par->entryinfo;
 
        if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
-               printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
-               return false;
+               pr_info("ECHOREPLY is not supported.\n");
+               return -EINVAL;
        } else if (rejinfo->with == IP6T_TCP_RESET) {
                /* Must specify that it's a TCP packet */
                if (e->ipv6.proto != IPPROTO_TCP ||
                    (e->ipv6.invflags & XT_INV_PROTO)) {
-                       printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
-                       return false;
+                       pr_info("TCP_RESET illegal for non-tcp\n");
+                       return -EINVAL;
                }
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target reject_tg6_reg __read_mostly = {
index ac0b7c629d78d05715400f2160b029eba32b081c..89cccc5a9c929a1912a400858e322d09bb829279 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -29,14 +29,14 @@ spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
 {
        bool r;
 
-       pr_debug("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",
+       pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n",
                 invert ? '!' : ' ', min, spi, max);
        r = (spi >= min && spi <= max) ^ invert;
        pr_debug(" result %s\n", r ? "PASS" : "FAILED");
        return r;
 }
 
-static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ip_auth_hdr _ah;
        const struct ip_auth_hdr *ah;
@@ -48,13 +48,13 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
        if (err < 0) {
                if (err != -ENOENT)
-                       *par->hotdrop = true;
+                       par->hotdrop = true;
                return false;
        }
 
        ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
        if (ah == NULL) {
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -87,15 +87,15 @@ static bool ah_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
                !(ahinfo->hdrres && ah->reserved);
 }
 
-static bool ah_mt6_check(const struct xt_mtchk_param *par)
+static int ah_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_ah *ahinfo = par->matchinfo;
 
        if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
-               pr_debug("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
-               return false;
+               pr_debug("unknown flags %X\n", ahinfo->invflags);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match ah_mt6_reg __read_mostly = {
index ca287f6d2bcec9539ccc5a34e874b95e68316622..aab0706908c5491fc4405468232dfdd440f23c4d 100644 (file)
@@ -20,14 +20,14 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
 static bool
-eui64_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        unsigned char eui64[8];
 
        if (!(skb_mac_header(skb) >= skb->head &&
              skb_mac_header(skb) + ETH_HLEN <= skb->data) &&
            par->fragoff != 0) {
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
index 7b91c2598ed51085f7e79951c4a79b8fc355be11..eda898fda6ca0615ec5a314f47b1f86be9c1a280 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ipv6.h>
@@ -27,7 +27,7 @@ static inline bool
 id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
 {
        bool r;
-       pr_debug("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
+       pr_debug("id_match:%c 0x%x <= 0x%x <= 0x%x\n", invert ? '!' : ' ',
                 min, id, max);
        r = (id >= min && id <= max) ^ invert;
        pr_debug(" result %s\n", r ? "PASS" : "FAILED");
@@ -35,7 +35,7 @@ id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
 }
 
 static bool
-frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+frag_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct frag_hdr _frag;
        const struct frag_hdr *fh;
@@ -46,13 +46,13 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
        if (err < 0) {
                if (err != -ENOENT)
-                       *par->hotdrop = true;
+                       par->hotdrop = true;
                return false;
        }
 
        fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
        if (fh == NULL) {
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -102,15 +102,15 @@ frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
                  (ntohs(fh->frag_off) & IP6_MF));
 }
 
-static bool frag_mt6_check(const struct xt_mtchk_param *par)
+static int frag_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_frag *fraginfo = par->matchinfo;
 
        if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
-               pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
-               return false;
+               pr_debug("unknown flags %X\n", fraginfo->invflags);
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match frag_mt6_reg __read_mostly = {
index cbe8dec9744ba465de332a8044192b21f7c22afe..59df051eaef636cc7f665a2cfb5dc2d21b30b33f 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ipv6.h>
@@ -41,8 +41,10 @@ MODULE_ALIAS("ip6t_dst");
  *     5       -> RTALERT 2 x x
  */
 
+static struct xt_match hbh_mt6_reg[] __read_mostly;
+
 static bool
-hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ipv6_opt_hdr _optsh;
        const struct ipv6_opt_hdr *oh;
@@ -58,16 +60,18 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        unsigned int optlen;
        int err;
 
-       err = ipv6_find_hdr(skb, &ptr, par->match->data, NULL);
+       err = ipv6_find_hdr(skb, &ptr,
+                           (par->match == &hbh_mt6_reg[0]) ?
+                           NEXTHDR_HOP : NEXTHDR_DEST, NULL);
        if (err < 0) {
                if (err != -ENOENT)
-                       *par->hotdrop = true;
+                       par->hotdrop = true;
                return false;
        }
 
        oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
        if (oh == NULL) {
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -141,11 +145,11 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
                        }
 
                        /* Step to the next */
-                       pr_debug("len%04X \n", optlen);
+                       pr_debug("len%04X\n", optlen);
 
                        if ((ptr > skb->len - optlen || hdrlen < optlen) &&
                            temp < optinfo->optsnr - 1) {
-                               pr_debug("new pointer is too large! \n");
+                               pr_debug("new pointer is too large!\n");
                                break;
                        }
                        ptr += optlen;
@@ -160,32 +164,32 @@ hbh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        return false;
 }
 
-static bool hbh_mt6_check(const struct xt_mtchk_param *par)
+static int hbh_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_opts *optsinfo = par->matchinfo;
 
        if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
-               pr_debug("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
-               return false;
+               pr_debug("unknown flags %X\n", optsinfo->invflags);
+               return -EINVAL;
        }
 
        if (optsinfo->flags & IP6T_OPTS_NSTRICT) {
-               pr_debug("ip6t_opts: Not strict - not implemented");
-               return false;
+               pr_debug("Not strict - not implemented");
+               return -EINVAL;
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match hbh_mt6_reg[] __read_mostly = {
        {
+               /* Note, hbh_mt6 relies on the order of hbh_mt6_reg */
                .name           = "hbh",
                .family         = NFPROTO_IPV6,
                .match          = hbh_mt6,
                .matchsize      = sizeof(struct ip6t_opts),
                .checkentry     = hbh_mt6_check,
                .me             = THIS_MODULE,
-               .data           = NEXTHDR_HOP,
        },
        {
                .name           = "dst",
@@ -194,7 +198,6 @@ static struct xt_match hbh_mt6_reg[] __read_mostly = {
                .matchsize      = sizeof(struct ip6t_opts),
                .checkentry     = hbh_mt6_check,
                .me             = THIS_MODULE,
-               .data           = NEXTHDR_DEST,
        },
 };
 
index 91490ad9302ccc692c23fd6f37a7f8e9f78bdb7e..54bd9790603f253a417971eea50a4157fd0c75ae 100644 (file)
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Xtables: IPv6 header types match");
 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
 static bool
-ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+ipv6header_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ip6t_ipv6header_info *info = par->matchinfo;
        unsigned int temp;
@@ -118,16 +118,16 @@ ipv6header_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        }
 }
 
-static bool ipv6header_mt6_check(const struct xt_mtchk_param *par)
+static int ipv6header_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_ipv6header_info *info = par->matchinfo;
 
        /* invflags is 0 or 0xff in hard mode */
        if ((!info->modeflag) && info->invflags != 0x00 &&
            info->invflags != 0xFF)
-               return false;
+               return -EINVAL;
 
-       return true;
+       return 0;
 }
 
 static struct xt_match ipv6header_mt6_reg __read_mostly = {
index aafe4e66577b54332919e1f67dc27c48f19629a8..0c90c66b199257dfd6123c1cc6a2ec904aa0053a 100644 (file)
@@ -11,6 +11,7 @@
  * Based on net/netfilter/xt_tcpudp.c
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/types.h>
 #include <linux/module.h>
 #include <net/ip.h>
 MODULE_DESCRIPTION("Xtables: IPv6 Mobility Header match");
 MODULE_LICENSE("GPL");
 
-#ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
 /* Returns 1 if the type is matched by the range, 0 otherwise */
 static inline bool
 type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert)
@@ -37,7 +32,7 @@ type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert)
        return (type >= min && type <= max) ^ invert;
 }
 
-static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool mh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ip6_mh _mh;
        const struct ip6_mh *mh;
@@ -51,15 +46,15 @@ static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        if (mh == NULL) {
                /* We've been asked to examine this packet, and we
                   can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil MH tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil MH tinygram.\n");
+               par->hotdrop = true;
                return false;
        }
 
        if (mh->ip6mh_proto != IPPROTO_NONE) {
-               duprintf("Dropping invalid MH Payload Proto: %u\n",
+               pr_debug("Dropping invalid MH Payload Proto: %u\n",
                         mh->ip6mh_proto);
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -67,12 +62,12 @@ static bool mh_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
                          !!(mhinfo->invflags & IP6T_MH_INV_TYPE));
 }
 
-static bool mh_mt6_check(const struct xt_mtchk_param *par)
+static int mh_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_mh *mhinfo = par->matchinfo;
 
        /* Must specify no unknown invflags */
-       return !(mhinfo->invflags & ~IP6T_MH_INV_MASK);
+       return (mhinfo->invflags & ~IP6T_MH_INV_MASK) ? -EINVAL : 0;
 }
 
 static struct xt_match mh_mt6_reg __read_mostly = {
index b77307fc8743b15c31e08b0e1d924005c1a72c5c..d8488c50a8e0292e3b59515ec0c8ea6d7bf79f66 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ipv6.h>
@@ -29,14 +29,14 @@ static inline bool
 segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
 {
        bool r;
-       pr_debug("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",
+       pr_debug("segsleft_match:%c 0x%x <= 0x%x <= 0x%x\n",
                 invert ? '!' : ' ', min, id, max);
        r = (id >= min && id <= max) ^ invert;
        pr_debug(" result %s\n", r ? "PASS" : "FAILED");
        return r;
 }
 
-static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct ipv6_rt_hdr _route;
        const struct ipv6_rt_hdr *rh;
@@ -52,13 +52,13 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
        if (err < 0) {
                if (err != -ENOENT)
-                       *par->hotdrop = true;
+                       par->hotdrop = true;
                return false;
        }
 
        rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
        if (rh == NULL) {
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -183,23 +183,23 @@ static bool rt_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        return false;
 }
 
-static bool rt_mt6_check(const struct xt_mtchk_param *par)
+static int rt_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_rt *rtinfo = par->matchinfo;
 
        if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
-               pr_debug("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
-               return false;
+               pr_debug("unknown flags %X\n", rtinfo->invflags);
+               return -EINVAL;
        }
        if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
            (!(rtinfo->flags & IP6T_RT_TYP) ||
             (rtinfo->rt_type != 0) ||
             (rtinfo->invflags & IP6T_RT_INV_TYP))) {
                pr_debug("`--rt-type 0' required before `--rt-0-*'");
-               return false;
+               return -EINVAL;
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match rt_mt6_reg __read_mostly = {
index d6fc9aff3163eb417c6aeadffe481e643d55566d..c9e37c8fd62c97ed0e2d3058f177a38b25a79348 100644 (file)
@@ -81,7 +81,7 @@ static int __init ip6table_filter_init(void)
        int ret;
 
        if (forward < 0 || forward > NF_MAX_VERDICT) {
-               printk("iptables forward must be 0 or 1\n");
+               pr_err("iptables forward must be 0 or 1\n");
                return -EINVAL;
        }
 
index 6a102b57f35623c055c1eca22fd80995427ff428..679a0a3b7b3c7c17a4d0cd6ae7c43d34bf5e279f 100644 (file)
@@ -43,7 +43,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
        if (skb->len < sizeof(struct iphdr) ||
            ip_hdrlen(skb) < sizeof(struct iphdr)) {
                if (net_ratelimit())
-                       printk("ip6t_hook: happy cracking.\n");
+                       pr_warning("ip6t_hook: happy cracking.\n");
                return NF_ACCEPT;
        }
 #endif
index 996c3f41fecd419223107751b4e2d66764820599..ff43461704be5c9433d7468f1fe99c63aab7d613 100644 (file)
@@ -280,7 +280,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
        /* root is playing with raw sockets. */
        if (skb->len < sizeof(struct ipv6hdr)) {
                if (net_ratelimit())
-                       printk("ipv6_conntrack_local: packet too short\n");
+                       pr_notice("ipv6_conntrack_local: packet too short\n");
                return NF_ACCEPT;
        }
        return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn);
@@ -406,37 +406,37 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
 
        ret = nf_ct_frag6_init();
        if (ret < 0) {
-               printk("nf_conntrack_ipv6: can't initialize frag6.\n");
+               pr_err("nf_conntrack_ipv6: can't initialize frag6.\n");
                return ret;
        }
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6);
        if (ret < 0) {
-               printk("nf_conntrack_ipv6: can't register tcp.\n");
+               pr_err("nf_conntrack_ipv6: can't register tcp.\n");
                goto cleanup_frag6;
        }
 
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6);
        if (ret < 0) {
-               printk("nf_conntrack_ipv6: can't register udp.\n");
+               pr_err("nf_conntrack_ipv6: can't register udp.\n");
                goto cleanup_tcp;
        }
 
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6);
        if (ret < 0) {
-               printk("nf_conntrack_ipv6: can't register icmpv6.\n");
+               pr_err("nf_conntrack_ipv6: can't register icmpv6.\n");
                goto cleanup_udp;
        }
 
        ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
        if (ret < 0) {
-               printk("nf_conntrack_ipv6: can't register ipv6\n");
+               pr_err("nf_conntrack_ipv6: can't register ipv6\n");
                goto cleanup_icmpv6;
        }
 
        ret = nf_register_hooks(ipv6_conntrack_ops,
                                ARRAY_SIZE(ipv6_conntrack_ops));
        if (ret < 0) {
-               printk("nf_conntrack_ipv6: can't register pre-routing defrag "
+               pr_err("nf_conntrack_ipv6: can't register pre-routing defrag "
                       "hook.\n");
                goto cleanup_ipv6;
        }
index dd5b9bd61c6298474af25539617809428ed45418..6fb890187de09b01f8dc6453b7862a70de2edb8f 100644 (file)
@@ -644,7 +644,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
                s2 = s->next;
                s->next = NULL;
 
-               NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn,
+               NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn,
                               NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
                s = s2;
        }
index 58344c0fbd13a3603d29eef3adc6a96f36ff1248..566798d69f37d223016cfc31a398d0649dad68bf 100644 (file)
@@ -97,6 +97,7 @@ static const struct snmp_mib snmp6_icmp6_list[] = {
        SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS),
        SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS),
        SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS),
+       SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS),
        SNMP_MIB_SENTINEL
 };
 
@@ -167,7 +168,6 @@ static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void __percpu **mib)
                        i & 0x100 ?  "Out" : "In", i & 0xff);
                seq_printf(seq, "%-32s\t%lu\n", name, val);
        }
-       return;
 }
 
 static void snmp6_seq_show_item(struct seq_file *seq, void __percpu **mib,
index 8763b1a0814a44b150e4c7f9e075f6e684f09243..4a4dcbe4f8b22bdc813cc75aaf821b023952d187 100644 (file)
@@ -381,7 +381,7 @@ static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
        }
 
        /* Charge it to the socket. */
-       if (sock_queue_rcv_skb(sk, skb) < 0) {
+       if (ip_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
@@ -461,6 +461,9 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        if (flags & MSG_ERRQUEUE)
                return ipv6_recv_error(sk, msg, len);
 
+       if (np->rxpmtu && np->rxopt.bits.rxpmtu)
+               return ipv6_recv_rxpmtu(sk, msg, len);
+
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
                goto out;
@@ -637,8 +640,8 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
                goto error_fault;
 
        IP6_UPD_PO_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len);
-       err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                     dst_output);
+       err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL,
+                     rt->u.dst.dev, dst_output);
        if (err > 0)
                err = net_xmit_errno(err);
        if (err)
@@ -733,6 +736,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        int addr_len = msg->msg_namelen;
        int hlimit = -1;
        int tclass = -1;
+       int dontfrag = -1;
        u16 proto;
        int err;
 
@@ -811,7 +815,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(struct ipv6_txoptions);
 
-               err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass);
+               err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit,
+                                       &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
@@ -880,6 +885,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        if (tclass < 0)
                tclass = np->tclass;
 
+       if (dontfrag < 0)
+               dontfrag = np->dontfrag;
+
        if (msg->msg_flags&MSG_CONFIRM)
                goto do_confirm;
 
@@ -890,7 +898,7 @@ back_from_confirm:
                lock_sock(sk);
                err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
                        len, 0, hlimit, tclass, opt, &fl, (struct rt6_info*)dst,
-                       msg->msg_flags);
+                       msg->msg_flags, dontfrag);
 
                if (err)
                        ip6_flush_pending_frames(sk);
index 05ebd7833043c687010382fb2d1534ef1bd45b8a..294cbe8b0725f7ad9f58690f2b511829d391a672 100644 (file)
@@ -316,7 +316,6 @@ static void rt6_probe(struct rt6_info *rt)
 #else
 static inline void rt6_probe(struct rt6_info *rt)
 {
-       return;
 }
 #endif
 
@@ -1553,7 +1552,6 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
 
 out:
        dst_release(&rt->u.dst);
-       return;
 }
 
 /*
index 5abae10cd8844c8d2acb30ceced10055dbdf3856..e51e650ea80be7e4e2e0e0fe8514e3f14f0f1890 100644 (file)
@@ -566,11 +566,9 @@ static int ipip6_rcv(struct sk_buff *skb)
                        kfree_skb(skb);
                        return 0;
                }
-               tunnel->dev->stats.rx_packets++;
-               tunnel->dev->stats.rx_bytes += skb->len;
-               skb->dev = tunnel->dev;
-               skb_dst_drop(skb);
-               nf_reset(skb);
+
+               skb_tunnel_rx(skb, tunnel->dev);
+
                ipip6_ecn_decapsulate(iph, skb);
                netif_rx(skb);
                rcu_read_unlock();
index 075f540ec1975cdce6148e75661219cfe5decb6e..2b7c3a100e2c327f3e3c057e309733e221b22061 100644 (file)
@@ -75,6 +75,9 @@ static void   tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
                                      struct request_sock *req);
 
 static int     tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
+static void    __tcp_v6_send_check(struct sk_buff *skb,
+                                   struct in6_addr *saddr,
+                                   struct in6_addr *daddr);
 
 static const struct inet_connection_sock_af_ops ipv6_mapped;
 static const struct inet_connection_sock_af_ops ipv6_specific;
@@ -350,6 +353,11 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        if (sk->sk_state == TCP_CLOSE)
                goto out;
 
+       if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) {
+               NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
+               goto out;
+       }
+
        tp = tcp_sk(sk);
        seq = ntohl(th->seq);
        if (sk->sk_state != TCP_LISTEN &&
@@ -503,14 +511,10 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 
        skb = tcp_make_synack(sk, dst, req, rvp);
        if (skb) {
-               struct tcphdr *th = tcp_hdr(skb);
-
-               th->check = tcp_v6_check(skb->len,
-                                        &treq->loc_addr, &treq->rmt_addr,
-                                        csum_partial(th, skb->len, skb->csum));
+               __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
 
                ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
-               err = ip6_xmit(sk, skb, &fl, opt, 0);
+               err = ip6_xmit(sk, skb, &fl, opt);
                err = net_xmit_eval(err);
        }
 
@@ -600,7 +604,7 @@ static int tcp_v6_md5_do_add(struct sock *sk, struct in6_addr *peer,
                                kfree(newkey);
                                return -ENOMEM;
                        }
-                       sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+                       sk_nocaps_add(sk, NETIF_F_GSO_MASK);
                }
                if (tcp_alloc_md5sig_pool(sk) == NULL) {
                        kfree(newkey);
@@ -737,7 +741,7 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
                        return -ENOMEM;
 
                tp->md5sig_info = p;
-               sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
+               sk_nocaps_add(sk, NETIF_F_GSO_MASK);
        }
 
        newkey = kmemdup(cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL);
@@ -918,22 +922,29 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = {
        .twsk_destructor= tcp_twsk_destructor,
 };
 
-static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
+static void __tcp_v6_send_check(struct sk_buff *skb,
+                               struct in6_addr *saddr, struct in6_addr *daddr)
 {
-       struct ipv6_pinfo *np = inet6_sk(sk);
        struct tcphdr *th = tcp_hdr(skb);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,  0);
+               th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
                skb->csum_start = skb_transport_header(skb) - skb->head;
                skb->csum_offset = offsetof(struct tcphdr, check);
        } else {
-               th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
-                                           csum_partial(th, th->doff<<2,
-                                                        skb->csum));
+               th->check = tcp_v6_check(skb->len, saddr, daddr,
+                                        csum_partial(th, th->doff << 2,
+                                                     skb->csum));
        }
 }
 
+static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+
+       __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
+}
+
 static int tcp_v6_gso_send_check(struct sk_buff *skb)
 {
        struct ipv6hdr *ipv6h;
@@ -946,11 +957,8 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
        th = tcp_hdr(skb);
 
        th->check = 0;
-       th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
-                                    IPPROTO_TCP, 0);
-       skb->csum_start = skb_transport_header(skb) - skb->head;
-       skb->csum_offset = offsetof(struct tcphdr, check);
        skb->ip_summed = CHECKSUM_PARTIAL;
+       __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
        return 0;
 }
 
@@ -1047,15 +1055,14 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
        }
 #endif
 
-       buff->csum = csum_partial(t1, tot_len, 0);
-
        memset(&fl, 0, sizeof(fl));
        ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr);
        ipv6_addr_copy(&fl.fl6_src, &ipv6_hdr(skb)->daddr);
 
-       t1->check = csum_ipv6_magic(&fl.fl6_src, &fl.fl6_dst,
-                                   tot_len, IPPROTO_TCP,
-                                   buff->csum);
+       buff->ip_summed = CHECKSUM_PARTIAL;
+       buff->csum = 0;
+
+       __tcp_v6_send_check(buff, &fl.fl6_src, &fl.fl6_dst);
 
        fl.proto = IPPROTO_TCP;
        fl.oif = inet6_iif(skb);
@@ -1070,7 +1077,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
        if (!ip6_dst_lookup(ctl_sk, &dst, &fl)) {
                if (xfrm_lookup(net, &dst, &fl, NULL, 0) >= 0) {
                        skb_dst_set(buff, dst);
-                       ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
+                       ip6_xmit(ctl_sk, buff, &fl, NULL);
                        TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
                        if (rst)
                                TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
@@ -1233,12 +1240,12 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
                        goto drop_and_free;
 
                /* Secret recipe starts with IP addresses */
-               d = &ipv6_hdr(skb)->daddr.s6_addr32[0];
+               d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
                *mess++ ^= *d++;
                *mess++ ^= *d++;
                *mess++ ^= *d++;
                *mess++ ^= *d++;
-               d = &ipv6_hdr(skb)->saddr.s6_addr32[0];
+               d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
                *mess++ ^= *d++;
                *mess++ ^= *d++;
                *mess++ ^= *d++;
@@ -1676,6 +1683,7 @@ ipv6_pktoptions:
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
        struct tcphdr *th;
+       struct ipv6hdr *hdr;
        struct sock *sk;
        int ret;
        struct net *net = dev_net(skb->dev);
@@ -1702,12 +1710,13 @@ static int tcp_v6_rcv(struct sk_buff *skb)
                goto bad_packet;
 
        th = tcp_hdr(skb);
+       hdr = ipv6_hdr(skb);
        TCP_SKB_CB(skb)->seq = ntohl(th->seq);
        TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
                                    skb->len - th->doff*4);
        TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
        TCP_SKB_CB(skb)->when = 0;
-       TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
+       TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(hdr);
        TCP_SKB_CB(skb)->sacked = 0;
 
        sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
@@ -1718,6 +1727,11 @@ process:
        if (sk->sk_state == TCP_TIME_WAIT)
                goto do_time_wait;
 
+       if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) {
+               NET_INC_STATS_BH(net, LINUX_MIB_TCPMINTTLDROP);
+               goto discard_and_relse;
+       }
+
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
 
index 90824852f598d34f4c544392e247a6f93a7bd0b0..3d7a2c0b836afa6a4b458c724e2118c58d35e959 100644 (file)
@@ -91,9 +91,9 @@ static unsigned int udp6_portaddr_hash(struct net *net,
        if (ipv6_addr_any(addr6))
                hash = jhash_1word(0, mix);
        else if (ipv6_addr_v4mapped(addr6))
-               hash = jhash_1word(addr6->s6_addr32[3], mix);
+               hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix);
        else
-               hash = jhash2(addr6->s6_addr32, 4, mix);
+               hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix);
 
        return hash ^ port;
 }
@@ -335,6 +335,9 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        if (flags & MSG_ERRQUEUE)
                return ipv6_recv_error(sk, msg, len);
 
+       if (np->rxpmtu && np->rxopt.bits.rxpmtu)
+               return ipv6_recv_rxpmtu(sk, msg, len);
+
 try_again:
        skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
                                  &peeked, &err);
@@ -421,7 +424,7 @@ out:
        return err;
 
 csum_copy_err:
-       lock_sock(sk);
+       lock_sock_bh(sk);
        if (!skb_kill_datagram(sk, skb, flags)) {
                if (is_udp4)
                        UDP_INC_STATS_USER(sock_net(sk),
@@ -430,7 +433,7 @@ csum_copy_err:
                        UDP6_INC_STATS_USER(sock_net(sk),
                                        UDP_MIB_INERRORS, is_udplite);
        }
-       release_sock(sk);
+       unlock_sock_bh(sk);
 
        if (flags & MSG_DONTWAIT)
                return -EAGAIN;
@@ -511,7 +514,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                        goto drop;
        }
 
-       if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) {
+       if ((rc = ip_queue_rcv_skb(sk, skb)) < 0) {
                /* Note that an ENOMEM error is charged twice */
                if (rc == -ENOMEM)
                        UDP6_INC_STATS_BH(sock_net(sk),
@@ -581,6 +584,10 @@ static void flush_stack(struct sock **stack, unsigned int count,
 
                sk = stack[i];
                if (skb1) {
+                       if (sk_rcvqueues_full(sk, skb)) {
+                               kfree_skb(skb1);
+                               goto drop;
+                       }
                        bh_lock_sock(sk);
                        if (!sock_owned_by_user(sk))
                                udpv6_queue_rcv_skb(sk, skb1);
@@ -692,7 +699,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        u32 ulen = 0;
 
        if (!pskb_may_pull(skb, sizeof(struct udphdr)))
-               goto short_packet;
+               goto discard;
 
        saddr = &ipv6_hdr(skb)->saddr;
        daddr = &ipv6_hdr(skb)->daddr;
@@ -756,6 +763,10 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
 
        /* deliver */
 
+       if (sk_rcvqueues_full(sk, skb)) {
+               sock_put(sk);
+               goto discard;
+       }
        bh_lock_sock(sk);
        if (!sock_owned_by_user(sk))
                udpv6_queue_rcv_skb(sk, skb);
@@ -770,9 +781,14 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
        return 0;
 
 short_packet:
-       LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n",
+       LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n",
                       proto == IPPROTO_UDPLITE ? "-Lite" : "",
-                      ulen, skb->len);
+                      saddr,
+                      ntohs(uh->source),
+                      ulen,
+                      skb->len,
+                      daddr,
+                      ntohs(uh->dest));
 
 discard:
        UDP6_INC_STATS_BH(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE);
@@ -919,6 +935,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
        int ulen = len;
        int hlimit = -1;
        int tclass = -1;
+       int dontfrag = -1;
        int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
        int err;
        int connected = 0;
@@ -1049,7 +1066,8 @@ do_udp_sendmsg:
                memset(opt, 0, sizeof(struct ipv6_txoptions));
                opt->tot_len = sizeof(*opt);
 
-               err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit, &tclass);
+               err = datagram_send_ctl(sock_net(sk), msg, &fl, opt, &hlimit,
+                                       &tclass, &dontfrag);
                if (err < 0) {
                        fl6_sock_release(flowlabel);
                        return err;
@@ -1120,6 +1138,9 @@ do_udp_sendmsg:
        if (tclass < 0)
                tclass = np->tclass;
 
+       if (dontfrag < 0)
+               dontfrag = np->dontfrag;
+
        if (msg->msg_flags&MSG_CONFIRM)
                goto do_confirm;
 back_from_confirm:
@@ -1143,7 +1164,7 @@ do_append_data:
        err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen,
                sizeof(struct udphdr), hlimit, tclass, opt, &fl,
                (struct rt6_info*)dst,
-               corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+               corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, dontfrag);
        if (err)
                udp_v6_flush_pending_frames(sk);
        else if (!corkreq)
index 2bc98ede1235311a7188ccad4a5392451d54824c..f8c3cf842f534e3e87c35a1213afcb320880998b 100644 (file)
@@ -42,7 +42,7 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
        ipv6_hdr(skb)->payload_len = htons(skb->len);
        __skb_push(skb, skb->data - skb_network_header(skb));
 
-       NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
+       NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
                ip6_rcv_finish);
        return -1;
 }
index 0c92112dcba3754f6eb7b468970bbabbf2021acc..6434bd5ce0885ad20408a2f79eb198b8f30c269a 100644 (file)
@@ -90,6 +90,6 @@ static int xfrm6_output_finish(struct sk_buff *skb)
 
 int xfrm6_output(struct sk_buff *skb)
 {
-       return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev,
-                      xfrm6_output_finish);
+       return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL,
+                      skb_dst(skb)->dev, xfrm6_output_finish);
 }
index 00bf7c962b7e84134734d74bac80482da87bdcd6..4a0e77e14468e106b51d0ce5629d837a6e95fae2 100644 (file)
@@ -67,36 +67,6 @@ static int xfrm6_get_saddr(struct net *net,
        return 0;
 }
 
-static struct dst_entry *
-__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
-{
-       struct dst_entry *dst;
-
-       /* Still not clear if we should set fl->fl6_{src,dst}... */
-       read_lock_bh(&policy->lock);
-       for (dst = policy->bundles; dst; dst = dst->next) {
-               struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
-               struct in6_addr fl_dst_prefix, fl_src_prefix;
-
-               ipv6_addr_prefix(&fl_dst_prefix,
-                                &fl->fl6_dst,
-                                xdst->u.rt6.rt6i_dst.plen);
-               ipv6_addr_prefix(&fl_src_prefix,
-                                &fl->fl6_src,
-                                xdst->u.rt6.rt6i_src.plen);
-               if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) &&
-                   ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) &&
-                   xfrm_bundle_ok(policy, xdst, fl, AF_INET6,
-                                  (xdst->u.rt6.rt6i_dst.plen != 128 ||
-                                   xdst->u.rt6.rt6i_src.plen != 128))) {
-                       dst_clone(dst);
-                       break;
-               }
-       }
-       read_unlock_bh(&policy->lock);
-       return dst;
-}
-
 static int xfrm6_get_tos(struct flowi *fl)
 {
        return 0;
@@ -291,7 +261,6 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
        .dst_ops =              &xfrm6_dst_ops,
        .dst_lookup =           xfrm6_dst_lookup,
        .get_saddr =            xfrm6_get_saddr,
-       .find_bundle =          __xfrm6_find_bundle,
        .decode_session =       _decode_session6,
        .get_tos =              xfrm6_get_tos,
        .init_path =            xfrm6_init_path,
index 2a4efcea342389ef054f1c3f42558448e8fa22bf..79986a674f6ea23329fb5a3960f1d3ece82b9a9d 100644 (file)
@@ -347,7 +347,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
                self->tx_flow = flow;
                IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n",
                           __func__);
-               wake_up_interruptible(sk->sk_sleep);
+               wake_up_interruptible(sk_sleep(sk));
                break;
        default:
                IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __func__);
@@ -900,7 +900,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
                if (flags & O_NONBLOCK)
                        goto out;
 
-               err = wait_event_interruptible(*(sk->sk_sleep),
+               err = wait_event_interruptible(*(sk_sleep(sk)),
                                        skb_peek(&sk->sk_receive_queue));
                if (err)
                        goto out;
@@ -1066,7 +1066,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
                goto out;
 
        err = -ERESTARTSYS;
-       if (wait_event_interruptible(*(sk->sk_sleep),
+       if (wait_event_interruptible(*(sk_sleep(sk)),
                                     (sk->sk_state != TCP_SYN_SENT)))
                goto out;
 
@@ -1318,7 +1318,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        /* Check if IrTTP is wants us to slow down */
 
-       if (wait_event_interruptible(*(sk->sk_sleep),
+       if (wait_event_interruptible(*(sk_sleep(sk)),
            (self->tx_flow != FLOW_STOP  ||  sk->sk_state != TCP_ESTABLISHED))) {
                err = -ERESTARTSYS;
                goto out;
@@ -1477,7 +1477,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
                        if (copied >= target)
                                break;
 
-                       prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+                       prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
                        /*
                         *      POSIX 1003.1g mandates this order.
@@ -1497,7 +1497,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
                                /* Wait process until data arrives */
                                schedule();
 
-                       finish_wait(sk->sk_sleep, &wait);
+                       finish_wait(sk_sleep(sk), &wait);
 
                        if (err)
                                goto out;
@@ -1787,7 +1787,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
        IRDA_DEBUG(4, "%s()\n", __func__);
 
        lock_kernel();
-       poll_wait(file, sk->sk_sleep, wait);
+       poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* Exceptional events? */
index e2e893b474e92b356454e8b7c674196ac465e7ee..8b915f3ac3b91a6b2471149799117d8bdd5b8b00 100644 (file)
@@ -475,7 +475,7 @@ static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
        /* Check if any of the settings have changed */
        if (dce & 0x0f) {
                if (dce & IRCOMM_DELTA_CTS) {
-                       IRDA_DEBUG(2, "%s(), CTS \n", __func__ );
+                       IRDA_DEBUG(2, "%s(), CTS\n", __func__ );
                }
        }
 
index 79a1e5a23e10e6e0aa1b14837bdfbe29cf7d7000..fce364c6c71a5e612fb9f0c2c65b0166749821af 100644 (file)
@@ -685,8 +685,6 @@ static void iriap_getvaluebyclass_indication(struct iriap_cb *self,
        /* We have a match; send the value.  */
        iriap_getvaluebyclass_response(self, obj->id, IAS_SUCCESS,
                                       attrib->value);
-
-       return;
 }
 
 /*
index df18ab4b6c5e8dffd4ec2532851a88cd3d6eb9f2..e98e40d76f4f4f256e6bf43d95d577f4eedeb312 100644 (file)
@@ -678,7 +678,6 @@ irda_irnet_destroy(irnet_socket *   self)
   self->stsap_sel = 0;
 
   DEXIT(IRDA_SOCK_TRACE, "\n");
-  return;
 }
 
 
@@ -928,7 +927,6 @@ irnet_disconnect_server(irnet_socket *      self,
   irttp_listen(self->tsap);
 
   DEXIT(IRDA_SERV_TRACE, "\n");
-  return;
 }
 
 /*------------------------------------------------------------------*/
@@ -1013,7 +1011,6 @@ irnet_destroy_server(void)
   irda_irnet_destroy(&irnet_server.s);
 
   DEXIT(IRDA_SERV_TRACE, "\n");
-  return;
 }
 
 
index c18286a2167b9987f15dd0f765d1ed8e2aa1625b..c8b4599a752ea0480450c95610b3d914d634573d 100644 (file)
@@ -59,7 +59,7 @@ do {                                                                  \
        DEFINE_WAIT(__wait);                                            \
        long __timeo = timeo;                                           \
        ret = 0;                                                        \
-       prepare_to_wait(sk->sk_sleep, &__wait, TASK_INTERRUPTIBLE);     \
+       prepare_to_wait(sk_sleep(sk), &__wait, TASK_INTERRUPTIBLE);     \
        while (!(condition)) {                                          \
                if (!__timeo) {                                         \
                        ret = -EAGAIN;                                  \
@@ -76,7 +76,7 @@ do {                                                                  \
                if (ret)                                                \
                        break;                                          \
        }                                                               \
-       finish_wait(sk->sk_sleep, &__wait);                             \
+       finish_wait(sk_sleep(sk), &__wait);                             \
 } while (0)
 
 #define iucv_sock_wait(sk, condition, timeo)                           \
@@ -136,7 +136,6 @@ static void afiucv_pm_complete(struct device *dev)
 #ifdef CONFIG_PM_DEBUG
        printk(KERN_WARNING "afiucv_pm_complete\n");
 #endif
-       return;
 }
 
 /**
@@ -305,11 +304,14 @@ static inline int iucv_below_msglim(struct sock *sk)
  */
 static void iucv_sock_wake_msglim(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
-       if (sk_has_sleeper(sk))
-               wake_up_interruptible_all(sk->sk_sleep);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible_all(&wq->wait);
        sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 /* Timers */
@@ -795,7 +797,7 @@ static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
        timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
 
        /* Wait for an incoming connection */
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        while (!(nsk = iucv_accept_dequeue(sk, newsock))) {
                set_current_state(TASK_INTERRUPTIBLE);
                if (!timeo) {
@@ -819,7 +821,7 @@ static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
        }
 
        set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
 
        if (err)
                goto done;
@@ -1269,7 +1271,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        unsigned int mask = 0;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
 
        if (sk->sk_state == IUCV_LISTEN)
                return iucv_accept_poll(sk);
index ba9a3fcc2fedff60c23b3cae9e394dca5890bdf0..43040e97c474b54dc36cfdc635b2639c28766c74 100644 (file)
@@ -99,7 +99,7 @@ static void pfkey_sock_destruct(struct sock *sk)
        skb_queue_purge(&sk->sk_receive_queue);
 
        if (!sock_flag(sk, SOCK_DEAD)) {
-               printk("Attempt to release alive pfkey socket: %p\n", sk);
+               pr_err("Attempt to release alive pfkey socket: %p\n", sk);
                return;
        }
 
@@ -1402,7 +1402,7 @@ static inline int event2poltype(int event)
        case XFRM_MSG_POLEXPIRE:
        //      return SADB_X_SPDEXPIRE;
        default:
-               printk("pfkey: Unknown policy event %d\n", event);
+               pr_err("pfkey: Unknown policy event %d\n", event);
                break;
        }
 
@@ -1421,7 +1421,7 @@ static inline int event2keytype(int event)
        case XFRM_MSG_EXPIRE:
                return SADB_EXPIRE;
        default:
-               printk("pfkey: Unknown SA event %d\n", event);
+               pr_err("pfkey: Unknown SA event %d\n", event);
                break;
        }
 
@@ -2969,7 +2969,7 @@ static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
        case XFRM_MSG_NEWAE: /* not yet supported */
                break;
        default:
-               printk("pfkey: Unknown SA event %d\n", c->event);
+               pr_err("pfkey: Unknown SA event %d\n", c->event);
                break;
        }
 
@@ -2993,7 +2993,7 @@ static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_e
                        break;
                return key_notify_policy_flush(c);
        default:
-               printk("pfkey: Unknown policy event %d\n", c->event);
+               pr_err("pfkey: Unknown policy event %d\n", c->event);
                break;
        }
 
diff --git a/net/l2tp/Kconfig b/net/l2tp/Kconfig
new file mode 100644 (file)
index 0000000..4b1e717
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# Layer Two Tunneling Protocol (L2TP)
+#
+
+menuconfig L2TP
+       tristate "Layer Two Tunneling Protocol (L2TP)"
+       depends on INET
+       ---help---
+         Layer Two Tunneling Protocol
+
+         From RFC 2661 <http://www.ietf.org/rfc/rfc2661.txt>.
+
+         L2TP facilitates the tunneling of packets across an
+         intervening network in a way that is as transparent as
+         possible to both end-users and applications.
+
+         L2TP is often used to tunnel PPP traffic over IP
+         tunnels. One IP tunnel may carry thousands of individual PPP
+         connections. L2TP is also used as a VPN protocol, popular
+         with home workers to connect to their offices.
+
+         L2TPv3 allows other protocols as well as PPP to be carried
+         over L2TP tunnels. L2TPv3 is defined in RFC 3931
+         <http://www.ietf.org/rfc/rfc3931.txt>.
+
+         The kernel component handles only L2TP data packets: a
+         userland daemon handles L2TP the control protocol (tunnel
+         and session setup). One such daemon is OpenL2TP
+         (http://openl2tp.org/).
+
+         If you don't need L2TP, say N. To compile all L2TP code as
+         modules, choose M here.
+
+config L2TP_DEBUGFS
+       tristate "L2TP debugfs support"
+       depends on L2TP && DEBUG_FS
+       help
+         Support for l2tp directory in debugfs filesystem. This may be
+         used to dump internal state of the l2tp drivers for problem
+         analysis.
+
+         If unsure, say 'Y'.
+
+         To compile this driver as a module, choose M here. The module
+         will be called l2tp_debugfs.
+
+config L2TP_V3
+       bool "L2TPv3 support (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && L2TP
+       help
+         Layer Two Tunneling Protocol Version 3
+
+         From RFC 3931 <http://www.ietf.org/rfc/rfc3931.txt>.
+
+         The Layer Two Tunneling Protocol (L2TP) provides a dynamic
+         mechanism for tunneling Layer 2 (L2) "circuits" across a
+         packet-oriented data network (e.g., over IP).  L2TP, as
+         originally defined in RFC 2661, is a standard method for
+         tunneling Point-to-Point Protocol (PPP) [RFC1661] sessions.
+         L2TP has since been adopted for tunneling a number of other
+         L2 protocols, including ATM, Frame Relay, HDLC and even raw
+         ethernet frames.
+
+         If you are connecting to L2TPv3 equipment, or you want to
+         tunnel raw ethernet frames using L2TP, say Y here. If
+         unsure, say N.
+
+config L2TP_IP
+       tristate "L2TP IP encapsulation for L2TPv3"
+       depends on L2TP_V3
+       help
+         Support for L2TP-over-IP socket family.
+
+         The L2TPv3 protocol defines two possible encapsulations for
+         L2TP frames, namely UDP and plain IP (without UDP). This
+         driver provides a new L2TPIP socket family with which
+         userspace L2TPv3 daemons may create L2TP/IP tunnel sockets
+         when UDP encapsulation is not required. When L2TP is carried
+         in IP packets, it used IP protocol number 115, so this port
+         must be enabled in firewalls.
+
+         To compile this driver as a module, choose M here. The module
+         will be called l2tp_ip.
+
+config L2TP_ETH
+       tristate "L2TP ethernet pseudowire support for L2TPv3"
+       depends on L2TP_V3
+       help
+         Support for carrying raw ethernet frames over L2TPv3.
+
+         From RFC 4719 <http://www.ietf.org/rfc/rfc4719.txt>.
+
+         The Layer 2 Tunneling Protocol, Version 3 (L2TPv3) can be
+         used as a control protocol and for data encapsulation to set
+         up Pseudowires for transporting layer 2 Packet Data Units
+         across an IP network [RFC3931].
+
+         This driver provides an ethernet virtual interface for each
+         L2TP ethernet pseudowire instance. Standard Linux tools may
+         be used to assign an IP address to the local virtual
+         interface, or add the interface to a bridge.
+
+         If you are using L2TPv3, you will almost certainly want to
+         enable this option.
+
+         To compile this driver as a module, choose M here. The module
+         will be called l2tp_eth.
diff --git a/net/l2tp/Makefile b/net/l2tp/Makefile
new file mode 100644 (file)
index 0000000..110e7bc
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the L2TP.
+#
+
+obj-$(CONFIG_L2TP) += l2tp_core.o
+
+# Build l2tp as modules if L2TP is M
+obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_PPPOL2TP)) += l2tp_ppp.o
+obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip.o
+obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_V3)) += l2tp_netlink.o
+obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_ETH)) += l2tp_eth.o
+obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_DEBUGFS)) += l2tp_debugfs.o
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
new file mode 100644 (file)
index 0000000..1712af1
--- /dev/null
@@ -0,0 +1,1666 @@
+/*
+ * L2TP core.
+ *
+ * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
+ *
+ * This file contains some code of the original L2TPv2 pppol2tp
+ * driver, which has the following copyright:
+ *
+ * Authors:    Martijn van Oosterhout <kleptog@svana.org>
+ *             James Chapman (jchapman@katalix.com)
+ * Contributors:
+ *             Michal Ostrowski <mostrows@speakeasy.net>
+ *             Arnaldo Carvalho de Melo <acme@xconectiva.com.br>
+ *             David S. Miller (davem@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/rculist.h>
+#include <linux/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/l2tp.h>
+#include <linux/hash.h>
+#include <linux/sort.h>
+#include <linux/file.h>
+#include <linux/nsproxy.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/dst.h>
+#include <net/ip.h>
+#include <net/udp.h>
+#include <net/inet_common.h>
+#include <net/xfrm.h>
+#include <net/protocol.h>
+
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+
+#include "l2tp_core.h"
+
+#define L2TP_DRV_VERSION       "V2.0"
+
+/* L2TP header constants */
+#define L2TP_HDRFLAG_T    0x8000
+#define L2TP_HDRFLAG_L    0x4000
+#define L2TP_HDRFLAG_S    0x0800
+#define L2TP_HDRFLAG_O    0x0200
+#define L2TP_HDRFLAG_P    0x0100
+
+#define L2TP_HDR_VER_MASK  0x000F
+#define L2TP_HDR_VER_2    0x0002
+#define L2TP_HDR_VER_3    0x0003
+
+/* L2TPv3 default L2-specific sublayer */
+#define L2TP_SLFLAG_S     0x40000000
+#define L2TP_SL_SEQ_MASK   0x00ffffff
+
+#define L2TP_HDR_SIZE_SEQ              10
+#define L2TP_HDR_SIZE_NOSEQ            6
+
+/* Default trace flags */
+#define L2TP_DEFAULT_DEBUG_FLAGS       0
+
+#define PRINTK(_mask, _type, _lvl, _fmt, args...)                      \
+       do {                                                            \
+               if ((_mask) & (_type))                                  \
+                       printk(_lvl "L2TP: " _fmt, ##args);             \
+       } while (0)
+
+/* Private data stored for received packets in the skb.
+ */
+struct l2tp_skb_cb {
+       u32                     ns;
+       u16                     has_seq;
+       u16                     length;
+       unsigned long           expires;
+};
+
+#define L2TP_SKB_CB(skb)       ((struct l2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)])
+
+static atomic_t l2tp_tunnel_count;
+static atomic_t l2tp_session_count;
+
+/* per-net private data for this module */
+static unsigned int l2tp_net_id;
+struct l2tp_net {
+       struct list_head l2tp_tunnel_list;
+       spinlock_t l2tp_tunnel_list_lock;
+       struct hlist_head l2tp_session_hlist[L2TP_HASH_SIZE_2];
+       spinlock_t l2tp_session_hlist_lock;
+};
+
+static inline struct l2tp_net *l2tp_pernet(struct net *net)
+{
+       BUG_ON(!net);
+
+       return net_generic(net, l2tp_net_id);
+}
+
+/* Session hash global list for L2TPv3.
+ * The session_id SHOULD be random according to RFC3931, but several
+ * L2TP implementations use incrementing session_ids.  So we do a real
+ * hash on the session_id, rather than a simple bitmask.
+ */
+static inline struct hlist_head *
+l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
+{
+       return &pn->l2tp_session_hlist[hash_32(session_id, L2TP_HASH_BITS_2)];
+
+}
+
+/* Lookup a session by id in the global session list
+ */
+static struct l2tp_session *l2tp_session_find_2(struct net *net, u32 session_id)
+{
+       struct l2tp_net *pn = l2tp_pernet(net);
+       struct hlist_head *session_list =
+               l2tp_session_id_hash_2(pn, session_id);
+       struct l2tp_session *session;
+       struct hlist_node *walk;
+
+       rcu_read_lock_bh();
+       hlist_for_each_entry_rcu(session, walk, session_list, global_hlist) {
+               if (session->session_id == session_id) {
+                       rcu_read_unlock_bh();
+                       return session;
+               }
+       }
+       rcu_read_unlock_bh();
+
+       return NULL;
+}
+
+/* Session hash list.
+ * The session_id SHOULD be random according to RFC2661, but several
+ * L2TP implementations (Cisco and Microsoft) use incrementing
+ * session_ids.  So we do a real hash on the session_id, rather than a
+ * simple bitmask.
+ */
+static inline struct hlist_head *
+l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id)
+{
+       return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
+}
+
+/* Lookup a session by id
+ */
+struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id)
+{
+       struct hlist_head *session_list;
+       struct l2tp_session *session;
+       struct hlist_node *walk;
+
+       /* In L2TPv3, session_ids are unique over all tunnels and we
+        * sometimes need to look them up before we know the
+        * tunnel.
+        */
+       if (tunnel == NULL)
+               return l2tp_session_find_2(net, session_id);
+
+       session_list = l2tp_session_id_hash(tunnel, session_id);
+       read_lock_bh(&tunnel->hlist_lock);
+       hlist_for_each_entry(session, walk, session_list, hlist) {
+               if (session->session_id == session_id) {
+                       read_unlock_bh(&tunnel->hlist_lock);
+                       return session;
+               }
+       }
+       read_unlock_bh(&tunnel->hlist_lock);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_find);
+
+struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth)
+{
+       int hash;
+       struct hlist_node *walk;
+       struct l2tp_session *session;
+       int count = 0;
+
+       read_lock_bh(&tunnel->hlist_lock);
+       for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
+               hlist_for_each_entry(session, walk, &tunnel->session_hlist[hash], hlist) {
+                       if (++count > nth) {
+                               read_unlock_bh(&tunnel->hlist_lock);
+                               return session;
+                       }
+               }
+       }
+
+       read_unlock_bh(&tunnel->hlist_lock);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_find_nth);
+
+/* Lookup a session by interface name.
+ * This is very inefficient but is only used by management interfaces.
+ */
+struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname)
+{
+       struct l2tp_net *pn = l2tp_pernet(net);
+       int hash;
+       struct hlist_node *walk;
+       struct l2tp_session *session;
+
+       rcu_read_lock_bh();
+       for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) {
+               hlist_for_each_entry_rcu(session, walk, &pn->l2tp_session_hlist[hash], global_hlist) {
+                       if (!strcmp(session->ifname, ifname)) {
+                               rcu_read_unlock_bh();
+                               return session;
+                       }
+               }
+       }
+
+       rcu_read_unlock_bh();
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname);
+
+/* Lookup a tunnel by id
+ */
+struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id)
+{
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_net *pn = l2tp_pernet(net);
+
+       rcu_read_lock_bh();
+       list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
+               if (tunnel->tunnel_id == tunnel_id) {
+                       rcu_read_unlock_bh();
+                       return tunnel;
+               }
+       }
+       rcu_read_unlock_bh();
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_find);
+
+struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth)
+{
+       struct l2tp_net *pn = l2tp_pernet(net);
+       struct l2tp_tunnel *tunnel;
+       int count = 0;
+
+       rcu_read_lock_bh();
+       list_for_each_entry_rcu(tunnel, &pn->l2tp_tunnel_list, list) {
+               if (++count > nth) {
+                       rcu_read_unlock_bh();
+                       return tunnel;
+               }
+       }
+
+       rcu_read_unlock_bh();
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_find_nth);
+
+/*****************************************************************************
+ * Receive data handling
+ *****************************************************************************/
+
+/* Queue a skb in order. We come here only if the skb has an L2TP sequence
+ * number.
+ */
+static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *skb)
+{
+       struct sk_buff *skbp;
+       struct sk_buff *tmp;
+       u32 ns = L2TP_SKB_CB(skb)->ns;
+
+       spin_lock_bh(&session->reorder_q.lock);
+       skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
+               if (L2TP_SKB_CB(skbp)->ns > ns) {
+                       __skb_queue_before(&session->reorder_q, skbp, skb);
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                              "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
+                              session->name, ns, L2TP_SKB_CB(skbp)->ns,
+                              skb_queue_len(&session->reorder_q));
+                       session->stats.rx_oos_packets++;
+                       goto out;
+               }
+       }
+
+       __skb_queue_tail(&session->reorder_q, skb);
+
+out:
+       spin_unlock_bh(&session->reorder_q.lock);
+}
+
+/* Dequeue a single skb.
+ */
+static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *skb)
+{
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       int length = L2TP_SKB_CB(skb)->length;
+
+       /* We're about to requeue the skb, so return resources
+        * to its current owner (a socket receive buffer).
+        */
+       skb_orphan(skb);
+
+       tunnel->stats.rx_packets++;
+       tunnel->stats.rx_bytes += length;
+       session->stats.rx_packets++;
+       session->stats.rx_bytes += length;
+
+       if (L2TP_SKB_CB(skb)->has_seq) {
+               /* Bump our Nr */
+               session->nr++;
+               if (tunnel->version == L2TP_HDR_VER_2)
+                       session->nr &= 0xffff;
+               else
+                       session->nr &= 0xffffff;
+
+               PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                      "%s: updated nr to %hu\n", session->name, session->nr);
+       }
+
+       /* call private receive handler */
+       if (session->recv_skb != NULL)
+               (*session->recv_skb)(session, skb, L2TP_SKB_CB(skb)->length);
+       else
+               kfree_skb(skb);
+
+       if (session->deref)
+               (*session->deref)(session);
+}
+
+/* Dequeue skbs from the session's reorder_q, subject to packet order.
+ * Skbs that have been in the queue for too long are simply discarded.
+ */
+static void l2tp_recv_dequeue(struct l2tp_session *session)
+{
+       struct sk_buff *skb;
+       struct sk_buff *tmp;
+
+       /* If the pkt at the head of the queue has the nr that we
+        * expect to send up next, dequeue it and any other
+        * in-sequence packets behind it.
+        */
+       spin_lock_bh(&session->reorder_q.lock);
+       skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
+               if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) {
+                       session->stats.rx_seq_discards++;
+                       session->stats.rx_errors++;
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                              "%s: oos pkt %u len %d discarded (too old), "
+                              "waiting for %u, reorder_q_len=%d\n",
+                              session->name, L2TP_SKB_CB(skb)->ns,
+                              L2TP_SKB_CB(skb)->length, session->nr,
+                              skb_queue_len(&session->reorder_q));
+                       __skb_unlink(skb, &session->reorder_q);
+                       kfree_skb(skb);
+                       if (session->deref)
+                               (*session->deref)(session);
+                       continue;
+               }
+
+               if (L2TP_SKB_CB(skb)->has_seq) {
+                       if (L2TP_SKB_CB(skb)->ns != session->nr) {
+                               PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                                      "%s: holding oos pkt %u len %d, "
+                                      "waiting for %u, reorder_q_len=%d\n",
+                                      session->name, L2TP_SKB_CB(skb)->ns,
+                                      L2TP_SKB_CB(skb)->length, session->nr,
+                                      skb_queue_len(&session->reorder_q));
+                               goto out;
+                       }
+               }
+               __skb_unlink(skb, &session->reorder_q);
+
+               /* Process the skb. We release the queue lock while we
+                * do so to let other contexts process the queue.
+                */
+               spin_unlock_bh(&session->reorder_q.lock);
+               l2tp_recv_dequeue_skb(session, skb);
+               spin_lock_bh(&session->reorder_q.lock);
+       }
+
+out:
+       spin_unlock_bh(&session->reorder_q.lock);
+}
+
+static inline int l2tp_verify_udp_checksum(struct sock *sk,
+                                          struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+       u16 ulen = ntohs(uh->len);
+       struct inet_sock *inet;
+       __wsum psum;
+
+       if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check)
+               return 0;
+
+       inet = inet_sk(sk);
+       psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr, ulen,
+                                 IPPROTO_UDP, 0);
+
+       if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
+           !csum_fold(csum_add(psum, skb->csum)))
+               return 0;
+
+       skb->csum = psum;
+
+       return __skb_checksum_complete(skb);
+}
+
+/* Do receive processing of L2TP data frames. We handle both L2TPv2
+ * and L2TPv3 data frames here.
+ *
+ * L2TPv2 Data Message Header
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |T|L|x|x|S|x|O|P|x|x|x|x|  Ver  |          Length (opt)         |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |           Tunnel ID           |           Session ID          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |             Ns (opt)          |             Nr (opt)          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |      Offset Size (opt)        |    Offset pad... (opt)
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Data frames are marked by T=0. All other fields are the same as
+ * those in L2TP control frames.
+ *
+ * L2TPv3 Data Message Header
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      L2TP Session Header                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      L2-Specific Sublayer                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                        Tunnel Payload                      ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * L2TPv3 Session Header Over IP
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           Session ID                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |               Cookie (optional, maximum 64 bits)...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                                                                 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * L2TPv3 L2-Specific Sublayer Format
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |x|S|x|x|x|x|x|x|              Sequence Number                  |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Cookie value, sublayer format and offset (pad) are negotiated with
+ * the peer when the session is set up. Unlike L2TPv2, we do not need
+ * to parse the packet header to determine if optional fields are
+ * present.
+ *
+ * Caller must already have parsed the frame and determined that it is
+ * a data (not control) frame before coming here. Fields up to the
+ * session-id have already been parsed and ptr points to the data
+ * after the session-id.
+ */
+void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
+                     unsigned char *ptr, unsigned char *optr, u16 hdrflags,
+                     int length, int (*payload_hook)(struct sk_buff *skb))
+{
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       int offset;
+       u32 ns, nr;
+
+       /* The ref count is increased since we now hold a pointer to
+        * the session. Take care to decrement the refcnt when exiting
+        * this function from now on...
+        */
+       l2tp_session_inc_refcount(session);
+       if (session->ref)
+               (*session->ref)(session);
+
+       /* Parse and check optional cookie */
+       if (session->peer_cookie_len > 0) {
+               if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) {
+                       PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+                              "%s: cookie mismatch (%u/%u). Discarding.\n",
+                              tunnel->name, tunnel->tunnel_id, session->session_id);
+                       session->stats.rx_cookie_discards++;
+                       goto discard;
+               }
+               ptr += session->peer_cookie_len;
+       }
+
+       /* Handle the optional sequence numbers. Sequence numbers are
+        * in different places for L2TPv2 and L2TPv3.
+        *
+        * If we are the LAC, enable/disable sequence numbers under
+        * the control of the LNS.  If no sequence numbers present but
+        * we were expecting them, discard frame.
+        */
+       ns = nr = 0;
+       L2TP_SKB_CB(skb)->has_seq = 0;
+       if (tunnel->version == L2TP_HDR_VER_2) {
+               if (hdrflags & L2TP_HDRFLAG_S) {
+                       ns = ntohs(*(__be16 *) ptr);
+                       ptr += 2;
+                       nr = ntohs(*(__be16 *) ptr);
+                       ptr += 2;
+
+                       /* Store L2TP info in the skb */
+                       L2TP_SKB_CB(skb)->ns = ns;
+                       L2TP_SKB_CB(skb)->has_seq = 1;
+
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                              "%s: recv data ns=%u, nr=%u, session nr=%u\n",
+                              session->name, ns, nr, session->nr);
+               }
+       } else if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
+               u32 l2h = ntohl(*(__be32 *) ptr);
+
+               if (l2h & 0x40000000) {
+                       ns = l2h & 0x00ffffff;
+
+                       /* Store L2TP info in the skb */
+                       L2TP_SKB_CB(skb)->ns = ns;
+                       L2TP_SKB_CB(skb)->has_seq = 1;
+
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                              "%s: recv data ns=%u, session nr=%u\n",
+                              session->name, ns, session->nr);
+               }
+       }
+
+       /* Advance past L2-specific header, if present */
+       ptr += session->l2specific_len;
+
+       if (L2TP_SKB_CB(skb)->has_seq) {
+               /* Received a packet with sequence numbers. If we're the LNS,
+                * check if we sre sending sequence numbers and if not,
+                * configure it so.
+                */
+               if ((!session->lns_mode) && (!session->send_seq)) {
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_INFO,
+                              "%s: requested to enable seq numbers by LNS\n",
+                              session->name);
+                       session->send_seq = -1;
+                       l2tp_session_set_header_len(session, tunnel->version);
+               }
+       } else {
+               /* No sequence numbers.
+                * If user has configured mandatory sequence numbers, discard.
+                */
+               if (session->recv_seq) {
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_WARNING,
+                              "%s: recv data has no seq numbers when required. "
+                              "Discarding\n", session->name);
+                       session->stats.rx_seq_discards++;
+                       goto discard;
+               }
+
+               /* If we're the LAC and we're sending sequence numbers, the
+                * LNS has requested that we no longer send sequence numbers.
+                * If we're the LNS and we're sending sequence numbers, the
+                * LAC is broken. Discard the frame.
+                */
+               if ((!session->lns_mode) && (session->send_seq)) {
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_INFO,
+                              "%s: requested to disable seq numbers by LNS\n",
+                              session->name);
+                       session->send_seq = 0;
+                       l2tp_session_set_header_len(session, tunnel->version);
+               } else if (session->send_seq) {
+                       PRINTK(session->debug, L2TP_MSG_SEQ, KERN_WARNING,
+                              "%s: recv data has no seq numbers when required. "
+                              "Discarding\n", session->name);
+                       session->stats.rx_seq_discards++;
+                       goto discard;
+               }
+       }
+
+       /* Session data offset is handled differently for L2TPv2 and
+        * L2TPv3. For L2TPv2, there is an optional 16-bit value in
+        * the header. For L2TPv3, the offset is negotiated using AVPs
+        * in the session setup control protocol.
+        */
+       if (tunnel->version == L2TP_HDR_VER_2) {
+               /* If offset bit set, skip it. */
+               if (hdrflags & L2TP_HDRFLAG_O) {
+                       offset = ntohs(*(__be16 *)ptr);
+                       ptr += 2 + offset;
+               }
+       } else
+               ptr += session->offset;
+
+       offset = ptr - optr;
+       if (!pskb_may_pull(skb, offset))
+               goto discard;
+
+       __skb_pull(skb, offset);
+
+       /* If caller wants to process the payload before we queue the
+        * packet, do so now.
+        */
+       if (payload_hook)
+               if ((*payload_hook)(skb))
+                       goto discard;
+
+       /* Prepare skb for adding to the session's reorder_q.  Hold
+        * packets for max reorder_timeout or 1 second if not
+        * reordering.
+        */
+       L2TP_SKB_CB(skb)->length = length;
+       L2TP_SKB_CB(skb)->expires = jiffies +
+               (session->reorder_timeout ? session->reorder_timeout : HZ);
+
+       /* Add packet to the session's receive queue. Reordering is done here, if
+        * enabled. Saved L2TP protocol info is stored in skb->sb[].
+        */
+       if (L2TP_SKB_CB(skb)->has_seq) {
+               if (session->reorder_timeout != 0) {
+                       /* Packet reordering enabled. Add skb to session's
+                        * reorder queue, in order of ns.
+                        */
+                       l2tp_recv_queue_skb(session, skb);
+               } else {
+                       /* Packet reordering disabled. Discard out-of-sequence
+                        * packets
+                        */
+                       if (L2TP_SKB_CB(skb)->ns != session->nr) {
+                               session->stats.rx_seq_discards++;
+                               PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                                      "%s: oos pkt %u len %d discarded, "
+                                      "waiting for %u, reorder_q_len=%d\n",
+                                      session->name, L2TP_SKB_CB(skb)->ns,
+                                      L2TP_SKB_CB(skb)->length, session->nr,
+                                      skb_queue_len(&session->reorder_q));
+                               goto discard;
+                       }
+                       skb_queue_tail(&session->reorder_q, skb);
+               }
+       } else {
+               /* No sequence numbers. Add the skb to the tail of the
+                * reorder queue. This ensures that it will be
+                * delivered after all previous sequenced skbs.
+                */
+               skb_queue_tail(&session->reorder_q, skb);
+       }
+
+       /* Try to dequeue as many skbs from reorder_q as we can. */
+       l2tp_recv_dequeue(session);
+
+       l2tp_session_dec_refcount(session);
+
+       return;
+
+discard:
+       session->stats.rx_errors++;
+       kfree_skb(skb);
+
+       if (session->deref)
+               (*session->deref)(session);
+
+       l2tp_session_dec_refcount(session);
+}
+EXPORT_SYMBOL(l2tp_recv_common);
+
+/* Internal UDP receive frame. Do the real work of receiving an L2TP data frame
+ * here. The skb is not on a list when we get here.
+ * Returns 0 if the packet was a data packet and was successfully passed on.
+ * Returns 1 if the packet was not a good data packet and could not be
+ * forwarded.  All such packets are passed up to userspace to deal with.
+ */
+int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
+                      int (*payload_hook)(struct sk_buff *skb))
+{
+       struct l2tp_session *session = NULL;
+       unsigned char *ptr, *optr;
+       u16 hdrflags;
+       u32 tunnel_id, session_id;
+       int offset;
+       u16 version;
+       int length;
+
+       if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb))
+               goto discard_bad_csum;
+
+       /* UDP always verifies the packet length. */
+       __skb_pull(skb, sizeof(struct udphdr));
+
+       /* Short packet? */
+       if (!pskb_may_pull(skb, L2TP_HDR_SIZE_SEQ)) {
+               PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+                      "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
+               goto error;
+       }
+
+       /* Point to L2TP header */
+       optr = ptr = skb->data;
+
+       /* Trace packet contents, if enabled */
+       if (tunnel->debug & L2TP_MSG_DATA) {
+               length = min(32u, skb->len);
+               if (!pskb_may_pull(skb, length))
+                       goto error;
+
+               printk(KERN_DEBUG "%s: recv: ", tunnel->name);
+
+               offset = 0;
+               do {
+                       printk(" %02X", ptr[offset]);
+               } while (++offset < length);
+
+               printk("\n");
+       }
+
+       /* Get L2TP header flags */
+       hdrflags = ntohs(*(__be16 *) ptr);
+
+       /* Check protocol version */
+       version = hdrflags & L2TP_HDR_VER_MASK;
+       if (version != tunnel->version) {
+               PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+                      "%s: recv protocol version mismatch: got %d expected %d\n",
+                      tunnel->name, version, tunnel->version);
+               goto error;
+       }
+
+       /* Get length of L2TP packet */
+       length = skb->len;
+
+       /* If type is control packet, it is handled by userspace. */
+       if (hdrflags & L2TP_HDRFLAG_T) {
+               PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG,
+                      "%s: recv control packet, len=%d\n", tunnel->name, length);
+               goto error;
+       }
+
+       /* Skip flags */
+       ptr += 2;
+
+       if (tunnel->version == L2TP_HDR_VER_2) {
+               /* If length is present, skip it */
+               if (hdrflags & L2TP_HDRFLAG_L)
+                       ptr += 2;
+
+               /* Extract tunnel and session ID */
+               tunnel_id = ntohs(*(__be16 *) ptr);
+               ptr += 2;
+               session_id = ntohs(*(__be16 *) ptr);
+               ptr += 2;
+       } else {
+               ptr += 2;       /* skip reserved bits */
+               tunnel_id = tunnel->tunnel_id;
+               session_id = ntohl(*(__be32 *) ptr);
+               ptr += 4;
+       }
+
+       /* Find the session context */
+       session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id);
+       if (!session || !session->recv_skb) {
+               /* Not found? Pass to userspace to deal with */
+               PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_INFO,
+                      "%s: no session found (%u/%u). Passing up.\n",
+                      tunnel->name, tunnel_id, session_id);
+               goto error;
+       }
+
+       l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook);
+
+       return 0;
+
+discard_bad_csum:
+       LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
+       UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0);
+       tunnel->stats.rx_errors++;
+       kfree_skb(skb);
+
+       return 0;
+
+error:
+       /* Put UDP header back */
+       __skb_push(skb, sizeof(struct udphdr));
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(l2tp_udp_recv_core);
+
+/* UDP encapsulation receive handler. See net/ipv4/udp.c.
+ * Return codes:
+ * 0 : success.
+ * <0: error
+ * >0: skb should be passed up to userspace as UDP.
+ */
+int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
+{
+       struct l2tp_tunnel *tunnel;
+
+       tunnel = l2tp_sock_to_tunnel(sk);
+       if (tunnel == NULL)
+               goto pass_up;
+
+       PRINTK(tunnel->debug, L2TP_MSG_DATA, KERN_DEBUG,
+              "%s: received %d bytes\n", tunnel->name, skb->len);
+
+       if (l2tp_udp_recv_core(tunnel, skb, tunnel->recv_payload_hook))
+               goto pass_up_put;
+
+       sock_put(sk);
+       return 0;
+
+pass_up_put:
+       sock_put(sk);
+pass_up:
+       return 1;
+}
+EXPORT_SYMBOL_GPL(l2tp_udp_encap_recv);
+
+/************************************************************************
+ * Transmit handling
+ ***********************************************************************/
+
+/* Build an L2TP header for the session into the buffer provided.
+ */
+static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf)
+{
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       __be16 *bufp = buf;
+       __be16 *optr = buf;
+       u16 flags = L2TP_HDR_VER_2;
+       u32 tunnel_id = tunnel->peer_tunnel_id;
+       u32 session_id = session->peer_session_id;
+
+       if (session->send_seq)
+               flags |= L2TP_HDRFLAG_S;
+
+       /* Setup L2TP header. */
+       *bufp++ = htons(flags);
+       *bufp++ = htons(tunnel_id);
+       *bufp++ = htons(session_id);
+       if (session->send_seq) {
+               *bufp++ = htons(session->ns);
+               *bufp++ = 0;
+               session->ns++;
+               session->ns &= 0xffff;
+               PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                      "%s: updated ns to %u\n", session->name, session->ns);
+       }
+
+       return bufp - optr;
+}
+
+static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf)
+{
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       char *bufp = buf;
+       char *optr = bufp;
+
+       /* Setup L2TP header. The header differs slightly for UDP and
+        * IP encapsulations. For UDP, there is 4 bytes of flags.
+        */
+       if (tunnel->encap == L2TP_ENCAPTYPE_UDP) {
+               u16 flags = L2TP_HDR_VER_3;
+               *((__be16 *) bufp) = htons(flags);
+               bufp += 2;
+               *((__be16 *) bufp) = 0;
+               bufp += 2;
+       }
+
+       *((__be32 *) bufp) = htonl(session->peer_session_id);
+       bufp += 4;
+       if (session->cookie_len) {
+               memcpy(bufp, &session->cookie[0], session->cookie_len);
+               bufp += session->cookie_len;
+       }
+       if (session->l2specific_len) {
+               if (session->l2specific_type == L2TP_L2SPECTYPE_DEFAULT) {
+                       u32 l2h = 0;
+                       if (session->send_seq) {
+                               l2h = 0x40000000 | session->ns;
+                               session->ns++;
+                               session->ns &= 0xffffff;
+                               PRINTK(session->debug, L2TP_MSG_SEQ, KERN_DEBUG,
+                                      "%s: updated ns to %u\n", session->name, session->ns);
+                       }
+
+                       *((__be32 *) bufp) = htonl(l2h);
+               }
+               bufp += session->l2specific_len;
+       }
+       if (session->offset)
+               bufp += session->offset;
+
+       return bufp - optr;
+}
+
+int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len)
+{
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       unsigned int len = skb->len;
+       int error;
+
+       /* Debug */
+       if (session->send_seq)
+               PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG,
+                      "%s: send %Zd bytes, ns=%u\n", session->name,
+                      data_len, session->ns - 1);
+       else
+               PRINTK(session->debug, L2TP_MSG_DATA, KERN_DEBUG,
+                      "%s: send %Zd bytes\n", session->name, data_len);
+
+       if (session->debug & L2TP_MSG_DATA) {
+               int i;
+               int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
+               unsigned char *datap = skb->data + uhlen;
+
+               printk(KERN_DEBUG "%s: xmit:", session->name);
+               for (i = 0; i < (len - uhlen); i++) {
+                       printk(" %02X", *datap++);
+                       if (i == 31) {
+                               printk(" ...");
+                               break;
+                       }
+               }
+               printk("\n");
+       }
+
+       /* Queue the packet to IP for output */
+       skb->local_df = 1;
+       error = ip_queue_xmit(skb);
+
+       /* Update stats */
+       if (error >= 0) {
+               tunnel->stats.tx_packets++;
+               tunnel->stats.tx_bytes += len;
+               session->stats.tx_packets++;
+               session->stats.tx_bytes += len;
+       } else {
+               tunnel->stats.tx_errors++;
+               session->stats.tx_errors++;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(l2tp_xmit_core);
+
+/* Automatically called when the skb is freed.
+ */
+static void l2tp_sock_wfree(struct sk_buff *skb)
+{
+       sock_put(skb->sk);
+}
+
+/* For data skbs that we transmit, we associate with the tunnel socket
+ * but don't do accounting.
+ */
+static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
+{
+       sock_hold(sk);
+       skb->sk = sk;
+       skb->destructor = l2tp_sock_wfree;
+}
+
+/* If caller requires the skb to have a ppp header, the header must be
+ * inserted in the skb data before calling this function.
+ */
+int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len)
+{
+       int data_len = skb->len;
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       struct sock *sk = tunnel->sock;
+       struct udphdr *uh;
+       struct inet_sock *inet;
+       __wsum csum;
+       int old_headroom;
+       int new_headroom;
+       int headroom;
+       int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
+       int udp_len;
+
+       /* Check that there's enough headroom in the skb to insert IP,
+        * UDP and L2TP headers. If not enough, expand it to
+        * make room. Adjust truesize.
+        */
+       headroom = NET_SKB_PAD + sizeof(struct iphdr) +
+               uhlen + hdr_len;
+       old_headroom = skb_headroom(skb);
+       if (skb_cow_head(skb, headroom))
+               goto abort;
+
+       new_headroom = skb_headroom(skb);
+       skb_orphan(skb);
+       skb->truesize += new_headroom - old_headroom;
+
+       /* Setup L2TP header */
+       session->build_header(session, __skb_push(skb, hdr_len));
+
+       /* Reset skb netfilter state */
+       memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+       IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+                             IPSKB_REROUTED);
+       nf_reset(skb);
+
+       /* Get routing info from the tunnel socket */
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst_clone(__sk_dst_get(sk)));
+
+       switch (tunnel->encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               /* Setup UDP header */
+               inet = inet_sk(sk);
+               __skb_push(skb, sizeof(*uh));
+               skb_reset_transport_header(skb);
+               uh = udp_hdr(skb);
+               uh->source = inet->inet_sport;
+               uh->dest = inet->inet_dport;
+               udp_len = uhlen + hdr_len + data_len;
+               uh->len = htons(udp_len);
+               uh->check = 0;
+
+               /* Calculate UDP checksum if configured to do so */
+               if (sk->sk_no_check == UDP_CSUM_NOXMIT)
+                       skb->ip_summed = CHECKSUM_NONE;
+               else if ((skb_dst(skb) && skb_dst(skb)->dev) &&
+                        (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) {
+                       skb->ip_summed = CHECKSUM_COMPLETE;
+                       csum = skb_checksum(skb, 0, udp_len, 0);
+                       uh->check = csum_tcpudp_magic(inet->inet_saddr,
+                                                     inet->inet_daddr,
+                                                     udp_len, IPPROTO_UDP, csum);
+                       if (uh->check == 0)
+                               uh->check = CSUM_MANGLED_0;
+               } else {
+                       skb->ip_summed = CHECKSUM_PARTIAL;
+                       skb->csum_start = skb_transport_header(skb) - skb->head;
+                       skb->csum_offset = offsetof(struct udphdr, check);
+                       uh->check = ~csum_tcpudp_magic(inet->inet_saddr,
+                                                      inet->inet_daddr,
+                                                      udp_len, IPPROTO_UDP, 0);
+               }
+               break;
+
+       case L2TP_ENCAPTYPE_IP:
+               break;
+       }
+
+       l2tp_skb_set_owner_w(skb, sk);
+
+       l2tp_xmit_core(session, skb, data_len);
+
+abort:
+       return 0;
+}
+EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
+
+/*****************************************************************************
+ * Tinnel and session create/destroy.
+ *****************************************************************************/
+
+/* Tunnel socket destruct hook.
+ * The tunnel context is deleted only when all session sockets have been
+ * closed.
+ */
+void l2tp_tunnel_destruct(struct sock *sk)
+{
+       struct l2tp_tunnel *tunnel;
+
+       tunnel = sk->sk_user_data;
+       if (tunnel == NULL)
+               goto end;
+
+       PRINTK(tunnel->debug, L2TP_MSG_CONTROL, KERN_INFO,
+              "%s: closing...\n", tunnel->name);
+
+       /* Close all sessions */
+       l2tp_tunnel_closeall(tunnel);
+
+       switch (tunnel->encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               /* No longer an encapsulation socket. See net/ipv4/udp.c */
+               (udp_sk(sk))->encap_type = 0;
+               (udp_sk(sk))->encap_rcv = NULL;
+               break;
+       case L2TP_ENCAPTYPE_IP:
+               break;
+       }
+
+       /* Remove hooks into tunnel socket */
+       tunnel->sock = NULL;
+       sk->sk_destruct = tunnel->old_sk_destruct;
+       sk->sk_user_data = NULL;
+
+       /* Call the original destructor */
+       if (sk->sk_destruct)
+               (*sk->sk_destruct)(sk);
+
+       /* We're finished with the socket */
+       l2tp_tunnel_dec_refcount(tunnel);
+
+end:
+       return;
+}
+EXPORT_SYMBOL(l2tp_tunnel_destruct);
+
+/* When the tunnel is closed, all the attached sessions need to go too.
+ */
+void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
+{
+       int hash;
+       struct hlist_node *walk;
+       struct hlist_node *tmp;
+       struct l2tp_session *session;
+
+       BUG_ON(tunnel == NULL);
+
+       PRINTK(tunnel->debug, L2TP_MSG_CONTROL, KERN_INFO,
+              "%s: closing all sessions...\n", tunnel->name);
+
+       write_lock_bh(&tunnel->hlist_lock);
+       for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
+again:
+               hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
+                       session = hlist_entry(walk, struct l2tp_session, hlist);
+
+                       PRINTK(session->debug, L2TP_MSG_CONTROL, KERN_INFO,
+                              "%s: closing session\n", session->name);
+
+                       hlist_del_init(&session->hlist);
+
+                       /* Since we should hold the sock lock while
+                        * doing any unbinding, we need to release the
+                        * lock we're holding before taking that lock.
+                        * Hold a reference to the sock so it doesn't
+                        * disappear as we're jumping between locks.
+                        */
+                       if (session->ref != NULL)
+                               (*session->ref)(session);
+
+                       write_unlock_bh(&tunnel->hlist_lock);
+
+                       if (tunnel->version != L2TP_HDR_VER_2) {
+                               struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+                               spin_lock_bh(&pn->l2tp_session_hlist_lock);
+                               hlist_del_init_rcu(&session->global_hlist);
+                               spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+                               synchronize_rcu();
+                       }
+
+                       if (session->session_close != NULL)
+                               (*session->session_close)(session);
+
+                       if (session->deref != NULL)
+                               (*session->deref)(session);
+
+                       write_lock_bh(&tunnel->hlist_lock);
+
+                       /* Now restart from the beginning of this hash
+                        * chain.  We always remove a session from the
+                        * list so we are guaranteed to make forward
+                        * progress.
+                        */
+                       goto again;
+               }
+       }
+       write_unlock_bh(&tunnel->hlist_lock);
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall);
+
+/* Really kill the tunnel.
+ * Come here only when all sessions have been cleared from the tunnel.
+ */
+void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
+{
+       struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+       BUG_ON(atomic_read(&tunnel->ref_count) != 0);
+       BUG_ON(tunnel->sock != NULL);
+
+       PRINTK(tunnel->debug, L2TP_MSG_CONTROL, KERN_INFO,
+              "%s: free...\n", tunnel->name);
+
+       /* Remove from tunnel list */
+       spin_lock_bh(&pn->l2tp_tunnel_list_lock);
+       list_del_rcu(&tunnel->list);
+       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
+       synchronize_rcu();
+
+       atomic_dec(&l2tp_tunnel_count);
+       kfree(tunnel);
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_free);
+
+/* Create a socket for the tunnel, if one isn't set up by
+ * userspace. This is used for static tunnels where there is no
+ * managing L2TP daemon.
+ */
+static int l2tp_tunnel_sock_create(u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct socket **sockp)
+{
+       int err = -EINVAL;
+       struct sockaddr_in udp_addr;
+       struct sockaddr_l2tpip ip_addr;
+       struct socket *sock = NULL;
+
+       switch (cfg->encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               err = sock_create(AF_INET, SOCK_DGRAM, 0, sockp);
+               if (err < 0)
+                       goto out;
+
+               sock = *sockp;
+
+               memset(&udp_addr, 0, sizeof(udp_addr));
+               udp_addr.sin_family = AF_INET;
+               udp_addr.sin_addr = cfg->local_ip;
+               udp_addr.sin_port = htons(cfg->local_udp_port);
+               err = kernel_bind(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr));
+               if (err < 0)
+                       goto out;
+
+               udp_addr.sin_family = AF_INET;
+               udp_addr.sin_addr = cfg->peer_ip;
+               udp_addr.sin_port = htons(cfg->peer_udp_port);
+               err = kernel_connect(sock, (struct sockaddr *) &udp_addr, sizeof(udp_addr), 0);
+               if (err < 0)
+                       goto out;
+
+               if (!cfg->use_udp_checksums)
+                       sock->sk->sk_no_check = UDP_CSUM_NOXMIT;
+
+               break;
+
+       case L2TP_ENCAPTYPE_IP:
+               err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_L2TP, sockp);
+               if (err < 0)
+                       goto out;
+
+               sock = *sockp;
+
+               memset(&ip_addr, 0, sizeof(ip_addr));
+               ip_addr.l2tp_family = AF_INET;
+               ip_addr.l2tp_addr = cfg->local_ip;
+               ip_addr.l2tp_conn_id = tunnel_id;
+               err = kernel_bind(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr));
+               if (err < 0)
+                       goto out;
+
+               ip_addr.l2tp_family = AF_INET;
+               ip_addr.l2tp_addr = cfg->peer_ip;
+               ip_addr.l2tp_conn_id = peer_tunnel_id;
+               err = kernel_connect(sock, (struct sockaddr *) &ip_addr, sizeof(ip_addr), 0);
+               if (err < 0)
+                       goto out;
+
+               break;
+
+       default:
+               goto out;
+       }
+
+out:
+       if ((err < 0) && sock) {
+               sock_release(sock);
+               *sockp = NULL;
+       }
+
+       return err;
+}
+
+int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp)
+{
+       struct l2tp_tunnel *tunnel = NULL;
+       int err;
+       struct socket *sock = NULL;
+       struct sock *sk = NULL;
+       struct l2tp_net *pn;
+       enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP;
+
+       /* Get the tunnel socket from the fd, which was opened by
+        * the userspace L2TP daemon. If not specified, create a
+        * kernel socket.
+        */
+       if (fd < 0) {
+               err = l2tp_tunnel_sock_create(tunnel_id, peer_tunnel_id, cfg, &sock);
+               if (err < 0)
+                       goto err;
+       } else {
+               err = -EBADF;
+               sock = sockfd_lookup(fd, &err);
+               if (!sock) {
+                       printk(KERN_ERR "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
+                              tunnel_id, fd, err);
+                       goto err;
+               }
+       }
+
+       sk = sock->sk;
+
+       if (cfg != NULL)
+               encap = cfg->encap;
+
+       /* Quick sanity checks */
+       switch (encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               err = -EPROTONOSUPPORT;
+               if (sk->sk_protocol != IPPROTO_UDP) {
+                       printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
+                              tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
+                       goto err;
+               }
+               break;
+       case L2TP_ENCAPTYPE_IP:
+               err = -EPROTONOSUPPORT;
+               if (sk->sk_protocol != IPPROTO_L2TP) {
+                       printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
+                              tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP);
+                       goto err;
+               }
+               break;
+       }
+
+       /* Check if this socket has already been prepped */
+       tunnel = (struct l2tp_tunnel *)sk->sk_user_data;
+       if (tunnel != NULL) {
+               /* This socket has already been prepped */
+               err = -EBUSY;
+               goto err;
+       }
+
+       tunnel = kzalloc(sizeof(struct l2tp_tunnel), GFP_KERNEL);
+       if (tunnel == NULL) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       tunnel->version = version;
+       tunnel->tunnel_id = tunnel_id;
+       tunnel->peer_tunnel_id = peer_tunnel_id;
+       tunnel->debug = L2TP_DEFAULT_DEBUG_FLAGS;
+
+       tunnel->magic = L2TP_TUNNEL_MAGIC;
+       sprintf(&tunnel->name[0], "tunl %u", tunnel_id);
+       rwlock_init(&tunnel->hlist_lock);
+
+       /* The net we belong to */
+       tunnel->l2tp_net = net;
+       pn = l2tp_pernet(net);
+
+       if (cfg != NULL)
+               tunnel->debug = cfg->debug;
+
+       /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
+       tunnel->encap = encap;
+       if (encap == L2TP_ENCAPTYPE_UDP) {
+               /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
+               udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
+               udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
+       }
+
+       sk->sk_user_data = tunnel;
+
+       /* Hook on the tunnel socket destructor so that we can cleanup
+        * if the tunnel socket goes away.
+        */
+       tunnel->old_sk_destruct = sk->sk_destruct;
+       sk->sk_destruct = &l2tp_tunnel_destruct;
+       tunnel->sock = sk;
+       sk->sk_allocation = GFP_ATOMIC;
+
+       /* Add tunnel to our list */
+       INIT_LIST_HEAD(&tunnel->list);
+       spin_lock_bh(&pn->l2tp_tunnel_list_lock);
+       list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
+       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
+       synchronize_rcu();
+       atomic_inc(&l2tp_tunnel_count);
+
+       /* Bump the reference count. The tunnel context is deleted
+        * only when this drops to zero.
+        */
+       l2tp_tunnel_inc_refcount(tunnel);
+
+       err = 0;
+err:
+       if (tunnelp)
+               *tunnelp = tunnel;
+
+       /* If tunnel's socket was created by the kernel, it doesn't
+        *  have a file.
+        */
+       if (sock && sock->file)
+               sockfd_put(sock);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
+
+/* This function is used by the netlink TUNNEL_DELETE command.
+ */
+int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
+{
+       int err = 0;
+       struct socket *sock = tunnel->sock ? tunnel->sock->sk_socket : NULL;
+
+       /* Force the tunnel socket to close. This will eventually
+        * cause the tunnel to be deleted via the normal socket close
+        * mechanisms when userspace closes the tunnel socket.
+        */
+       if (sock != NULL) {
+               err = inet_shutdown(sock, 2);
+
+               /* If the tunnel's socket was created by the kernel,
+                * close the socket here since the socket was not
+                * created by userspace.
+                */
+               if (sock->file == NULL)
+                       err = inet_release(sock);
+       }
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
+
+/* Really kill the session.
+ */
+void l2tp_session_free(struct l2tp_session *session)
+{
+       struct l2tp_tunnel *tunnel;
+
+       BUG_ON(atomic_read(&session->ref_count) != 0);
+
+       tunnel = session->tunnel;
+       if (tunnel != NULL) {
+               BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
+
+               /* Delete the session from the hash */
+               write_lock_bh(&tunnel->hlist_lock);
+               hlist_del_init(&session->hlist);
+               write_unlock_bh(&tunnel->hlist_lock);
+
+               /* Unlink from the global hash if not L2TPv2 */
+               if (tunnel->version != L2TP_HDR_VER_2) {
+                       struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+                       spin_lock_bh(&pn->l2tp_session_hlist_lock);
+                       hlist_del_init_rcu(&session->global_hlist);
+                       spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+                       synchronize_rcu();
+               }
+
+               if (session->session_id != 0)
+                       atomic_dec(&l2tp_session_count);
+
+               sock_put(tunnel->sock);
+
+               /* This will delete the tunnel context if this
+                * is the last session on the tunnel.
+                */
+               session->tunnel = NULL;
+               l2tp_tunnel_dec_refcount(tunnel);
+       }
+
+       kfree(session);
+
+       return;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_free);
+
+/* This function is used by the netlink SESSION_DELETE command and by
+   pseudowire modules.
+ */
+int l2tp_session_delete(struct l2tp_session *session)
+{
+       if (session->session_close != NULL)
+               (*session->session_close)(session);
+
+       l2tp_session_dec_refcount(session);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_delete);
+
+
+/* We come here whenever a session's send_seq, cookie_len or
+ * l2specific_len parameters are set.
+ */
+void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+{
+       if (version == L2TP_HDR_VER_2) {
+               session->hdr_len = 6;
+               if (session->send_seq)
+                       session->hdr_len += 4;
+       } else {
+               session->hdr_len = 4 + session->cookie_len + session->l2specific_len + session->offset;
+               if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP)
+                       session->hdr_len += 4;
+       }
+
+}
+EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
+
+struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+{
+       struct l2tp_session *session;
+
+       session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL);
+       if (session != NULL) {
+               session->magic = L2TP_SESSION_MAGIC;
+               session->tunnel = tunnel;
+
+               session->session_id = session_id;
+               session->peer_session_id = peer_session_id;
+               session->nr = 1;
+
+               sprintf(&session->name[0], "sess %u/%u",
+                       tunnel->tunnel_id, session->session_id);
+
+               skb_queue_head_init(&session->reorder_q);
+
+               INIT_HLIST_NODE(&session->hlist);
+               INIT_HLIST_NODE(&session->global_hlist);
+
+               /* Inherit debug options from tunnel */
+               session->debug = tunnel->debug;
+
+               if (cfg) {
+                       session->pwtype = cfg->pw_type;
+                       session->debug = cfg->debug;
+                       session->mtu = cfg->mtu;
+                       session->mru = cfg->mru;
+                       session->send_seq = cfg->send_seq;
+                       session->recv_seq = cfg->recv_seq;
+                       session->lns_mode = cfg->lns_mode;
+                       session->reorder_timeout = cfg->reorder_timeout;
+                       session->offset = cfg->offset;
+                       session->l2specific_type = cfg->l2specific_type;
+                       session->l2specific_len = cfg->l2specific_len;
+                       session->cookie_len = cfg->cookie_len;
+                       memcpy(&session->cookie[0], &cfg->cookie[0], cfg->cookie_len);
+                       session->peer_cookie_len = cfg->peer_cookie_len;
+                       memcpy(&session->peer_cookie[0], &cfg->peer_cookie[0], cfg->peer_cookie_len);
+               }
+
+               if (tunnel->version == L2TP_HDR_VER_2)
+                       session->build_header = l2tp_build_l2tpv2_header;
+               else
+                       session->build_header = l2tp_build_l2tpv3_header;
+
+               l2tp_session_set_header_len(session, tunnel->version);
+
+               /* Bump the reference count. The session context is deleted
+                * only when this drops to zero.
+                */
+               l2tp_session_inc_refcount(session);
+               l2tp_tunnel_inc_refcount(tunnel);
+
+               /* Ensure tunnel socket isn't deleted */
+               sock_hold(tunnel->sock);
+
+               /* Add session to the tunnel's hash list */
+               write_lock_bh(&tunnel->hlist_lock);
+               hlist_add_head(&session->hlist,
+                              l2tp_session_id_hash(tunnel, session_id));
+               write_unlock_bh(&tunnel->hlist_lock);
+
+               /* And to the global session list if L2TPv3 */
+               if (tunnel->version != L2TP_HDR_VER_2) {
+                       struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
+
+                       spin_lock_bh(&pn->l2tp_session_hlist_lock);
+                       hlist_add_head_rcu(&session->global_hlist,
+                                          l2tp_session_id_hash_2(pn, session_id));
+                       spin_unlock_bh(&pn->l2tp_session_hlist_lock);
+                       synchronize_rcu();
+               }
+
+               /* Ignore management session in session count value */
+               if (session->session_id != 0)
+                       atomic_inc(&l2tp_session_count);
+       }
+
+       return session;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_create);
+
+/*****************************************************************************
+ * Init and cleanup
+ *****************************************************************************/
+
+static __net_init int l2tp_init_net(struct net *net)
+{
+       struct l2tp_net *pn = net_generic(net, l2tp_net_id);
+       int hash;
+
+       INIT_LIST_HEAD(&pn->l2tp_tunnel_list);
+       spin_lock_init(&pn->l2tp_tunnel_list_lock);
+
+       for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++)
+               INIT_HLIST_HEAD(&pn->l2tp_session_hlist[hash]);
+
+       spin_lock_init(&pn->l2tp_session_hlist_lock);
+
+       return 0;
+}
+
+static struct pernet_operations l2tp_net_ops = {
+       .init = l2tp_init_net,
+       .id   = &l2tp_net_id,
+       .size = sizeof(struct l2tp_net),
+};
+
+static int __init l2tp_init(void)
+{
+       int rc = 0;
+
+       rc = register_pernet_device(&l2tp_net_ops);
+       if (rc)
+               goto out;
+
+       printk(KERN_INFO "L2TP core driver, %s\n", L2TP_DRV_VERSION);
+
+out:
+       return rc;
+}
+
+static void __exit l2tp_exit(void)
+{
+       unregister_pernet_device(&l2tp_net_ops);
+}
+
+module_init(l2tp_init);
+module_exit(l2tp_exit);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("L2TP core");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(L2TP_DRV_VERSION);
+
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
new file mode 100644 (file)
index 0000000..f0f318e
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * L2TP internal definitions.
+ *
+ * Copyright (c) 2008,2009 Katalix Systems Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _L2TP_CORE_H_
+#define _L2TP_CORE_H_
+
+/* Just some random numbers */
+#define L2TP_TUNNEL_MAGIC      0x42114DDA
+#define L2TP_SESSION_MAGIC     0x0C04EB7D
+
+/* Per tunnel, session hash table size */
+#define L2TP_HASH_BITS 4
+#define L2TP_HASH_SIZE (1 << L2TP_HASH_BITS)
+
+/* System-wide, session hash table size */
+#define L2TP_HASH_BITS_2       8
+#define L2TP_HASH_SIZE_2       (1 << L2TP_HASH_BITS_2)
+
+/* Debug message categories for the DEBUG socket option */
+enum {
+       L2TP_MSG_DEBUG          = (1 << 0),     /* verbose debug (if
+                                                * compiled in) */
+       L2TP_MSG_CONTROL        = (1 << 1),     /* userspace - kernel
+                                                * interface */
+       L2TP_MSG_SEQ            = (1 << 2),     /* sequence numbers */
+       L2TP_MSG_DATA           = (1 << 3),     /* data packets */
+};
+
+struct sk_buff;
+
+struct l2tp_stats {
+       u64                     tx_packets;
+       u64                     tx_bytes;
+       u64                     tx_errors;
+       u64                     rx_packets;
+       u64                     rx_bytes;
+       u64                     rx_seq_discards;
+       u64                     rx_oos_packets;
+       u64                     rx_errors;
+       u64                     rx_cookie_discards;
+};
+
+struct l2tp_tunnel;
+
+/* Describes a session. Contains information to determine incoming
+ * packets and transmit outgoing ones.
+ */
+struct l2tp_session_cfg {
+       enum l2tp_pwtype        pw_type;
+       unsigned                data_seq:2;     /* data sequencing level
+                                                * 0 => none, 1 => IP only,
+                                                * 2 => all
+                                                */
+       unsigned                recv_seq:1;     /* expect receive packets with
+                                                * sequence numbers? */
+       unsigned                send_seq:1;     /* send packets with sequence
+                                                * numbers? */
+       unsigned                lns_mode:1;     /* behave as LNS? LAC enables
+                                                * sequence numbers under
+                                                * control of LNS. */
+       int                     debug;          /* bitmask of debug message
+                                                * categories */
+       u16                     vlan_id;        /* VLAN pseudowire only */
+       u16                     offset;         /* offset to payload */
+       u16                     l2specific_len; /* Layer 2 specific length */
+       u16                     l2specific_type; /* Layer 2 specific type */
+       u8                      cookie[8];      /* optional cookie */
+       int                     cookie_len;     /* 0, 4 or 8 bytes */
+       u8                      peer_cookie[8]; /* peer's cookie */
+       int                     peer_cookie_len; /* 0, 4 or 8 bytes */
+       int                     reorder_timeout; /* configured reorder timeout
+                                                 * (in jiffies) */
+       int                     mtu;
+       int                     mru;
+       char                    *ifname;
+};
+
+struct l2tp_session {
+       int                     magic;          /* should be
+                                                * L2TP_SESSION_MAGIC */
+
+       struct l2tp_tunnel      *tunnel;        /* back pointer to tunnel
+                                                * context */
+       u32                     session_id;
+       u32                     peer_session_id;
+       u8                      cookie[8];
+       int                     cookie_len;
+       u8                      peer_cookie[8];
+       int                     peer_cookie_len;
+       u16                     offset;         /* offset from end of L2TP header
+                                                  to beginning of data */
+       u16                     l2specific_len;
+       u16                     l2specific_type;
+       u16                     hdr_len;
+       u32                     nr;             /* session NR state (receive) */
+       u32                     ns;             /* session NR state (send) */
+       struct sk_buff_head     reorder_q;      /* receive reorder queue */
+       struct hlist_node       hlist;          /* Hash list node */
+       atomic_t                ref_count;
+
+       char                    name[32];       /* for logging */
+       char                    ifname[IFNAMSIZ];
+       unsigned                data_seq:2;     /* data sequencing level
+                                                * 0 => none, 1 => IP only,
+                                                * 2 => all
+                                                */
+       unsigned                recv_seq:1;     /* expect receive packets with
+                                                * sequence numbers? */
+       unsigned                send_seq:1;     /* send packets with sequence
+                                                * numbers? */
+       unsigned                lns_mode:1;     /* behave as LNS? LAC enables
+                                                * sequence numbers under
+                                                * control of LNS. */
+       int                     debug;          /* bitmask of debug message
+                                                * categories */
+       int                     reorder_timeout; /* configured reorder timeout
+                                                 * (in jiffies) */
+       int                     mtu;
+       int                     mru;
+       enum l2tp_pwtype        pwtype;
+       struct l2tp_stats       stats;
+       struct hlist_node       global_hlist;   /* Global hash list node */
+
+       int (*build_header)(struct l2tp_session *session, void *buf);
+       void (*recv_skb)(struct l2tp_session *session, struct sk_buff *skb, int data_len);
+       void (*session_close)(struct l2tp_session *session);
+       void (*ref)(struct l2tp_session *session);
+       void (*deref)(struct l2tp_session *session);
+#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
+       void (*show)(struct seq_file *m, void *priv);
+#endif
+       uint8_t                 priv[0];        /* private data */
+};
+
+/* Describes the tunnel. It contains info to track all the associated
+ * sessions so incoming packets can be sorted out
+ */
+struct l2tp_tunnel_cfg {
+       int                     debug;          /* bitmask of debug message
+                                                * categories */
+       enum l2tp_encap_type    encap;
+
+       /* Used only for kernel-created sockets */
+       struct in_addr          local_ip;
+       struct in_addr          peer_ip;
+       u16                     local_udp_port;
+       u16                     peer_udp_port;
+       unsigned int            use_udp_checksums:1;
+};
+
+struct l2tp_tunnel {
+       int                     magic;          /* Should be L2TP_TUNNEL_MAGIC */
+       rwlock_t                hlist_lock;     /* protect session_hlist */
+       struct hlist_head       session_hlist[L2TP_HASH_SIZE];
+                                               /* hashed list of sessions,
+                                                * hashed by id */
+       u32                     tunnel_id;
+       u32                     peer_tunnel_id;
+       int                     version;        /* 2=>L2TPv2, 3=>L2TPv3 */
+
+       char                    name[20];       /* for logging */
+       int                     debug;          /* bitmask of debug message
+                                                * categories */
+       enum l2tp_encap_type    encap;
+       struct l2tp_stats       stats;
+
+       struct list_head        list;           /* Keep a list of all tunnels */
+       struct net              *l2tp_net;      /* the net we belong to */
+
+       atomic_t                ref_count;
+#ifdef CONFIG_DEBUG_FS
+       void (*show)(struct seq_file *m, void *arg);
+#endif
+       int (*recv_payload_hook)(struct sk_buff *skb);
+       void (*old_sk_destruct)(struct sock *);
+       struct sock             *sock;          /* Parent socket */
+       int                     fd;
+
+       uint8_t                 priv[0];        /* private data */
+};
+
+struct l2tp_nl_cmd_ops {
+       int (*session_create)(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
+       int (*session_delete)(struct l2tp_session *session);
+};
+
+static inline void *l2tp_tunnel_priv(struct l2tp_tunnel *tunnel)
+{
+       return &tunnel->priv[0];
+}
+
+static inline void *l2tp_session_priv(struct l2tp_session *session)
+{
+       return &session->priv[0];
+}
+
+static inline struct l2tp_tunnel *l2tp_sock_to_tunnel(struct sock *sk)
+{
+       struct l2tp_tunnel *tunnel;
+
+       if (sk == NULL)
+               return NULL;
+
+       sock_hold(sk);
+       tunnel = (struct l2tp_tunnel *)(sk->sk_user_data);
+       if (tunnel == NULL) {
+               sock_put(sk);
+               goto out;
+       }
+
+       BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
+
+out:
+       return tunnel;
+}
+
+extern struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunnel, u32 session_id);
+extern struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth);
+extern struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname);
+extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
+extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
+
+extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp);
+extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
+extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
+extern int l2tp_session_delete(struct l2tp_session *session);
+extern void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
+extern void l2tp_session_free(struct l2tp_session *session);
+extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
+extern int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, int (*payload_hook)(struct sk_buff *skb));
+extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
+
+extern int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t data_len);
+extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len);
+extern void l2tp_tunnel_destruct(struct sock *sk);
+extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
+extern void l2tp_session_set_header_len(struct l2tp_session *session, int version);
+
+extern int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops);
+extern void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
+
+/* Tunnel reference counts. Incremented per session that is added to
+ * the tunnel.
+ */
+static inline void l2tp_tunnel_inc_refcount_1(struct l2tp_tunnel *tunnel)
+{
+       atomic_inc(&tunnel->ref_count);
+}
+
+static inline void l2tp_tunnel_dec_refcount_1(struct l2tp_tunnel *tunnel)
+{
+       if (atomic_dec_and_test(&tunnel->ref_count))
+               l2tp_tunnel_free(tunnel);
+}
+#ifdef L2TP_REFCNT_DEBUG
+#define l2tp_tunnel_inc_refcount(_t) do { \
+               printk(KERN_DEBUG "l2tp_tunnel_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
+               l2tp_tunnel_inc_refcount_1(_t);                         \
+       } while (0)
+#define l2tp_tunnel_dec_refcount(_t) do { \
+               printk(KERN_DEBUG "l2tp_tunnel_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_t)->name, atomic_read(&_t->ref_count)); \
+               l2tp_tunnel_dec_refcount_1(_t);                         \
+       } while (0)
+#else
+#define l2tp_tunnel_inc_refcount(t) l2tp_tunnel_inc_refcount_1(t)
+#define l2tp_tunnel_dec_refcount(t) l2tp_tunnel_dec_refcount_1(t)
+#endif
+
+/* Session reference counts. Incremented when code obtains a reference
+ * to a session.
+ */
+static inline void l2tp_session_inc_refcount_1(struct l2tp_session *session)
+{
+       atomic_inc(&session->ref_count);
+}
+
+static inline void l2tp_session_dec_refcount_1(struct l2tp_session *session)
+{
+       if (atomic_dec_and_test(&session->ref_count))
+               l2tp_session_free(session);
+}
+
+#ifdef L2TP_REFCNT_DEBUG
+#define l2tp_session_inc_refcount(_s) do { \
+               printk(KERN_DEBUG "l2tp_session_inc_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_s)->name, atomic_read(&_s->ref_count)); \
+               l2tp_session_inc_refcount_1(_s);                                \
+       } while (0)
+#define l2tp_session_dec_refcount(_s) do { \
+               printk(KERN_DEBUG "l2tp_session_dec_refcount: %s:%d %s: cnt=%d\n", __func__, __LINE__, (_s)->name, atomic_read(&_s->ref_count)); \
+               l2tp_session_dec_refcount_1(_s);                                \
+       } while (0)
+#else
+#define l2tp_session_inc_refcount(s) l2tp_session_inc_refcount_1(s)
+#define l2tp_session_dec_refcount(s) l2tp_session_dec_refcount_1(s)
+#endif
+
+#endif /* _L2TP_CORE_H_ */
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c
new file mode 100644 (file)
index 0000000..104ec3b
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * L2TP subsystem debugfs
+ *
+ * Copyright (c) 2010 Katalix Systems Ltd
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/hash.h>
+#include <linux/l2tp.h>
+#include <linux/in.h>
+#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/inet_common.h>
+#include <net/inet_hashtables.h>
+#include <net/tcp_states.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+#include "l2tp_core.h"
+
+static struct dentry *rootdir;
+static struct dentry *tunnels;
+
+struct l2tp_dfs_seq_data {
+       struct net *net;
+       int tunnel_idx;                 /* current tunnel */
+       int session_idx;                /* index of session within current tunnel */
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_session *session;   /* NULL means get next tunnel */
+};
+
+static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd)
+{
+       pd->tunnel = l2tp_tunnel_find_nth(pd->net, pd->tunnel_idx);
+       pd->tunnel_idx++;
+}
+
+static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd)
+{
+       pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx);
+       pd->session_idx++;
+
+       if (pd->session == NULL) {
+               pd->session_idx = 0;
+               l2tp_dfs_next_tunnel(pd);
+       }
+
+}
+
+static void *l2tp_dfs_seq_start(struct seq_file *m, loff_t *offs)
+{
+       struct l2tp_dfs_seq_data *pd = SEQ_START_TOKEN;
+       loff_t pos = *offs;
+
+       if (!pos)
+               goto out;
+
+       BUG_ON(m->private == NULL);
+       pd = m->private;
+
+       if (pd->tunnel == NULL)
+               l2tp_dfs_next_tunnel(pd);
+       else
+               l2tp_dfs_next_session(pd);
+
+       /* NULL tunnel and session indicates end of list */
+       if ((pd->tunnel == NULL) && (pd->session == NULL))
+               pd = NULL;
+
+out:
+       return pd;
+}
+
+
+static void *l2tp_dfs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return NULL;
+}
+
+static void l2tp_dfs_seq_stop(struct seq_file *p, void *v)
+{
+       /* nothing to do */
+}
+
+static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)
+{
+       struct l2tp_tunnel *tunnel = v;
+       int session_count = 0;
+       int hash;
+       struct hlist_node *walk;
+       struct hlist_node *tmp;
+
+       read_lock_bh(&tunnel->hlist_lock);
+       for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
+               hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
+                       struct l2tp_session *session;
+
+                       session = hlist_entry(walk, struct l2tp_session, hlist);
+                       if (session->session_id == 0)
+                               continue;
+
+                       session_count++;
+               }
+       }
+       read_unlock_bh(&tunnel->hlist_lock);
+
+       seq_printf(m, "\nTUNNEL %u peer %u", tunnel->tunnel_id, tunnel->peer_tunnel_id);
+       if (tunnel->sock) {
+               struct inet_sock *inet = inet_sk(tunnel->sock);
+               seq_printf(m, " from %pI4 to %pI4\n",
+                          &inet->inet_saddr, &inet->inet_daddr);
+               if (tunnel->encap == L2TP_ENCAPTYPE_UDP)
+                       seq_printf(m, " source port %hu, dest port %hu\n",
+                                  ntohs(inet->inet_sport), ntohs(inet->inet_dport));
+       }
+       seq_printf(m, " L2TPv%d, %s\n", tunnel->version,
+                  tunnel->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
+                  tunnel->encap == L2TP_ENCAPTYPE_IP ? "IP" :
+                  "");
+       seq_printf(m, " %d sessions, refcnt %d/%d\n", session_count,
+                  tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0,
+                  atomic_read(&tunnel->ref_count));
+
+       seq_printf(m, " %08x rx %llu/%llu/%llu rx %llu/%llu/%llu\n",
+                  tunnel->debug,
+                  (unsigned long long)tunnel->stats.tx_packets,
+                  (unsigned long long)tunnel->stats.tx_bytes,
+                  (unsigned long long)tunnel->stats.tx_errors,
+                  (unsigned long long)tunnel->stats.rx_packets,
+                  (unsigned long long)tunnel->stats.rx_bytes,
+                  (unsigned long long)tunnel->stats.rx_errors);
+
+       if (tunnel->show != NULL)
+               tunnel->show(m, tunnel);
+}
+
+static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v)
+{
+       struct l2tp_session *session = v;
+
+       seq_printf(m, "  SESSION %u, peer %u, %s\n", session->session_id,
+                  session->peer_session_id,
+                  session->pwtype == L2TP_PWTYPE_ETH ? "ETH" :
+                  session->pwtype == L2TP_PWTYPE_PPP ? "PPP" :
+                  "");
+       if (session->send_seq || session->recv_seq)
+               seq_printf(m, "   nr %hu, ns %hu\n", session->nr, session->ns);
+       seq_printf(m, "   refcnt %d\n", atomic_read(&session->ref_count));
+       seq_printf(m, "   config %d/%d/%c/%c/%s/%s %08x %u\n",
+                  session->mtu, session->mru,
+                  session->recv_seq ? 'R' : '-',
+                  session->send_seq ? 'S' : '-',
+                  session->data_seq == 1 ? "IPSEQ" :
+                  session->data_seq == 2 ? "DATASEQ" : "-",
+                  session->lns_mode ? "LNS" : "LAC",
+                  session->debug,
+                  jiffies_to_msecs(session->reorder_timeout));
+       seq_printf(m, "   offset %hu l2specific %hu/%hu\n",
+                  session->offset, session->l2specific_type, session->l2specific_len);
+       if (session->cookie_len) {
+               seq_printf(m, "   cookie %02x%02x%02x%02x",
+                          session->cookie[0], session->cookie[1],
+                          session->cookie[2], session->cookie[3]);
+               if (session->cookie_len == 8)
+                       seq_printf(m, "%02x%02x%02x%02x",
+                                  session->cookie[4], session->cookie[5],
+                                  session->cookie[6], session->cookie[7]);
+               seq_printf(m, "\n");
+       }
+       if (session->peer_cookie_len) {
+               seq_printf(m, "   peer cookie %02x%02x%02x%02x",
+                          session->peer_cookie[0], session->peer_cookie[1],
+                          session->peer_cookie[2], session->peer_cookie[3]);
+               if (session->peer_cookie_len == 8)
+                       seq_printf(m, "%02x%02x%02x%02x",
+                                  session->peer_cookie[4], session->peer_cookie[5],
+                                  session->peer_cookie[6], session->peer_cookie[7]);
+               seq_printf(m, "\n");
+       }
+
+       seq_printf(m, "   %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n",
+                  session->nr, session->ns,
+                  (unsigned long long)session->stats.tx_packets,
+                  (unsigned long long)session->stats.tx_bytes,
+                  (unsigned long long)session->stats.tx_errors,
+                  (unsigned long long)session->stats.rx_packets,
+                  (unsigned long long)session->stats.rx_bytes,
+                  (unsigned long long)session->stats.rx_errors);
+
+       if (session->show != NULL)
+               session->show(m, session);
+}
+
+static int l2tp_dfs_seq_show(struct seq_file *m, void *v)
+{
+       struct l2tp_dfs_seq_data *pd = v;
+
+       /* display header on line 1 */
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(m, "TUNNEL ID, peer ID from IP to IP\n");
+               seq_puts(m, " L2TPv2/L2TPv3, UDP/IP\n");
+               seq_puts(m, " sessions session-count, refcnt refcnt/sk->refcnt\n");
+               seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
+               seq_puts(m, "  SESSION ID, peer ID, PWTYPE\n");
+               seq_puts(m, "   refcnt cnt\n");
+               seq_puts(m, "   offset OFFSET l2specific TYPE/LEN\n");
+               seq_puts(m, "   [ cookie ]\n");
+               seq_puts(m, "   [ peer cookie ]\n");
+               seq_puts(m, "   config mtu/mru/rcvseq/sendseq/dataseq/lns debug reorderto\n");
+               seq_puts(m, "   nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
+               goto out;
+       }
+
+       /* Show the tunnel or session context */
+       if (pd->session == NULL)
+               l2tp_dfs_seq_tunnel_show(m, pd->tunnel);
+       else
+               l2tp_dfs_seq_session_show(m, pd->session);
+
+out:
+       return 0;
+}
+
+static const struct seq_operations l2tp_dfs_seq_ops = {
+       .start          = l2tp_dfs_seq_start,
+       .next           = l2tp_dfs_seq_next,
+       .stop           = l2tp_dfs_seq_stop,
+       .show           = l2tp_dfs_seq_show,
+};
+
+static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
+{
+       struct l2tp_dfs_seq_data *pd;
+       struct seq_file *seq;
+       int rc = -ENOMEM;
+
+       pd = kzalloc(GFP_KERNEL, sizeof(*pd));
+       if (pd == NULL)
+               goto out;
+
+       /* Derive the network namespace from the pid opening the
+        * file.
+        */
+       pd->net = get_net_ns_by_pid(current->pid);
+       if (IS_ERR(pd->net)) {
+               rc = -PTR_ERR(pd->net);
+               goto err_free_pd;
+       }
+
+       rc = seq_open(file, &l2tp_dfs_seq_ops);
+       if (rc)
+               goto err_free_net;
+
+       seq = file->private_data;
+       seq->private = pd;
+
+out:
+       return rc;
+
+err_free_net:
+       put_net(pd->net);
+err_free_pd:
+       kfree(pd);
+       goto out;
+}
+
+static int l2tp_dfs_seq_release(struct inode *inode, struct file *file)
+{
+       struct l2tp_dfs_seq_data *pd;
+       struct seq_file *seq;
+
+       seq = file->private_data;
+       pd = seq->private;
+       if (pd->net)
+               put_net(pd->net);
+       kfree(pd);
+       seq_release(inode, file);
+
+       return 0;
+}
+
+static const struct file_operations l2tp_dfs_fops = {
+       .owner          = THIS_MODULE,
+       .open           = l2tp_dfs_seq_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = l2tp_dfs_seq_release,
+};
+
+static int __init l2tp_debugfs_init(void)
+{
+       int rc = 0;
+
+       rootdir = debugfs_create_dir("l2tp", NULL);
+       if (IS_ERR(rootdir)) {
+               rc = PTR_ERR(rootdir);
+               rootdir = NULL;
+               goto out;
+       }
+
+       tunnels = debugfs_create_file("tunnels", 0600, rootdir, NULL, &l2tp_dfs_fops);
+       if (tunnels == NULL)
+               rc = -EIO;
+
+       printk(KERN_INFO "L2TP debugfs support\n");
+
+out:
+       if (rc)
+               printk(KERN_WARNING "l2tp debugfs: unable to init\n");
+
+       return rc;
+}
+
+static void __exit l2tp_debugfs_exit(void)
+{
+       debugfs_remove(tunnels);
+       debugfs_remove(rootdir);
+}
+
+module_init(l2tp_debugfs_init);
+module_exit(l2tp_debugfs_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("L2TP debugfs driver");
+MODULE_VERSION("1.0");
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c
new file mode 100644 (file)
index 0000000..58c6c4c
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * L2TPv3 ethernet pseudowire driver
+ *
+ * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/hash.h>
+#include <linux/l2tp.h>
+#include <linux/in.h>
+#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/inet_common.h>
+#include <net/inet_hashtables.h>
+#include <net/tcp_states.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+
+#include "l2tp_core.h"
+
+/* Default device name. May be overridden by name specified by user */
+#define L2TP_ETH_DEV_NAME      "l2tpeth%d"
+
+/* via netdev_priv() */
+struct l2tp_eth {
+       struct net_device       *dev;
+       struct sock             *tunnel_sock;
+       struct l2tp_session     *session;
+       struct list_head        list;
+};
+
+/* via l2tp_session_priv() */
+struct l2tp_eth_sess {
+       struct net_device       *dev;
+};
+
+/* per-net private data for this module */
+static unsigned int l2tp_eth_net_id;
+struct l2tp_eth_net {
+       struct list_head l2tp_eth_dev_list;
+       spinlock_t l2tp_eth_lock;
+};
+
+static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net)
+{
+       return net_generic(net, l2tp_eth_net_id);
+}
+
+static int l2tp_eth_dev_init(struct net_device *dev)
+{
+       struct l2tp_eth *priv = netdev_priv(dev);
+
+       priv->dev = dev;
+       random_ether_addr(dev->dev_addr);
+       memset(&dev->broadcast[0], 0xff, 6);
+
+       return 0;
+}
+
+static void l2tp_eth_dev_uninit(struct net_device *dev)
+{
+       struct l2tp_eth *priv = netdev_priv(dev);
+       struct l2tp_eth_net *pn = l2tp_eth_pernet(dev_net(dev));
+
+       spin_lock(&pn->l2tp_eth_lock);
+       list_del_init(&priv->list);
+       spin_unlock(&pn->l2tp_eth_lock);
+       dev_put(dev);
+}
+
+static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct l2tp_eth *priv = netdev_priv(dev);
+       struct l2tp_session *session = priv->session;
+
+       l2tp_xmit_skb(session, skb, session->hdr_len);
+
+       dev->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
+
+       return 0;
+}
+
+static struct net_device_ops l2tp_eth_netdev_ops = {
+       .ndo_init               = l2tp_eth_dev_init,
+       .ndo_uninit             = l2tp_eth_dev_uninit,
+       .ndo_start_xmit         = l2tp_eth_dev_xmit,
+};
+
+static void l2tp_eth_dev_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+
+       dev->netdev_ops         = &l2tp_eth_netdev_ops;
+       dev->destructor         = free_netdev;
+}
+
+static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
+{
+       struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
+       struct net_device *dev = spriv->dev;
+
+       if (session->debug & L2TP_MSG_DATA) {
+               unsigned int length;
+               int offset;
+               u8 *ptr = skb->data;
+
+               length = min(32u, skb->len);
+               if (!pskb_may_pull(skb, length))
+                       goto error;
+
+               printk(KERN_DEBUG "%s: eth recv: ", session->name);
+
+               offset = 0;
+               do {
+                       printk(" %02X", ptr[offset]);
+               } while (++offset < length);
+
+               printk("\n");
+       }
+
+       if (data_len < ETH_HLEN)
+               goto error;
+
+       secpath_reset(skb);
+
+       /* checksums verified by L2TP */
+       skb->ip_summed = CHECKSUM_NONE;
+
+       skb_dst_drop(skb);
+       nf_reset(skb);
+
+       if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) {
+               dev->last_rx = jiffies;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += data_len;
+       } else
+               dev->stats.rx_errors++;
+
+       return;
+
+error:
+       dev->stats.rx_errors++;
+       kfree_skb(skb);
+}
+
+static void l2tp_eth_delete(struct l2tp_session *session)
+{
+       struct l2tp_eth_sess *spriv;
+       struct net_device *dev;
+
+       if (session) {
+               spriv = l2tp_session_priv(session);
+               dev = spriv->dev;
+               if (dev) {
+                       unregister_netdev(dev);
+                       spriv->dev = NULL;
+               }
+       }
+}
+
+#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
+static void l2tp_eth_show(struct seq_file *m, void *arg)
+{
+       struct l2tp_session *session = arg;
+       struct l2tp_eth_sess *spriv = l2tp_session_priv(session);
+       struct net_device *dev = spriv->dev;
+
+       seq_printf(m, "   interface %s\n", dev->name);
+}
+#endif
+
+static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+{
+       struct net_device *dev;
+       char name[IFNAMSIZ];
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_session *session;
+       struct l2tp_eth *priv;
+       struct l2tp_eth_sess *spriv;
+       int rc;
+       struct l2tp_eth_net *pn;
+
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       if (!tunnel) {
+               rc = -ENODEV;
+               goto out;
+       }
+
+       session = l2tp_session_find(net, tunnel, session_id);
+       if (session) {
+               rc = -EEXIST;
+               goto out;
+       }
+
+       if (cfg->ifname) {
+               dev = dev_get_by_name(net, cfg->ifname);
+               if (dev) {
+                       dev_put(dev);
+                       rc = -EEXIST;
+                       goto out;
+               }
+               strlcpy(name, cfg->ifname, IFNAMSIZ);
+       } else
+               strcpy(name, L2TP_ETH_DEV_NAME);
+
+       session = l2tp_session_create(sizeof(*spriv), tunnel, session_id,
+                                     peer_session_id, cfg);
+       if (!session) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       dev = alloc_netdev(sizeof(*priv), name, l2tp_eth_dev_setup);
+       if (!dev) {
+               rc = -ENOMEM;
+               goto out_del_session;
+       }
+
+       dev_net_set(dev, net);
+       if (session->mtu == 0)
+               session->mtu = dev->mtu - session->hdr_len;
+       dev->mtu = session->mtu;
+       dev->needed_headroom += session->hdr_len;
+
+       priv = netdev_priv(dev);
+       priv->dev = dev;
+       priv->session = session;
+       INIT_LIST_HEAD(&priv->list);
+
+       priv->tunnel_sock = tunnel->sock;
+       session->recv_skb = l2tp_eth_dev_recv;
+       session->session_close = l2tp_eth_delete;
+#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
+       session->show = l2tp_eth_show;
+#endif
+
+       spriv = l2tp_session_priv(session);
+       spriv->dev = dev;
+
+       rc = register_netdev(dev);
+       if (rc < 0)
+               goto out_del_dev;
+
+       /* Must be done after register_netdev() */
+       strlcpy(session->ifname, dev->name, IFNAMSIZ);
+
+       dev_hold(dev);
+       pn = l2tp_eth_pernet(dev_net(dev));
+       spin_lock(&pn->l2tp_eth_lock);
+       list_add(&priv->list, &pn->l2tp_eth_dev_list);
+       spin_unlock(&pn->l2tp_eth_lock);
+
+       return 0;
+
+out_del_dev:
+       free_netdev(dev);
+out_del_session:
+       l2tp_session_delete(session);
+out:
+       return rc;
+}
+
+static __net_init int l2tp_eth_init_net(struct net *net)
+{
+       struct l2tp_eth_net *pn = net_generic(net, l2tp_eth_net_id);
+
+       INIT_LIST_HEAD(&pn->l2tp_eth_dev_list);
+       spin_lock_init(&pn->l2tp_eth_lock);
+
+       return 0;
+}
+
+static __net_initdata struct pernet_operations l2tp_eth_net_ops = {
+       .init = l2tp_eth_init_net,
+       .id   = &l2tp_eth_net_id,
+       .size = sizeof(struct l2tp_eth_net),
+};
+
+
+static const struct l2tp_nl_cmd_ops l2tp_eth_nl_cmd_ops = {
+       .session_create = l2tp_eth_create,
+       .session_delete = l2tp_session_delete,
+};
+
+
+static int __init l2tp_eth_init(void)
+{
+       int err = 0;
+
+       err = l2tp_nl_register_ops(L2TP_PWTYPE_ETH, &l2tp_eth_nl_cmd_ops);
+       if (err)
+               goto out;
+
+       err = register_pernet_device(&l2tp_eth_net_ops);
+       if (err)
+               goto out_unreg;
+
+       printk(KERN_INFO "L2TP ethernet pseudowire support (L2TPv3)\n");
+
+       return 0;
+
+out_unreg:
+       l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH);
+out:
+       return err;
+}
+
+static void __exit l2tp_eth_exit(void)
+{
+       unregister_pernet_device(&l2tp_eth_net_ops);
+       l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH);
+}
+
+module_init(l2tp_eth_init);
+module_exit(l2tp_eth_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("L2TP ethernet pseudowire driver");
+MODULE_VERSION("1.0");
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
new file mode 100644 (file)
index 0000000..0852512
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * L2TPv3 IP encapsulation support
+ *
+ * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/icmp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <linux/socket.h>
+#include <linux/l2tp.h>
+#include <linux/in.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/inet_common.h>
+#include <net/inet_hashtables.h>
+#include <net/tcp_states.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+#include "l2tp_core.h"
+
+struct l2tp_ip_sock {
+       /* inet_sock has to be the first member of l2tp_ip_sock */
+       struct inet_sock        inet;
+
+       __u32                   conn_id;
+       __u32                   peer_conn_id;
+
+       __u64                   tx_packets;
+       __u64                   tx_bytes;
+       __u64                   tx_errors;
+       __u64                   rx_packets;
+       __u64                   rx_bytes;
+       __u64                   rx_errors;
+};
+
+static DEFINE_RWLOCK(l2tp_ip_lock);
+static struct hlist_head l2tp_ip_table;
+static struct hlist_head l2tp_ip_bind_table;
+
+static inline struct l2tp_ip_sock *l2tp_ip_sk(const struct sock *sk)
+{
+       return (struct l2tp_ip_sock *)sk;
+}
+
+static struct sock *__l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif, u32 tunnel_id)
+{
+       struct hlist_node *node;
+       struct sock *sk;
+
+       sk_for_each_bound(sk, node, &l2tp_ip_bind_table) {
+               struct inet_sock *inet = inet_sk(sk);
+               struct l2tp_ip_sock *l2tp = l2tp_ip_sk(sk);
+
+               if (l2tp == NULL)
+                       continue;
+
+               if ((l2tp->conn_id == tunnel_id) &&
+#ifdef CONFIG_NET_NS
+                   (sk->sk_net == net) &&
+#endif
+                   !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) &&
+                   !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+                       goto found;
+       }
+
+       sk = NULL;
+found:
+       return sk;
+}
+
+static inline struct sock *l2tp_ip_bind_lookup(struct net *net, __be32 laddr, int dif, u32 tunnel_id)
+{
+       struct sock *sk = __l2tp_ip_bind_lookup(net, laddr, dif, tunnel_id);
+       if (sk)
+               sock_hold(sk);
+
+       return sk;
+}
+
+/* When processing receive frames, there are two cases to
+ * consider. Data frames consist of a non-zero session-id and an
+ * optional cookie. Control frames consist of a regular L2TP header
+ * preceded by 32-bits of zeros.
+ *
+ * L2TPv3 Session Header Over IP
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           Session ID                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |               Cookie (optional, maximum 64 bits)...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                                                                 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * L2TPv3 Control Message Header Over IP
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      (32 bits of zeros)                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     Control Connection ID                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |               Ns              |               Nr              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * All control frames are passed to userspace.
+ */
+static int l2tp_ip_recv(struct sk_buff *skb)
+{
+       struct sock *sk;
+       u32 session_id;
+       u32 tunnel_id;
+       unsigned char *ptr, *optr;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel = NULL;
+       int length;
+       int offset;
+
+       /* Point to L2TP header */
+       optr = ptr = skb->data;
+
+       if (!pskb_may_pull(skb, 4))
+               goto discard;
+
+       session_id = ntohl(*((__be32 *) ptr));
+       ptr += 4;
+
+       /* RFC3931: L2TP/IP packets have the first 4 bytes containing
+        * the session_id. If it is 0, the packet is a L2TP control
+        * frame and the session_id value can be discarded.
+        */
+       if (session_id == 0) {
+               __skb_pull(skb, 4);
+               goto pass_up;
+       }
+
+       /* Ok, this is a data packet. Lookup the session. */
+       session = l2tp_session_find(&init_net, NULL, session_id);
+       if (session == NULL)
+               goto discard;
+
+       tunnel = session->tunnel;
+       if (tunnel == NULL)
+               goto discard;
+
+       /* Trace packet contents, if enabled */
+       if (tunnel->debug & L2TP_MSG_DATA) {
+               length = min(32u, skb->len);
+               if (!pskb_may_pull(skb, length))
+                       goto discard;
+
+               printk(KERN_DEBUG "%s: ip recv: ", tunnel->name);
+
+               offset = 0;
+               do {
+                       printk(" %02X", ptr[offset]);
+               } while (++offset < length);
+
+               printk("\n");
+       }
+
+       l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook);
+
+       return 0;
+
+pass_up:
+       /* Get the tunnel_id from the L2TP header */
+       if (!pskb_may_pull(skb, 12))
+               goto discard;
+
+       if ((skb->data[0] & 0xc0) != 0xc0)
+               goto discard;
+
+       tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
+       tunnel = l2tp_tunnel_find(&init_net, tunnel_id);
+       if (tunnel != NULL)
+               sk = tunnel->sock;
+       else {
+               struct iphdr *iph = (struct iphdr *) skb_network_header(skb);
+
+               read_lock_bh(&l2tp_ip_lock);
+               sk = __l2tp_ip_bind_lookup(&init_net, iph->daddr, 0, tunnel_id);
+               read_unlock_bh(&l2tp_ip_lock);
+       }
+
+       if (sk == NULL)
+               goto discard;
+
+       sock_hold(sk);
+
+       if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
+               goto discard_put;
+
+       nf_reset(skb);
+
+       return sk_receive_skb(sk, skb, 1);
+
+discard_put:
+       sock_put(sk);
+
+discard:
+       kfree_skb(skb);
+       return 0;
+}
+
+static int l2tp_ip_open(struct sock *sk)
+{
+       /* Prevent autobind. We don't have ports. */
+       inet_sk(sk)->inet_num = IPPROTO_L2TP;
+
+       write_lock_bh(&l2tp_ip_lock);
+       sk_add_node(sk, &l2tp_ip_table);
+       write_unlock_bh(&l2tp_ip_lock);
+
+       return 0;
+}
+
+static void l2tp_ip_close(struct sock *sk, long timeout)
+{
+       write_lock_bh(&l2tp_ip_lock);
+       hlist_del_init(&sk->sk_bind_node);
+       hlist_del_init(&sk->sk_node);
+       write_unlock_bh(&l2tp_ip_lock);
+       sk_common_release(sk);
+}
+
+static void l2tp_ip_destroy_sock(struct sock *sk)
+{
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
+               kfree_skb(skb);
+
+       sk_refcnt_debug_dec(sk);
+}
+
+static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct sockaddr_l2tpip *addr = (struct sockaddr_l2tpip *) uaddr;
+       int ret = -EINVAL;
+       int chk_addr_ret;
+
+       ret = -EADDRINUSE;
+       read_lock_bh(&l2tp_ip_lock);
+       if (__l2tp_ip_bind_lookup(&init_net, addr->l2tp_addr.s_addr, sk->sk_bound_dev_if, addr->l2tp_conn_id))
+               goto out_in_use;
+
+       read_unlock_bh(&l2tp_ip_lock);
+
+       lock_sock(sk);
+       if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_l2tpip))
+               goto out;
+
+       chk_addr_ret = inet_addr_type(&init_net, addr->l2tp_addr.s_addr);
+       ret = -EADDRNOTAVAIL;
+       if (addr->l2tp_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
+           chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
+               goto out;
+
+       inet->inet_rcv_saddr = inet->inet_saddr = addr->l2tp_addr.s_addr;
+       if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
+               inet->inet_saddr = 0;  /* Use device */
+       sk_dst_reset(sk);
+
+       l2tp_ip_sk(sk)->conn_id = addr->l2tp_conn_id;
+
+       write_lock_bh(&l2tp_ip_lock);
+       sk_add_bind_node(sk, &l2tp_ip_bind_table);
+       sk_del_node_init(sk);
+       write_unlock_bh(&l2tp_ip_lock);
+       ret = 0;
+out:
+       release_sock(sk);
+
+       return ret;
+
+out_in_use:
+       read_unlock_bh(&l2tp_ip_lock);
+
+       return ret;
+}
+
+static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+       int rc;
+       struct inet_sock *inet = inet_sk(sk);
+       struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr;
+       struct rtable *rt;
+       __be32 saddr;
+       int oif;
+
+       rc = -EINVAL;
+       if (addr_len < sizeof(*lsa))
+               goto out;
+
+       rc = -EAFNOSUPPORT;
+       if (lsa->l2tp_family != AF_INET)
+               goto out;
+
+       sk_dst_reset(sk);
+
+       oif = sk->sk_bound_dev_if;
+       saddr = inet->inet_saddr;
+
+       rc = -EINVAL;
+       if (ipv4_is_multicast(lsa->l2tp_addr.s_addr))
+               goto out;
+
+       rc = ip_route_connect(&rt, lsa->l2tp_addr.s_addr, saddr,
+                             RT_CONN_FLAGS(sk), oif,
+                             IPPROTO_L2TP,
+                             0, 0, sk, 1);
+       if (rc) {
+               if (rc == -ENETUNREACH)
+                       IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES);
+               goto out;
+       }
+
+       rc = -ENETUNREACH;
+       if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
+               ip_rt_put(rt);
+               goto out;
+       }
+
+       l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
+
+       if (!inet->inet_saddr)
+               inet->inet_saddr = rt->rt_src;
+       if (!inet->inet_rcv_saddr)
+               inet->inet_rcv_saddr = rt->rt_src;
+       inet->inet_daddr = rt->rt_dst;
+       sk->sk_state = TCP_ESTABLISHED;
+       inet->inet_id = jiffies;
+
+       sk_dst_set(sk, &rt->u.dst);
+
+       write_lock_bh(&l2tp_ip_lock);
+       hlist_del_init(&sk->sk_bind_node);
+       sk_add_bind_node(sk, &l2tp_ip_bind_table);
+       write_unlock_bh(&l2tp_ip_lock);
+
+       rc = 0;
+out:
+       return rc;
+}
+
+static int l2tp_ip_getname(struct socket *sock, struct sockaddr *uaddr,
+                          int *uaddr_len, int peer)
+{
+       struct sock *sk         = sock->sk;
+       struct inet_sock *inet  = inet_sk(sk);
+       struct l2tp_ip_sock *lsk = l2tp_ip_sk(sk);
+       struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *)uaddr;
+
+       memset(lsa, 0, sizeof(*lsa));
+       lsa->l2tp_family = AF_INET;
+       if (peer) {
+               if (!inet->inet_dport)
+                       return -ENOTCONN;
+               lsa->l2tp_conn_id = lsk->peer_conn_id;
+               lsa->l2tp_addr.s_addr = inet->inet_daddr;
+       } else {
+               __be32 addr = inet->inet_rcv_saddr;
+               if (!addr)
+                       addr = inet->inet_saddr;
+               lsa->l2tp_conn_id = lsk->conn_id;
+               lsa->l2tp_addr.s_addr = addr;
+       }
+       *uaddr_len = sizeof(*lsa);
+       return 0;
+}
+
+static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb)
+{
+       int rc;
+
+       if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb))
+               goto drop;
+
+       nf_reset(skb);
+
+       /* Charge it to the socket, dropping if the queue is full. */
+       rc = sock_queue_rcv_skb(sk, skb);
+       if (rc < 0)
+               goto drop;
+
+       return 0;
+
+drop:
+       IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS);
+       kfree_skb(skb);
+       return -1;
+}
+
+/* Userspace will call sendmsg() on the tunnel socket to send L2TP
+ * control frames.
+ */
+static int l2tp_ip_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len)
+{
+       struct sk_buff *skb;
+       int rc;
+       struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
+       struct ip_options *opt = inet->opt;
+       struct rtable *rt = NULL;
+       int connected = 0;
+       __be32 daddr;
+
+       if (sock_flag(sk, SOCK_DEAD))
+               return -ENOTCONN;
+
+       /* Get and verify the address. */
+       if (msg->msg_name) {
+               struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name;
+               if (msg->msg_namelen < sizeof(*lip))
+                       return -EINVAL;
+
+               if (lip->l2tp_family != AF_INET) {
+                       if (lip->l2tp_family != AF_UNSPEC)
+                               return -EAFNOSUPPORT;
+               }
+
+               daddr = lip->l2tp_addr.s_addr;
+       } else {
+               if (sk->sk_state != TCP_ESTABLISHED)
+                       return -EDESTADDRREQ;
+
+               daddr = inet->inet_daddr;
+               connected = 1;
+       }
+
+       /* Allocate a socket buffer */
+       rc = -ENOMEM;
+       skb = sock_wmalloc(sk, 2 + NET_SKB_PAD + sizeof(struct iphdr) +
+                          4 + len, 0, GFP_KERNEL);
+       if (!skb)
+               goto error;
+
+       /* Reserve space for headers, putting IP header on 4-byte boundary. */
+       skb_reserve(skb, 2 + NET_SKB_PAD);
+       skb_reset_network_header(skb);
+       skb_reserve(skb, sizeof(struct iphdr));
+       skb_reset_transport_header(skb);
+
+       /* Insert 0 session_id */
+       *((__be32 *) skb_put(skb, 4)) = 0;
+
+       /* Copy user data into skb */
+       rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+       if (rc < 0) {
+               kfree_skb(skb);
+               goto error;
+       }
+
+       if (connected)
+               rt = (struct rtable *) __sk_dst_check(sk, 0);
+
+       if (rt == NULL) {
+               /* Use correct destination address if we have options. */
+               if (opt && opt->srr)
+                       daddr = opt->faddr;
+
+               {
+                       struct flowi fl = { .oif = sk->sk_bound_dev_if,
+                                           .nl_u = { .ip4_u = {
+                                                       .daddr = daddr,
+                                                       .saddr = inet->inet_saddr,
+                                                       .tos = RT_CONN_FLAGS(sk) } },
+                                           .proto = sk->sk_protocol,
+                                           .flags = inet_sk_flowi_flags(sk),
+                                           .uli_u = { .ports = {
+                                                        .sport = inet->inet_sport,
+                                                        .dport = inet->inet_dport } } };
+
+                       /* If this fails, retransmit mechanism of transport layer will
+                        * keep trying until route appears or the connection times
+                        * itself out.
+                        */
+                       security_sk_classify_flow(sk, &fl);
+                       if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
+                               goto no_route;
+               }
+               sk_setup_caps(sk, &rt->u.dst);
+       }
+       skb_dst_set(skb, dst_clone(&rt->u.dst));
+
+       /* Queue the packet to IP for output */
+       rc = ip_queue_xmit(skb);
+
+error:
+       /* Update stats */
+       if (rc >= 0) {
+               lsa->tx_packets++;
+               lsa->tx_bytes += len;
+               rc = len;
+       } else {
+               lsa->tx_errors++;
+       }
+
+       return rc;
+
+no_route:
+       IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
+       kfree_skb(skb);
+       return -EHOSTUNREACH;
+}
+
+static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+                          size_t len, int noblock, int flags, int *addr_len)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct l2tp_ip_sock *lsk = l2tp_ip_sk(sk);
+       size_t copied = 0;
+       int err = -EOPNOTSUPP;
+       struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
+       struct sk_buff *skb;
+
+       if (flags & MSG_OOB)
+               goto out;
+
+       if (addr_len)
+               *addr_len = sizeof(*sin);
+
+       skb = skb_recv_datagram(sk, flags, noblock, &err);
+       if (!skb)
+               goto out;
+
+       copied = skb->len;
+       if (len < copied) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto done;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       /* Copy the address. */
+       if (sin) {
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
+               sin->sin_port = 0;
+               memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+       if (inet->cmsg_flags)
+               ip_cmsg_recv(msg, skb);
+       if (flags & MSG_TRUNC)
+               copied = skb->len;
+done:
+       skb_free_datagram(sk, skb);
+out:
+       if (err) {
+               lsk->rx_errors++;
+               return err;
+       }
+
+       lsk->rx_packets++;
+       lsk->rx_bytes += copied;
+
+       return copied;
+}
+
+struct proto l2tp_ip_prot = {
+       .name              = "L2TP/IP",
+       .owner             = THIS_MODULE,
+       .init              = l2tp_ip_open,
+       .close             = l2tp_ip_close,
+       .bind              = l2tp_ip_bind,
+       .connect           = l2tp_ip_connect,
+       .disconnect        = udp_disconnect,
+       .ioctl             = udp_ioctl,
+       .destroy           = l2tp_ip_destroy_sock,
+       .setsockopt        = ip_setsockopt,
+       .getsockopt        = ip_getsockopt,
+       .sendmsg           = l2tp_ip_sendmsg,
+       .recvmsg           = l2tp_ip_recvmsg,
+       .backlog_rcv       = l2tp_ip_backlog_recv,
+       .hash              = inet_hash,
+       .unhash            = inet_unhash,
+       .obj_size          = sizeof(struct l2tp_ip_sock),
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_ip_setsockopt,
+       .compat_getsockopt = compat_ip_getsockopt,
+#endif
+};
+
+static const struct proto_ops l2tp_ip_ops = {
+       .family            = PF_INET,
+       .owner             = THIS_MODULE,
+       .release           = inet_release,
+       .bind              = inet_bind,
+       .connect           = inet_dgram_connect,
+       .socketpair        = sock_no_socketpair,
+       .accept            = sock_no_accept,
+       .getname           = l2tp_ip_getname,
+       .poll              = datagram_poll,
+       .ioctl             = inet_ioctl,
+       .listen            = sock_no_listen,
+       .shutdown          = inet_shutdown,
+       .setsockopt        = sock_common_setsockopt,
+       .getsockopt        = sock_common_getsockopt,
+       .sendmsg           = inet_sendmsg,
+       .recvmsg           = sock_common_recvmsg,
+       .mmap              = sock_no_mmap,
+       .sendpage          = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+       .compat_setsockopt = compat_sock_common_setsockopt,
+       .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
+static struct inet_protosw l2tp_ip_protosw = {
+       .type           = SOCK_DGRAM,
+       .protocol       = IPPROTO_L2TP,
+       .prot           = &l2tp_ip_prot,
+       .ops            = &l2tp_ip_ops,
+       .no_check       = 0,
+};
+
+static struct net_protocol l2tp_ip_protocol __read_mostly = {
+       .handler        = l2tp_ip_recv,
+};
+
+static int __init l2tp_ip_init(void)
+{
+       int err;
+
+       printk(KERN_INFO "L2TP IP encapsulation support (L2TPv3)\n");
+
+       err = proto_register(&l2tp_ip_prot, 1);
+       if (err != 0)
+               goto out;
+
+       err = inet_add_protocol(&l2tp_ip_protocol, IPPROTO_L2TP);
+       if (err)
+               goto out1;
+
+       inet_register_protosw(&l2tp_ip_protosw);
+       return 0;
+
+out1:
+       proto_unregister(&l2tp_ip_prot);
+out:
+       return err;
+}
+
+static void __exit l2tp_ip_exit(void)
+{
+       inet_unregister_protosw(&l2tp_ip_protosw);
+       inet_del_protocol(&l2tp_ip_protocol, IPPROTO_L2TP);
+       proto_unregister(&l2tp_ip_prot);
+}
+
+module_init(l2tp_ip_init);
+module_exit(l2tp_ip_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("L2TP over IP");
+MODULE_VERSION("1.0");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
new file mode 100644 (file)
index 0000000..4c1e540
--- /dev/null
@@ -0,0 +1,840 @@
+/*
+ * L2TP netlink layer, for management
+ *
+ * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
+ *
+ * Partly based on the IrDA nelink implementation
+ * (see net/irda/irnetlink.c) which is:
+ * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
+ * which is in turn partly based on the wireless netlink code:
+ * Copyright 2006 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/sock.h>
+#include <net/genetlink.h>
+#include <net/udp.h>
+#include <linux/in.h>
+#include <linux/udp.h>
+#include <linux/socket.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <net/net_namespace.h>
+
+#include <linux/l2tp.h>
+
+#include "l2tp_core.h"
+
+
+static struct genl_family l2tp_nl_family = {
+       .id             = GENL_ID_GENERATE,
+       .name           = L2TP_GENL_NAME,
+       .version        = L2TP_GENL_VERSION,
+       .hdrsize        = 0,
+       .maxattr        = L2TP_ATTR_MAX,
+};
+
+/* Accessed under genl lock */
+static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX];
+
+static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info)
+{
+       u32 tunnel_id;
+       u32 session_id;
+       char *ifname;
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_session *session = NULL;
+       struct net *net = genl_info_net(info);
+
+       if (info->attrs[L2TP_ATTR_IFNAME]) {
+               ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]);
+               session = l2tp_session_find_by_ifname(net, ifname);
+       } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) &&
+                  (info->attrs[L2TP_ATTR_CONN_ID])) {
+               tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+               session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
+               tunnel = l2tp_tunnel_find(net, tunnel_id);
+               if (tunnel)
+                       session = l2tp_session_find(net, tunnel, session_id);
+       }
+
+       return session;
+}
+
+static int l2tp_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
+{
+       struct sk_buff *msg;
+       void *hdr;
+       int ret = -ENOBUFS;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+                         &l2tp_nl_family, 0, L2TP_CMD_NOOP);
+       if (IS_ERR(hdr)) {
+               ret = PTR_ERR(hdr);
+               goto err_out;
+       }
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
+
+err_out:
+       nlmsg_free(msg);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_tunnel_create(struct sk_buff *skb, struct genl_info *info)
+{
+       u32 tunnel_id;
+       u32 peer_tunnel_id;
+       int proto_version;
+       int fd;
+       int ret = 0;
+       struct l2tp_tunnel_cfg cfg = { 0, };
+       struct l2tp_tunnel *tunnel;
+       struct net *net = genl_info_net(info);
+
+       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+
+       if (!info->attrs[L2TP_ATTR_PEER_CONN_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       peer_tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_CONN_ID]);
+
+       if (!info->attrs[L2TP_ATTR_PROTO_VERSION]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       proto_version = nla_get_u8(info->attrs[L2TP_ATTR_PROTO_VERSION]);
+
+       if (!info->attrs[L2TP_ATTR_ENCAP_TYPE]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       cfg.encap = nla_get_u16(info->attrs[L2TP_ATTR_ENCAP_TYPE]);
+
+       fd = -1;
+       if (info->attrs[L2TP_ATTR_FD]) {
+               fd = nla_get_u32(info->attrs[L2TP_ATTR_FD]);
+       } else {
+               if (info->attrs[L2TP_ATTR_IP_SADDR])
+                       cfg.local_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_SADDR]);
+               if (info->attrs[L2TP_ATTR_IP_DADDR])
+                       cfg.peer_ip.s_addr = nla_get_be32(info->attrs[L2TP_ATTR_IP_DADDR]);
+               if (info->attrs[L2TP_ATTR_UDP_SPORT])
+                       cfg.local_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_SPORT]);
+               if (info->attrs[L2TP_ATTR_UDP_DPORT])
+                       cfg.peer_udp_port = nla_get_u16(info->attrs[L2TP_ATTR_UDP_DPORT]);
+               if (info->attrs[L2TP_ATTR_UDP_CSUM])
+                       cfg.use_udp_checksums = nla_get_flag(info->attrs[L2TP_ATTR_UDP_CSUM]);
+       }
+
+       if (info->attrs[L2TP_ATTR_DEBUG])
+               cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
+
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       if (tunnel != NULL) {
+               ret = -EEXIST;
+               goto out;
+       }
+
+       ret = -EINVAL;
+       switch (cfg.encap) {
+       case L2TP_ENCAPTYPE_UDP:
+       case L2TP_ENCAPTYPE_IP:
+               ret = l2tp_tunnel_create(net, fd, proto_version, tunnel_id,
+                                        peer_tunnel_id, &cfg, &tunnel);
+               break;
+       }
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_tunnel_delete(struct sk_buff *skb, struct genl_info *info)
+{
+       struct l2tp_tunnel *tunnel;
+       u32 tunnel_id;
+       int ret = 0;
+       struct net *net = genl_info_net(info);
+
+       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       if (tunnel == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       (void) l2tp_tunnel_delete(tunnel);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_tunnel_modify(struct sk_buff *skb, struct genl_info *info)
+{
+       struct l2tp_tunnel *tunnel;
+       u32 tunnel_id;
+       int ret = 0;
+       struct net *net = genl_info_net(info);
+
+       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       if (tunnel == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (info->attrs[L2TP_ATTR_DEBUG])
+               tunnel->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 pid, u32 seq, int flags,
+                              struct l2tp_tunnel *tunnel)
+{
+       void *hdr;
+       struct nlattr *nest;
+       struct sock *sk = NULL;
+       struct inet_sock *inet;
+
+       hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags,
+                         L2TP_CMD_TUNNEL_GET);
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
+
+       NLA_PUT_U8(skb, L2TP_ATTR_PROTO_VERSION, tunnel->version);
+       NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id);
+       NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id);
+       NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, tunnel->debug);
+       NLA_PUT_U16(skb, L2TP_ATTR_ENCAP_TYPE, tunnel->encap);
+
+       nest = nla_nest_start(skb, L2TP_ATTR_STATS);
+       if (nest == NULL)
+               goto nla_put_failure;
+
+       NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, tunnel->stats.tx_packets);
+       NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, tunnel->stats.tx_bytes);
+       NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, tunnel->stats.tx_errors);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, tunnel->stats.rx_packets);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, tunnel->stats.rx_bytes);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, tunnel->stats.rx_seq_discards);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, tunnel->stats.rx_oos_packets);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, tunnel->stats.rx_errors);
+       nla_nest_end(skb, nest);
+
+       sk = tunnel->sock;
+       if (!sk)
+               goto out;
+
+       inet = inet_sk(sk);
+
+       switch (tunnel->encap) {
+       case L2TP_ENCAPTYPE_UDP:
+               NLA_PUT_U16(skb, L2TP_ATTR_UDP_SPORT, ntohs(inet->inet_sport));
+               NLA_PUT_U16(skb, L2TP_ATTR_UDP_DPORT, ntohs(inet->inet_dport));
+               NLA_PUT_U8(skb, L2TP_ATTR_UDP_CSUM, (sk->sk_no_check != UDP_CSUM_NOXMIT));
+               /* NOBREAK */
+       case L2TP_ENCAPTYPE_IP:
+               NLA_PUT_BE32(skb, L2TP_ATTR_IP_SADDR, inet->inet_saddr);
+               NLA_PUT_BE32(skb, L2TP_ATTR_IP_DADDR, inet->inet_daddr);
+               break;
+       }
+
+out:
+       return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+       genlmsg_cancel(skb, hdr);
+       return -1;
+}
+
+static int l2tp_nl_cmd_tunnel_get(struct sk_buff *skb, struct genl_info *info)
+{
+       struct l2tp_tunnel *tunnel;
+       struct sk_buff *msg;
+       u32 tunnel_id;
+       int ret = -ENOBUFS;
+       struct net *net = genl_info_net(info);
+
+       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       if (tunnel == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = l2tp_nl_tunnel_send(msg, info->snd_pid, info->snd_seq,
+                                 NLM_F_ACK, tunnel);
+       if (ret < 0)
+               goto err_out;
+
+       return genlmsg_unicast(net, msg, info->snd_pid);
+
+err_out:
+       nlmsg_free(msg);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_tunnel_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       int ti = cb->args[0];
+       struct l2tp_tunnel *tunnel;
+       struct net *net = sock_net(skb->sk);
+
+       for (;;) {
+               tunnel = l2tp_tunnel_find_nth(net, ti);
+               if (tunnel == NULL)
+                       goto out;
+
+               if (l2tp_nl_tunnel_send(skb, NETLINK_CB(cb->skb).pid,
+                                       cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                       tunnel) <= 0)
+                       goto out;
+
+               ti++;
+       }
+
+out:
+       cb->args[0] = ti;
+
+       return skb->len;
+}
+
+static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *info)
+{
+       u32 tunnel_id = 0;
+       u32 session_id;
+       u32 peer_session_id;
+       int ret = 0;
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_session *session;
+       struct l2tp_session_cfg cfg = { 0, };
+       struct net *net = genl_info_net(info);
+
+       if (!info->attrs[L2TP_ATTR_CONN_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]);
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+       if (!tunnel) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (!info->attrs[L2TP_ATTR_SESSION_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]);
+       session = l2tp_session_find(net, tunnel, session_id);
+       if (session) {
+               ret = -EEXIST;
+               goto out;
+       }
+
+       if (!info->attrs[L2TP_ATTR_PEER_SESSION_ID]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       peer_session_id = nla_get_u32(info->attrs[L2TP_ATTR_PEER_SESSION_ID]);
+
+       if (!info->attrs[L2TP_ATTR_PW_TYPE]) {
+               ret = -EINVAL;
+               goto out;
+       }
+       cfg.pw_type = nla_get_u16(info->attrs[L2TP_ATTR_PW_TYPE]);
+       if (cfg.pw_type >= __L2TP_PWTYPE_MAX) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (tunnel->version > 2) {
+               if (info->attrs[L2TP_ATTR_OFFSET])
+                       cfg.offset = nla_get_u16(info->attrs[L2TP_ATTR_OFFSET]);
+
+               if (info->attrs[L2TP_ATTR_DATA_SEQ])
+                       cfg.data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]);
+
+               cfg.l2specific_type = L2TP_L2SPECTYPE_DEFAULT;
+               if (info->attrs[L2TP_ATTR_L2SPEC_TYPE])
+                       cfg.l2specific_type = nla_get_u8(info->attrs[L2TP_ATTR_L2SPEC_TYPE]);
+
+               cfg.l2specific_len = 4;
+               if (info->attrs[L2TP_ATTR_L2SPEC_LEN])
+                       cfg.l2specific_len = nla_get_u8(info->attrs[L2TP_ATTR_L2SPEC_LEN]);
+
+               if (info->attrs[L2TP_ATTR_COOKIE]) {
+                       u16 len = nla_len(info->attrs[L2TP_ATTR_COOKIE]);
+                       if (len > 8) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       cfg.cookie_len = len;
+                       memcpy(&cfg.cookie[0], nla_data(info->attrs[L2TP_ATTR_COOKIE]), len);
+               }
+               if (info->attrs[L2TP_ATTR_PEER_COOKIE]) {
+                       u16 len = nla_len(info->attrs[L2TP_ATTR_PEER_COOKIE]);
+                       if (len > 8) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       cfg.peer_cookie_len = len;
+                       memcpy(&cfg.peer_cookie[0], nla_data(info->attrs[L2TP_ATTR_PEER_COOKIE]), len);
+               }
+               if (info->attrs[L2TP_ATTR_IFNAME])
+                       cfg.ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]);
+
+               if (info->attrs[L2TP_ATTR_VLAN_ID])
+                       cfg.vlan_id = nla_get_u16(info->attrs[L2TP_ATTR_VLAN_ID]);
+       }
+
+       if (info->attrs[L2TP_ATTR_DEBUG])
+               cfg.debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
+
+       if (info->attrs[L2TP_ATTR_RECV_SEQ])
+               cfg.recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
+
+       if (info->attrs[L2TP_ATTR_SEND_SEQ])
+               cfg.send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
+
+       if (info->attrs[L2TP_ATTR_LNS_MODE])
+               cfg.lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
+
+       if (info->attrs[L2TP_ATTR_RECV_TIMEOUT])
+               cfg.reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]);
+
+       if (info->attrs[L2TP_ATTR_MTU])
+               cfg.mtu = nla_get_u16(info->attrs[L2TP_ATTR_MTU]);
+
+       if (info->attrs[L2TP_ATTR_MRU])
+               cfg.mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]);
+
+       if ((l2tp_nl_cmd_ops[cfg.pw_type] == NULL) ||
+           (l2tp_nl_cmd_ops[cfg.pw_type]->session_create == NULL)) {
+               ret = -EPROTONOSUPPORT;
+               goto out;
+       }
+
+       /* Check that pseudowire-specific params are present */
+       switch (cfg.pw_type) {
+       case L2TP_PWTYPE_NONE:
+               break;
+       case L2TP_PWTYPE_ETH_VLAN:
+               if (!info->attrs[L2TP_ATTR_VLAN_ID]) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               break;
+       case L2TP_PWTYPE_ETH:
+               break;
+       case L2TP_PWTYPE_PPP:
+       case L2TP_PWTYPE_PPP_AC:
+               break;
+       case L2TP_PWTYPE_IP:
+       default:
+               ret = -EPROTONOSUPPORT;
+               break;
+       }
+
+       ret = -EPROTONOSUPPORT;
+       if (l2tp_nl_cmd_ops[cfg.pw_type]->session_create)
+               ret = (*l2tp_nl_cmd_ops[cfg.pw_type]->session_create)(net, tunnel_id,
+                       session_id, peer_session_id, &cfg);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *info)
+{
+       int ret = 0;
+       struct l2tp_session *session;
+       u16 pw_type;
+
+       session = l2tp_nl_session_find(info);
+       if (session == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       pw_type = session->pwtype;
+       if (pw_type < __L2TP_PWTYPE_MAX)
+               if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete)
+                       ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *info)
+{
+       int ret = 0;
+       struct l2tp_session *session;
+
+       session = l2tp_nl_session_find(info);
+       if (session == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (info->attrs[L2TP_ATTR_DEBUG])
+               session->debug = nla_get_u32(info->attrs[L2TP_ATTR_DEBUG]);
+
+       if (info->attrs[L2TP_ATTR_DATA_SEQ])
+               session->data_seq = nla_get_u8(info->attrs[L2TP_ATTR_DATA_SEQ]);
+
+       if (info->attrs[L2TP_ATTR_RECV_SEQ])
+               session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
+
+       if (info->attrs[L2TP_ATTR_SEND_SEQ])
+               session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
+
+       if (info->attrs[L2TP_ATTR_LNS_MODE])
+               session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
+
+       if (info->attrs[L2TP_ATTR_RECV_TIMEOUT])
+               session->reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]);
+
+       if (info->attrs[L2TP_ATTR_MTU])
+               session->mtu = nla_get_u16(info->attrs[L2TP_ATTR_MTU]);
+
+       if (info->attrs[L2TP_ATTR_MRU])
+               session->mru = nla_get_u16(info->attrs[L2TP_ATTR_MRU]);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_session_send(struct sk_buff *skb, u32 pid, u32 seq, int flags,
+                               struct l2tp_session *session)
+{
+       void *hdr;
+       struct nlattr *nest;
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       struct sock *sk = NULL;
+
+       sk = tunnel->sock;
+
+       hdr = genlmsg_put(skb, pid, seq, &l2tp_nl_family, flags, L2TP_CMD_SESSION_GET);
+       if (IS_ERR(hdr))
+               return PTR_ERR(hdr);
+
+       NLA_PUT_U32(skb, L2TP_ATTR_CONN_ID, tunnel->tunnel_id);
+       NLA_PUT_U32(skb, L2TP_ATTR_SESSION_ID, session->session_id);
+       NLA_PUT_U32(skb, L2TP_ATTR_PEER_CONN_ID, tunnel->peer_tunnel_id);
+       NLA_PUT_U32(skb, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id);
+       NLA_PUT_U32(skb, L2TP_ATTR_DEBUG, session->debug);
+       NLA_PUT_U16(skb, L2TP_ATTR_PW_TYPE, session->pwtype);
+       NLA_PUT_U16(skb, L2TP_ATTR_MTU, session->mtu);
+       if (session->mru)
+               NLA_PUT_U16(skb, L2TP_ATTR_MRU, session->mru);
+
+       if (session->ifname && session->ifname[0])
+               NLA_PUT_STRING(skb, L2TP_ATTR_IFNAME, session->ifname);
+       if (session->cookie_len)
+               NLA_PUT(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0]);
+       if (session->peer_cookie_len)
+               NLA_PUT(skb, L2TP_ATTR_PEER_COOKIE, session->peer_cookie_len, &session->peer_cookie[0]);
+       NLA_PUT_U8(skb, L2TP_ATTR_RECV_SEQ, session->recv_seq);
+       NLA_PUT_U8(skb, L2TP_ATTR_SEND_SEQ, session->send_seq);
+       NLA_PUT_U8(skb, L2TP_ATTR_LNS_MODE, session->lns_mode);
+#ifdef CONFIG_XFRM
+       if ((sk) && (sk->sk_policy[0] || sk->sk_policy[1]))
+               NLA_PUT_U8(skb, L2TP_ATTR_USING_IPSEC, 1);
+#endif
+       if (session->reorder_timeout)
+               NLA_PUT_MSECS(skb, L2TP_ATTR_RECV_TIMEOUT, session->reorder_timeout);
+
+       nest = nla_nest_start(skb, L2TP_ATTR_STATS);
+       if (nest == NULL)
+               goto nla_put_failure;
+       NLA_PUT_U64(skb, L2TP_ATTR_TX_PACKETS, session->stats.tx_packets);
+       NLA_PUT_U64(skb, L2TP_ATTR_TX_BYTES, session->stats.tx_bytes);
+       NLA_PUT_U64(skb, L2TP_ATTR_TX_ERRORS, session->stats.tx_errors);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_PACKETS, session->stats.rx_packets);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_BYTES, session->stats.rx_bytes);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_SEQ_DISCARDS, session->stats.rx_seq_discards);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_OOS_PACKETS, session->stats.rx_oos_packets);
+       NLA_PUT_U64(skb, L2TP_ATTR_RX_ERRORS, session->stats.rx_errors);
+       nla_nest_end(skb, nest);
+
+       return genlmsg_end(skb, hdr);
+
+ nla_put_failure:
+       genlmsg_cancel(skb, hdr);
+       return -1;
+}
+
+static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info)
+{
+       struct l2tp_session *session;
+       struct sk_buff *msg;
+       int ret;
+
+       session = l2tp_nl_session_find(info);
+       if (session == NULL) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = l2tp_nl_session_send(msg, info->snd_pid, info->snd_seq,
+                                  0, session);
+       if (ret < 0)
+               goto err_out;
+
+       return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid);
+
+err_out:
+       nlmsg_free(msg);
+
+out:
+       return ret;
+}
+
+static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct net *net = sock_net(skb->sk);
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel = NULL;
+       int ti = cb->args[0];
+       int si = cb->args[1];
+
+       for (;;) {
+               if (tunnel == NULL) {
+                       tunnel = l2tp_tunnel_find_nth(net, ti);
+                       if (tunnel == NULL)
+                               goto out;
+               }
+
+               session = l2tp_session_find_nth(tunnel, si);
+               if (session == NULL) {
+                       ti++;
+                       tunnel = NULL;
+                       si = 0;
+                       continue;
+               }
+
+               if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).pid,
+                                        cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                        session) <= 0)
+                       break;
+
+               si++;
+       }
+
+out:
+       cb->args[0] = ti;
+       cb->args[1] = si;
+
+       return skb->len;
+}
+
+static struct nla_policy l2tp_nl_policy[L2TP_ATTR_MAX + 1] = {
+       [L2TP_ATTR_NONE]                = { .type = NLA_UNSPEC, },
+       [L2TP_ATTR_PW_TYPE]             = { .type = NLA_U16, },
+       [L2TP_ATTR_ENCAP_TYPE]          = { .type = NLA_U16, },
+       [L2TP_ATTR_OFFSET]              = { .type = NLA_U16, },
+       [L2TP_ATTR_DATA_SEQ]            = { .type = NLA_U8, },
+       [L2TP_ATTR_L2SPEC_TYPE]         = { .type = NLA_U8, },
+       [L2TP_ATTR_L2SPEC_LEN]          = { .type = NLA_U8, },
+       [L2TP_ATTR_PROTO_VERSION]       = { .type = NLA_U8, },
+       [L2TP_ATTR_CONN_ID]             = { .type = NLA_U32, },
+       [L2TP_ATTR_PEER_CONN_ID]        = { .type = NLA_U32, },
+       [L2TP_ATTR_SESSION_ID]          = { .type = NLA_U32, },
+       [L2TP_ATTR_PEER_SESSION_ID]     = { .type = NLA_U32, },
+       [L2TP_ATTR_UDP_CSUM]            = { .type = NLA_U8, },
+       [L2TP_ATTR_VLAN_ID]             = { .type = NLA_U16, },
+       [L2TP_ATTR_DEBUG]               = { .type = NLA_U32, },
+       [L2TP_ATTR_RECV_SEQ]            = { .type = NLA_U8, },
+       [L2TP_ATTR_SEND_SEQ]            = { .type = NLA_U8, },
+       [L2TP_ATTR_LNS_MODE]            = { .type = NLA_U8, },
+       [L2TP_ATTR_USING_IPSEC]         = { .type = NLA_U8, },
+       [L2TP_ATTR_RECV_TIMEOUT]        = { .type = NLA_MSECS, },
+       [L2TP_ATTR_FD]                  = { .type = NLA_U32, },
+       [L2TP_ATTR_IP_SADDR]            = { .type = NLA_U32, },
+       [L2TP_ATTR_IP_DADDR]            = { .type = NLA_U32, },
+       [L2TP_ATTR_UDP_SPORT]           = { .type = NLA_U16, },
+       [L2TP_ATTR_UDP_DPORT]           = { .type = NLA_U16, },
+       [L2TP_ATTR_MTU]                 = { .type = NLA_U16, },
+       [L2TP_ATTR_MRU]                 = { .type = NLA_U16, },
+       [L2TP_ATTR_STATS]               = { .type = NLA_NESTED, },
+       [L2TP_ATTR_IFNAME] = {
+               .type = NLA_NUL_STRING,
+               .len = IFNAMSIZ - 1,
+       },
+       [L2TP_ATTR_COOKIE] = {
+               .type = NLA_BINARY,
+               .len = 8,
+       },
+       [L2TP_ATTR_PEER_COOKIE] = {
+               .type = NLA_BINARY,
+               .len = 8,
+       },
+};
+
+static struct genl_ops l2tp_nl_ops[] = {
+       {
+               .cmd = L2TP_CMD_NOOP,
+               .doit = l2tp_nl_cmd_noop,
+               .policy = l2tp_nl_policy,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = L2TP_CMD_TUNNEL_CREATE,
+               .doit = l2tp_nl_cmd_tunnel_create,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_TUNNEL_DELETE,
+               .doit = l2tp_nl_cmd_tunnel_delete,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_TUNNEL_MODIFY,
+               .doit = l2tp_nl_cmd_tunnel_modify,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_TUNNEL_GET,
+               .doit = l2tp_nl_cmd_tunnel_get,
+               .dumpit = l2tp_nl_cmd_tunnel_dump,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_SESSION_CREATE,
+               .doit = l2tp_nl_cmd_session_create,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_SESSION_DELETE,
+               .doit = l2tp_nl_cmd_session_delete,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_SESSION_MODIFY,
+               .doit = l2tp_nl_cmd_session_modify,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = L2TP_CMD_SESSION_GET,
+               .doit = l2tp_nl_cmd_session_get,
+               .dumpit = l2tp_nl_cmd_session_dump,
+               .policy = l2tp_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+};
+
+int l2tp_nl_register_ops(enum l2tp_pwtype pw_type, const struct l2tp_nl_cmd_ops *ops)
+{
+       int ret;
+
+       ret = -EINVAL;
+       if (pw_type >= __L2TP_PWTYPE_MAX)
+               goto err;
+
+       genl_lock();
+       ret = -EBUSY;
+       if (l2tp_nl_cmd_ops[pw_type])
+               goto out;
+
+       l2tp_nl_cmd_ops[pw_type] = ops;
+
+out:
+       genl_unlock();
+err:
+       return 0;
+}
+EXPORT_SYMBOL_GPL(l2tp_nl_register_ops);
+
+void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type)
+{
+       if (pw_type < __L2TP_PWTYPE_MAX) {
+               genl_lock();
+               l2tp_nl_cmd_ops[pw_type] = NULL;
+               genl_unlock();
+       }
+}
+EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);
+
+static int l2tp_nl_init(void)
+{
+       int err;
+
+       printk(KERN_INFO "L2TP netlink interface\n");
+       err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops,
+                                           ARRAY_SIZE(l2tp_nl_ops));
+
+       return err;
+}
+
+static void l2tp_nl_cleanup(void)
+{
+       genl_unregister_family(&l2tp_nl_family);
+}
+
+module_init(l2tp_nl_init);
+module_exit(l2tp_nl_cleanup);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("L2TP netlink");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("net-pf-" __stringify(PF_NETLINK) "-proto-" \
+            __stringify(NETLINK_GENERIC) "-type-" "l2tp");
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
new file mode 100644 (file)
index 0000000..90d82b3
--- /dev/null
@@ -0,0 +1,1837 @@
+/*****************************************************************************
+ * Linux PPP over L2TP (PPPoX/PPPoL2TP) Sockets
+ *
+ * PPPoX    --- Generic PPP encapsulation socket family
+ * PPPoL2TP --- PPP over L2TP (RFC 2661)
+ *
+ * Version:    2.0.0
+ *
+ * Authors:    James Chapman (jchapman@katalix.com)
+ *
+ * Based on original work by Martijn van Oosterhout <kleptog@svana.org>
+ *
+ * License:
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ */
+
+/* This driver handles only L2TP data frames; control frames are handled by a
+ * userspace application.
+ *
+ * To send data in an L2TP session, userspace opens a PPPoL2TP socket and
+ * attaches it to a bound UDP socket with local tunnel_id / session_id and
+ * peer tunnel_id / session_id set. Data can then be sent or received using
+ * regular socket sendmsg() / recvmsg() calls. Kernel parameters of the socket
+ * can be read or modified using ioctl() or [gs]etsockopt() calls.
+ *
+ * When a PPPoL2TP socket is connected with local and peer session_id values
+ * zero, the socket is treated as a special tunnel management socket.
+ *
+ * Here's example userspace code to create a socket for sending/receiving data
+ * over an L2TP session:-
+ *
+ *     struct sockaddr_pppol2tp sax;
+ *     int fd;
+ *     int session_fd;
+ *
+ *     fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+ *
+ *     sax.sa_family = AF_PPPOX;
+ *     sax.sa_protocol = PX_PROTO_OL2TP;
+ *     sax.pppol2tp.fd = tunnel_fd;    // bound UDP socket
+ *     sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr;
+ *     sax.pppol2tp.addr.sin_port = addr->sin_port;
+ *     sax.pppol2tp.addr.sin_family = AF_INET;
+ *     sax.pppol2tp.s_tunnel  = tunnel_id;
+ *     sax.pppol2tp.s_session = session_id;
+ *     sax.pppol2tp.d_tunnel  = peer_tunnel_id;
+ *     sax.pppol2tp.d_session = peer_session_id;
+ *
+ *     session_fd = connect(fd, (struct sockaddr *)&sax, sizeof(sax));
+ *
+ * A pppd plugin that allows PPP traffic to be carried over L2TP using
+ * this driver is available from the OpenL2TP project at
+ * http://openl2tp.sourceforge.net.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/if_pppox.h>
+#include <linux/if_pppol2tp.h>
+#include <net/sock.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/file.h>
+#include <linux/hash.h>
+#include <linux/sort.h>
+#include <linux/proc_fs.h>
+#include <linux/l2tp.h>
+#include <linux/nsproxy.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/dst.h>
+#include <net/ip.h>
+#include <net/udp.h>
+#include <net/xfrm.h>
+
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+
+#include "l2tp_core.h"
+
+#define PPPOL2TP_DRV_VERSION   "V2.0"
+
+/* Space for UDP, L2TP and PPP headers */
+#define PPPOL2TP_HEADER_OVERHEAD       40
+
+#define PRINTK(_mask, _type, _lvl, _fmt, args...)                      \
+       do {                                                            \
+               if ((_mask) & (_type))                                  \
+                       printk(_lvl "PPPOL2TP: " _fmt, ##args);         \
+       } while (0)
+
+/* Number of bytes to build transmit L2TP headers.
+ * Unfortunately the size is different depending on whether sequence numbers
+ * are enabled.
+ */
+#define PPPOL2TP_L2TP_HDR_SIZE_SEQ             10
+#define PPPOL2TP_L2TP_HDR_SIZE_NOSEQ           6
+
+/* Private data of each session. This data lives at the end of struct
+ * l2tp_session, referenced via session->priv[].
+ */
+struct pppol2tp_session {
+       int                     owner;          /* pid that opened the socket */
+
+       struct sock             *sock;          /* Pointer to the session
+                                                * PPPoX socket */
+       struct sock             *tunnel_sock;   /* Pointer to the tunnel UDP
+                                                * socket */
+       int                     flags;          /* accessed by PPPIOCGFLAGS.
+                                                * Unused. */
+};
+
+static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+
+static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit , NULL };
+static const struct proto_ops pppol2tp_ops;
+
+/* Helpers to obtain tunnel/session contexts from sockets.
+ */
+static inline struct l2tp_session *pppol2tp_sock_to_session(struct sock *sk)
+{
+       struct l2tp_session *session;
+
+       if (sk == NULL)
+               return NULL;
+
+       sock_hold(sk);
+       session = (struct l2tp_session *)(sk->sk_user_data);
+       if (session == NULL) {
+               sock_put(sk);
+               goto out;
+       }
+
+       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
+out:
+       return session;
+}
+
+/*****************************************************************************
+ * Receive data handling
+ *****************************************************************************/
+
+static int pppol2tp_recv_payload_hook(struct sk_buff *skb)
+{
+       /* Skip PPP header, if present.  In testing, Microsoft L2TP clients
+        * don't send the PPP header (PPP header compression enabled), but
+        * other clients can include the header. So we cope with both cases
+        * here. The PPP header is always FF03 when using L2TP.
+        *
+        * Note that skb->data[] isn't dereferenced from a u16 ptr here since
+        * the field may be unaligned.
+        */
+       if (!pskb_may_pull(skb, 2))
+               return 1;
+
+       if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
+               skb_pull(skb, 2);
+
+       return 0;
+}
+
+/* Receive message. This is the recvmsg for the PPPoL2TP socket.
+ */
+static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
+                           struct msghdr *msg, size_t len,
+                           int flags)
+{
+       int err;
+       struct sk_buff *skb;
+       struct sock *sk = sock->sk;
+
+       err = -EIO;
+       if (sk->sk_state & PPPOX_BOUND)
+               goto end;
+
+       msg->msg_namelen = 0;
+
+       err = 0;
+       skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+                               flags & MSG_DONTWAIT, &err);
+       if (!skb)
+               goto end;
+
+       if (len > skb->len)
+               len = skb->len;
+       else if (len < skb->len)
+               msg->msg_flags |= MSG_TRUNC;
+
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
+       if (likely(err == 0))
+               err = len;
+
+       kfree_skb(skb);
+end:
+       return err;
+}
+
+static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct sock *sk = NULL;
+
+       /* If the socket is bound, send it in to PPP's input queue. Otherwise
+        * queue it on the session socket.
+        */
+       sk = ps->sock;
+       if (sk == NULL)
+               goto no_sock;
+
+       if (sk->sk_state & PPPOX_BOUND) {
+               struct pppox_sock *po;
+               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+                      "%s: recv %d byte data frame, passing to ppp\n",
+                      session->name, data_len);
+
+               /* We need to forget all info related to the L2TP packet
+                * gathered in the skb as we are going to reuse the same
+                * skb for the inner packet.
+                * Namely we need to:
+                * - reset xfrm (IPSec) information as it applies to
+                *   the outer L2TP packet and not to the inner one
+                * - release the dst to force a route lookup on the inner
+                *   IP packet since skb->dst currently points to the dst
+                *   of the UDP tunnel
+                * - reset netfilter information as it doesn't apply
+                *   to the inner packet either
+                */
+               secpath_reset(skb);
+               skb_dst_drop(skb);
+               nf_reset(skb);
+
+               po = pppox_sk(sk);
+               ppp_input(&po->chan, skb);
+       } else {
+               PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
+                      "%s: socket not bound\n", session->name);
+
+               /* Not bound. Nothing we can do, so discard. */
+               session->stats.rx_errors++;
+               kfree_skb(skb);
+       }
+
+       return;
+
+no_sock:
+       PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
+              "%s: no socket\n", session->name);
+       kfree_skb(skb);
+}
+
+static void pppol2tp_session_sock_hold(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+
+       if (ps->sock)
+               sock_hold(ps->sock);
+}
+
+static void pppol2tp_session_sock_put(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+
+       if (ps->sock)
+               sock_put(ps->sock);
+}
+
+/************************************************************************
+ * Transmit handling
+ ***********************************************************************/
+
+/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket.  We come here
+ * when a user application does a sendmsg() on the session socket. L2TP and
+ * PPP headers must be inserted into the user's data.
+ */
+static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+                           size_t total_len)
+{
+       static const unsigned char ppph[2] = { 0xff, 0x03 };
+       struct sock *sk = sock->sk;
+       struct sk_buff *skb;
+       int error;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel;
+       struct pppol2tp_session *ps;
+       int uhlen;
+
+       error = -ENOTCONN;
+       if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
+               goto error;
+
+       /* Get session and tunnel contexts */
+       error = -EBADF;
+       session = pppol2tp_sock_to_session(sk);
+       if (session == NULL)
+               goto error;
+
+       ps = l2tp_session_priv(session);
+       tunnel = l2tp_sock_to_tunnel(ps->tunnel_sock);
+       if (tunnel == NULL)
+               goto error_put_sess;
+
+       uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0;
+
+       /* Allocate a socket buffer */
+       error = -ENOMEM;
+       skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
+                          uhlen + session->hdr_len +
+                          sizeof(ppph) + total_len,
+                          0, GFP_KERNEL);
+       if (!skb)
+               goto error_put_sess_tun;
+
+       /* Reserve space for headers. */
+       skb_reserve(skb, NET_SKB_PAD);
+       skb_reset_network_header(skb);
+       skb_reserve(skb, sizeof(struct iphdr));
+       skb_reset_transport_header(skb);
+       skb_reserve(skb, uhlen);
+
+       /* Add PPP header */
+       skb->data[0] = ppph[0];
+       skb->data[1] = ppph[1];
+       skb_put(skb, 2);
+
+       /* Copy user data into skb */
+       error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);
+       if (error < 0) {
+               kfree_skb(skb);
+               goto error_put_sess_tun;
+       }
+       skb_put(skb, total_len);
+
+       l2tp_xmit_skb(session, skb, session->hdr_len);
+
+       sock_put(ps->tunnel_sock);
+
+       return error;
+
+error_put_sess_tun:
+       sock_put(ps->tunnel_sock);
+error_put_sess:
+       sock_put(sk);
+error:
+       return error;
+}
+
+/* Transmit function called by generic PPP driver.  Sends PPP frame
+ * over PPPoL2TP socket.
+ *
+ * This is almost the same as pppol2tp_sendmsg(), but rather than
+ * being called with a msghdr from userspace, it is called with a skb
+ * from the kernel.
+ *
+ * The supplied skb from ppp doesn't have enough headroom for the
+ * insertion of L2TP, UDP and IP headers so we need to allocate more
+ * headroom in the skb. This will create a cloned skb. But we must be
+ * careful in the error case because the caller will expect to free
+ * the skb it supplied, not our cloned skb. So we take care to always
+ * leave the original skb unfreed if we return an error.
+ */
+static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+       static const u8 ppph[2] = { 0xff, 0x03 };
+       struct sock *sk = (struct sock *) chan->private;
+       struct sock *sk_tun;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel;
+       struct pppol2tp_session *ps;
+       int old_headroom;
+       int new_headroom;
+
+       if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
+               goto abort;
+
+       /* Get session and tunnel contexts from the socket */
+       session = pppol2tp_sock_to_session(sk);
+       if (session == NULL)
+               goto abort;
+
+       ps = l2tp_session_priv(session);
+       sk_tun = ps->tunnel_sock;
+       if (sk_tun == NULL)
+               goto abort_put_sess;
+       tunnel = l2tp_sock_to_tunnel(sk_tun);
+       if (tunnel == NULL)
+               goto abort_put_sess;
+
+       old_headroom = skb_headroom(skb);
+       if (skb_cow_head(skb, sizeof(ppph)))
+               goto abort_put_sess_tun;
+
+       new_headroom = skb_headroom(skb);
+       skb->truesize += new_headroom - old_headroom;
+
+       /* Setup PPP header */
+       __skb_push(skb, sizeof(ppph));
+       skb->data[0] = ppph[0];
+       skb->data[1] = ppph[1];
+
+       l2tp_xmit_skb(session, skb, session->hdr_len);
+
+       sock_put(sk_tun);
+       sock_put(sk);
+       return 1;
+
+abort_put_sess_tun:
+       sock_put(sk_tun);
+abort_put_sess:
+       sock_put(sk);
+abort:
+       /* Free the original skb */
+       kfree_skb(skb);
+       return 1;
+}
+
+/*****************************************************************************
+ * Session (and tunnel control) socket create/destroy.
+ *****************************************************************************/
+
+/* Called by l2tp_core when a session socket is being closed.
+ */
+static void pppol2tp_session_close(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct sock *sk = ps->sock;
+       struct sk_buff *skb;
+
+       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
+       if (session->session_id == 0)
+               goto out;
+
+       if (sk != NULL) {
+               lock_sock(sk);
+
+               if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+                       pppox_unbind_sock(sk);
+                       sk->sk_state = PPPOX_DEAD;
+                       sk->sk_state_change(sk);
+               }
+
+               /* Purge any queued data */
+               skb_queue_purge(&sk->sk_receive_queue);
+               skb_queue_purge(&sk->sk_write_queue);
+               while ((skb = skb_dequeue(&session->reorder_q))) {
+                       kfree_skb(skb);
+                       sock_put(sk);
+               }
+
+               release_sock(sk);
+       }
+
+out:
+       return;
+}
+
+/* Really kill the session socket. (Called from sock_put() if
+ * refcnt == 0.)
+ */
+static void pppol2tp_session_destruct(struct sock *sk)
+{
+       struct l2tp_session *session;
+
+       if (sk->sk_user_data != NULL) {
+               session = sk->sk_user_data;
+               if (session == NULL)
+                       goto out;
+
+               sk->sk_user_data = NULL;
+               BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+               l2tp_session_dec_refcount(session);
+       }
+
+out:
+       return;
+}
+
+/* Called when the PPPoX socket (session) is closed.
+ */
+static int pppol2tp_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct l2tp_session *session;
+       int error;
+
+       if (!sk)
+               return 0;
+
+       error = -EBADF;
+       lock_sock(sk);
+       if (sock_flag(sk, SOCK_DEAD) != 0)
+               goto error;
+
+       pppox_unbind_sock(sk);
+
+       /* Signal the death of the socket. */
+       sk->sk_state = PPPOX_DEAD;
+       sock_orphan(sk);
+       sock->sk = NULL;
+
+       session = pppol2tp_sock_to_session(sk);
+
+       /* Purge any queued data */
+       skb_queue_purge(&sk->sk_receive_queue);
+       skb_queue_purge(&sk->sk_write_queue);
+       if (session != NULL) {
+               struct sk_buff *skb;
+               while ((skb = skb_dequeue(&session->reorder_q))) {
+                       kfree_skb(skb);
+                       sock_put(sk);
+               }
+               sock_put(sk);
+       }
+
+       release_sock(sk);
+
+       /* This will delete the session context via
+        * pppol2tp_session_destruct() if the socket's refcnt drops to
+        * zero.
+        */
+       sock_put(sk);
+
+       return 0;
+
+error:
+       release_sock(sk);
+       return error;
+}
+
+static struct proto pppol2tp_sk_proto = {
+       .name     = "PPPOL2TP",
+       .owner    = THIS_MODULE,
+       .obj_size = sizeof(struct pppox_sock),
+};
+
+static int pppol2tp_backlog_recv(struct sock *sk, struct sk_buff *skb)
+{
+       int rc;
+
+       rc = l2tp_udp_encap_recv(sk, skb);
+       if (rc)
+               kfree_skb(skb);
+
+       return NET_RX_SUCCESS;
+}
+
+/* socket() handler. Initialize a new struct sock.
+ */
+static int pppol2tp_create(struct net *net, struct socket *sock)
+{
+       int error = -ENOMEM;
+       struct sock *sk;
+
+       sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto);
+       if (!sk)
+               goto out;
+
+       sock_init_data(sock, sk);
+
+       sock->state  = SS_UNCONNECTED;
+       sock->ops    = &pppol2tp_ops;
+
+       sk->sk_backlog_rcv = pppol2tp_backlog_recv;
+       sk->sk_protocol    = PX_PROTO_OL2TP;
+       sk->sk_family      = PF_PPPOX;
+       sk->sk_state       = PPPOX_NONE;
+       sk->sk_type        = SOCK_STREAM;
+       sk->sk_destruct    = pppol2tp_session_destruct;
+
+       error = 0;
+
+out:
+       return error;
+}
+
+#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
+static void pppol2tp_show(struct seq_file *m, void *arg)
+{
+       struct l2tp_session *session = arg;
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+
+       if (ps) {
+               struct pppox_sock *po = pppox_sk(ps->sock);
+               if (po)
+                       seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+       }
+}
+#endif
+
+/* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
+ */
+static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
+                           int sockaddr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr;
+       struct sockaddr_pppol2tpv3 *sp3 = (struct sockaddr_pppol2tpv3 *) uservaddr;
+       struct pppox_sock *po = pppox_sk(sk);
+       struct l2tp_session *session = NULL;
+       struct l2tp_tunnel *tunnel;
+       struct pppol2tp_session *ps;
+       struct dst_entry *dst;
+       struct l2tp_session_cfg cfg = { 0, };
+       int error = 0;
+       u32 tunnel_id, peer_tunnel_id;
+       u32 session_id, peer_session_id;
+       int ver = 2;
+       int fd;
+
+       lock_sock(sk);
+
+       error = -EINVAL;
+       if (sp->sa_protocol != PX_PROTO_OL2TP)
+               goto end;
+
+       /* Check for already bound sockets */
+       error = -EBUSY;
+       if (sk->sk_state & PPPOX_CONNECTED)
+               goto end;
+
+       /* We don't supporting rebinding anyway */
+       error = -EALREADY;
+       if (sk->sk_user_data)
+               goto end; /* socket is already attached */
+
+       /* Get params from socket address. Handle L2TPv2 and L2TPv3 */
+       if (sockaddr_len == sizeof(struct sockaddr_pppol2tp)) {
+               fd = sp->pppol2tp.fd;
+               tunnel_id = sp->pppol2tp.s_tunnel;
+               peer_tunnel_id = sp->pppol2tp.d_tunnel;
+               session_id = sp->pppol2tp.s_session;
+               peer_session_id = sp->pppol2tp.d_session;
+       } else if (sockaddr_len == sizeof(struct sockaddr_pppol2tpv3)) {
+               ver = 3;
+               fd = sp3->pppol2tp.fd;
+               tunnel_id = sp3->pppol2tp.s_tunnel;
+               peer_tunnel_id = sp3->pppol2tp.d_tunnel;
+               session_id = sp3->pppol2tp.s_session;
+               peer_session_id = sp3->pppol2tp.d_session;
+       } else {
+               error = -EINVAL;
+               goto end; /* bad socket address */
+       }
+
+       /* Don't bind if tunnel_id is 0 */
+       error = -EINVAL;
+       if (tunnel_id == 0)
+               goto end;
+
+       tunnel = l2tp_tunnel_find(sock_net(sk), tunnel_id);
+
+       /* Special case: create tunnel context if session_id and
+        * peer_session_id is 0. Otherwise look up tunnel using supplied
+        * tunnel id.
+        */
+       if ((session_id == 0) && (peer_session_id == 0)) {
+               if (tunnel == NULL) {
+                       struct l2tp_tunnel_cfg tcfg = {
+                               .encap = L2TP_ENCAPTYPE_UDP,
+                               .debug = 0,
+                       };
+                       error = l2tp_tunnel_create(sock_net(sk), fd, ver, tunnel_id, peer_tunnel_id, &tcfg, &tunnel);
+                       if (error < 0)
+                               goto end;
+               }
+       } else {
+               /* Error if we can't find the tunnel */
+               error = -ENOENT;
+               if (tunnel == NULL)
+                       goto end;
+
+               /* Error if socket is not prepped */
+               if (tunnel->sock == NULL)
+                       goto end;
+       }
+
+       if (tunnel->recv_payload_hook == NULL)
+               tunnel->recv_payload_hook = pppol2tp_recv_payload_hook;
+
+       if (tunnel->peer_tunnel_id == 0) {
+               if (ver == 2)
+                       tunnel->peer_tunnel_id = sp->pppol2tp.d_tunnel;
+               else
+                       tunnel->peer_tunnel_id = sp3->pppol2tp.d_tunnel;
+       }
+
+       /* Create session if it doesn't already exist. We handle the
+        * case where a session was previously created by the netlink
+        * interface by checking that the session doesn't already have
+        * a socket and its tunnel socket are what we expect. If any
+        * of those checks fail, return EEXIST to the caller.
+        */
+       session = l2tp_session_find(sock_net(sk), tunnel, session_id);
+       if (session == NULL) {
+               /* Default MTU must allow space for UDP/L2TP/PPP
+                * headers.
+                */
+               cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
+
+               /* Allocate and initialize a new session context. */
+               session = l2tp_session_create(sizeof(struct pppol2tp_session),
+                                             tunnel, session_id,
+                                             peer_session_id, &cfg);
+               if (session == NULL) {
+                       error = -ENOMEM;
+                       goto end;
+               }
+       } else {
+               ps = l2tp_session_priv(session);
+               error = -EEXIST;
+               if (ps->sock != NULL)
+                       goto end;
+
+               /* consistency checks */
+               if (ps->tunnel_sock != tunnel->sock)
+                       goto end;
+       }
+
+       /* Associate session with its PPPoL2TP socket */
+       ps = l2tp_session_priv(session);
+       ps->owner            = current->pid;
+       ps->sock             = sk;
+       ps->tunnel_sock = tunnel->sock;
+
+       session->recv_skb       = pppol2tp_recv;
+       session->session_close  = pppol2tp_session_close;
+#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
+       session->show           = pppol2tp_show;
+#endif
+
+       /* We need to know each time a skb is dropped from the reorder
+        * queue.
+        */
+       session->ref = pppol2tp_session_sock_hold;
+       session->deref = pppol2tp_session_sock_put;
+
+       /* If PMTU discovery was enabled, use the MTU that was discovered */
+       dst = sk_dst_get(sk);
+       if (dst != NULL) {
+               u32 pmtu = dst_mtu(__sk_dst_get(sk));
+               if (pmtu != 0)
+                       session->mtu = session->mru = pmtu -
+                               PPPOL2TP_HEADER_OVERHEAD;
+               dst_release(dst);
+       }
+
+       /* Special case: if source & dest session_id == 0x0000, this
+        * socket is being created to manage the tunnel. Just set up
+        * the internal context for use by ioctl() and sockopt()
+        * handlers.
+        */
+       if ((session->session_id == 0) &&
+           (session->peer_session_id == 0)) {
+               error = 0;
+               goto out_no_ppp;
+       }
+
+       /* The only header we need to worry about is the L2TP
+        * header. This size is different depending on whether
+        * sequence numbers are enabled for the data channel.
+        */
+       po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+
+       po->chan.private = sk;
+       po->chan.ops     = &pppol2tp_chan_ops;
+       po->chan.mtu     = session->mtu;
+
+       error = ppp_register_net_channel(sock_net(sk), &po->chan);
+       if (error)
+               goto end;
+
+out_no_ppp:
+       /* This is how we get the session context from the socket. */
+       sk->sk_user_data = session;
+       sk->sk_state = PPPOX_CONNECTED;
+       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+              "%s: created\n", session->name);
+
+end:
+       release_sock(sk);
+
+       return error;
+}
+
+#ifdef CONFIG_L2TP_V3
+
+/* Called when creating sessions via the netlink interface.
+ */
+static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
+{
+       int error;
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_session *session;
+       struct pppol2tp_session *ps;
+
+       tunnel = l2tp_tunnel_find(net, tunnel_id);
+
+       /* Error if we can't find the tunnel */
+       error = -ENOENT;
+       if (tunnel == NULL)
+               goto out;
+
+       /* Error if tunnel socket is not prepped */
+       if (tunnel->sock == NULL)
+               goto out;
+
+       /* Check that this session doesn't already exist */
+       error = -EEXIST;
+       session = l2tp_session_find(net, tunnel, session_id);
+       if (session != NULL)
+               goto out;
+
+       /* Default MTU values. */
+       if (cfg->mtu == 0)
+               cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD;
+       if (cfg->mru == 0)
+               cfg->mru = cfg->mtu;
+
+       /* Allocate and initialize a new session context. */
+       error = -ENOMEM;
+       session = l2tp_session_create(sizeof(struct pppol2tp_session),
+                                     tunnel, session_id,
+                                     peer_session_id, cfg);
+       if (session == NULL)
+               goto out;
+
+       ps = l2tp_session_priv(session);
+       ps->tunnel_sock = tunnel->sock;
+
+       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+              "%s: created\n", session->name);
+
+       error = 0;
+
+out:
+       return error;
+}
+
+/* Called when deleting sessions via the netlink interface.
+ */
+static int pppol2tp_session_delete(struct l2tp_session *session)
+{
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+
+       if (ps->sock == NULL)
+               l2tp_session_dec_refcount(session);
+
+       return 0;
+}
+
+#endif /* CONFIG_L2TP_V3 */
+
+/* getname() support.
+ */
+static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
+                           int *usockaddr_len, int peer)
+{
+       int len = 0;
+       int error = 0;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel;
+       struct sock *sk = sock->sk;
+       struct inet_sock *inet;
+       struct pppol2tp_session *pls;
+
+       error = -ENOTCONN;
+       if (sk == NULL)
+               goto end;
+       if (sk->sk_state != PPPOX_CONNECTED)
+               goto end;
+
+       error = -EBADF;
+       session = pppol2tp_sock_to_session(sk);
+       if (session == NULL)
+               goto end;
+
+       pls = l2tp_session_priv(session);
+       tunnel = l2tp_sock_to_tunnel(pls->tunnel_sock);
+       if (tunnel == NULL) {
+               error = -EBADF;
+               goto end_put_sess;
+       }
+
+       inet = inet_sk(sk);
+       if (tunnel->version == 2) {
+               struct sockaddr_pppol2tp sp;
+               len = sizeof(sp);
+               memset(&sp, 0, len);
+               sp.sa_family    = AF_PPPOX;
+               sp.sa_protocol  = PX_PROTO_OL2TP;
+               sp.pppol2tp.fd  = tunnel->fd;
+               sp.pppol2tp.pid = pls->owner;
+               sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
+               sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
+               sp.pppol2tp.s_session = session->session_id;
+               sp.pppol2tp.d_session = session->peer_session_id;
+               sp.pppol2tp.addr.sin_family = AF_INET;
+               sp.pppol2tp.addr.sin_port = inet->inet_dport;
+               sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
+               memcpy(uaddr, &sp, len);
+       } else if (tunnel->version == 3) {
+               struct sockaddr_pppol2tpv3 sp;
+               len = sizeof(sp);
+               memset(&sp, 0, len);
+               sp.sa_family    = AF_PPPOX;
+               sp.sa_protocol  = PX_PROTO_OL2TP;
+               sp.pppol2tp.fd  = tunnel->fd;
+               sp.pppol2tp.pid = pls->owner;
+               sp.pppol2tp.s_tunnel = tunnel->tunnel_id;
+               sp.pppol2tp.d_tunnel = tunnel->peer_tunnel_id;
+               sp.pppol2tp.s_session = session->session_id;
+               sp.pppol2tp.d_session = session->peer_session_id;
+               sp.pppol2tp.addr.sin_family = AF_INET;
+               sp.pppol2tp.addr.sin_port = inet->inet_dport;
+               sp.pppol2tp.addr.sin_addr.s_addr = inet->inet_daddr;
+               memcpy(uaddr, &sp, len);
+       }
+
+       *usockaddr_len = len;
+
+       sock_put(pls->tunnel_sock);
+end_put_sess:
+       sock_put(sk);
+       error = 0;
+
+end:
+       return error;
+}
+
+/****************************************************************************
+ * ioctl() handlers.
+ *
+ * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP
+ * sockets. However, in order to control kernel tunnel features, we allow
+ * userspace to create a special "tunnel" PPPoX socket which is used for
+ * control only.  Tunnel PPPoX sockets have session_id == 0 and simply allow
+ * the user application to issue L2TP setsockopt(), getsockopt() and ioctl()
+ * calls.
+ ****************************************************************************/
+
+static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,
+                               struct l2tp_stats *stats)
+{
+       dest->tx_packets = stats->tx_packets;
+       dest->tx_bytes = stats->tx_bytes;
+       dest->tx_errors = stats->tx_errors;
+       dest->rx_packets = stats->rx_packets;
+       dest->rx_bytes = stats->rx_bytes;
+       dest->rx_seq_discards = stats->rx_seq_discards;
+       dest->rx_oos_packets = stats->rx_oos_packets;
+       dest->rx_errors = stats->rx_errors;
+}
+
+/* Session ioctl helper.
+ */
+static int pppol2tp_session_ioctl(struct l2tp_session *session,
+                                 unsigned int cmd, unsigned long arg)
+{
+       struct ifreq ifr;
+       int err = 0;
+       struct sock *sk;
+       int val = (int) arg;
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       struct pppol2tp_ioc_stats stats;
+
+       PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG,
+              "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
+              session->name, cmd, arg);
+
+       sk = ps->sock;
+       sock_hold(sk);
+
+       switch (cmd) {
+       case SIOCGIFMTU:
+               err = -ENXIO;
+               if (!(sk->sk_state & PPPOX_CONNECTED))
+                       break;
+
+               err = -EFAULT;
+               if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq)))
+                       break;
+               ifr.ifr_mtu = session->mtu;
+               if (copy_to_user((void __user *) arg, &ifr, sizeof(struct ifreq)))
+                       break;
+
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get mtu=%d\n", session->name, session->mtu);
+               err = 0;
+               break;
+
+       case SIOCSIFMTU:
+               err = -ENXIO;
+               if (!(sk->sk_state & PPPOX_CONNECTED))
+                       break;
+
+               err = -EFAULT;
+               if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq)))
+                       break;
+
+               session->mtu = ifr.ifr_mtu;
+
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set mtu=%d\n", session->name, session->mtu);
+               err = 0;
+               break;
+
+       case PPPIOCGMRU:
+               err = -ENXIO;
+               if (!(sk->sk_state & PPPOX_CONNECTED))
+                       break;
+
+               err = -EFAULT;
+               if (put_user(session->mru, (int __user *) arg))
+                       break;
+
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get mru=%d\n", session->name, session->mru);
+               err = 0;
+               break;
+
+       case PPPIOCSMRU:
+               err = -ENXIO;
+               if (!(sk->sk_state & PPPOX_CONNECTED))
+                       break;
+
+               err = -EFAULT;
+               if (get_user(val, (int __user *) arg))
+                       break;
+
+               session->mru = val;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set mru=%d\n", session->name, session->mru);
+               err = 0;
+               break;
+
+       case PPPIOCGFLAGS:
+               err = -EFAULT;
+               if (put_user(ps->flags, (int __user *) arg))
+                       break;
+
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get flags=%d\n", session->name, ps->flags);
+               err = 0;
+               break;
+
+       case PPPIOCSFLAGS:
+               err = -EFAULT;
+               if (get_user(val, (int __user *) arg))
+                       break;
+               ps->flags = val;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set flags=%d\n", session->name, ps->flags);
+               err = 0;
+               break;
+
+       case PPPIOCGL2TPSTATS:
+               err = -ENXIO;
+               if (!(sk->sk_state & PPPOX_CONNECTED))
+                       break;
+
+               memset(&stats, 0, sizeof(stats));
+               stats.tunnel_id = tunnel->tunnel_id;
+               stats.session_id = session->session_id;
+               pppol2tp_copy_stats(&stats, &session->stats);
+               if (copy_to_user((void __user *) arg, &stats,
+                                sizeof(stats)))
+                       break;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get L2TP stats\n", session->name);
+               err = 0;
+               break;
+
+       default:
+               err = -ENOSYS;
+               break;
+       }
+
+       sock_put(sk);
+
+       return err;
+}
+
+/* Tunnel ioctl helper.
+ *
+ * Note the special handling for PPPIOCGL2TPSTATS below. If the ioctl data
+ * specifies a session_id, the session ioctl handler is called. This allows an
+ * application to retrieve session stats via a tunnel socket.
+ */
+static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel,
+                                unsigned int cmd, unsigned long arg)
+{
+       int err = 0;
+       struct sock *sk;
+       struct pppol2tp_ioc_stats stats;
+
+       PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG,
+              "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n",
+              tunnel->name, cmd, arg);
+
+       sk = tunnel->sock;
+       sock_hold(sk);
+
+       switch (cmd) {
+       case PPPIOCGL2TPSTATS:
+               err = -ENXIO;
+               if (!(sk->sk_state & PPPOX_CONNECTED))
+                       break;
+
+               if (copy_from_user(&stats, (void __user *) arg,
+                                  sizeof(stats))) {
+                       err = -EFAULT;
+                       break;
+               }
+               if (stats.session_id != 0) {
+                       /* resend to session ioctl handler */
+                       struct l2tp_session *session =
+                               l2tp_session_find(sock_net(sk), tunnel, stats.session_id);
+                       if (session != NULL)
+                               err = pppol2tp_session_ioctl(session, cmd, arg);
+                       else
+                               err = -EBADR;
+                       break;
+               }
+#ifdef CONFIG_XFRM
+               stats.using_ipsec = (sk->sk_policy[0] || sk->sk_policy[1]) ? 1 : 0;
+#endif
+               pppol2tp_copy_stats(&stats, &tunnel->stats);
+               if (copy_to_user((void __user *) arg, &stats, sizeof(stats))) {
+                       err = -EFAULT;
+                       break;
+               }
+               PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get L2TP stats\n", tunnel->name);
+               err = 0;
+               break;
+
+       default:
+               err = -ENOSYS;
+               break;
+       }
+
+       sock_put(sk);
+
+       return err;
+}
+
+/* Main ioctl() handler.
+ * Dispatch to tunnel or session helpers depending on the socket.
+ */
+static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
+                         unsigned long arg)
+{
+       struct sock *sk = sock->sk;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel;
+       struct pppol2tp_session *ps;
+       int err;
+
+       if (!sk)
+               return 0;
+
+       err = -EBADF;
+       if (sock_flag(sk, SOCK_DEAD) != 0)
+               goto end;
+
+       err = -ENOTCONN;
+       if ((sk->sk_user_data == NULL) ||
+           (!(sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND))))
+               goto end;
+
+       /* Get session context from the socket */
+       err = -EBADF;
+       session = pppol2tp_sock_to_session(sk);
+       if (session == NULL)
+               goto end;
+
+       /* Special case: if session's session_id is zero, treat ioctl as a
+        * tunnel ioctl
+        */
+       ps = l2tp_session_priv(session);
+       if ((session->session_id == 0) &&
+           (session->peer_session_id == 0)) {
+               err = -EBADF;
+               tunnel = l2tp_sock_to_tunnel(ps->tunnel_sock);
+               if (tunnel == NULL)
+                       goto end_put_sess;
+
+               err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
+               sock_put(ps->tunnel_sock);
+               goto end_put_sess;
+       }
+
+       err = pppol2tp_session_ioctl(session, cmd, arg);
+
+end_put_sess:
+       sock_put(sk);
+end:
+       return err;
+}
+
+/*****************************************************************************
+ * setsockopt() / getsockopt() support.
+ *
+ * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP
+ * sockets. In order to control kernel tunnel features, we allow userspace to
+ * create a special "tunnel" PPPoX socket which is used for control only.
+ * Tunnel PPPoX sockets have session_id == 0 and simply allow the user
+ * application to issue L2TP setsockopt(), getsockopt() and ioctl() calls.
+ *****************************************************************************/
+
+/* Tunnel setsockopt() helper.
+ */
+static int pppol2tp_tunnel_setsockopt(struct sock *sk,
+                                     struct l2tp_tunnel *tunnel,
+                                     int optname, int val)
+{
+       int err = 0;
+
+       switch (optname) {
+       case PPPOL2TP_SO_DEBUG:
+               tunnel->debug = val;
+               PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set debug=%x\n", tunnel->name, tunnel->debug);
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       return err;
+}
+
+/* Session setsockopt helper.
+ */
+static int pppol2tp_session_setsockopt(struct sock *sk,
+                                      struct l2tp_session *session,
+                                      int optname, int val)
+{
+       int err = 0;
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+
+       switch (optname) {
+       case PPPOL2TP_SO_RECVSEQ:
+               if ((val != 0) && (val != 1)) {
+                       err = -EINVAL;
+                       break;
+               }
+               session->recv_seq = val ? -1 : 0;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set recv_seq=%d\n", session->name, session->recv_seq);
+               break;
+
+       case PPPOL2TP_SO_SENDSEQ:
+               if ((val != 0) && (val != 1)) {
+                       err = -EINVAL;
+                       break;
+               }
+               session->send_seq = val ? -1 : 0;
+               {
+                       struct sock *ssk      = ps->sock;
+                       struct pppox_sock *po = pppox_sk(ssk);
+                       po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
+                               PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+               }
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set send_seq=%d\n", session->name, session->send_seq);
+               break;
+
+       case PPPOL2TP_SO_LNSMODE:
+               if ((val != 0) && (val != 1)) {
+                       err = -EINVAL;
+                       break;
+               }
+               session->lns_mode = val ? -1 : 0;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set lns_mode=%d\n", session->name, session->lns_mode);
+               break;
+
+       case PPPOL2TP_SO_DEBUG:
+               session->debug = val;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set debug=%x\n", session->name, session->debug);
+               break;
+
+       case PPPOL2TP_SO_REORDERTO:
+               session->reorder_timeout = msecs_to_jiffies(val);
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: set reorder_timeout=%d\n", session->name, session->reorder_timeout);
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       return err;
+}
+
+/* Main setsockopt() entry point.
+ * Does API checks, then calls either the tunnel or session setsockopt
+ * handler, according to whether the PPPoL2TP socket is a for a regular
+ * session or the special tunnel type.
+ */
+static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
+                              char __user *optval, unsigned int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel;
+       struct pppol2tp_session *ps;
+       int val;
+       int err;
+
+       if (level != SOL_PPPOL2TP)
+               return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
+       if (optlen < sizeof(int))
+               return -EINVAL;
+
+       if (get_user(val, (int __user *)optval))
+               return -EFAULT;
+
+       err = -ENOTCONN;
+       if (sk->sk_user_data == NULL)
+               goto end;
+
+       /* Get session context from the socket */
+       err = -EBADF;
+       session = pppol2tp_sock_to_session(sk);
+       if (session == NULL)
+               goto end;
+
+       /* Special case: if session_id == 0x0000, treat as operation on tunnel
+        */
+       ps = l2tp_session_priv(session);
+       if ((session->session_id == 0) &&
+           (session->peer_session_id == 0)) {
+               err = -EBADF;
+               tunnel = l2tp_sock_to_tunnel(ps->tunnel_sock);
+               if (tunnel == NULL)
+                       goto end_put_sess;
+
+               err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val);
+               sock_put(ps->tunnel_sock);
+       } else
+               err = pppol2tp_session_setsockopt(sk, session, optname, val);
+
+       err = 0;
+
+end_put_sess:
+       sock_put(sk);
+end:
+       return err;
+}
+
+/* Tunnel getsockopt helper. Called with sock locked.
+ */
+static int pppol2tp_tunnel_getsockopt(struct sock *sk,
+                                     struct l2tp_tunnel *tunnel,
+                                     int optname, int *val)
+{
+       int err = 0;
+
+       switch (optname) {
+       case PPPOL2TP_SO_DEBUG:
+               *val = tunnel->debug;
+               PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get debug=%x\n", tunnel->name, tunnel->debug);
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       return err;
+}
+
+/* Session getsockopt helper. Called with sock locked.
+ */
+static int pppol2tp_session_getsockopt(struct sock *sk,
+                                      struct l2tp_session *session,
+                                      int optname, int *val)
+{
+       int err = 0;
+
+       switch (optname) {
+       case PPPOL2TP_SO_RECVSEQ:
+               *val = session->recv_seq;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get recv_seq=%d\n", session->name, *val);
+               break;
+
+       case PPPOL2TP_SO_SENDSEQ:
+               *val = session->send_seq;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get send_seq=%d\n", session->name, *val);
+               break;
+
+       case PPPOL2TP_SO_LNSMODE:
+               *val = session->lns_mode;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get lns_mode=%d\n", session->name, *val);
+               break;
+
+       case PPPOL2TP_SO_DEBUG:
+               *val = session->debug;
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get debug=%d\n", session->name, *val);
+               break;
+
+       case PPPOL2TP_SO_REORDERTO:
+               *val = (int) jiffies_to_msecs(session->reorder_timeout);
+               PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+                      "%s: get reorder_timeout=%d\n", session->name, *val);
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+       }
+
+       return err;
+}
+
+/* Main getsockopt() entry point.
+ * Does API checks, then calls either the tunnel or session getsockopt
+ * handler, according to whether the PPPoX socket is a for a regular session
+ * or the special tunnel type.
+ */
+static int pppol2tp_getsockopt(struct socket *sock, int level,
+                              int optname, char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       struct l2tp_session *session;
+       struct l2tp_tunnel *tunnel;
+       int val, len;
+       int err;
+       struct pppol2tp_session *ps;
+
+       if (level != SOL_PPPOL2TP)
+               return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+
+       if (get_user(len, (int __user *) optlen))
+               return -EFAULT;
+
+       len = min_t(unsigned int, len, sizeof(int));
+
+       if (len < 0)
+               return -EINVAL;
+
+       err = -ENOTCONN;
+       if (sk->sk_user_data == NULL)
+               goto end;
+
+       /* Get the session context */
+       err = -EBADF;
+       session = pppol2tp_sock_to_session(sk);
+       if (session == NULL)
+               goto end;
+
+       /* Special case: if session_id == 0x0000, treat as operation on tunnel */
+       ps = l2tp_session_priv(session);
+       if ((session->session_id == 0) &&
+           (session->peer_session_id == 0)) {
+               err = -EBADF;
+               tunnel = l2tp_sock_to_tunnel(ps->tunnel_sock);
+               if (tunnel == NULL)
+                       goto end_put_sess;
+
+               err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val);
+               sock_put(ps->tunnel_sock);
+       } else
+               err = pppol2tp_session_getsockopt(sk, session, optname, &val);
+
+       err = -EFAULT;
+       if (put_user(len, (int __user *) optlen))
+               goto end_put_sess;
+
+       if (copy_to_user((void __user *) optval, &val, len))
+               goto end_put_sess;
+
+       err = 0;
+
+end_put_sess:
+       sock_put(sk);
+end:
+       return err;
+}
+
+/*****************************************************************************
+ * /proc filesystem for debug
+ * Since the original pppol2tp driver provided /proc/net/pppol2tp for
+ * L2TPv2, we dump only L2TPv2 tunnels and sessions here.
+ *****************************************************************************/
+
+static unsigned int pppol2tp_net_id;
+
+#ifdef CONFIG_PROC_FS
+
+struct pppol2tp_seq_data {
+       struct seq_net_private p;
+       int tunnel_idx;                 /* current tunnel */
+       int session_idx;                /* index of session within current tunnel */
+       struct l2tp_tunnel *tunnel;
+       struct l2tp_session *session;   /* NULL means get next tunnel */
+};
+
+static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd)
+{
+       for (;;) {
+               pd->tunnel = l2tp_tunnel_find_nth(net, pd->tunnel_idx);
+               pd->tunnel_idx++;
+
+               if (pd->tunnel == NULL)
+                       break;
+
+               /* Ignore L2TPv3 tunnels */
+               if (pd->tunnel->version < 3)
+                       break;
+       }
+}
+
+static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd)
+{
+       pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx);
+       pd->session_idx++;
+
+       if (pd->session == NULL) {
+               pd->session_idx = 0;
+               pppol2tp_next_tunnel(net, pd);
+       }
+}
+
+static void *pppol2tp_seq_start(struct seq_file *m, loff_t *offs)
+{
+       struct pppol2tp_seq_data *pd = SEQ_START_TOKEN;
+       loff_t pos = *offs;
+       struct net *net;
+
+       if (!pos)
+               goto out;
+
+       BUG_ON(m->private == NULL);
+       pd = m->private;
+       net = seq_file_net(m);
+
+       if (pd->tunnel == NULL)
+               pppol2tp_next_tunnel(net, pd);
+       else
+               pppol2tp_next_session(net, pd);
+
+       /* NULL tunnel and session indicates end of list */
+       if ((pd->tunnel == NULL) && (pd->session == NULL))
+               pd = NULL;
+
+out:
+       return pd;
+}
+
+static void *pppol2tp_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return NULL;
+}
+
+static void pppol2tp_seq_stop(struct seq_file *p, void *v)
+{
+       /* nothing to do */
+}
+
+static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
+{
+       struct l2tp_tunnel *tunnel = v;
+
+       seq_printf(m, "\nTUNNEL '%s', %c %d\n",
+                  tunnel->name,
+                  (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N',
+                  atomic_read(&tunnel->ref_count) - 1);
+       seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n",
+                  tunnel->debug,
+                  (unsigned long long)tunnel->stats.tx_packets,
+                  (unsigned long long)tunnel->stats.tx_bytes,
+                  (unsigned long long)tunnel->stats.tx_errors,
+                  (unsigned long long)tunnel->stats.rx_packets,
+                  (unsigned long long)tunnel->stats.rx_bytes,
+                  (unsigned long long)tunnel->stats.rx_errors);
+}
+
+static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
+{
+       struct l2tp_session *session = v;
+       struct l2tp_tunnel *tunnel = session->tunnel;
+       struct pppol2tp_session *ps = l2tp_session_priv(session);
+       struct pppox_sock *po = pppox_sk(ps->sock);
+       u32 ip = 0;
+       u16 port = 0;
+
+       if (tunnel->sock) {
+               struct inet_sock *inet = inet_sk(tunnel->sock);
+               ip = ntohl(inet->inet_saddr);
+               port = ntohs(inet->inet_sport);
+       }
+
+       seq_printf(m, "  SESSION '%s' %08X/%d %04X/%04X -> "
+                  "%04X/%04X %d %c\n",
+                  session->name, ip, port,
+                  tunnel->tunnel_id,
+                  session->session_id,
+                  tunnel->peer_tunnel_id,
+                  session->peer_session_id,
+                  ps->sock->sk_state,
+                  (session == ps->sock->sk_user_data) ?
+                  'Y' : 'N');
+       seq_printf(m, "   %d/%d/%c/%c/%s %08x %u\n",
+                  session->mtu, session->mru,
+                  session->recv_seq ? 'R' : '-',
+                  session->send_seq ? 'S' : '-',
+                  session->lns_mode ? "LNS" : "LAC",
+                  session->debug,
+                  jiffies_to_msecs(session->reorder_timeout));
+       seq_printf(m, "   %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n",
+                  session->nr, session->ns,
+                  (unsigned long long)session->stats.tx_packets,
+                  (unsigned long long)session->stats.tx_bytes,
+                  (unsigned long long)session->stats.tx_errors,
+                  (unsigned long long)session->stats.rx_packets,
+                  (unsigned long long)session->stats.rx_bytes,
+                  (unsigned long long)session->stats.rx_errors);
+
+       if (po)
+               seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
+}
+
+static int pppol2tp_seq_show(struct seq_file *m, void *v)
+{
+       struct pppol2tp_seq_data *pd = v;
+
+       /* display header on line 1 */
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(m, "PPPoL2TP driver info, " PPPOL2TP_DRV_VERSION "\n");
+               seq_puts(m, "TUNNEL name, user-data-ok session-count\n");
+               seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
+               seq_puts(m, "  SESSION name, addr/port src-tid/sid "
+                        "dest-tid/sid state user-data-ok\n");
+               seq_puts(m, "   mtu/mru/rcvseq/sendseq/lns debug reorderto\n");
+               seq_puts(m, "   nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
+               goto out;
+       }
+
+       /* Show the tunnel or session context.
+        */
+       if (pd->session == NULL)
+               pppol2tp_seq_tunnel_show(m, pd->tunnel);
+       else
+               pppol2tp_seq_session_show(m, pd->session);
+
+out:
+       return 0;
+}
+
+static const struct seq_operations pppol2tp_seq_ops = {
+       .start          = pppol2tp_seq_start,
+       .next           = pppol2tp_seq_next,
+       .stop           = pppol2tp_seq_stop,
+       .show           = pppol2tp_seq_show,
+};
+
+/* Called when our /proc file is opened. We allocate data for use when
+ * iterating our tunnel / session contexts and store it in the private
+ * data of the seq_file.
+ */
+static int pppol2tp_proc_open(struct inode *inode, struct file *file)
+{
+       return seq_open_net(inode, file, &pppol2tp_seq_ops,
+                           sizeof(struct pppol2tp_seq_data));
+}
+
+static const struct file_operations pppol2tp_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = pppol2tp_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release_net,
+};
+
+#endif /* CONFIG_PROC_FS */
+
+/*****************************************************************************
+ * Network namespace
+ *****************************************************************************/
+
+static __net_init int pppol2tp_init_net(struct net *net)
+{
+       struct proc_dir_entry *pde;
+       int err = 0;
+
+       pde = proc_net_fops_create(net, "pppol2tp", S_IRUGO, &pppol2tp_proc_fops);
+       if (!pde) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+out:
+       return err;
+}
+
+static __net_exit void pppol2tp_exit_net(struct net *net)
+{
+       proc_net_remove(net, "pppol2tp");
+}
+
+static struct pernet_operations pppol2tp_net_ops = {
+       .init = pppol2tp_init_net,
+       .exit = pppol2tp_exit_net,
+       .id   = &pppol2tp_net_id,
+};
+
+/*****************************************************************************
+ * Init and cleanup
+ *****************************************************************************/
+
+static const struct proto_ops pppol2tp_ops = {
+       .family         = AF_PPPOX,
+       .owner          = THIS_MODULE,
+       .release        = pppol2tp_release,
+       .bind           = sock_no_bind,
+       .connect        = pppol2tp_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = sock_no_accept,
+       .getname        = pppol2tp_getname,
+       .poll           = datagram_poll,
+       .listen         = sock_no_listen,
+       .shutdown       = sock_no_shutdown,
+       .setsockopt     = pppol2tp_setsockopt,
+       .getsockopt     = pppol2tp_getsockopt,
+       .sendmsg        = pppol2tp_sendmsg,
+       .recvmsg        = pppol2tp_recvmsg,
+       .mmap           = sock_no_mmap,
+       .ioctl          = pppox_ioctl,
+};
+
+static struct pppox_proto pppol2tp_proto = {
+       .create         = pppol2tp_create,
+       .ioctl          = pppol2tp_ioctl
+};
+
+#ifdef CONFIG_L2TP_V3
+
+static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = {
+       .session_create = pppol2tp_session_create,
+       .session_delete = pppol2tp_session_delete,
+};
+
+#endif /* CONFIG_L2TP_V3 */
+
+static int __init pppol2tp_init(void)
+{
+       int err;
+
+       err = register_pernet_device(&pppol2tp_net_ops);
+       if (err)
+               goto out;
+
+       err = proto_register(&pppol2tp_sk_proto, 0);
+       if (err)
+               goto out_unregister_pppol2tp_pernet;
+
+       err = register_pppox_proto(PX_PROTO_OL2TP, &pppol2tp_proto);
+       if (err)
+               goto out_unregister_pppol2tp_proto;
+
+#ifdef CONFIG_L2TP_V3
+       err = l2tp_nl_register_ops(L2TP_PWTYPE_PPP, &pppol2tp_nl_cmd_ops);
+       if (err)
+               goto out_unregister_pppox;
+#endif
+
+       printk(KERN_INFO "PPPoL2TP kernel driver, %s\n",
+              PPPOL2TP_DRV_VERSION);
+
+out:
+       return err;
+
+#ifdef CONFIG_L2TP_V3
+out_unregister_pppox:
+       unregister_pppox_proto(PX_PROTO_OL2TP);
+#endif
+out_unregister_pppol2tp_proto:
+       proto_unregister(&pppol2tp_sk_proto);
+out_unregister_pppol2tp_pernet:
+       unregister_pernet_device(&pppol2tp_net_ops);
+       goto out;
+}
+
+static void __exit pppol2tp_exit(void)
+{
+#ifdef CONFIG_L2TP_V3
+       l2tp_nl_unregister_ops(L2TP_PWTYPE_PPP);
+#endif
+       unregister_pppox_proto(PX_PROTO_OL2TP);
+       proto_unregister(&pppol2tp_sk_proto);
+       unregister_pernet_device(&pppol2tp_net_ops);
+}
+
+module_init(pppol2tp_init);
+module_exit(pppol2tp_exit);
+
+MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("PPP over L2TP over UDP");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PPPOL2TP_DRV_VERSION);
index 2db6a9f759130f4277739619018713c521b4522f..023ba820236f391a01595418873b7c5e0df3ece8 100644 (file)
@@ -536,7 +536,7 @@ static int llc_ui_wait_for_disc(struct sock *sk, long timeout)
        int rc = 0;
 
        while (1) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (sk_wait_event(sk, &timeout, sk->sk_state == TCP_CLOSE))
                        break;
                rc = -ERESTARTSYS;
@@ -547,7 +547,7 @@ static int llc_ui_wait_for_disc(struct sock *sk, long timeout)
                        break;
                rc = 0;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return rc;
 }
 
@@ -556,13 +556,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, long timeout)
        DEFINE_WAIT(wait);
 
        while (1) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (sk_wait_event(sk, &timeout, sk->sk_state != TCP_SYN_SENT))
                        break;
                if (signal_pending(current) || !timeout)
                        break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return timeout;
 }
 
@@ -573,7 +573,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout)
        int rc;
 
        while (1) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                rc = 0;
                if (sk_wait_event(sk, &timeout,
                                  (sk->sk_shutdown & RCV_SHUTDOWN) ||
@@ -588,7 +588,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout)
                if (!timeout)
                        break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return rc;
 }
 
index 78167e81dfebdf0be0510df3ff82b7c82da68b38..2bb0ddff8c0fe3d72c072f175d54675a91a6922c 100644 (file)
@@ -144,12 +144,6 @@ static struct packet_type llc_tr_packet_type __read_mostly = {
 
 static int __init llc_init(void)
 {
-       struct net_device *dev;
-
-       dev = first_net_device(&init_net);
-       if (dev != NULL)
-               dev = next_net_device(dev);
-
        dev_add_pack(&llc_packet_type);
        dev_add_pack(&llc_tr_packet_type);
        return 0;
index a952b7f8c6482ae76b6a14aed59c5f4c63e113d8..8a91f6c0bb1800a8149623c059bdde6e135361b7 100644 (file)
@@ -15,8 +15,12 @@ comment "CFG80211 needs to be enabled for MAC80211"
 
 if MAC80211 != n
 
+config MAC80211_HAS_RC
+       def_bool n
+
 config MAC80211_RC_PID
        bool "PID controller based rate control algorithm" if EMBEDDED
+       select MAC80211_HAS_RC
        ---help---
          This option enables a TX rate control algorithm for
          mac80211 that uses a PID controller to select the TX
@@ -24,12 +28,14 @@ config MAC80211_RC_PID
 
 config MAC80211_RC_MINSTREL
        bool "Minstrel" if EMBEDDED
+       select MAC80211_HAS_RC
        default y
        ---help---
          This option enables the 'minstrel' TX rate control algorithm
 
 choice
        prompt "Default rate control algorithm"
+       depends on MAC80211_HAS_RC
        default MAC80211_RC_DEFAULT_MINSTREL
        ---help---
          This option selects the default rate control algorithm
@@ -62,6 +68,9 @@ config MAC80211_RC_DEFAULT
 
 endif
 
+comment "Some wireless drivers require a rate control algorithm"
+       depends on MAC80211_HAS_RC=n
+
 config MAC80211_MESH
        bool "Enable mac80211 mesh networking (pre-802.11s) support"
        depends on MAC80211 && EXPERIMENTAL
@@ -212,8 +221,8 @@ config MAC80211_DRIVER_API_TRACER
        depends on EVENT_TRACING
        help
          Say Y here to make mac80211 register with the ftrace
-         framework for the driver API -- you can see which
-         driver methods it is calling then by looking at the
-         trace.
+         framework for the driver API -- you can then see which
+         driver methods it is calling and which API functions
+         drivers are calling by looking at the trace.
 
-         If unsure, say N.
+         If unsure, say Y.
index 04420291e7ad7b0d85e3456cbe93c5804dd2d6f9..84b48ba8a77e559dcc5b1d8120f5428b4c07314c 100644 (file)
@@ -23,7 +23,8 @@ mac80211-y := \
        key.o \
        util.o \
        wme.o \
-       event.o
+       event.o \
+       chan.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
index f9516a27e233ba09ebf1d69a81968552d47902ee..6bb9a9a94960e9214e92f1debf023aa0ebb3b987 100644 (file)
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
-void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
-                                   u16 initiator, u16 reason)
+static void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+                                           u16 initiator, u16 reason,
+                                           bool from_timer)
 {
        struct ieee80211_local *local = sta->local;
+       struct tid_ampdu_rx *tid_rx;
        int i;
 
-       /* check if TID is in operational state */
        spin_lock_bh(&sta->lock);
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) {
+
+       /* check if TID is in operational state */
+       if (!sta->ampdu_mlme.tid_active_rx[tid]) {
                spin_unlock_bh(&sta->lock);
                return;
        }
 
-       sta->ampdu_mlme.tid_state_rx[tid] =
-               HT_AGG_STATE_REQ_STOP_BA_MSK |
-               (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
-       spin_unlock_bh(&sta->lock);
+       sta->ampdu_mlme.tid_active_rx[tid] = false;
+
+       tid_rx = sta->ampdu_mlme.tid_rx[tid];
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n",
@@ -47,61 +49,42 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                printk(KERN_DEBUG "HW problem - can not stop rx "
                                "aggregation for tid %d\n", tid);
 
-       /* shutdown timer has not expired */
-       if (initiator != WLAN_BACK_TIMER)
-               del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
-
        /* check if this is a self generated aggregation halt */
-       if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
+       if (initiator == WLAN_BACK_RECIPIENT)
                ieee80211_send_delba(sta->sdata, sta->sta.addr,
                                     tid, 0, reason);
 
        /* free the reordering buffer */
-       for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
-               if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
+       for (i = 0; i < tid_rx->buf_size; i++) {
+               if (tid_rx->reorder_buf[i]) {
                        /* release the reordered frames */
-                       dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
-                       sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
-                       sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
+                       dev_kfree_skb(tid_rx->reorder_buf[i]);
+                       tid_rx->stored_mpdu_num--;
+                       tid_rx->reorder_buf[i] = NULL;
                }
        }
 
-       spin_lock_bh(&sta->lock);
        /* free resources */
-       kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
-       kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_time);
-
-       if (!sta->ampdu_mlme.tid_rx[tid]->shutdown) {
-               kfree(sta->ampdu_mlme.tid_rx[tid]);
-               sta->ampdu_mlme.tid_rx[tid] = NULL;
-       }
+       kfree(tid_rx->reorder_buf);
+       kfree(tid_rx->reorder_time);
+       sta->ampdu_mlme.tid_rx[tid] = NULL;
 
-       sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
        spin_unlock_bh(&sta->lock);
+
+       if (!from_timer)
+               del_timer_sync(&tid_rx->session_timer);
+       kfree(tid_rx);
 }
 
-void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid,
-                                       u16 initiator, u16 reason)
+void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
+                                   u16 initiator, u16 reason)
 {
-       struct sta_info *sta;
-
-       rcu_read_lock();
-
-       sta = sta_info_get(sdata, ra);
-       if (!sta) {
-               rcu_read_unlock();
-               return;
-       }
-
-       __ieee80211_stop_rx_ba_session(sta, tid, initiator, reason);
-
-       rcu_read_unlock();
+       ___ieee80211_stop_rx_ba_session(sta, tid, initiator, reason, false);
 }
 
 /*
  * After accepting the AddBA Request we activated a timer,
  * resetting it after each frame that arrives from the originator.
- * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
  */
 static void sta_rx_agg_session_timer_expired(unsigned long data)
 {
@@ -117,9 +100,8 @@ static void sta_rx_agg_session_timer_expired(unsigned long data)
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
 #endif
-       ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-                                        (u16)*ptid, WLAN_BACK_TIMER,
-                                        WLAN_REASON_QSTA_TIMEOUT);
+       ___ieee80211_stop_rx_ba_session(sta, *ptid, WLAN_BACK_RECIPIENT,
+                                       WLAN_REASON_QSTA_TIMEOUT, true);
 }
 
 static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *da, u16 tid,
@@ -194,7 +176,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
        status = WLAN_STATUS_REQUEST_DECLINED;
 
-       if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
+       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Suspend in progress. "
                       "Denying ADDBA request\n");
@@ -232,7 +214,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        /* examine state machine */
        spin_lock_bh(&sta->lock);
 
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
+       if (sta->ampdu_mlme.tid_active_rx[tid]) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
                        printk(KERN_DEBUG "unexpected AddBA Req from "
@@ -294,7 +276,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        }
 
        /* change state and send addba resp */
-       sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
+       sta->ampdu_mlme.tid_active_rx[tid] = true;
        tid_agg_rx->dialog_token = dialog_token;
        tid_agg_rx->ssn = start_seq_num;
        tid_agg_rx->head_seq_num = start_seq_num;
index 87782a4bb541251714236dc1218104e71cd3c315..c163d0a149f49be05b07fa879562f2d821004beb 100644 (file)
@@ -186,7 +186,7 @@ static void sta_addba_resp_timer_expired(unsigned long data)
                spin_unlock_bh(&sta->lock);
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "timer expired on tid %d but we are not "
-                               "(or no longer) expecting addBA response there",
+                               "(or no longer) expecting addBA response there\n",
                        tid);
 #endif
                return;
@@ -214,6 +214,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
        int ret = 0;
        u16 start_seq_num;
 
+       trace_api_start_tx_ba_session(pubsta, tid);
+
        if (WARN_ON(!local->ops->ampdu_action))
                return -EINVAL;
 
@@ -245,7 +247,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
                return -EINVAL;
        }
 
-       if (test_sta_flags(sta, WLAN_STA_SUSPEND)) {
+       if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Suspend in progress. "
                       "Denying BA session request\n");
@@ -414,7 +416,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
                                         struct sta_info *sta, u16 tid)
 {
 #ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+       printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
 #endif
 
        spin_lock(&local->ampdu_lock);
@@ -440,6 +442,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
        struct sta_info *sta;
        u8 *state;
 
+       trace_api_start_tx_ba_cb(sdata, ra, tid);
+
        if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
@@ -541,6 +545,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
 
+       trace_api_stop_tx_ba_session(pubsta, tid, initiator);
+
        if (!local->ops->ampdu_action)
                return -EINVAL;
 
@@ -558,6 +564,8 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
        struct sta_info *sta;
        u8 *state;
 
+       trace_api_stop_tx_ba_cb(sdata, ra, tid);
+
        if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
@@ -674,7 +682,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
        del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
-       printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+       printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
index edc872e22c9b6211fcd32342296462d871e64f88..c7000a6ca379a2e206be38292dd550a39b396a17 100644 (file)
@@ -97,9 +97,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                                            params->mesh_id_len,
                                            params->mesh_id);
 
-       if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags)
-               return 0;
-
        if (type == NL80211_IFTYPE_AP_VLAN &&
            params && params->use_4addr == 0)
                rcu_assign_pointer(sdata->u.vlan.sta, NULL);
@@ -107,7 +104,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
                 params && params->use_4addr >= 0)
                sdata->u.mgd.use_4addr = params->use_4addr;
 
-       sdata->u.mntr_flags = *flags;
+       if (sdata->vif.type == NL80211_IFTYPE_MONITOR && flags)
+               sdata->u.mntr_flags = *flags;
+
        return 0;
 }
 
@@ -411,6 +410,17 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
+static int ieee80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
+                                int idx, struct survey_info *survey)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+       if (!local->ops->get_survey)
+               return -EOPNOTSUPP;
+
+       return drv_get_survey(local, idx, survey);
+}
+
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
                                 u8 *mac, struct station_info *sinfo)
 {
@@ -1104,6 +1114,13 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
                changed |= BSS_CHANGED_BASIC_RATES;
        }
 
+       if (params->ap_isolate >= 0) {
+               if (params->ap_isolate)
+                       sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+               else
+                       sdata->flags &= ~IEEE80211_SDATA_DONT_BRIDGE_PACKETS;
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 
        return 0;
@@ -1137,19 +1154,47 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
                return -EINVAL;
        }
 
+       /* enable WMM or activate new settings */
+       local->hw.conf.flags |= IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
+
        return 0;
 }
 
 static int ieee80211_set_channel(struct wiphy *wiphy,
+                                struct net_device *netdev,
                                 struct ieee80211_channel *chan,
                                 enum nl80211_channel_type channel_type)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = NULL;
+
+       if (netdev)
+               sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+
+       switch (ieee80211_get_channel_mode(local, NULL)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel != chan)
+                       return -EBUSY;
+               if (!sdata && local->_oper_channel_type == channel_type)
+                       return 0;
+               break;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
 
        local->oper_channel = chan;
-       local->oper_channel_type = channel_type;
 
-       return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (!ieee80211_set_channel_type(local, sdata, channel_type))
+               return -EBUSY;
+
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
+
+       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1193,6 +1238,20 @@ static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
                           struct cfg80211_assoc_request *req)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       switch (ieee80211_get_channel_mode(local, sdata)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (local->oper_channel == req->bss->channel)
+                       break;
+               return -EBUSY;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
+
        return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
 }
 
@@ -1215,8 +1274,22 @@ static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
                               struct cfg80211_ibss_params *params)
 {
+       struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
+       switch (ieee80211_get_channel_mode(local, sdata)) {
+       case CHAN_MODE_HOPPING:
+               return -EBUSY;
+       case CHAN_MODE_FIXED:
+               if (!params->channel_fixed)
+                       return -EBUSY;
+               if (local->oper_channel == params->channel)
+                       break;
+               return -EBUSY;
+       case CHAN_MODE_UNDEFINED:
+               break;
+       }
+
        return ieee80211_ibss_join(sdata, params);
 }
 
@@ -1345,7 +1418,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
         * association, there's no need to send an action frame.
         */
        if (!sdata->u.mgd.associated ||
-           sdata->local->oper_channel_type == NL80211_CHAN_NO_HT) {
+           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) {
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_smps(sdata->local, sdata);
                mutex_unlock(&sdata->local->iflist_mtx);
@@ -1384,11 +1457,11 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
                return -EOPNOTSUPP;
 
        if (enabled == sdata->u.mgd.powersave &&
-           timeout == conf->dynamic_ps_timeout)
+           timeout == conf->dynamic_ps_forced_timeout)
                return 0;
 
        sdata->u.mgd.powersave = enabled;
-       conf->dynamic_ps_timeout = timeout;
+       conf->dynamic_ps_forced_timeout = timeout;
 
        /* no change, but if automatic follow powersave */
        mutex_lock(&sdata->u.mgd.mtx);
@@ -1403,6 +1476,35 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
+                                        struct net_device *dev,
+                                        s32 rssi_thold, u32 rssi_hyst)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct ieee80211_vif *vif = &sdata->vif;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+       if (rssi_thold == bss_conf->cqm_rssi_thold &&
+           rssi_hyst == bss_conf->cqm_rssi_hyst)
+               return 0;
+
+       bss_conf->cqm_rssi_thold = rssi_thold;
+       bss_conf->cqm_rssi_hyst = rssi_hyst;
+
+       if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       return -EOPNOTSUPP;
+               return 0;
+       }
+
+       /* tell the driver upon association, unless already associated */
+       if (sdata->u.mgd.associated)
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+       return 0;
+}
+
 static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
                                      struct net_device *dev,
                                      const u8 *addr,
@@ -1475,6 +1577,7 @@ struct cfg80211_ops mac80211_config_ops = {
        .change_station = ieee80211_change_station,
        .get_station = ieee80211_get_station,
        .dump_station = ieee80211_dump_station,
+       .dump_survey = ieee80211_dump_survey,
 #ifdef CONFIG_MAC80211_MESH
        .add_mpath = ieee80211_add_mpath,
        .del_mpath = ieee80211_del_mpath,
@@ -1507,4 +1610,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .remain_on_channel = ieee80211_remain_on_channel,
        .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
        .action = ieee80211_action,
+       .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
 };
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
new file mode 100644 (file)
index 0000000..5d218c5
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * mac80211 - channel management
+ */
+
+#include <linux/nl80211.h>
+#include "ieee80211_i.h"
+
+enum ieee80211_chan_mode
+__ieee80211_get_channel_mode(struct ieee80211_local *local,
+                            struct ieee80211_sub_if_data *ignore)
+{
+       struct ieee80211_sub_if_data *sdata;
+
+       WARN_ON(!mutex_is_locked(&local->iflist_mtx));
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata == ignore)
+                       continue;
+
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+                       continue;
+
+               if (sdata->vif.type == NL80211_IFTYPE_STATION &&
+                   !sdata->u.mgd.associated)
+                       continue;
+
+               if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+                       if (!sdata->u.ibss.ssid_len)
+                               continue;
+                       if (!sdata->u.ibss.fixed_channel)
+                               return CHAN_MODE_HOPPING;
+               }
+
+               if (sdata->vif.type == NL80211_IFTYPE_AP &&
+                   !sdata->u.ap.beacon)
+                       continue;
+
+               return CHAN_MODE_FIXED;
+       }
+
+       return CHAN_MODE_UNDEFINED;
+}
+
+enum ieee80211_chan_mode
+ieee80211_get_channel_mode(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *ignore)
+{
+       enum ieee80211_chan_mode mode;
+
+       mutex_lock(&local->iflist_mtx);
+       mode = __ieee80211_get_channel_mode(local, ignore);
+       mutex_unlock(&local->iflist_mtx);
+
+       return mode;
+}
+
+bool ieee80211_set_channel_type(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata,
+                               enum nl80211_channel_type chantype)
+{
+       struct ieee80211_sub_if_data *tmp;
+       enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT;
+       bool result;
+
+       mutex_lock(&local->iflist_mtx);
+
+       list_for_each_entry(tmp, &local->interfaces, list) {
+               if (tmp == sdata)
+                       continue;
+
+               if (!ieee80211_sdata_running(tmp))
+                       continue;
+
+               switch (tmp->vif.bss_conf.channel_type) {
+               case NL80211_CHAN_NO_HT:
+               case NL80211_CHAN_HT20:
+                       superchan = tmp->vif.bss_conf.channel_type;
+                       break;
+               case NL80211_CHAN_HT40PLUS:
+                       WARN_ON(superchan == NL80211_CHAN_HT40MINUS);
+                       superchan = NL80211_CHAN_HT40PLUS;
+                       break;
+               case NL80211_CHAN_HT40MINUS:
+                       WARN_ON(superchan == NL80211_CHAN_HT40PLUS);
+                       superchan = NL80211_CHAN_HT40MINUS;
+                       break;
+               }
+       }
+
+       switch (superchan) {
+       case NL80211_CHAN_NO_HT:
+       case NL80211_CHAN_HT20:
+               /*
+                * allow any change that doesn't go to no-HT
+                * (if it already is no-HT no change is needed)
+                */
+               if (chantype == NL80211_CHAN_NO_HT)
+                       break;
+               superchan = chantype;
+               break;
+       case NL80211_CHAN_HT40PLUS:
+       case NL80211_CHAN_HT40MINUS:
+               /* allow smaller bandwidth and same */
+               if (chantype == NL80211_CHAN_NO_HT)
+                       break;
+               if (chantype == NL80211_CHAN_HT20)
+                       break;
+               if (superchan == chantype)
+                       break;
+               result = false;
+               goto out;
+       }
+
+       local->_oper_channel_type = superchan;
+
+       if (sdata)
+               sdata->vif.bss_conf.channel_type = chantype;
+
+       result = true;
+ out:
+       mutex_unlock(&local->iflist_mtx);
+
+       return result;
+}
index 68e6a2050f9aafff5c287264b96c1bbfbe674f2e..09cc9be347964a7d03ef4d4487b88b331f2df0a9 100644 (file)
@@ -7,7 +7,6 @@ extern int mac80211_open_file_generic(struct inode *inode, struct file *file);
 #else
 static inline void debugfs_hw_add(struct ieee80211_local *local)
 {
-       return;
 }
 #endif
 
index 83d4289d954bfacd1db317ec71b709623b44fa82..20b2998fa0ed07b68b410f77a82d0f159603d79e 100644 (file)
@@ -100,6 +100,14 @@ static ssize_t ieee80211_if_fmt_##name(                                    \
        return scnprintf(buf, buflen, "%pM\n", sdata->field);           \
 }
 
+#define IEEE80211_IF_FMT_DEC_DIV_16(name, field)                       \
+static ssize_t ieee80211_if_fmt_##name(                                        \
+       const struct ieee80211_sub_if_data *sdata,                      \
+       char *buf, int buflen)                                          \
+{                                                                      \
+       return scnprintf(buf, buflen, "%d\n", sdata->field / 16);       \
+}
+
 #define __IEEE80211_IF_FILE(name, _write)                              \
 static ssize_t ieee80211_if_read_##name(struct file *file,             \
                                        char __user *userbuf,           \
@@ -140,6 +148,8 @@ IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ],
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
 IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
+IEEE80211_IF_FILE(last_beacon, u.mgd.last_beacon_signal, DEC);
+IEEE80211_IF_FILE(ave_beacon, u.mgd.ave_beacon_signal, DEC_DIV_16);
 
 static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
                              enum ieee80211_smps_mode smps_mode)
@@ -276,6 +286,8 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 
        DEBUGFS_ADD(bssid);
        DEBUGFS_ADD(aid);
+       DEBUGFS_ADD(last_beacon);
+       DEBUGFS_ADD(ave_beacon);
        DEBUGFS_ADD_MODE(smps, 0600);
 }
 
index d92800bb2d2f4c0ec2cfe3333548e992aee1fb8c..e763f1529ddbca6ce54c3af0dd848cd96c643f61 100644 (file)
@@ -39,6 +39,13 @@ static const struct file_operations sta_ ##name## _ops = {           \
        .open = mac80211_open_file_generic,                             \
 }
 
+#define STA_OPS_RW(name)                                               \
+static const struct file_operations sta_ ##name## _ops = {             \
+       .read = sta_##name##_read,                                      \
+       .write = sta_##name##_write,                                    \
+       .open = mac80211_open_file_generic,                             \
+}
+
 #define STA_FILE(name, field, format)                                  \
                STA_READ_##format(name, field)                          \
                STA_OPS(name)
@@ -57,7 +64,6 @@ STA_FILE(tx_filtered, tx_filtered_count, LU);
 STA_FILE(tx_retry_failed, tx_retry_failed, LU);
 STA_FILE(tx_retry_count, tx_retry_count, LU);
 STA_FILE(last_signal, last_signal, D);
-STA_FILE(last_noise, last_noise, D);
 STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
 
 static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
@@ -120,7 +126,7 @@ STA_OPS(last_seq_ctrl);
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
-       char buf[64 + STA_TID_NUM * 40], *p = buf;
+       char buf[71 + STA_TID_NUM * 40], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
 
@@ -128,16 +134,16 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
        p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
                        sta->ampdu_mlme.dialog_token_allocator + 1);
        p += scnprintf(p, sizeof(buf) + buf - p,
-                      "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n");
+                      "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n");
        for (i = 0; i < STA_TID_NUM; i++) {
                p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
-                               sta->ampdu_mlme.tid_state_rx[i]);
+                               sta->ampdu_mlme.tid_active_rx[i]);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-                               sta->ampdu_mlme.tid_state_rx[i] ?
+                               sta->ampdu_mlme.tid_active_rx[i] ?
                                sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
-                               sta->ampdu_mlme.tid_state_rx[i] ?
+                               sta->ampdu_mlme.tid_active_rx[i] ?
                                sta->ampdu_mlme.tid_rx[i]->ssn : 0);
 
                p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
@@ -157,7 +163,63 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 
        return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
-STA_OPS(agg_status);
+
+static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf,
+                                   size_t count, loff_t *ppos)
+{
+       char _buf[12], *buf = _buf;
+       struct sta_info *sta = file->private_data;
+       bool start, tx;
+       unsigned long tid;
+       int ret;
+
+       if (count > sizeof(_buf))
+               return -EINVAL;
+
+       if (copy_from_user(buf, userbuf, count))
+               return -EFAULT;
+
+       buf[sizeof(_buf) - 1] = '\0';
+
+       if (strncmp(buf, "tx ", 3) == 0) {
+               buf += 3;
+               tx = true;
+       } else if (strncmp(buf, "rx ", 3) == 0) {
+               buf += 3;
+               tx = false;
+       } else
+               return -EINVAL;
+
+       if (strncmp(buf, "start ", 6) == 0) {
+               buf += 6;
+               start = true;
+               if (!tx)
+                       return -EINVAL;
+       } else if (strncmp(buf, "stop ", 5) == 0) {
+               buf += 5;
+               start = false;
+       } else
+               return -EINVAL;
+
+       tid = simple_strtoul(buf, NULL, 0);
+
+       if (tid >= STA_TID_NUM)
+               return -EINVAL;
+
+       if (tx) {
+               if (start)
+                       ret = ieee80211_start_tx_ba_session(&sta->sta, tid);
+               else
+                       ret = ieee80211_stop_tx_ba_session(&sta->sta, tid,
+                                                          WLAN_BACK_RECIPIENT);
+       } else {
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
+               ret = 0;
+       }
+
+       return ret ?: count;
+}
+STA_OPS_RW(agg_status);
 
 static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
@@ -177,7 +239,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf,
        if (htc->ht_supported) {
                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(0)), "RX LDPC");
                PRINT_HT_CAP((htc->cap & BIT(1)), "HT20/HT40");
                PRINT_HT_CAP(!(htc->cap & BIT(1)), "HT20");
 
@@ -289,7 +351,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD(tx_retry_failed);
        DEBUGFS_ADD(tx_retry_count);
        DEBUGFS_ADD(last_signal);
-       DEBUGFS_ADD(last_noise);
        DEBUGFS_ADD(wep_weak_iv_count);
        DEBUGFS_ADD(ht_capa);
 }
index c3d844093a2f9203127f1cb10ee1f1d9b97a68ae..4f2271316650d98f08de2f1c460b4b8fb283d752 100644 (file)
@@ -84,16 +84,14 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 }
 
 static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
-                                       int mc_count,
-                                       struct dev_addr_list *mc_list)
+                                       struct netdev_hw_addr_list *mc_list)
 {
        u64 ret = 0;
 
        if (local->ops->prepare_multicast)
-               ret = local->ops->prepare_multicast(&local->hw, mc_count,
-                                                   mc_list);
+               ret = local->ops->prepare_multicast(&local->hw, mc_list);
 
-       trace_drv_prepare_multicast(local, mc_count, ret);
+       trace_drv_prepare_multicast(local, mc_list->count, ret);
 
        return ret;
 }
@@ -154,14 +152,15 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
 }
 
 static inline int drv_hw_scan(struct ieee80211_local *local,
+                             struct ieee80211_sub_if_data *sdata,
                              struct cfg80211_scan_request *req)
 {
        int ret;
 
        might_sleep();
 
-       ret = local->ops->hw_scan(&local->hw, req);
-       trace_drv_hw_scan(local, req, ret);
+       ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
+       trace_drv_hw_scan(local, sdata, req, ret);
        return ret;
 }
 
@@ -346,6 +345,15 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
        return ret;
 }
 
+static inline int drv_get_survey(struct ieee80211_local *local, int idx,
+                               struct survey_info *survey)
+{
+       int ret = -EOPNOTSUPP;
+       if (local->ops->conf_tx)
+               ret = local->ops->get_survey(&local->hw, idx, survey);
+       /* trace_drv_get_survey(local, idx, survey, ret); */
+       return ret;
+}
 
 static inline void drv_rfkill_poll(struct ieee80211_local *local)
 {
@@ -363,4 +371,15 @@ static inline void drv_flush(struct ieee80211_local *local, bool drop)
        if (local->ops->flush)
                local->ops->flush(&local->hw, drop);
 }
+
+static inline void drv_channel_switch(struct ieee80211_local *local,
+                                    struct ieee80211_channel_switch *ch_switch)
+{
+       might_sleep();
+
+       local->ops->channel_switch(&local->hw, ch_switch);
+
+       trace_drv_channel_switch(local, ch_switch);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index 41baf730a5c7b92f2debfb73ebfaf3b6bd3b079b..6a9b2342a9c2d3982c83d235149762271a4f9c83 100644 (file)
@@ -32,6 +32,10 @@ static inline void trace_ ## name(proto) {}
 #define VIF_PR_FMT     " vif:%s(%d)"
 #define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type
 
+/*
+ * Tracing for driver callbacks.
+ */
+
 TRACE_EVENT(drv_start,
        TP_PROTO(struct ieee80211_local *local, int ret),
 
@@ -359,23 +363,26 @@ TRACE_EVENT(drv_update_tkip_key,
 
 TRACE_EVENT(drv_hw_scan,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
                 struct cfg80211_scan_request *req, int ret),
 
-       TP_ARGS(local, req, ret),
+       TP_ARGS(local, sdata, req, ret),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(int, ret)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->ret = ret;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " ret:%d",
-               LOCAL_PR_ARG, __entry->ret
+               LOCAL_PR_FMT VIF_PR_FMT " ret:%d",
+               LOCAL_PR_ARG,VIF_PR_ARG, __entry->ret
        )
 );
 
@@ -766,6 +773,326 @@ TRACE_EVENT(drv_flush,
                LOCAL_PR_ARG, __entry->drop
        )
 );
+
+TRACE_EVENT(drv_channel_switch,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_channel_switch *ch_switch),
+
+       TP_ARGS(local, ch_switch),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u64, timestamp)
+               __field(bool, block_tx)
+               __field(u16, freq)
+               __field(u8, count)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->timestamp = ch_switch->timestamp;
+               __entry->block_tx = ch_switch->block_tx;
+               __entry->freq = ch_switch->channel->center_freq;
+               __entry->count = ch_switch->count;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " new freq:%u count:%d",
+               LOCAL_PR_ARG, __entry->freq, __entry->count
+       )
+);
+
+/*
+ * Tracing for API calls that drivers call.
+ */
+
+TRACE_EVENT(api_start_tx_ba_session,
+       TP_PROTO(struct ieee80211_sta *sta, u16 tid),
+
+       TP_ARGS(sta, tid),
+
+       TP_STRUCT__entry(
+               STA_ENTRY
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               STA_ASSIGN;
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               STA_PR_FMT " tid:%d",
+               STA_PR_ARG, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_start_tx_ba_cb,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+       TP_ARGS(sdata, ra, tid),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, ra, ETH_ALEN)
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->ra, ra, ETH_ALEN);
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " ra:%pM tid:%d",
+               VIF_PR_ARG, __entry->ra, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_stop_tx_ba_session,
+       TP_PROTO(struct ieee80211_sta *sta, u16 tid, u16 initiator),
+
+       TP_ARGS(sta, tid, initiator),
+
+       TP_STRUCT__entry(
+               STA_ENTRY
+               __field(u16, tid)
+               __field(u16, initiator)
+       ),
+
+       TP_fast_assign(
+               STA_ASSIGN;
+               __entry->tid = tid;
+               __entry->initiator = initiator;
+       ),
+
+       TP_printk(
+               STA_PR_FMT " tid:%d initiator:%d",
+               STA_PR_ARG, __entry->tid, __entry->initiator
+       )
+);
+
+TRACE_EVENT(api_stop_tx_ba_cb,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, const u8 *ra, u16 tid),
+
+       TP_ARGS(sdata, ra, tid),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __array(u8, ra, ETH_ALEN)
+               __field(u16, tid)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               memcpy(__entry->ra, ra, ETH_ALEN);
+               __entry->tid = tid;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " ra:%pM tid:%d",
+               VIF_PR_ARG, __entry->ra, __entry->tid
+       )
+);
+
+TRACE_EVENT(api_restart_hw,
+       TP_PROTO(struct ieee80211_local *local),
+
+       TP_ARGS(local),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT,
+               LOCAL_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_beacon_loss,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+       TP_ARGS(sdata),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT,
+               VIF_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_connection_loss,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata),
+
+       TP_ARGS(sdata),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT,
+               VIF_PR_ARG
+       )
+);
+
+TRACE_EVENT(api_cqm_rssi_notify,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata,
+                enum nl80211_cqm_rssi_threshold_event rssi_event),
+
+       TP_ARGS(sdata, rssi_event),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(u32, rssi_event)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->rssi_event = rssi_event;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " event:%d",
+               VIF_PR_ARG, __entry->rssi_event
+       )
+);
+
+TRACE_EVENT(api_scan_completed,
+       TP_PROTO(struct ieee80211_local *local, bool aborted),
+
+       TP_ARGS(local, aborted),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(bool, aborted)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->aborted = aborted;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " aborted:%d",
+               LOCAL_PR_ARG, __entry->aborted
+       )
+);
+
+TRACE_EVENT(api_sta_block_awake,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sta *sta, bool block),
+
+       TP_ARGS(local, sta, block),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               STA_ENTRY
+               __field(bool, block)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               STA_ASSIGN;
+               __entry->block = block;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT STA_PR_FMT " block:%d",
+               LOCAL_PR_ARG, STA_PR_FMT, __entry->block
+       )
+);
+
+TRACE_EVENT(api_chswitch_done,
+       TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success),
+
+       TP_ARGS(sdata, success),
+
+       TP_STRUCT__entry(
+               VIF_ENTRY
+               __field(bool, success)
+       ),
+
+       TP_fast_assign(
+               VIF_ASSIGN;
+               __entry->success = success;
+       ),
+
+       TP_printk(
+               VIF_PR_FMT " success=%d",
+               VIF_PR_ARG, __entry->success
+       )
+);
+
+/*
+ * Tracing for internal functions
+ * (which may also be called in response to driver calls)
+ */
+
+TRACE_EVENT(wake_queue,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                enum queue_stop_reason reason),
+
+       TP_ARGS(local, queue, reason),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u32, reason)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->reason = reason;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d, reason:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->reason
+       )
+);
+
+TRACE_EVENT(stop_queue,
+       TP_PROTO(struct ieee80211_local *local, u16 queue,
+                enum queue_stop_reason reason),
+
+       TP_ARGS(local, queue, reason),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               __field(u16, queue)
+               __field(u32, reason)
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               __entry->queue = queue;
+               __entry->reason = reason;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT " queue:%d, reason:%d",
+               LOCAL_PR_ARG, __entry->queue, __entry->reason
+       )
+);
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
index bb677a73b7c9d67a623e962ad9419231bb11e3f4..2ab106a0a49189fb23169c1d2b4b5717c67f7731 100644 (file)
@@ -175,8 +175,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
        if (initiator == WLAN_BACK_INITIATOR)
-               ieee80211_sta_stop_rx_ba_session(sdata, sta->sta.addr, tid,
-                                                WLAN_BACK_INITIATOR, 0);
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0);
        else { /* WLAN_BACK_RECIPIENT */
                spin_lock_bh(&sta->lock);
                if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK)
index e2976da4e0d9c7e86b21557c1571e2dd7e449db6..b2cc1fda6cfdb6ba1054aa2bb224f9fce7bba5e8 100644 (file)
@@ -92,12 +92,18 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        if (memcmp(ifibss->bssid, bssid, ETH_ALEN))
                sta_info_flush(sdata->local, sdata);
 
+       /* if merging, indicate to driver that we leave the old IBSS */
+       if (sdata->vif.bss_conf.ibss_joined) {
+               sdata->vif.bss_conf.ibss_joined = false;
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
+       }
+
        memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
        sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
        local->oper_channel = chan;
-       local->oper_channel_type = NL80211_CHAN_NO_HT;
+       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
        ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
        sband = local->hw.wiphy->bands[chan->band];
@@ -171,6 +177,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        bss_change |= BSS_CHANGED_BSSID;
        bss_change |= BSS_CHANGED_BEACON;
        bss_change |= BSS_CHANGED_BEACON_ENABLED;
+       bss_change |= BSS_CHANGED_IBSS;
+       sdata->vif.bss_conf.ibss_joined = true;
        ieee80211_bss_info_change_notify(sdata, bss_change);
 
        ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
@@ -265,17 +273,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                        sta->sta.supp_rates[band] = supp_rates |
                                ieee80211_mandatory_rates(local, band);
 
+                       if (sta->sta.supp_rates[band] != prev_rates) {
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
-                       if (sta->sta.supp_rates[band] != prev_rates)
                                printk(KERN_DEBUG "%s: updated supp_rates set "
-                                   "for %pM based on beacon info (0x%llx | "
-                                   "0x%llx -> 0x%llx)\n",
-                                   sdata->name,
-                                   sta->sta.addr,
-                                   (unsigned long long) prev_rates,
-                                   (unsigned long long) supp_rates,
-                                   (unsigned long long) sta->sta.supp_rates[band]);
+                                   "for %pM based on beacon/probe_response "
+                                   "(0x%x -> 0x%x)\n",
+                                   sdata->name, sta->sta.addr,
+                                   prev_rates, sta->sta.supp_rates[band]);
 #endif
+                               rate_control_rate_init(sta);
+                       }
                        rcu_read_unlock();
                } else {
                        rcu_read_unlock();
@@ -371,6 +378,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                       sdata->name, mgmt->bssid);
 #endif
                ieee80211_sta_join_ibss(sdata, bss);
+               supp_rates = ieee80211_sta_get_rates(local, elems, band);
                ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
                                       supp_rates, GFP_KERNEL);
        }
@@ -481,7 +489,9 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
        printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
               "IBSS networks with same SSID (merge)\n", sdata->name);
 
-       ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len);
+       ieee80211_request_internal_scan(sdata,
+                       ifibss->ssid, ifibss->ssid_len,
+                       ifibss->fixed_channel ? ifibss->channel : NULL);
 }
 
 static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
@@ -588,8 +598,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
                printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
                       "join\n", sdata->name);
 
-               ieee80211_request_internal_scan(sdata, ifibss->ssid,
-                                               ifibss->ssid_len);
+               ieee80211_request_internal_scan(sdata,
+                               ifibss->ssid, ifibss->ssid_len,
+                               ifibss->fixed_channel ? ifibss->channel : NULL);
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
 
@@ -897,6 +908,13 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
        sdata->u.ibss.channel = params->channel;
        sdata->u.ibss.fixed_channel = params->channel_fixed;
 
+       /* fix ourselves to that channel now already */
+       if (params->channel_fixed) {
+               sdata->local->oper_channel = params->channel;
+               WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
+                                                   NL80211_CHAN_NO_HT));
+       }
+
        if (params->ie) {
                sdata->u.ibss.ie = kmemdup(params->ie, params->ie_len,
                                           GFP_KERNEL);
@@ -951,7 +969,9 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        kfree(sdata->u.ibss.ie);
        skb = sdata->u.ibss.presp;
        rcu_assign_pointer(sdata->u.ibss.presp, NULL);
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+       sdata->vif.bss_conf.ibss_joined = false;
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
+                                               BSS_CHANGED_IBSS);
        synchronize_rcu();
        kfree_skb(skb);
 
index 241533e1bc03116304d64d4ba9f10c34af255ec3..1a9e2da37a93d91320a6f20ec7594423e535da77 100644 (file)
@@ -317,6 +317,7 @@ enum ieee80211_sta_flags {
        IEEE80211_STA_MFP_ENABLED       = BIT(6),
        IEEE80211_STA_UAPSD_ENABLED     = BIT(7),
        IEEE80211_STA_NULLFUNC_ACKED    = BIT(8),
+       IEEE80211_STA_RESET_SIGNAL_AVE  = BIT(9),
 };
 
 struct ieee80211_if_managed {
@@ -327,7 +328,7 @@ struct ieee80211_if_managed {
        struct work_struct work;
        struct work_struct monitor_work;
        struct work_struct chswitch_work;
-       struct work_struct beacon_loss_work;
+       struct work_struct beacon_connection_loss_work;
 
        unsigned long probe_timeout;
        int probe_send_count;
@@ -359,6 +360,24 @@ struct ieee80211_if_managed {
        int wmm_last_param_set;
 
        u8 use_4addr;
+
+       /* Signal strength from the last Beacon frame in the current BSS. */
+       int last_beacon_signal;
+
+       /*
+        * Weighted average of the signal strength from Beacon frames in the
+        * current BSS. This is in units of 1/16 of the signal unit to maintain
+        * accuracy and to speed up calculations, i.e., the value need to be
+        * divided by 16 to get the actual value.
+        */
+       int ave_beacon_signal;
+
+       /*
+        * Last Beacon frame signal strength average (ave_beacon_signal / 16)
+        * that triggered a cqm event. 0 indicates that no event has been
+        * generated for the current association.
+        */
+       int last_cqm_event_signal;
 };
 
 enum ieee80211_ibss_request {
@@ -646,8 +665,7 @@ struct ieee80211_local {
        struct work_struct recalc_smps;
 
        /* aggregated multicast list */
-       struct dev_addr_list *mc_list;
-       int mc_count;
+       struct netdev_hw_addr_list mc_list;
 
        bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 
@@ -745,10 +763,11 @@ struct ieee80211_local {
        int scan_channel_idx;
        int scan_ies_len;
 
+       unsigned long leave_oper_channel_time;
        enum mac80211_scan_state next_scan_state;
        struct delayed_work scan_work;
        struct ieee80211_sub_if_data *scan_sdata;
-       enum nl80211_channel_type oper_channel_type;
+       enum nl80211_channel_type _oper_channel_type;
        struct ieee80211_channel *oper_channel, *csa_channel;
 
        /* Temporary remain-on-channel for off-channel operations */
@@ -979,7 +998,8 @@ int ieee80211_max_network_latency(struct notifier_block *nb,
                                  unsigned long data, void *dummy);
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_channel_sw_ie *sw_elem,
-                                     struct ieee80211_bss *bss);
+                                     struct ieee80211_bss *bss,
+                                     u64 timestamp);
 void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
 void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
 
@@ -1000,7 +1020,8 @@ void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
 /* scan/BSS handling */
 void ieee80211_scan_work(struct work_struct *work);
 int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
-                                   const u8 *ssid, u8 ssid_len);
+                                   const u8 *ssid, u8 ssid_len,
+                                   struct ieee80211_channel *chan);
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
 void ieee80211_scan_cancel(struct ieee80211_local *local);
@@ -1078,8 +1099,6 @@ 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);
 void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
                                    u16 initiator, u16 reason);
 void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta);
@@ -1155,7 +1174,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             int powersave);
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_hdr *hdr);
-void ieee80211_beacon_loss_work(struct work_struct *work);
+void ieee80211_beacon_connection_loss_work(struct work_struct *work);
 
 void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
                                     enum queue_stop_reason reason);
@@ -1210,6 +1229,20 @@ int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
 int ieee80211_wk_cancel_remain_on_channel(
        struct ieee80211_sub_if_data *sdata, u64 cookie);
 
+/* channel management */
+enum ieee80211_chan_mode {
+       CHAN_MODE_UNDEFINED,
+       CHAN_MODE_HOPPING,
+       CHAN_MODE_FIXED,
+};
+
+enum ieee80211_chan_mode
+ieee80211_get_channel_mode(struct ieee80211_local *local,
+                          struct ieee80211_sub_if_data *ignore);
+bool ieee80211_set_channel_type(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata,
+                               enum nl80211_channel_type chantype);
+
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
 #else
index e08fa8eda1b36aabfda2b591b31ac4f2fe641817..50deb017fd6e771c923f91b9e46264017a4e1cf0 100644 (file)
@@ -413,8 +413,7 @@ static int ieee80211_stop(struct net_device *dev)
 
        netif_addr_lock_bh(dev);
        spin_lock_bh(&local->filter_lock);
-       __dev_addr_unsync(&local->mc_list, &local->mc_count,
-                         &dev->mc_list, &dev->mc_count);
+       __hw_addr_unsync(&local->mc_list, &dev->mc, dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
        netif_addr_unlock_bh(dev);
 
@@ -487,7 +486,7 @@ static int ieee80211_stop(struct net_device *dev)
                cancel_work_sync(&sdata->u.mgd.work);
                cancel_work_sync(&sdata->u.mgd.chswitch_work);
                cancel_work_sync(&sdata->u.mgd.monitor_work);
-               cancel_work_sync(&sdata->u.mgd.beacon_loss_work);
+               cancel_work_sync(&sdata->u.mgd.beacon_connection_loss_work);
 
                /*
                 * When we get here, the interface is marked down.
@@ -597,8 +596,7 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
                sdata->flags ^= IEEE80211_SDATA_PROMISC;
        }
        spin_lock_bh(&local->filter_lock);
-       __dev_addr_sync(&local->mc_list, &local->mc_count,
-                       &dev->mc_list, &dev->mc_count);
+       __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
        spin_unlock_bh(&local->filter_lock);
        ieee80211_queue_work(&local->hw, &local->reconfig_filter);
 }
@@ -816,6 +814,118 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
+static void ieee80211_assign_perm_addr(struct ieee80211_local *local,
+                                      struct net_device *dev,
+                                      enum nl80211_iftype type)
+{
+       struct ieee80211_sub_if_data *sdata;
+       u64 mask, start, addr, val, inc;
+       u8 *m;
+       u8 tmp_addr[ETH_ALEN];
+       int i;
+
+       /* default ... something at least */
+       memcpy(dev->perm_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+
+       if (is_zero_ether_addr(local->hw.wiphy->addr_mask) &&
+           local->hw.wiphy->n_addresses <= 1)
+               return;
+
+
+       mutex_lock(&local->iflist_mtx);
+
+       switch (type) {
+       case NL80211_IFTYPE_MONITOR:
+               /* doesn't matter */
+               break;
+       case NL80211_IFTYPE_WDS:
+       case NL80211_IFTYPE_AP_VLAN:
+               /* match up with an AP interface */
+               list_for_each_entry(sdata, &local->interfaces, list) {
+                       if (sdata->vif.type != NL80211_IFTYPE_AP)
+                               continue;
+                       memcpy(dev->perm_addr, sdata->vif.addr, ETH_ALEN);
+                       break;
+               }
+               /* keep default if no AP interface present */
+               break;
+       default:
+               /* assign a new address if possible -- try n_addresses first */
+               for (i = 0; i < local->hw.wiphy->n_addresses; i++) {
+                       bool used = false;
+
+                       list_for_each_entry(sdata, &local->interfaces, list) {
+                               if (memcmp(local->hw.wiphy->addresses[i].addr,
+                                          sdata->vif.addr, ETH_ALEN) == 0) {
+                                       used = true;
+                                       break;
+                               }
+                       }
+
+                       if (!used) {
+                               memcpy(dev->perm_addr,
+                                      local->hw.wiphy->addresses[i].addr,
+                                      ETH_ALEN);
+                               break;
+                       }
+               }
+
+               /* try mask if available */
+               if (is_zero_ether_addr(local->hw.wiphy->addr_mask))
+                       break;
+
+               m = local->hw.wiphy->addr_mask;
+               mask =  ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
+                       ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
+                       ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
+
+               if (__ffs64(mask) + hweight64(mask) != fls64(mask)) {
+                       /* not a contiguous mask ... not handled now! */
+                       printk(KERN_DEBUG "not contiguous\n");
+                       break;
+               }
+
+               m = local->hw.wiphy->perm_addr;
+               start = ((u64)m[0] << 5*8) | ((u64)m[1] << 4*8) |
+                       ((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
+                       ((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);
+
+               inc = 1ULL<<__ffs64(mask);
+               val = (start & mask);
+               addr = (start & ~mask) | (val & mask);
+               do {
+                       bool used = false;
+
+                       tmp_addr[5] = addr >> 0*8;
+                       tmp_addr[4] = addr >> 1*8;
+                       tmp_addr[3] = addr >> 2*8;
+                       tmp_addr[2] = addr >> 3*8;
+                       tmp_addr[1] = addr >> 4*8;
+                       tmp_addr[0] = addr >> 5*8;
+
+                       val += inc;
+
+                       list_for_each_entry(sdata, &local->interfaces, list) {
+                               if (memcmp(tmp_addr, sdata->vif.addr,
+                                                       ETH_ALEN) == 0) {
+                                       used = true;
+                                       break;
+                               }
+                       }
+
+                       if (!used) {
+                               memcpy(dev->perm_addr, tmp_addr, ETH_ALEN);
+                               break;
+                       }
+                       addr = (start & ~mask) | (val & mask);
+               } while (addr != start);
+
+               break;
+       }
+
+       mutex_unlock(&local->iflist_mtx);
+}
+
 int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                     struct net_device **new_dev, enum nl80211_iftype type,
                     struct vif_params *params)
@@ -845,8 +955,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
        if (ret < 0)
                goto fail;
 
-       memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
-       memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+       ieee80211_assign_perm_addr(local, ndev, type);
+       memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
        SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
 
        /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
index e8f6e3b252d8b8ee3ef4210695dfc44283534bc4..8d4b41787dcf5146b94267a4aff7c8025b4a21c0 100644 (file)
@@ -140,6 +140,7 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                                     struct ieee80211_sub_if_data,
                                     u.ap);
 
+       key->conf.ap_addr = sdata->dev->dev_addr;
        ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
 
        if (!ret) {
index b887e484ae04427d3ec2118c13e9238c5fc650e9..22a384dfab65d1bd3a8539f39066d8401ff0f649 100644 (file)
@@ -71,7 +71,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
        spin_lock_bh(&local->filter_lock);
        changed_flags = local->filter_flags ^ new_flags;
 
-       mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
+       mc = drv_prepare_multicast(local, &local->mc_list);
        spin_unlock_bh(&local->filter_lock);
 
        /* be a bit nasty */
@@ -111,7 +111,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
-               channel_type = local->oper_channel_type;
+               channel_type = local->_oper_channel_type;
        }
 
        if (chan != local->hw.conf.channel ||
@@ -309,6 +309,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
+       trace_api_restart_hw(local);
+
        /* use this reason, __ieee80211_resume will unblock it */
        ieee80211_stop_queues_by_reason(hw,
                IEEE80211_QUEUE_STOP_REASON_SUSPEND);
@@ -388,6 +390,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN;
 
        INIT_LIST_HEAD(&local->interfaces);
+
+       __hw_addr_init(&local->mc_list);
+
        mutex_init(&local->iflist_mtx);
        mutex_init(&local->scan_mtx);
 
@@ -437,7 +442,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        struct ieee80211_local *local = hw_to_local(hw);
        int result;
        enum ieee80211_band band;
-       int channels, i, j, max_bitrates;
+       int channels, max_bitrates;
        bool supp_ht;
        static const u32 cipher_suites[] = {
                WLAN_CIPHER_SUITE_WEP40,
@@ -567,6 +572,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        local->hw.conf.listen_interval = local->hw.max_listen_interval;
 
+       local->hw.conf.dynamic_ps_forced_timeout = -1;
+
        result = sta_info_start(local);
        if (result < 0)
                goto fail_sta_info;
@@ -601,21 +608,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        ieee80211_led_init(local);
 
-       /* alloc internal scan request */
-       i = 0;
-       local->int_scan_req->ssids = &local->scan_ssid;
-       local->int_scan_req->n_ssids = 1;
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (!hw->wiphy->bands[band])
-                       continue;
-               for (j = 0; j < hw->wiphy->bands[band]->n_channels; j++) {
-                       local->int_scan_req->channels[i] =
-                               &hw->wiphy->bands[band]->channels[j];
-                       i++;
-               }
-       }
-       local->int_scan_req->n_channels = i;
-
        local->network_latency_notifier.notifier_call =
                ieee80211_max_network_latency;
        result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
index 859ee5f3d94146a5103b5c2188847da3a302d12d..bde81031727a6a78cadfa070f95ead4f45b3538b 100644 (file)
@@ -287,8 +287,6 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
        *pos++ |= sdata->u.mesh.accepting_plinks ?
            MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
        *pos++ = 0x00;
-
-       return;
 }
 
 u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl)
@@ -601,10 +599,10 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
                                          struct ieee80211_rx_status *rx_status)
 {
        switch (mgmt->u.action.category) {
-       case MESH_PLINK_CATEGORY:
+       case WLAN_CATEGORY_MESH_PLINK:
                mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
                break;
-       case MESH_PATH_SEL_CATEGORY:
+       case WLAN_CATEGORY_MESH_PATH_SEL:
                mesh_rx_path_sel_frame(sdata, mgmt, len);
                break;
        }
index 85562c59d7d68bd656fdd1ca00f6129b8adefe8c..c88087f1cd0ff79a4a5f28c57f2626d5c7ce8eac 100644 (file)
@@ -209,8 +209,6 @@ struct mesh_rmc {
 #define MESH_MAX_MPATHS                1024
 
 /* Pending ANA approval */
-#define MESH_PLINK_CATEGORY    30
-#define MESH_PATH_SEL_CATEGORY 32
 #define MESH_PATH_SEL_ACTION   0
 
 /* PERR reason codes */
index fefc45c4b4e8cad4a792d9f6787284270f3510bd..0705018d8d1e7ac9a185f3bea2fffe43aaaaed24 100644 (file)
@@ -132,7 +132,7 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        /* BSSID == SA */
        memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
-       mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+       mgmt->u.action.category = WLAN_CATEGORY_MESH_PATH_SEL;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
 
        switch (action) {
@@ -225,7 +225,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
        memcpy(mgmt->da, ra, 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.category = WLAN_CATEGORY_MESH_PATH_SEL;
        mgmt->u.action.u.mesh_action.action_code = MESH_PATH_SEL_ACTION;
        ie_len = 15;
        pos = skb_put(skb, 2 + ie_len);
@@ -624,7 +624,6 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
 fail:
        rcu_read_unlock();
        sdata->u.mesh.mshstats.dropped_frames_no_route++;
-       return;
 }
 
 static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
index 7b7080e2b49f47a1dcac316432341b89b3a9a5cb..3cd5f7b5d693be131e75baeb8f7474fb4ab2bef3 100644 (file)
@@ -172,7 +172,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, 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.category = WLAN_CATEGORY_MESH_PLINK;
        mgmt->u.action.u.plink_action.action_code = action;
 
        if (action == PLINK_CLOSE)
index 88f95e7bab49624cde1fbf7a446c165cb5c58e3f..0839c4e8fd2e35b2042e968a9eddebb1e49dc99e 100644 (file)
  */
 #define IEEE80211_PROBE_WAIT           (HZ / 2)
 
+/*
+ * Weight given to the latest Beacon frame when calculating average signal
+ * strength for Beacon frames received in the current BSS. This must be
+ * between 1 and 15.
+ */
+#define IEEE80211_SIGNAL_AVE_WEIGHT    3
+
 #define TMR_RUNNING_TIMER      0
 #define TMR_RUNNING_CHANSW     1
 
@@ -130,11 +137,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta;
        u32 changed = 0;
        u16 ht_opmode;
-       bool enable_ht = true, ht_changed;
+       bool enable_ht = true;
+       enum nl80211_channel_type prev_chantype;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
+       prev_chantype = sdata->vif.bss_conf.channel_type;
+
        /* HT is not supported */
        if (!sband->ht_cap.ht_supported)
                enable_ht = false;
@@ -165,38 +175,37 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       ht_changed = conf_is_ht(&local->hw.conf) != enable_ht ||
-                    channel_type != local->hw.conf.channel_type;
-
        if (local->tmp_channel)
                local->tmp_channel_type = channel_type;
-       local->oper_channel_type = channel_type;
 
-       if (ht_changed) {
-                /* channel_type change automatically detected */
-               ieee80211_hw_config(local, 0);
+       if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
+               /* can only fail due to HT40+/- mismatch */
+               channel_type = NL80211_CHAN_HT20;
+               WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
+       }
+
+       /* channel_type change automatically detected */
+       ieee80211_hw_config(local, 0);
 
+       if (prev_chantype != channel_type) {
                rcu_read_lock();
                sta = sta_info_get(sdata, bssid);
                if (sta)
                        rate_control_rate_update(local, sband, sta,
                                                 IEEE80211_RC_HT_CHANGED,
-                                                local->oper_channel_type);
+                                                channel_type);
                rcu_read_unlock();
-        }
-
-       /* disable HT */
-       if (!enable_ht)
-               return 0;
+       }
 
        ht_opmode = le16_to_cpu(hti->operation_mode);
 
        /* if bss configuration changed store the new one */
-       if (!sdata->ht_opmode_valid ||
-           sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
+       if (sdata->ht_opmode_valid != enable_ht ||
+           sdata->vif.bss_conf.ht_operation_mode != ht_opmode ||
+           prev_chantype != channel_type) {
                changed |= BSS_CHANGED_HT;
                sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
-               sdata->ht_opmode_valid = true;
+               sdata->ht_opmode_valid = enable_ht;
        }
 
        return changed;
@@ -206,7 +215,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 
 static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                                           const u8 *bssid, u16 stype, u16 reason,
-                                          void *cookie)
+                                          void *cookie, bool send_frame)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -243,7 +252,11 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                        cfg80211_send_disassoc(sdata->dev, (u8 *)mgmt, skb->len);
        if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED))
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
-       ieee80211_tx_skb(sdata, skb);
+
+       if (send_frame)
+               ieee80211_tx_skb(sdata, skb);
+       else
+               kfree_skb(skb);
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
@@ -329,7 +342,11 @@ static void ieee80211_chswitch_work(struct work_struct *work)
                goto out;
 
        sdata->local->oper_channel = sdata->local->csa_channel;
-       ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL);
+       if (!sdata->local->ops->channel_switch) {
+               /* call "hw_config" only if doing sw channel switch */
+               ieee80211_hw_config(sdata->local,
+                       IEEE80211_CONF_CHANGE_CHANNEL);
+       }
 
        /* XXX: shouldn't really modify cfg80211-owned data! */
        ifmgd->associated->channel = sdata->local->oper_channel;
@@ -341,6 +358,29 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        mutex_unlock(&ifmgd->mtx);
 }
 
+void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_if_managed *ifmgd;
+
+       sdata = vif_to_sdata(vif);
+       ifmgd = &sdata->u.mgd;
+
+       trace_api_chswitch_done(sdata, success);
+       if (!success) {
+               /*
+                * If the channel switch was not successful, stay
+                * around on the old channel. We currently lack
+                * good handling of this situation, possibly we
+                * should just drop the association.
+                */
+               sdata->local->csa_channel = sdata->local->oper_channel;
+       }
+
+       ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
+}
+EXPORT_SYMBOL(ieee80211_chswitch_done);
+
 static void ieee80211_chswitch_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
@@ -357,7 +397,8 @@ static void ieee80211_chswitch_timer(unsigned long data)
 
 void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                      struct ieee80211_channel_sw_ie *sw_elem,
-                                     struct ieee80211_bss *bss)
+                                     struct ieee80211_bss *bss,
+                                     u64 timestamp)
 {
        struct cfg80211_bss *cbss =
                container_of((void *)bss, struct cfg80211_bss, priv);
@@ -385,10 +426,29 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        sdata->local->csa_channel = new_ch;
 
+       if (sdata->local->ops->channel_switch) {
+               /* use driver's channel switch callback */
+               struct ieee80211_channel_switch ch_switch;
+               memset(&ch_switch, 0, sizeof(ch_switch));
+               ch_switch.timestamp = timestamp;
+               if (sw_elem->mode) {
+                       ch_switch.block_tx = true;
+                       ieee80211_stop_queues_by_reason(&sdata->local->hw,
+                                       IEEE80211_QUEUE_STOP_REASON_CSA);
+               }
+               ch_switch.channel = new_ch;
+               ch_switch.count = sw_elem->count;
+               ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+               drv_channel_switch(sdata->local, &ch_switch);
+               return;
+       }
+
+       /* channel switch handled in software */
        if (sw_elem->count <= 1) {
                ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
        } else {
-               ieee80211_stop_queues_by_reason(&sdata->local->hw,
+               if (sw_elem->mode)
+                       ieee80211_stop_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
                ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
                mod_timer(&ifmgd->chswitch_timer,
@@ -467,6 +527,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
 {
        struct ieee80211_sub_if_data *sdata, *found = NULL;
        int count = 0;
+       int timeout;
 
        if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS)) {
                local->ps_sdata = NULL;
@@ -500,6 +561,26 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
                beaconint_us = ieee80211_tu_to_usec(
                                        found->vif.bss_conf.beacon_int);
 
+               timeout = local->hw.conf.dynamic_ps_forced_timeout;
+               if (timeout < 0) {
+                       /*
+                        * The 2 second value is there for compatibility until
+                        * the PM_QOS_NETWORK_LATENCY is configured with real
+                        * values.
+                        */
+                       if (latency == 2000000000)
+                               timeout = 100;
+                       else if (latency <= 50000)
+                               timeout = 300;
+                       else if (latency <= 100000)
+                               timeout = 100;
+                       else if (latency <= 500000)
+                               timeout = 50;
+                       else
+                               timeout = 0;
+               }
+               local->hw.conf.dynamic_ps_timeout = timeout;
+
                if (beaconint_us > latency) {
                        local->ps_sdata = NULL;
                } else {
@@ -592,6 +673,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        int count;
        u8 *pos, uapsd_queues = 0;
 
+       if (!local->ops->conf_tx)
+               return;
+
        if (local->hw.queues < 4)
                return;
 
@@ -666,11 +750,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                       params.aifs, params.cw_min, params.cw_max, params.txop,
                       params.uapsd);
 #endif
-               if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
+               if (drv_conf_tx(local, queue, &params))
                        printk(KERN_DEBUG "%s: failed to set TX queue "
                               "parameters for queue %d\n",
                               wiphy_name(local->hw.wiphy), queue);
        }
+
+       /* enable WMM or activate new settings */
+       local->hw.conf.flags |= IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
 }
 
 static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
@@ -731,6 +819,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        sdata->u.mgd.associated = cbss;
        memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
 
+       sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
+
        /* just to be sure */
        sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
                                IEEE80211_STA_BEACON_POLL);
@@ -756,6 +846,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        /* And the BSSID changed - we're associated now */
        bss_info_changed |= BSS_CHANGED_BSSID;
 
+       /* Tell the driver to monitor connection quality (if supported) */
+       if ((local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI) &&
+           sdata->vif.bss_conf.cqm_rssi_thold)
+               bss_info_changed |= BSS_CHANGED_CQM;
+
        ieee80211_bss_info_change_notify(sdata, bss_info_changed);
 
        mutex_lock(&local->iflist_mtx);
@@ -767,7 +862,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        netif_carrier_on(sdata->dev);
 }
 
-static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+                                  bool remove_sta)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
@@ -819,7 +915,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
        ieee80211_set_wmm_default(sdata);
 
        /* channel(_type) changes are handled by ieee80211_hw_config */
-       local->oper_channel_type = NL80211_CHAN_NO_HT;
+       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
 
        /* on the next assoc, re-program HT parameters */
        sdata->ht_opmode_valid = false;
@@ -836,11 +932,12 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata)
 
        ieee80211_hw_config(local, config_changed);
 
-       /* And the BSSID changed -- not very interesting here */
-       changed |= BSS_CHANGED_BSSID;
+       /* The BSSID (not really interesting) and HT changed */
+       changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
-       sta_info_destroy_addr(sdata, bssid);
+       if (remove_sta)
+               sta_info_destroy_addr(sdata, bssid);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -857,6 +954,9 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
        if (is_multicast_ether_addr(hdr->addr1))
                return;
 
+       if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+               return;
+
        mod_timer(&sdata->u.mgd.conn_mon_timer,
                  round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME));
 }
@@ -934,23 +1034,72 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
        mutex_unlock(&ifmgd->mtx);
 }
 
-void ieee80211_beacon_loss_work(struct work_struct *work)
+static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_local *local = sdata->local;
+       u8 bssid[ETH_ALEN];
+
+       mutex_lock(&ifmgd->mtx);
+       if (!ifmgd->associated) {
+               mutex_unlock(&ifmgd->mtx);
+               return;
+       }
+
+       memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
+
+       printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid);
+
+       ieee80211_set_disassoc(sdata, true);
+       ieee80211_recalc_idle(local);
+       mutex_unlock(&ifmgd->mtx);
+       /*
+        * must be outside lock due to cfg80211,
+        * but that's not a problem.
+        */
+       ieee80211_send_deauth_disassoc(sdata, bssid,
+                                      IEEE80211_STYPE_DEAUTH,
+                                      WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+                                      NULL, true);
+}
+
+void ieee80211_beacon_connection_loss_work(struct work_struct *work)
 {
        struct ieee80211_sub_if_data *sdata =
                container_of(work, struct ieee80211_sub_if_data,
-                            u.mgd.beacon_loss_work);
+                            u.mgd.beacon_connection_loss_work);
 
-       ieee80211_mgd_probe_ap(sdata, true);
+       if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+               __ieee80211_connection_loss(sdata);
+       else
+               ieee80211_mgd_probe_ap(sdata, true);
 }
 
 void ieee80211_beacon_loss(struct ieee80211_vif *vif)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_hw *hw = &sdata->local->hw;
 
-       ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
+       trace_api_beacon_loss(sdata);
+
+       WARN_ON(hw->flags & IEEE80211_HW_CONNECTION_MONITOR);
+       ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
 }
 EXPORT_SYMBOL(ieee80211_beacon_loss);
 
+void ieee80211_connection_loss(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct ieee80211_hw *hw = &sdata->local->hw;
+
+       trace_api_connection_loss(sdata);
+
+       WARN_ON(!(hw->flags & IEEE80211_HW_CONNECTION_MONITOR));
+       ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work);
+}
+EXPORT_SYMBOL(ieee80211_connection_loss);
+
+
 static enum rx_mgmt_action __must_check
 ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
                         struct ieee80211_mgmt *mgmt, size_t len)
@@ -971,7 +1120,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticated from %pM (Reason: %u)\n",
                        sdata->name, bssid, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(sdata->local);
 
        return RX_MGMT_CFG80211_DEAUTH;
@@ -1001,7 +1150,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n",
                        sdata->name, mgmt->sa, reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       ieee80211_set_disassoc(sdata, true);
        ieee80211_recalc_idle(sdata->local);
        return RX_MGMT_CFG80211_DISASSOC;
 }
@@ -1215,7 +1364,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                                        ETH_ALEN) == 0)) {
                struct ieee80211_channel_sw_ie *sw_elem =
                        (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
-               ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
+               ieee80211_sta_process_chanswitch(sdata, sw_elem,
+                                                bss, rx_status->mactime);
        }
 }
 
@@ -1254,12 +1404,17 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
                mutex_lock(&sdata->local->iflist_mtx);
                ieee80211_recalc_ps(sdata->local, -1);
                mutex_unlock(&sdata->local->iflist_mtx);
+
+               if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
+                       return;
+
                /*
                 * We've received a probe response, but are not sure whether
                 * we have or will be receiving any beacons or data, so let's
                 * schedule the timers again, just in case.
                 */
                mod_beacon_timer(sdata);
+
                mod_timer(&ifmgd->conn_mon_timer,
                          round_jiffies_up(jiffies +
                                           IEEE80211_CONNECTION_IDLE_TIME));
@@ -1293,6 +1448,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        size_t baselen;
        struct ieee802_11_elems elems;
        struct ieee80211_local *local = sdata->local;
@@ -1328,6 +1484,41 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
+       /* Track average RSSI from the Beacon frames of the current AP */
+       ifmgd->last_beacon_signal = rx_status->signal;
+       if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
+               ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
+               ifmgd->ave_beacon_signal = rx_status->signal;
+               ifmgd->last_cqm_event_signal = 0;
+       } else {
+               ifmgd->ave_beacon_signal =
+                       (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
+                        (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
+                        ifmgd->ave_beacon_signal) / 16;
+       }
+       if (bss_conf->cqm_rssi_thold &&
+           !(local->hw.flags & IEEE80211_HW_SUPPORTS_CQM_RSSI)) {
+               int sig = ifmgd->ave_beacon_signal / 16;
+               int last_event = ifmgd->last_cqm_event_signal;
+               int thold = bss_conf->cqm_rssi_thold;
+               int hyst = bss_conf->cqm_rssi_hyst;
+               if (sig < thold &&
+                   (last_event == 0 || sig < last_event - hyst)) {
+                       ifmgd->last_cqm_event_signal = sig;
+                       ieee80211_cqm_rssi_notify(
+                               &sdata->vif,
+                               NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+                               GFP_KERNEL);
+               } else if (sig > thold &&
+                          (last_event == 0 || sig > last_event + hyst)) {
+                       ifmgd->last_cqm_event_signal = sig;
+                       ieee80211_cqm_rssi_notify(
+                               &sdata->vif,
+                               NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+                               GFP_KERNEL);
+               }
+       }
+
        if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                if (net_ratelimit()) {
@@ -1506,7 +1697,8 @@ 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,
-                                       (void *)ifmgd->associated->priv);
+                                       (void *)ifmgd->associated->priv,
+                                       rx_status->mactime);
                        break;
                }
                mutex_unlock(&ifmgd->mtx);
@@ -1613,7 +1805,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);
+                       ieee80211_set_disassoc(sdata, true);
                        ieee80211_recalc_idle(local);
                        mutex_unlock(&ifmgd->mtx);
                        /*
@@ -1623,7 +1815,7 @@ static void ieee80211_sta_work(struct work_struct *work)
                        ieee80211_send_deauth_disassoc(sdata, bssid,
                                        IEEE80211_STYPE_DEAUTH,
                                        WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
-                                       NULL);
+                                       NULL, true);
                        mutex_lock(&ifmgd->mtx);
                }
        }
@@ -1640,7 +1832,8 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
        if (local->quiescing)
                return;
 
-       ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
+       ieee80211_queue_work(&sdata->local->hw,
+                            &sdata->u.mgd.beacon_connection_loss_work);
 }
 
 static void ieee80211_sta_conn_mon_timer(unsigned long data)
@@ -1692,7 +1885,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
         */
 
        cancel_work_sync(&ifmgd->work);
-       cancel_work_sync(&ifmgd->beacon_loss_work);
+       cancel_work_sync(&ifmgd->beacon_connection_loss_work);
        if (del_timer_sync(&ifmgd->timer))
                set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
 
@@ -1726,7 +1919,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
        INIT_WORK(&ifmgd->work, ieee80211_sta_work);
        INIT_WORK(&ifmgd->monitor_work, ieee80211_sta_monitor_work);
        INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
-       INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work);
+       INIT_WORK(&ifmgd->beacon_connection_loss_work,
+                 ieee80211_beacon_connection_loss_work);
        setup_timer(&ifmgd->timer, ieee80211_sta_timer,
                    (unsigned long) sdata);
        setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -1805,6 +1999,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_work *wk;
        u16 auth_alg;
 
+       if (req->local_state_change)
+               return 0; /* no need to update mac80211 state */
+
        switch (req->auth_type) {
        case NL80211_AUTHTYPE_OPEN_SYSTEM:
                auth_alg = WLAN_AUTH_OPEN;
@@ -1913,7 +2110,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
 
                /* Trying to reassociate - clear previous association state */
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
        }
        mutex_unlock(&ifmgd->mtx);
 
@@ -2017,7 +2214,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
 
        if (ifmgd->associated == req->bss) {
                bssid = req->bss->bssid;
-               ieee80211_set_disassoc(sdata);
+               ieee80211_set_disassoc(sdata, true);
                mutex_unlock(&ifmgd->mtx);
        } else {
                bool not_auth_yet = false;
@@ -2061,9 +2258,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
               sdata->name, bssid, req->reason_code);
 
-       ieee80211_send_deauth_disassoc(sdata, bssid,
-                       IEEE80211_STYPE_DEAUTH, req->reason_code,
-                       cookie);
+       ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
+                                      req->reason_code, cookie,
+                                      !req->local_state_change);
 
        ieee80211_recalc_idle(sdata->local);
 
@@ -2075,6 +2272,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
                           void *cookie)
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u8 bssid[ETH_ALEN];
 
        mutex_lock(&ifmgd->mtx);
 
@@ -2092,13 +2290,15 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
        printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n",
               sdata->name, req->bss->bssid, req->reason_code);
 
-       ieee80211_set_disassoc(sdata);
+       memcpy(bssid, req->bss->bssid, ETH_ALEN);
+       ieee80211_set_disassoc(sdata, false);
 
        mutex_unlock(&ifmgd->mtx);
 
        ieee80211_send_deauth_disassoc(sdata, req->bss->bssid,
                        IEEE80211_STYPE_DISASSOC, req->reason_code,
-                       cookie);
+                       cookie, !req->local_state_change);
+       sta_info_destroy_addr(sdata, bssid);
 
        ieee80211_recalc_idle(sdata->local);
 
@@ -2118,7 +2318,7 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
        if ((chan != local->tmp_channel ||
             channel_type != local->tmp_channel_type) &&
            (chan != local->oper_channel ||
-            channel_type != local->oper_channel_type))
+            channel_type != local->_oper_channel_type))
                return -EBUSY;
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);
@@ -2139,3 +2339,15 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
        *cookie = (unsigned long) skb;
        return 0;
 }
+
+void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
+                              enum nl80211_cqm_rssi_threshold_event rssi_event,
+                              gfp_t gfp)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       trace_api_cqm_rssi_notify(sdata, rssi_event);
+
+       cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
+}
+EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
index 0e64484e861c74ad145cea45e22ce480c5b51ff4..75202b295a4e81ba42691c61b4356347f94678bf 100644 (file)
@@ -46,7 +46,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 
        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                list_for_each_entry_rcu(sta, &local->sta_list, list) {
-                       set_sta_flags(sta, WLAN_STA_SUSPEND);
+                       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
                        ieee80211_sta_tear_down_BA_sessions(sta);
                }
        }
index 818abfae900773f27f39045a8163469bc8fed82f..f65ce6dcc8e25d3aec3afe2ea9af85bd1b5932de 100644 (file)
@@ -542,7 +542,7 @@ minstrel_free(void *priv)
        kfree(priv);
 }
 
-static struct rate_control_ops mac80211_minstrel = {
+struct rate_control_ops mac80211_minstrel = {
        .name = "minstrel",
        .tx_status = minstrel_tx_status,
        .get_rate = minstrel_get_rate,
index 38bf4168fc3ae1fe8b5d113218f5016066d34c09..0f5a83370aa637f18f854c7469cc21e8a491257c 100644 (file)
@@ -80,7 +80,18 @@ struct minstrel_priv {
        unsigned int lookaround_rate_mrr;
 };
 
+struct minstrel_debugfs_info {
+       size_t len;
+       char buf[];
+};
+
+extern struct rate_control_ops mac80211_minstrel;
 void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
 void minstrel_remove_sta_debugfs(void *priv, void *priv_sta);
 
+/* debugfs */
+int minstrel_stats_open(struct inode *inode, struct file *file);
+ssize_t minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos);
+int minstrel_stats_release(struct inode *inode, struct file *file);
+
 #endif
index 0e1f12b1b6dd1ee9971df741cbc8855e6bf05e16..241e76f3fdf2974a3a476c31d267eaa0d7c77db5 100644 (file)
 #include <net/mac80211.h>
 #include "rc80211_minstrel.h"
 
-struct minstrel_stats_info {
-       struct minstrel_sta_info *mi;
-       char buf[4096];
-       size_t len;
-};
-
-static int
+int
 minstrel_stats_open(struct inode *inode, struct file *file)
 {
        struct minstrel_sta_info *mi = inode->i_private;
-       struct minstrel_stats_info *ms;
+       struct minstrel_debugfs_info *ms;
        unsigned int i, tp, prob, eprob;
        char *p;
 
-       ms = kmalloc(sizeof(*ms), GFP_KERNEL);
+       ms = kmalloc(sizeof(*ms) + 4096, GFP_KERNEL);
        if (!ms)
                return -ENOMEM;
 
@@ -107,36 +101,19 @@ minstrel_stats_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-static ssize_t
-minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *o)
+ssize_t
+minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
 {
-       struct minstrel_stats_info *ms;
-       char *src;
+       struct minstrel_debugfs_info *ms;
 
        ms = file->private_data;
-       src = ms->buf;
-
-       len = min(len, ms->len);
-       if (len <= *o)
-               return 0;
-
-       src += *o;
-       len -= *o;
-       *o += len;
-
-       if (copy_to_user(buf, src, len))
-               return -EFAULT;
-
-       return len;
+       return simple_read_from_buffer(buf, len, ppos, ms->buf, ms->len);
 }
 
-static int
+int
 minstrel_stats_release(struct inode *inode, struct file *file)
 {
-       struct minstrel_stats_info *ms = file->private_data;
-
-       kfree(ms);
-
+       kfree(file->private_data);
        return 0;
 }
 
index 04ea07f0e78acd0fd30ee92a525897e64c49f5bc..6e2a7bcd8cb888ce24be03cc56cb2516ca95fade 100644 (file)
@@ -39,7 +39,7 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
 {
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
                if (likely(skb->len > FCS_LEN))
-                       skb_trim(skb, skb->len - FCS_LEN);
+                       __pskb_trim(skb, skb->len - FCS_LEN);
                else {
                        /* driver bug */
                        WARN_ON(1);
@@ -81,8 +81,6 @@ ieee80211_rx_radiotap_len(struct ieee80211_local *local,
                len += 8;
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
-       if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
-               len += 1;
 
        if (len & 1) /* padding for RX_FLAGS if necessary */
                len++;
@@ -179,14 +177,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                pos++;
        }
 
-       /* IEEE80211_RADIOTAP_DBM_ANTNOISE */
-       if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
-               *pos = status->noise;
-               rthdr->it_present |=
-                       cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE);
-               pos++;
-       }
-
        /* IEEE80211_RADIOTAP_LOCK_QUALITY is missing */
 
        /* IEEE80211_RADIOTAP_ANTENNA */
@@ -236,6 +226,12 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
 
+       /* make sure hdr->frame_control is on the linear part */
+       if (!pskb_may_pull(origskb, 2)) {
+               dev_kfree_skb(origskb);
+               return NULL;
+       }
+
        if (!local->monitors) {
                if (should_drop_frame(origskb, present_fcs_len)) {
                        dev_kfree_skb(origskb);
@@ -493,7 +489,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
                if (ieee80211_is_action(hdr->frame_control)) {
                        mgmt = (struct ieee80211_mgmt *)hdr;
-                       if (mgmt->u.action.category != MESH_PLINK_CATEGORY)
+                       if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
@@ -723,14 +719,16 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
 
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
-       if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
-               goto dont_reorder;
+       spin_lock(&sta->lock);
+
+       if (!sta->ampdu_mlme.tid_active_rx[tid])
+               goto dont_reorder_unlock;
 
        tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
 
        /* qos null data frames are excluded */
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
-               goto dont_reorder;
+               goto dont_reorder_unlock;
 
        /* new, potentially un-ordered, ampdu frame - process it */
 
@@ -742,15 +740,20 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx,
        /* if this mpdu is fragmented - terminate rx aggregation session */
        sc = le16_to_cpu(hdr->seq_ctrl);
        if (sc & IEEE80211_SCTL_FRAG) {
-               ieee80211_sta_stop_rx_ba_session(sta->sdata, sta->sta.addr,
-                       tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
+               spin_unlock(&sta->lock);
+               __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT,
+                                              WLAN_REASON_QSTA_REQUIRE_SETUP);
                dev_kfree_skb(skb);
                return;
        }
 
-       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames))
+       if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, frames)) {
+               spin_unlock(&sta->lock);
                return;
+       }
 
+ dont_reorder_unlock:
+       spin_unlock(&sta->lock);
  dont_reorder:
        __skb_queue_tail(frames, skb);
 }
@@ -897,6 +900,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                        rx->key = key;
                return RX_CONTINUE;
        } else {
+               u8 keyid;
                /*
                 * The device doesn't give us the IV so we won't be
                 * able to look up the key. That's ok though, we
@@ -919,7 +923,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                 * no need to call ieee80211_wep_get_keyidx,
                 * it verifies a bunch of things we've done already
                 */
-               keyidx = rx->skb->data[hdrlen + 3] >> 6;
+               skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);
+               keyidx = keyid >> 6;
 
                rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
 
@@ -940,6 +945,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
        }
 
+       if (skb_linearize(rx->skb))
+               return RX_DROP_UNUSABLE;
+
+       hdr = (struct ieee80211_hdr *)rx->skb->data;
+
        /* Check for weak IVs if possible */
        if (rx->sta && rx->key->conf.alg == ALG_WEP &&
            ieee80211_is_data(hdr->frame_control) &&
@@ -1078,7 +1088,6 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        sta->rx_fragments++;
        sta->rx_bytes += rx->skb->len;
        sta->last_signal = status->signal;
-       sta->last_noise = status->noise;
 
        /*
         * Change STA power saving mode only at the end of a frame
@@ -1241,6 +1250,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        }
        I802_DEBUG_INC(rx->local->rx_handlers_fragments);
 
+       if (skb_linearize(rx->skb))
+               return RX_DROP_UNUSABLE;
+
+       /*
+        *  skb_linearize() might change the skb->data and
+        *  previously cached variables (in this case, hdr) need to
+        *  be refreshed with the new data.
+        */
+       hdr = (struct ieee80211_hdr *)rx->skb->data;
        seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
 
        if (frag == 0) {
@@ -1406,21 +1424,24 @@ static int
 ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
        __le16 fc = hdr->frame_control;
-       int res;
 
-       res = ieee80211_drop_unencrypted(rx, fc);
-       if (unlikely(res))
-               return res;
+       /*
+        * Pass through unencrypted frames if the hardware has
+        * decrypted them already.
+        */
+       if (status->flag & RX_FLAG_DECRYPTED)
+               return 0;
 
        if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
-               if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
+               if (unlikely(!ieee80211_has_protected(fc) &&
+                            ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
                             rx->key))
                        return -EACCES;
                /* BIP does not use Protected field, so need to check MMIE */
                if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
-                            ieee80211_get_mmie_keyidx(rx->skb) < 0 &&
-                            rx->key))
+                            ieee80211_get_mmie_keyidx(rx->skb) < 0))
                        return -EACCES;
                /*
                 * When using MFP, Action frames are not allowed prior to
@@ -1598,6 +1619,9 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
        skb->dev = dev;
        __skb_queue_head_init(&frame_list);
 
+       if (skb_linearize(skb))
+               return RX_DROP_UNUSABLE;
+
        ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
                                 rx->sdata->vif.type,
                                 rx->local->hw.extra_tx_headroom);
@@ -1796,10 +1820,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
        if (ieee80211_is_back_req(bar->frame_control)) {
                if (!rx->sta)
                        return RX_DROP_MONITOR;
+               spin_lock(&rx->sta->lock);
                tid = le16_to_cpu(bar->control) >> 12;
-               if (rx->sta->ampdu_mlme.tid_state_rx[tid]
-                                       != HT_AGG_STATE_OPERATIONAL)
+               if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) {
+                       spin_unlock(&rx->sta->lock);
                        return RX_DROP_MONITOR;
+               }
                tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
                start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
@@ -1813,6 +1839,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
                                                 frames);
                kfree_skb(skb);
+               spin_unlock(&rx->sta->lock);
                return RX_QUEUED;
        }
 
@@ -1974,8 +2001,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                        goto handled;
                }
                break;
-       case MESH_PLINK_CATEGORY:
-       case MESH_PATH_SEL_CATEGORY:
+       case WLAN_CATEGORY_MESH_PLINK:
+       case WLAN_CATEGORY_MESH_PATH_SEL:
                if (ieee80211_vif_is_mesh(&sdata->vif))
                        return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
                break;
@@ -2372,29 +2399,42 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hdr *hdr;
+       __le16 fc;
        struct ieee80211_rx_data rx;
        int prepares;
        struct ieee80211_sub_if_data *prev = NULL;
        struct sk_buff *skb_new;
        struct sta_info *sta, *tmp;
        bool found_sta = false;
+       int err = 0;
 
-       hdr = (struct ieee80211_hdr *)skb->data;
+       fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
        memset(&rx, 0, sizeof(rx));
        rx.skb = skb;
        rx.local = local;
 
-       if (ieee80211_is_data(hdr->frame_control) || ieee80211_is_mgmt(hdr->frame_control))
+       if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc))
                local->dot11ReceivedFragmentCount++;
 
        if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
                     test_bit(SCAN_OFF_CHANNEL, &local->scanning)))
                rx.flags |= IEEE80211_RX_IN_SCAN;
 
+       if (ieee80211_is_mgmt(fc))
+               err = skb_linearize(skb);
+       else
+               err = !pskb_may_pull(skb, ieee80211_hdrlen(fc));
+
+       if (err) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       hdr = (struct ieee80211_hdr *)skb->data;
        ieee80211_parse_qos(&rx);
        ieee80211_verify_alignment(&rx);
 
-       if (ieee80211_is_data(hdr->frame_control)) {
+       if (ieee80211_is_data(fc)) {
                for_each_sta_info(local, hdr->addr2, sta, tmp) {
                        rx.sta = sta;
                        found_sta = true;
index 85507bd9e34109d3f06bb9248322b3b1ad7f615a..e1b0be7a57b9772ddb1c006793ca6a5929580aba 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
+#include <linux/pm_qos_params.h>
+#include <net/sch_generic.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
 
@@ -83,7 +85,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 {
        struct cfg80211_bss *cbss;
        struct ieee80211_bss *bss;
-       int clen;
+       int clen, srlen;
        s32 signal = 0;
 
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
@@ -112,23 +114,24 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
                bss->dtim_period = tim_ie->dtim_period;
        }
 
-       bss->supp_rates_len = 0;
+       /* replace old supported rates if we get new values */
+       srlen = 0;
        if (elems->supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+               clen = IEEE80211_MAX_SUPP_RATES;
                if (clen > elems->supp_rates_len)
                        clen = elems->supp_rates_len;
-               memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
-                      clen);
-               bss->supp_rates_len += clen;
+               memcpy(bss->supp_rates, elems->supp_rates, clen);
+               srlen += clen;
        }
        if (elems->ext_supp_rates) {
-               clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+               clen = IEEE80211_MAX_SUPP_RATES - srlen;
                if (clen > elems->ext_supp_rates_len)
                        clen = elems->ext_supp_rates_len;
-               memcpy(&bss->supp_rates[bss->supp_rates_len],
-                      elems->ext_supp_rates, clen);
-               bss->supp_rates_len += clen;
+               memcpy(bss->supp_rates + srlen, elems->ext_supp_rates, clen);
+               srlen += clen;
        }
+       if (srlen)
+               bss->supp_rates_len = srlen;
 
        bss->wmm_used = elems->wmm_param || elems->wmm_info;
        bss->uapsd_supported = is_uapsd_supported(elems);
@@ -246,6 +249,8 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        struct ieee80211_local *local = hw_to_local(hw);
        bool was_hw_scan;
 
+       trace_api_scan_completed(local, aborted);
+
        mutex_lock(&local->scan_mtx);
 
        /*
@@ -322,6 +327,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
 
        ieee80211_offchannel_stop_beaconing(local);
 
+       local->leave_oper_channel_time = 0;
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
@@ -406,7 +412,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        if (local->ops->hw_scan) {
                WARN_ON(!ieee80211_prep_hw_scan(local));
-               rc = drv_hw_scan(local, local->hw_scan_req);
+               rc = drv_hw_scan(local, sdata, local->hw_scan_req);
        } else
                rc = ieee80211_start_sw_scan(local);
 
@@ -426,11 +432,28 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        return rc;
 }
 
+static unsigned long
+ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
+{
+       /*
+        * TODO: channel switching also consumes quite some time,
+        * add that delay as well to get a better estimation
+        */
+       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+               return IEEE80211_PASSIVE_CHANNEL_TIME;
+       return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
+}
+
 static int ieee80211_scan_state_decision(struct ieee80211_local *local,
                                         unsigned long *next_delay)
 {
        bool associated = false;
+       bool tx_empty = true;
+       bool bad_latency;
+       bool listen_int_exceeded;
+       unsigned long min_beacon_int = 0;
        struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_channel *next_chan;
 
        /* if no more bands/channels left, complete scan and advance to the idle state */
        if (local->scan_channel_idx >= local->scan_req->n_channels) {
@@ -438,7 +461,11 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
                return 1;
        }
 
-       /* check if at least one STA interface is associated */
+       /*
+        * check if at least one STA interface is associated,
+        * check if at least one STA interface has pending tx frames
+        * and grab the lowest used beacon interval
+        */
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
@@ -447,7 +474,16 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                        if (sdata->u.mgd.associated) {
                                associated = true;
-                               break;
+
+                               if (sdata->vif.bss_conf.beacon_int <
+                                   min_beacon_int || min_beacon_int == 0)
+                                       min_beacon_int =
+                                               sdata->vif.bss_conf.beacon_int;
+
+                               if (!qdisc_all_tx_empty(sdata->dev)) {
+                                       tx_empty = false;
+                                       break;
+                               }
                        }
                }
        }
@@ -456,11 +492,34 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local,
        if (local->scan_channel) {
                /*
                 * we're currently scanning a different channel, let's
-                * switch back to the operating channel now if at least
-                * one interface is associated. Otherwise just scan the
-                * next channel
+                * see if we can scan another channel without interfering
+                * with the current traffic situation.
+                *
+                * Since we don't know if the AP has pending frames for us
+                * we can only check for our tx queues and use the current
+                * pm_qos requirements for rx. Hence, if no tx traffic occurs
+                * at all we will scan as many channels in a row as the pm_qos
+                * latency allows us to. Additionally we also check for the
+                * currently negotiated listen interval to prevent losing
+                * frames unnecessarily.
+                *
+                * Otherwise switch back to the operating channel.
                 */
-               if (associated)
+               next_chan = local->scan_req->channels[local->scan_channel_idx];
+
+               bad_latency = time_after(jiffies +
+                               ieee80211_scan_get_channel_time(next_chan),
+                               local->leave_oper_channel_time +
+                               usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
+
+               listen_int_exceeded = time_after(jiffies +
+                               ieee80211_scan_get_channel_time(next_chan),
+                               local->leave_oper_channel_time +
+                               usecs_to_jiffies(min_beacon_int * 1024) *
+                               local->hw.conf.listen_interval);
+
+               if (associated && ( !tx_empty || bad_latency ||
+                   listen_int_exceeded))
                        local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
                else
                        local->next_scan_state = SCAN_SET_CHANNEL;
@@ -492,6 +551,9 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
        else
                *next_delay = HZ / 10;
 
+       /* remember when we left the operating channel */
+       local->leave_oper_channel_time = jiffies;
+
        /* advance to the next channel to be scanned */
        local->next_scan_state = SCAN_SET_CHANNEL;
 }
@@ -594,7 +656,7 @@ void ieee80211_scan_work(struct work_struct *work)
        }
 
        if (local->hw_scan_req) {
-               int rc = drv_hw_scan(local, local->hw_scan_req);
+               int rc = drv_hw_scan(local, sdata, local->hw_scan_req);
                mutex_unlock(&local->scan_mtx);
                if (rc)
                        ieee80211_scan_completed(&local->hw, true);
@@ -667,10 +729,12 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
 }
 
 int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
-                                   const u8 *ssid, u8 ssid_len)
+                                   const u8 *ssid, u8 ssid_len,
+                                   struct ieee80211_channel *chan)
 {
        struct ieee80211_local *local = sdata->local;
        int ret = -EBUSY;
+       enum nl80211_band band;
 
        mutex_lock(&local->scan_mtx);
 
@@ -678,6 +742,30 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
        if (local->scan_req)
                goto unlock;
 
+       /* fill internal scan request */
+       if (!chan) {
+               int i, nchan = 0;
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+                       if (!local->hw.wiphy->bands[band])
+                               continue;
+                       for (i = 0;
+                            i < local->hw.wiphy->bands[band]->n_channels;
+                            i++) {
+                               local->int_scan_req->channels[nchan] =
+                                   &local->hw.wiphy->bands[band]->channels[i];
+                               nchan++;
+                       }
+               }
+
+               local->int_scan_req->n_channels = nchan;
+       } else {
+               local->int_scan_req->channels[0] = chan;
+               local->int_scan_req->n_channels = 1;
+       }
+
+       local->int_scan_req->ssids = &local->scan_ssid;
+       local->int_scan_req->n_ssids = 1;
        memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
        local->int_scan_req->ssids[0].ssid_len = ssid_len;
 
index fb12cec4d333a25d98c13dba1994d6bcbeb001ee..730197591ab5135e307317d7c9d8e358dae6bceb 100644 (file)
@@ -250,9 +250,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                 * enable session_timer's data differentiation. refer to
                 * sta_rx_agg_session_timer_expired for useage */
                sta->timer_to_tid[i] = i;
-               /* rx */
-               sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
-               sta->ampdu_mlme.tid_rx[i] = NULL;
                /* tx */
                sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
                sta->ampdu_mlme.tid_tx[i] = NULL;
@@ -578,7 +575,7 @@ static int sta_info_buffer_expired(struct sta_info *sta,
 }
 
 
-static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                                             struct sta_info *sta)
 {
        unsigned long flags;
@@ -586,7 +583,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
        struct ieee80211_sub_if_data *sdata;
 
        if (skb_queue_empty(&sta->ps_tx_buf))
-               return;
+               return false;
 
        for (;;) {
                spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
@@ -611,6 +608,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
                if (skb_queue_empty(&sta->ps_tx_buf))
                        sta_info_clear_tim_bit(sta);
        }
+
+       return true;
 }
 
 static int __must_check __sta_info_destroy(struct sta_info *sta)
@@ -619,7 +618,7 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        struct ieee80211_sub_if_data *sdata;
        struct sk_buff *skb;
        unsigned long flags;
-       int ret, i;
+       int ret;
 
        might_sleep();
 
@@ -629,6 +628,15 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        local = sta->local;
        sdata = sta->sdata;
 
+       /*
+        * Before removing the station from the driver and
+        * rate control, it might still start new aggregation
+        * sessions -- block that to make sure the tear-down
+        * will be sufficient.
+        */
+       set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+       ieee80211_sta_tear_down_BA_sessions(sta);
+
        spin_lock_irqsave(&local->sta_lock, flags);
        ret = sta_info_hash_del(local, sta);
        /* this might still be the pending list ... which is fine */
@@ -645,9 +653,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
                 * may mean it is removed from hardware which requires that
                 * the key->sta pointer is still valid, so flush the key todo
                 * list here.
-                *
-                * ieee80211_key_todo() will synchronize_rcu() so after this
-                * nothing can reference this sta struct any more.
                 */
                ieee80211_key_todo();
 
@@ -679,11 +684,17 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
                sdata = sta->sdata;
        }
 
+       /*
+        * At this point, after we wait for an RCU grace period,
+        * neither mac80211 nor the driver can reference this
+        * sta struct any more except by still existing timers
+        * associated with this station that we clean up below.
+        */
+       synchronize_rcu();
+
 #ifdef CONFIG_MAC80211_MESH
-       if (ieee80211_vif_is_mesh(&sdata->vif)) {
+       if (ieee80211_vif_is_mesh(&sdata->vif))
                mesh_accept_plinks_update(sdata);
-               del_timer(&sta->plink_timer);
-       }
 #endif
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -710,50 +721,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
        while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
                dev_kfree_skb_any(skb);
 
-       for (i = 0; i <  STA_TID_NUM; i++) {
-               struct tid_ampdu_rx *tid_rx;
-               struct tid_ampdu_tx *tid_tx;
-
-               spin_lock_bh(&sta->lock);
-               tid_rx = sta->ampdu_mlme.tid_rx[i];
-               /* Make sure timer won't free the tid_rx struct, see below */
-               if (tid_rx)
-                       tid_rx->shutdown = true;
-
-               spin_unlock_bh(&sta->lock);
-
-               /*
-                * Outside spinlock - shutdown is true now so that the timer
-                * won't free tid_rx, we have to do that now. Can't let the
-                * timer do it because we have to sync the timer outside the
-                * lock that it takes itself.
-                */
-               if (tid_rx) {
-                       del_timer_sync(&tid_rx->session_timer);
-                       kfree(tid_rx);
-               }
-
-               /*
-                * No need to do such complications for TX agg sessions, the
-                * path leading to freeing the tid_tx struct goes via a call
-                * from the driver, and thus needs to look up the sta struct
-                * again, which cannot be found when we get here. Hence, we
-                * just need to delete the timer and free the aggregation
-                * info; we won't be telling the peer about it then but that
-                * doesn't matter if we're not talking to it again anyway.
-                */
-               tid_tx = sta->ampdu_mlme.tid_tx[i];
-               if (tid_tx) {
-                       del_timer_sync(&tid_tx->addba_resp_timer);
-                       /*
-                        * STA removed while aggregation session being
-                        * started? Bit odd, but purge frames anyway.
-                        */
-                       skb_queue_purge(&tid_tx->pending);
-                       kfree(tid_tx);
-               }
-       }
-
        __sta_info_free(local, sta);
 
        return 0;
@@ -790,15 +757,20 @@ static void sta_info_cleanup(unsigned long data)
 {
        struct ieee80211_local *local = (struct ieee80211_local *) data;
        struct sta_info *sta;
+       bool timer_needed = false;
 
        rcu_read_lock();
        list_for_each_entry_rcu(sta, &local->sta_list, list)
-               sta_info_cleanup_expire_buffered(local, sta);
+               if (sta_info_cleanup_expire_buffered(local, sta))
+                       timer_needed = true;
        rcu_read_unlock();
 
        if (local->quiescing)
                return;
 
+       if (!timer_needed)
+               return;
+
        local->sta_cleanup.expires =
                round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
        add_timer(&local->sta_cleanup);
@@ -883,8 +855,12 @@ struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw,
        struct sta_info *sta, *nxt;
 
        /* Just return a random station ... first in list ... */
-       for_each_sta_info(hw_to_local(hw), addr, sta, nxt)
+       for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
+               if (!sta->uploaded)
+                       return NULL;
                return &sta->sta;
+       }
+
        return NULL;
 }
 EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
@@ -892,14 +868,19 @@ EXPORT_SYMBOL_GPL(ieee80211_find_sta_by_hw);
 struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
                                         const u8 *addr)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct sta_info *sta;
 
        if (!vif)
                return NULL;
 
-       sdata = vif_to_sdata(vif);
+       sta = sta_info_get_bss(vif_to_sdata(vif), addr);
+       if (!sta)
+               return NULL;
+
+       if (!sta->uploaded)
+               return NULL;
 
-       return ieee80211_find_sta_by_hw(&sdata->local->hw, addr);
+       return &sta->sta;
 }
 EXPORT_SYMBOL(ieee80211_find_sta);
 
@@ -992,6 +973,8 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
 {
        struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
+       trace_api_sta_block_awake(sta->local, pubsta, block);
+
        if (block)
                set_sta_flags(sta, WLAN_STA_PS_DRIVER);
        else
index 822d845229376116413cd07607b2e6a1ecb35f38..48a5e80957f0cc59748c2d0812c8b50536430b80 100644 (file)
@@ -35,8 +35,8 @@
  *     IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
  *     frame to this station is transmitted.
  * @WLAN_STA_MFP: Management frame protection is used with this STA.
- * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle.
- *     Used to deny ADDBA requests (both TX and RX).
+ * @WLAN_STA_BLOCK_BA: Used to deny ADDBA requests (both TX and RX)
+ *     during suspend/resume and station removal.
  * @WLAN_STA_PS_DRIVER: driver requires keeping this station in
  *     power-save mode logically to flush frames that might still
  *     be in the queues
@@ -57,7 +57,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_WDS            = 1<<7,
        WLAN_STA_CLEAR_PS_FILT  = 1<<9,
        WLAN_STA_MFP            = 1<<10,
-       WLAN_STA_SUSPEND        = 1<<11,
+       WLAN_STA_BLOCK_BA       = 1<<11,
        WLAN_STA_PS_DRIVER      = 1<<12,
        WLAN_STA_PSPOLL         = 1<<13,
        WLAN_STA_DISASSOC       = 1<<14,
@@ -106,7 +106,6 @@ struct tid_ampdu_tx {
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
- * @shutdown: this session is being shut down due to STA removal
  */
 struct tid_ampdu_rx {
        struct sk_buff **reorder_buf;
@@ -118,7 +117,6 @@ struct tid_ampdu_rx {
        u16 buf_size;
        u16 timeout;
        u8 dialog_token;
-       bool shutdown;
 };
 
 /**
@@ -156,7 +154,7 @@ enum plink_state {
  */
 struct sta_ampdu_mlme {
        /* rx */
-       u8 tid_state_rx[STA_TID_NUM];
+       bool tid_active_rx[STA_TID_NUM];
        struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
        /* tx */
        u8 tid_state_tx[STA_TID_NUM];
@@ -200,7 +198,6 @@ struct sta_ampdu_mlme {
  * @rx_fragments: number of received MPDUs
  * @rx_dropped: number of dropped MPDUs from this STA
  * @last_signal: signal of last received frame from this STA
- * @last_noise: noise of last received frame from this STA
  * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue)
  * @tx_filtered_count: number of frames the hardware filtered for this STA
  * @tx_retry_failed: number of frames that failed retry
@@ -267,7 +264,6 @@ struct sta_info {
        unsigned long rx_fragments;
        unsigned long rx_dropped;
        int last_signal;
-       int last_noise;
        __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
 
        /* Updated from TX status path only, no locking requirements */
index 56d5b9a6ec5b7fcfd433d2da9280bd24d27d1fda..94613af009f32d668f70e1522e5842d78eabf414 100644 (file)
@@ -171,13 +171,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct net_device *prev_dev = NULL;
        struct sta_info *sta, *tmp;
        int retry_count = -1, i;
-       bool injected;
+       int rates_idx = -1;
+       bool send_to_cooked;
 
        for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
                /* the HW cannot have attempted that rate */
                if (i >= hw->max_rates) {
                        info->status.rates[i].idx = -1;
                        info->status.rates[i].count = 0;
+               } else if (info->status.rates[i].idx >= 0) {
+                       rates_idx = i;
                }
 
                retry_count += info->status.rates[i].count;
@@ -206,6 +209,10 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        return;
                }
 
+               if ((local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) &&
+                   (rates_idx != -1))
+                       sta->last_tx_rate = info->status.rates[rates_idx];
+
                if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
                    (ieee80211_is_data_qos(fc))) {
                        u16 tid, ssn;
@@ -296,11 +303,15 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        /* this was a transmitted frame, but now we want to reuse it */
        skb_orphan(skb);
 
+       /* Need to make a copy before skb->cb gets cleared */
+       send_to_cooked = !!(info->flags & IEEE80211_TX_CTL_INJECTED) ||
+                       (type != IEEE80211_FTYPE_DATA);
+
        /*
         * This is a bit racy but we can avoid a lot of work
         * with this test...
         */
-       if (!local->monitors && !local->cooked_mntrs) {
+       if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
                dev_kfree_skb(skb);
                return;
        }
@@ -345,9 +356,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        /* for now report the total retry_count */
        rthdr->data_retries = retry_count;
 
-       /* Need to make a copy before skb->cb gets cleared */
-       injected = !!(info->flags & IEEE80211_TX_CTL_INJECTED);
-
        /* XXX: is this sufficient for BPF? */
        skb_set_mac_header(skb, 0);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -362,8 +370,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                continue;
 
                        if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) &&
-                           !injected &&
-                           (type == IEEE80211_FTYPE_DATA))
+                           !send_to_cooked)
                                continue;
 
                        if (prev_dev) {
index cfc473e1b0509ca1850d61a49b5dd59b23ecee55..680bcb7093dbdc4f00cf5baf374812379ccc0040 100644 (file)
@@ -429,6 +429,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
        struct sta_info *sta = tx->sta;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+       struct ieee80211_local *local = tx->local;
        u32 staflags;
 
        if (unlikely(!sta ||
@@ -476,6 +477,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                info->control.vif = &tx->sdata->vif;
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+
+               if (!timer_pending(&local->sta_cleanup))
+                       mod_timer(&local->sta_cleanup,
+                                 round_jiffies(jiffies +
+                                               STA_INFO_CLEANUP_INTERVAL));
+
                return TX_QUEUED;
        }
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
@@ -513,6 +520,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
                tx->key = key;
        else if (ieee80211_is_mgmt(hdr->frame_control) &&
+                is_multicast_ether_addr(hdr->addr1) &&
+                ieee80211_is_robust_mgmt_frame(hdr) &&
                 (key = rcu_dereference(tx->sdata->default_mgmt_key)))
                tx->key = key;
        else if ((key = rcu_dereference(tx->sdata->default_key)))
@@ -584,7 +593,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
        struct ieee80211_hdr *hdr = (void *)tx->skb->data;
        struct ieee80211_supported_band *sband;
        struct ieee80211_rate *rate;
-       int i, len;
+       int i;
+       u32 len;
        bool inval = false, rts = false, short_preamble = false;
        struct ieee80211_tx_rate_control txrc;
        u32 sta_flags;
@@ -593,7 +603,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       len = min_t(int, tx->skb->len + FCS_LEN,
+       len = min_t(u32, tx->skb->len + FCS_LEN,
                         tx->local->hw.wiphy->frag_threshold);
 
        /* set up the tx rate control struct we give the RC algo */
@@ -1142,13 +1152,12 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) {
-               unsigned long flags;
                struct tid_ampdu_tx *tid_tx;
 
                qc = ieee80211_get_qos_ctl(hdr);
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
 
-               spin_lock_irqsave(&tx->sta->lock, flags);
+               spin_lock(&tx->sta->lock);
                /*
                 * XXX: This spinlock could be fairly expensive, but see the
                 *      comment in agg-tx.c:ieee80211_agg_tx_operational().
@@ -1173,7 +1182,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        __skb_queue_tail(&tid_tx->pending, skb);
                }
-               spin_unlock_irqrestore(&tx->sta->lock, flags);
+               spin_unlock(&tx->sta->lock);
 
                if (unlikely(queued))
                        return TX_QUEUED;
@@ -2011,14 +2020,12 @@ void ieee80211_tx_pending(unsigned long data)
                while (!skb_queue_empty(&local->pending[i])) {
                        struct sk_buff *skb = __skb_dequeue(&local->pending[i]);
                        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-                       struct ieee80211_sub_if_data *sdata;
 
                        if (WARN_ON(!info->control.vif)) {
                                kfree_skb(skb);
                                continue;
                        }
 
-                       sdata = vif_to_sdata(info->control.vif);
                        spin_unlock_irqrestore(&local->queue_stop_reason_lock,
                                                flags);
 
@@ -2244,8 +2251,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 
        info->control.vif = vif;
 
-       info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
-       info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
+       info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT |
+                       IEEE80211_TX_CTL_ASSIGN_SEQ |
+                       IEEE80211_TX_CTL_FIRST_FRAGMENT;
  out:
        rcu_read_unlock();
        return skb;
index 53af570474351d69bbe7e18f15d60be377f4b159..5b79d552780a03dd68641e8693835ec818aaf280 100644 (file)
@@ -270,6 +270,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
 
+       trace_wake_queue(local, queue, reason);
+
        if (WARN_ON(queue >= hw->queues))
                return;
 
@@ -312,6 +314,8 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
 
+       trace_stop_queue(local, queue, reason);
+
        if (WARN_ON(queue >= hw->queues))
                return;
 
@@ -796,6 +800,11 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 
                drv_conf_tx(local, queue, &qparam);
        }
+
+       /* after reinitialize QoS TX queues setting to default,
+        * disable QoS at all */
+       local->hw.conf.flags &= ~IEEE80211_CONF_QOS;
+       drv_config(local, IEEE80211_CONF_CHANGE_QOS);
 }
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
@@ -1135,7 +1144,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
                list_for_each_entry_rcu(sta, &local->sta_list, list) {
-                       clear_sta_flags(sta, WLAN_STA_SUSPEND);
+                       clear_sta_flags(sta, WLAN_STA_BLOCK_BA);
                }
        }
 
@@ -1151,18 +1160,33 @@ 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;
+               u32 changed;
+
                if (!ieee80211_sdata_running(sdata))
                        continue;
+
+               /* common change flags for all interface types */
+               changed = BSS_CHANGED_ERP_CTS_PROT |
+                         BSS_CHANGED_ERP_PREAMBLE |
+                         BSS_CHANGED_ERP_SLOT |
+                         BSS_CHANGED_HT |
+                         BSS_CHANGED_BASIC_RATES |
+                         BSS_CHANGED_BEACON_INT |
+                         BSS_CHANGED_BSSID |
+                         BSS_CHANGED_CQM;
+
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
-                       /* disable beacon change bits */
-                       changed &= ~(BSS_CHANGED_BEACON |
-                                    BSS_CHANGED_BEACON_ENABLED);
-                       /* fall through */
+                       changed |= BSS_CHANGED_ASSOC;
+                       ieee80211_bss_info_change_notify(sdata, changed);
+                       break;
                case NL80211_IFTYPE_ADHOC:
+                       changed |= BSS_CHANGED_IBSS;
+                       /* fall through */
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_MESH_POINT:
+                       changed |= BSS_CHANGED_BEACON |
+                                  BSS_CHANGED_BEACON_ENABLED;
                        ieee80211_bss_info_change_notify(sdata, changed);
                        break;
                case NL80211_IFTYPE_WDS:
index 15e1ba931b87616ab1303ff50eb13f2b3c120fc2..be3d4a698692d1ce958b695c1e1676297b1d15cd 100644 (file)
@@ -33,6 +33,7 @@
 #define IEEE80211_MAX_PROBE_TRIES 5
 
 enum work_action {
+       WORK_ACT_MISMATCH,
        WORK_ACT_NONE,
        WORK_ACT_TIMEOUT,
        WORK_ACT_DONE,
@@ -213,15 +214,25 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 
        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);
+       if (wk->assoc.supp_rates_len) {
+               /*
+                * 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);
+       } else {
+               /*
+                * In case AP not provide any supported rates information
+                * before association, we send information element(s) with
+                * all rates that we support.
+                */
+               rates = ~0;
+               rates_len = sband->n_bitrates;
+       }
 
        skb = alloc_skb(local->hw.extra_tx_headroom +
                        sizeof(*mgmt) + /* bit too much but doesn't matter */
@@ -575,7 +586,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_work *wk,
        u16 auth_alg, auth_transaction, status_code;
 
        if (wk->type != IEEE80211_WORK_AUTH)
-               return WORK_ACT_NONE;
+               return WORK_ACT_MISMATCH;
 
        if (len < 24 + 6)
                return WORK_ACT_NONE;
@@ -626,6 +637,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk,
        struct ieee802_11_elems elems;
        u8 *pos;
 
+       if (wk->type != IEEE80211_WORK_ASSOC)
+               return WORK_ACT_MISMATCH;
+
        /*
         * AssocResp and ReassocResp have identical structure, so process both
         * of them in this function.
@@ -681,6 +695,12 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk,
 
        ASSERT_WORK_MTX(local);
 
+       if (wk->type != IEEE80211_WORK_DIRECT_PROBE)
+               return WORK_ACT_MISMATCH;
+
+       if (len < 24 + 12)
+               return WORK_ACT_NONE;
+
        baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
        if (baselen > len)
                return WORK_ACT_NONE;
@@ -695,7 +715,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_work *wk;
-       enum work_action rma = WORK_ACT_NONE;
+       enum work_action rma;
        u16 fc;
 
        rx_status = (struct ieee80211_rx_status *) skb->cb;
@@ -742,7 +762,17 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
                        break;
                default:
                        WARN_ON(1);
+                       rma = WORK_ACT_NONE;
                }
+
+               /*
+                * We've either received an unexpected frame, or we have
+                * multiple work items and need to match the frame to the
+                * right one.
+                */
+               if (rma == WORK_ACT_MISMATCH)
+                       continue;
+
                /*
                 * We've processed this frame for that work, so it can't
                 * belong to another work struct.
@@ -752,6 +782,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local,
        }
 
        switch (rma) {
+       case WORK_ACT_MISMATCH:
+               /* ignore this unmatched frame */
+               break;
        case WORK_ACT_NONE:
                break;
        case WORK_ACT_DONE:
@@ -920,11 +953,16 @@ static void ieee80211_work_work(struct work_struct *work)
                run_again(local, jiffies + HZ/2);
        }
 
-       if (list_empty(&local->work_list) && local->scan_req)
+       mutex_lock(&local->scan_mtx);
+
+       if (list_empty(&local->work_list) && local->scan_req &&
+           !local->scanning)
                ieee80211_queue_delayed_work(&local->hw,
                                             &local->scan_work,
                                             round_jiffies_relative(0));
 
+       mutex_unlock(&local->scan_mtx);
+
        mutex_unlock(&local->work_mtx);
 
        ieee80211_recalc_idle(local);
index 18d77b5c351a024626df3c8e2a21155a5ca754fc..8593a77cfea906ac0257405fb8aa9ae0e0bef597 100644 (file)
@@ -314,8 +314,39 @@ config NETFILTER_XTABLES
 
 if NETFILTER_XTABLES
 
+comment "Xtables combined modules"
+
+config NETFILTER_XT_MARK
+       tristate 'nfmark target and match support'
+       default m if NETFILTER_ADVANCED=n
+       ---help---
+       This option adds the "MARK" target and "mark" match.
+
+       Netfilter mark matching allows you to match packets based on the
+       "nfmark" value in the packet.
+       The target allows you to create rules in the "mangle" table which alter
+       the netfilter mark (nfmark) field associated with the packet.
+
+       Prior to routing, the nfmark can influence the routing method (see
+       "Use netfilter MARK value as routing key") and can also be used by
+       other subsystems to change their behavior.
+
+config NETFILTER_XT_CONNMARK
+       tristate 'ctmark target and match support'
+       depends on NF_CONNTRACK
+       depends on NETFILTER_ADVANCED
+       select NF_CONNTRACK_MARK
+       ---help---
+       This option adds the "CONNMARK" target and "connmark" match.
+
+       Netfilter allows you to store a mark value per connection (a.k.a.
+       ctmark), similarly to the packet mark (nfmark). Using this
+       target and match, you can set and match on this mark.
+
 # alphabetically ordered list of targets
 
+comment "Xtables targets"
+
 config NETFILTER_XT_TARGET_CLASSIFY
        tristate '"CLASSIFY" target support'
        depends on NETFILTER_ADVANCED
@@ -332,15 +363,11 @@ config NETFILTER_XT_TARGET_CONNMARK
        tristate  '"CONNMARK" target support'
        depends on NF_CONNTRACK
        depends on NETFILTER_ADVANCED
-       select NF_CONNTRACK_MARK
-       help
-         This option adds a `CONNMARK' target, which allows one to manipulate
-         the connection mark value.  Similar to the MARK target, but
-         affects the connection mark value rather than the packet mark value.
-
-         If you want to compile it as a module, say M here and read
-         <file:Documentation/kbuild/modules.txt>.  The module will be called
-         ipt_CONNMARK.  If unsure, say `N'.
+       select NETFILTER_XT_CONNMARK
+       ---help---
+       This is a backwards-compat option for the user's convenience
+       (e.g. when running oldconfig). It selects
+       CONFIG_NETFILTER_XT_CONNMARK (combined connmark/CONNMARK module).
 
 config NETFILTER_XT_TARGET_CONNSECMARK
        tristate '"CONNSECMARK" target support'
@@ -423,16 +450,12 @@ config NETFILTER_XT_TARGET_LED
 
 config NETFILTER_XT_TARGET_MARK
        tristate '"MARK" target support'
-       default m if NETFILTER_ADVANCED=n
-       help
-         This option adds a `MARK' target, which allows you to create rules
-         in the `mangle' table which alter the netfilter mark (nfmark) field
-         associated with the packet prior to routing. This can change
-         the routing method (see `Use netfilter MARK value as routing
-         key') and can also be used by other subsystems to change their
-         behavior.
-
-         To compile it as a module, choose M here.  If unsure, say N.
+       depends on NETFILTER_ADVANCED
+       select NETFILTER_XT_MARK
+       ---help---
+       This is a backwards-compat option for the user's convenience
+       (e.g. when running oldconfig). It selects
+       CONFIG_NETFILTER_XT_MARK (combined mark/MARK module).
 
 config NETFILTER_XT_TARGET_NFLOG
        tristate '"NFLOG" target support'
@@ -479,6 +502,15 @@ config NETFILTER_XT_TARGET_RATEEST
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_TEE
+       tristate '"TEE" - packet cloning to alternate destiantion'
+       depends on NETFILTER_ADVANCED
+       depends on (IPV6 || IPV6=n)
+       depends on !NF_CONNTRACK || NF_CONNTRACK
+       ---help---
+       This option adds a "TEE" target with which a packet can be cloned and
+       this clone be rerouted to another nexthop.
+
 config NETFILTER_XT_TARGET_TPROXY
        tristate '"TPROXY" target support (EXPERIMENTAL)'
        depends on EXPERIMENTAL
@@ -552,6 +584,10 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP
          This option adds a "TCPOPTSTRIP" target, which allows you to strip
          TCP options from TCP packets.
 
+# alphabetically ordered list of matches
+
+comment "Xtables matches"
+
 config NETFILTER_XT_MATCH_CLUSTER
        tristate '"cluster" match support'
        depends on NF_CONNTRACK
@@ -602,14 +638,11 @@ config NETFILTER_XT_MATCH_CONNMARK
        tristate  '"connmark" connection mark match support'
        depends on NF_CONNTRACK
        depends on NETFILTER_ADVANCED
-       select NF_CONNTRACK_MARK
-       help
-         This option adds a `connmark' match, which allows you to match the
-         connection mark value previously set for the session by `CONNMARK'. 
-
-         If you want to compile it as a module, say M here and read
-         <file:Documentation/kbuild/modules.txt>.  The module will be called
-         ipt_connmark.  If unsure, say `N'.
+       select NETFILTER_XT_CONNMARK
+       ---help---
+       This is a backwards-compat option for the user's convenience
+       (e.g. when running oldconfig). It selects
+       CONFIG_NETFILTER_XT_CONNMARK (combined connmark/CONNMARK module).
 
 config NETFILTER_XT_MATCH_CONNTRACK
        tristate '"conntrack" connection tracking match support'
@@ -733,13 +766,12 @@ config NETFILTER_XT_MATCH_MAC
 
 config NETFILTER_XT_MATCH_MARK
        tristate '"mark" match support'
-       default m if NETFILTER_ADVANCED=n
-       help
-         Netfilter mark matching allows you to match packets based on the
-         `nfmark' value in the packet.  This can be set by the MARK target
-         (see below).
-
-         To compile it as a module, choose M here.  If unsure, say N.
+       depends on NETFILTER_ADVANCED
+       select NETFILTER_XT_MARK
+       ---help---
+       This is a backwards-compat option for the user's convenience
+       (e.g. when running oldconfig). It selects
+       CONFIG_NETFILTER_XT_MARK (combined mark/MARK module).
 
 config NETFILTER_XT_MATCH_MULTIPORT
        tristate '"multiport" Multiple port match support'
@@ -751,6 +783,19 @@ config NETFILTER_XT_MATCH_MULTIPORT
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_MATCH_OSF
+       tristate '"osf" Passive OS fingerprint match'
+       depends on NETFILTER_ADVANCED && NETFILTER_NETLINK
+       help
+         This option selects the Passive OS Fingerprinting match module
+         that allows to passively match the remote operating system by
+         analyzing incoming TCP SYN packets.
+
+         Rules and loading software can be downloaded from
+         http://www.ioremap.net/projects/osf
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_MATCH_OWNER
        tristate '"owner" match support'
        depends on NETFILTER_ADVANCED
@@ -836,13 +881,6 @@ config NETFILTER_XT_MATCH_RECENT
        Short options are available by using 'iptables -m recent -h'
        Official Website: <http://snowman.net/projects/ipt_recent/>
 
-config NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-       bool 'Enable obsolete /proc/net/ipt_recent'
-       depends on NETFILTER_XT_MATCH_RECENT && PROC_FS
-       ---help---
-       This option enables the old /proc/net/ipt_recent interface,
-       which has been obsoleted by /proc/net/xt_recent.
-
 config NETFILTER_XT_MATCH_SCTP
        tristate  '"sctp" protocol match support (EXPERIMENTAL)'
        depends on EXPERIMENTAL
@@ -942,19 +980,6 @@ config NETFILTER_XT_MATCH_U32
 
          Details and examples are in the kernel module source.
 
-config NETFILTER_XT_MATCH_OSF
-       tristate '"osf" Passive OS fingerprint match'
-       depends on NETFILTER_ADVANCED && NETFILTER_NETLINK
-       help
-         This option selects the Passive OS Fingerprinting match module
-         that allows to passively match the remote operating system by
-         analyzing incoming TCP SYN packets.
-
-         Rules and loading software can be downloaded from
-         http://www.ioremap.net/projects/osf
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 endif # NETFILTER_XTABLES
 
 endmenu
index f873644f02f65ab28a769d3519c193e286ad7f97..14e3a8fd81803fd260f3af6580bf4e2567b30506 100644 (file)
@@ -40,15 +40,17 @@ obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
 # generic X tables 
 obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
 
+# combos
+obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o
+obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o
+
 # targets
 obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
-obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
-obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
@@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
 
 # matches
@@ -64,7 +67,6 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
-obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
@@ -76,7 +78,6 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o
-obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o
 obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o
index 2c7f185dfae464c09bf4c2146dda87063ad00314..2ae747a376a597296652be7b1051924aa5598bd8 100644 (file)
@@ -209,8 +209,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
                 */
                from.ip = n_cp->vaddr.ip;
                port = n_cp->vport;
-               sprintf(buf, "%u,%u,%u,%u,%u,%u", NIPQUAD(from.ip),
-                       (ntohs(port)>>8)&255, ntohs(port)&255);
+               snprintf(buf, sizeof(buf), "%u,%u,%u,%u,%u,%u",
+                        ((unsigned char *)&from.ip)[0],
+                        ((unsigned char *)&from.ip)[1],
+                        ((unsigned char *)&from.ip)[2],
+                        ((unsigned char *)&from.ip)[3],
+                        ntohs(port) >> 8,
+                        ntohs(port) & 0xFF);
+
                buf_len = strlen(buf);
 
                /*
index 7fc49f4cf5ad63905f4cb0a175b3e5124765002e..2d3d5e4b35f8f42f59c0cc0a838fab3903446a28 100644 (file)
@@ -167,26 +167,24 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp,
 
        ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
        if (ih == NULL)
-               sprintf(buf, "%s TRUNCATED", pp->name);
+               sprintf(buf, "TRUNCATED");
        else if (ih->frag_off & htons(IP_OFFSET))
-               sprintf(buf, "%s %pI4->%pI4 frag",
-                       pp->name, &ih->saddr, &ih->daddr);
+               sprintf(buf, "%pI4->%pI4 frag", &ih->saddr, &ih->daddr);
        else {
                __be16 _ports[2], *pptr
 ;
                pptr = skb_header_pointer(skb, offset + ih->ihl*4,
                                          sizeof(_ports), _ports);
                if (pptr == NULL)
-                       sprintf(buf, "%s TRUNCATED %pI4->%pI4",
-                               pp->name, &ih->saddr, &ih->daddr);
+                       sprintf(buf, "TRUNCATED %pI4->%pI4",
+                               &ih->saddr, &ih->daddr);
                else
-                       sprintf(buf, "%s %pI4:%u->%pI4:%u",
-                               pp->name,
+                       sprintf(buf, "%pI4:%u->%pI4:%u",
                                &ih->saddr, ntohs(pptr[0]),
                                &ih->daddr, ntohs(pptr[1]));
        }
 
-       pr_debug("%s: %s\n", msg, buf);
+       pr_debug("%s: %s %s\n", msg, pp->name, buf);
 }
 
 #ifdef CONFIG_IP_VS_IPV6
@@ -201,26 +199,24 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
 
        ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
        if (ih == NULL)
-               sprintf(buf, "%s TRUNCATED", pp->name);
+               sprintf(buf, "TRUNCATED");
        else if (ih->nexthdr == IPPROTO_FRAGMENT)
-               sprintf(buf, "%s %pI6->%pI6 frag",
-                       pp->name, &ih->saddr, &ih->daddr);
+               sprintf(buf, "%pI6->%pI6 frag", &ih->saddr, &ih->daddr);
        else {
                __be16 _ports[2], *pptr;
 
                pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
                                          sizeof(_ports), _ports);
                if (pptr == NULL)
-                       sprintf(buf, "%s TRUNCATED %pI6->%pI6",
-                               pp->name, &ih->saddr, &ih->daddr);
+                       sprintf(buf, "TRUNCATED %pI6->%pI6",
+                               &ih->saddr, &ih->daddr);
                else
-                       sprintf(buf, "%s %pI6:%u->%pI6:%u",
-                               pp->name,
+                       sprintf(buf, "%pI6:%u->%pI6:%u",
                                &ih->saddr, ntohs(pptr[0]),
                                &ih->daddr, ntohs(pptr[1]));
        }
 
-       pr_debug("%s: %s\n", msg, buf);
+       pr_debug("%s: %s %s\n", msg, pp->name, buf);
 }
 #endif
 
index c30b43c36cd7185569ef95354ccd552cc2600aee..1892dfc12fdd96ffa1169d5922243cfd0010e7e5 100644 (file)
@@ -136,12 +136,11 @@ ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb,
 
        ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
        if (ih == NULL)
-               sprintf(buf, "%s TRUNCATED", pp->name);
+               sprintf(buf, "TRUNCATED");
        else
-               sprintf(buf, "%s %pI4->%pI4",
-                       pp->name, &ih->saddr, &ih->daddr);
+               sprintf(buf, "%pI4->%pI4", &ih->saddr, &ih->daddr);
 
-       pr_debug("%s: %s\n", msg, buf);
+       pr_debug("%s: %s %s\n", msg, pp->name, buf);
 }
 
 #ifdef CONFIG_IP_VS_IPV6
@@ -154,12 +153,11 @@ ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb,
 
        ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
        if (ih == NULL)
-               sprintf(buf, "%s TRUNCATED", pp->name);
+               sprintf(buf, "TRUNCATED");
        else
-               sprintf(buf, "%s %pI6->%pI6",
-                       pp->name, &ih->saddr, &ih->daddr);
+               sprintf(buf, "%pI6->%pI6", &ih->saddr, &ih->daddr);
 
-       pr_debug("%s: %s\n", msg, buf);
+       pr_debug("%s: %s %s\n", msg, pp->name, buf);
 }
 #endif
 
index 8fb0ae61676116fd81604c7f157a357b3262f6ae..7ba06939829f3774ca34d813a41e58e8725cc6a8 100644 (file)
@@ -802,7 +802,7 @@ static int sync_thread_backup(void *data)
                ip_vs_backup_mcast_ifn, ip_vs_backup_syncid);
 
        while (!kthread_should_stop()) {
-               wait_event_interruptible(*tinfo->sock->sk->sk_sleep,
+               wait_event_interruptible(*sk_sleep(tinfo->sock->sk),
                         !skb_queue_empty(&tinfo->sock->sk->sk_receive_queue)
                         || kthread_should_stop());
 
index e450cd6f4eb5794c385bc0f63fbe76cf61393fa3..93c15a107b2ccde25d41e99e42e1a3aa28d86022 100644 (file)
@@ -270,7 +270,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
 
        LeaveFunction(10);
        return NF_STOLEN;
@@ -334,7 +334,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET6, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
 
        LeaveFunction(10);
        return NF_STOLEN;
@@ -410,7 +410,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
 
        LeaveFunction(10);
        return NF_STOLEN;
@@ -486,7 +486,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET6, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
 
        LeaveFunction(10);
        return NF_STOLEN;
@@ -785,7 +785,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
 
        LeaveFunction(10);
        return NF_STOLEN;
@@ -838,7 +838,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET6, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
 
        LeaveFunction(10);
        return NF_STOLEN;
@@ -912,7 +912,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV4, skb, rt);
 
        rc = NF_STOLEN;
        goto out;
@@ -987,7 +987,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(PF_INET6, skb, rt);
+       IP_VS_XMIT(NFPROTO_IPV6, skb, rt);
 
        rc = NF_STOLEN;
        goto out;
index 372e80f07a8160636a9f8530bbd6e05a0ec5664f..13fd2c55e32932b8424520d7b531ee0491eb87b7 100644 (file)
@@ -108,7 +108,7 @@ static int amanda_help(struct sk_buff *skb,
        dataoff = protoff + sizeof(struct udphdr);
        if (dataoff >= skb->len) {
                if (net_ratelimit())
-                       printk("amanda_help: skblen = %u\n", skb->len);
+                       printk(KERN_ERR "amanda_help: skblen = %u\n", skb->len);
                return NF_ACCEPT;
        }
 
index 0c9bbe93cc169c86ab2dbb241ae5a2654285e25f..b83c530c5e0a391c7f09e5ee8950884991377053 100644 (file)
@@ -319,8 +319,10 @@ begin:
         * not the expected one, we must restart lookup.
         * We probably met an item that was moved to another chain.
         */
-       if (get_nulls_value(n) != hash)
+       if (get_nulls_value(n) != hash) {
+               NF_CT_STAT_INC(net, search_restart);
                goto begin;
+       }
        local_bh_enable();
 
        return NULL;
@@ -1333,7 +1335,7 @@ static int nf_conntrack_init_init_net(void)
        }
        nf_conntrack_max = max_factor * nf_conntrack_htable_size;
 
-       printk("nf_conntrack version %s (%u buckets, %d max)\n",
+       printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n",
               NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
               nf_conntrack_max);
 
index f516961a83b44f9a2795dae259be5af3cf399abf..cdcc7649476b60e0e8584a7c2b2d31e7509a4bd4 100644 (file)
@@ -85,7 +85,8 @@ int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new)
        struct nf_ct_event_notifier *notify;
 
        mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference(nf_conntrack_event_cb);
+       notify = rcu_dereference_protected(nf_conntrack_event_cb,
+                                          lockdep_is_held(&nf_ct_ecache_mutex));
        if (notify != NULL) {
                ret = -EBUSY;
                goto out_unlock;
@@ -105,7 +106,8 @@ void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *new)
        struct nf_ct_event_notifier *notify;
 
        mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference(nf_conntrack_event_cb);
+       notify = rcu_dereference_protected(nf_conntrack_event_cb,
+                                          lockdep_is_held(&nf_ct_ecache_mutex));
        BUG_ON(notify != new);
        rcu_assign_pointer(nf_conntrack_event_cb, NULL);
        mutex_unlock(&nf_ct_ecache_mutex);
@@ -118,7 +120,8 @@ int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *new)
        struct nf_exp_event_notifier *notify;
 
        mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference(nf_expect_event_cb);
+       notify = rcu_dereference_protected(nf_expect_event_cb,
+                                          lockdep_is_held(&nf_ct_ecache_mutex));
        if (notify != NULL) {
                ret = -EBUSY;
                goto out_unlock;
@@ -138,7 +141,8 @@ void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new)
        struct nf_exp_event_notifier *notify;
 
        mutex_lock(&nf_ct_ecache_mutex);
-       notify = rcu_dereference(nf_expect_event_cb);
+       notify = rcu_dereference_protected(nf_expect_event_cb,
+                                          lockdep_is_held(&nf_ct_ecache_mutex));
        BUG_ON(notify != new);
        rcu_assign_pointer(nf_expect_event_cb, NULL);
        mutex_unlock(&nf_ct_ecache_mutex);
index 2ae3169e76330d6565d9f21e8a99f452e07ea8e8..e17cb7c7dd8fda61efabf12d8cefb45c4c8d4a78 100644 (file)
@@ -573,8 +573,8 @@ static int __init nf_conntrack_ftp_init(void)
                                 ftp[i][j].tuple.src.l3num, ports[i]);
                        ret = nf_conntrack_helper_register(&ftp[i][j]);
                        if (ret) {
-                               printk("nf_ct_ftp: failed to register helper "
-                                      " for pf: %d port: %d\n",
+                               printk(KERN_ERR "nf_ct_ftp: failed to register"
+                                      " helper for pf: %d port: %d\n",
                                        ftp[i][j].tuple.src.l3num, ports[i]);
                                nf_conntrack_ftp_fini();
                                return ret;
index a487c80380445a1c718c0f89cb984d62f987abaa..6eaee7c8a3375843eb2631ac1d79d155c2d12c1c 100644 (file)
@@ -194,8 +194,7 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
                        return 0;
                }
 
-               if (net_ratelimit())
-                       printk("nf_ct_h323: incomplete TPKT (fragmented?)\n");
+               pr_debug("nf_ct_h323: incomplete TPKT (fragmented?)\n");
                goto clear_out;
        }
 
@@ -608,7 +607,7 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
       drop:
        spin_unlock_bh(&nf_h323_lock);
        if (net_ratelimit())
-               printk("nf_ct_h245: packet dropped\n");
+               pr_info("nf_ct_h245: packet dropped\n");
        return NF_DROP;
 }
 
@@ -1153,7 +1152,7 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
       drop:
        spin_unlock_bh(&nf_h323_lock);
        if (net_ratelimit())
-               printk("nf_ct_q931: packet dropped\n");
+               pr_info("nf_ct_q931: packet dropped\n");
        return NF_DROP;
 }
 
@@ -1728,7 +1727,7 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
       drop:
        spin_unlock_bh(&nf_h323_lock);
        if (net_ratelimit())
-               printk("nf_ct_ras: packet dropped\n");
+               pr_info("nf_ct_ras: packet dropped\n");
        return NF_DROP;
 }
 
index 7673930ca3423fadd838d4f17d26aceda27061e7..b394aa318776447d243a2c95ed0aa0c86a754f4d 100644 (file)
@@ -235,7 +235,7 @@ static int __init nf_conntrack_irc_init(void)
        char *tmpname;
 
        if (max_dcc_channels < 1) {
-               printk("nf_ct_irc: max_dcc_channels must not be zero\n");
+               printk(KERN_ERR "nf_ct_irc: max_dcc_channels must not be zero\n");
                return -EINVAL;
        }
 
@@ -267,7 +267,7 @@ static int __init nf_conntrack_irc_init(void)
 
                ret = nf_conntrack_helper_register(&irc[i]);
                if (ret) {
-                       printk("nf_ct_irc: failed to register helper "
+                       printk(KERN_ERR "nf_ct_irc: failed to register helper "
                               "for pf: %u port: %u\n",
                               irc[i].tuple.src.l3num, ports[i]);
                        nf_conntrack_irc_fini();
index afc52f2ee4ac1f906b1daf2166faf9cff9256399..c42ff6aa441d657c03e2eb0207350e50b5adc239 100644 (file)
@@ -426,6 +426,17 @@ ctnetlink_proto_size(const struct nf_conn *ct)
        return len;
 }
 
+static inline size_t
+ctnetlink_counters_size(const struct nf_conn *ct)
+{
+       if (!nf_ct_ext_exist(ct, NF_CT_EXT_ACCT))
+               return 0;
+       return 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */
+              + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */
+              + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */
+              ;
+}
+
 static inline size_t
 ctnetlink_nlmsg_size(const struct nf_conn *ct)
 {
@@ -436,11 +447,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
               + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
               + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
               + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
-#ifdef CONFIG_NF_CT_ACCT
-              + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */
-              + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */
-              + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */
-#endif
+              + ctnetlink_counters_size(ct)
               + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
               + nla_total_size(0) /* CTA_PROTOINFO */
               + nla_total_size(0) /* CTA_HELP */
@@ -2050,29 +2057,29 @@ static int __init ctnetlink_init(void)
 {
        int ret;
 
-       printk("ctnetlink v%s: registering with nfnetlink.\n", version);
+       pr_info("ctnetlink v%s: registering with nfnetlink.\n", version);
        ret = nfnetlink_subsys_register(&ctnl_subsys);
        if (ret < 0) {
-               printk("ctnetlink_init: cannot register with nfnetlink.\n");
+               pr_err("ctnetlink_init: cannot register with nfnetlink.\n");
                goto err_out;
        }
 
        ret = nfnetlink_subsys_register(&ctnl_exp_subsys);
        if (ret < 0) {
-               printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
+               pr_err("ctnetlink_init: cannot register exp with nfnetlink.\n");
                goto err_unreg_subsys;
        }
 
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
        ret = nf_conntrack_register_notifier(&ctnl_notifier);
        if (ret < 0) {
-               printk("ctnetlink_init: cannot register notifier.\n");
+               pr_err("ctnetlink_init: cannot register notifier.\n");
                goto err_unreg_exp_subsys;
        }
 
        ret = nf_ct_expect_register_notifier(&ctnl_notifier_exp);
        if (ret < 0) {
-               printk("ctnetlink_init: cannot expect register notifier.\n");
+               pr_err("ctnetlink_init: cannot expect register notifier.\n");
                goto err_unreg_notifier;
        }
 #endif
@@ -2093,7 +2100,7 @@ err_out:
 
 static void __exit ctnetlink_exit(void)
 {
-       printk("ctnetlink: unregistering from nfnetlink.\n");
+       pr_info("ctnetlink: unregistering from nfnetlink.\n");
 
 #ifdef CONFIG_NF_CONNTRACK_EVENTS
        nf_ct_expect_unregister_notifier(&ctnl_notifier_exp);
@@ -2102,7 +2109,6 @@ static void __exit ctnetlink_exit(void)
 
        nfnetlink_subsys_unregister(&ctnl_exp_subsys);
        nfnetlink_subsys_unregister(&ctnl_subsys);
-       return;
 }
 
 module_init(ctnetlink_init);
index a44fa75b51783beefa9c44c93b70fba619df5d78..5886ba1d52a0c353a2538313c717328cacfdcac3 100644 (file)
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
-#include <linux/skbuff.h>
 #include <linux/vmalloc.h>
 #include <linux/stddef.h>
 #include <linux/err.h>
 #include <linux/percpu.h>
-#include <linux/moduleparam.h>
 #include <linux/notifier.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
@@ -119,9 +117,13 @@ void nf_ct_l3proto_module_put(unsigned short l3proto)
 {
        struct nf_conntrack_l3proto *p;
 
-       /* rcu_read_lock not necessary since the caller holds a reference */
+       /* rcu_read_lock not necessary since the caller holds a reference, but
+        * taken anyways to avoid lockdep warnings in __nf_ct_l3proto_find()
+        */
+       rcu_read_lock();
        p = __nf_ct_l3proto_find(l3proto);
        module_put(p->me);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put);
 
index b68ff15ed979b6b3694b7fd74000f9dd6839d900..c6049c2d5ea8d9be54aa6f1d77accafa3b2eb920 100644 (file)
@@ -717,12 +717,12 @@ static int __init nf_conntrack_proto_sctp_init(void)
 
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp4);
        if (ret) {
-               printk("nf_conntrack_l4proto_sctp4: protocol register failed\n");
+               pr_err("nf_conntrack_l4proto_sctp4: protocol register failed\n");
                goto out;
        }
        ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp6);
        if (ret) {
-               printk("nf_conntrack_l4proto_sctp6: protocol register failed\n");
+               pr_err("nf_conntrack_l4proto_sctp6: protocol register failed\n");
                goto cleanup_sctp4;
        }
 
index c6cd1b84eddd4e2f8a48f892282384dbc6515de0..b20f4275893c8a61b68304c17c44e379e2be9a65 100644 (file)
@@ -1549,8 +1549,8 @@ static int __init nf_conntrack_sip_init(void)
 
                        ret = nf_conntrack_helper_register(&sip[i][j]);
                        if (ret) {
-                               printk("nf_ct_sip: failed to register helper "
-                                      "for pf: %u port: %u\n",
+                               printk(KERN_ERR "nf_ct_sip: failed to register"
+                                      " helper for pf: %u port: %u\n",
                                       sip[i][j].tuple.src.l3num, ports[i]);
                                nf_conntrack_sip_fini();
                                return ret;
index faa8eb3722b96572edfd82298e275f10053e697d..eb973fcd67ab4273a3cdee566a5f4a4fb44a24f2 100644 (file)
@@ -252,12 +252,12 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
        const struct ip_conntrack_stat *st = v;
 
        if (v == SEQ_START_TOKEN) {
-               seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete\n");
+               seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart\n");
                return 0;
        }
 
        seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
-                       "%08x %08x %08x %08x %08x  %08x %08x %08x \n",
+                       "%08x %08x %08x %08x %08x  %08x %08x %08x %08x\n",
                   nr_conntracks,
                   st->searched,
                   st->found,
@@ -274,7 +274,8 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 
                   st->expect_new,
                   st->expect_create,
-                  st->expect_delete
+                  st->expect_delete,
+                  st->search_restart
                );
        return 0;
 }
@@ -445,7 +446,7 @@ out_kmemdup:
        if (net_eq(net, &init_net))
                unregister_sysctl_table(nf_ct_netfilter_header);
 out:
-       printk("nf_conntrack: can't register to sysctl.\n");
+       printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n");
        return -ENOMEM;
 }
 
index 46e646b2e9b922ff1210ff06c835f32538f0d0c7..75466fd72f4f4af4c0f948a57d06f664db503b48 100644 (file)
@@ -138,8 +138,8 @@ static int __init nf_conntrack_tftp_init(void)
 
                        ret = nf_conntrack_helper_register(&tftp[i][j]);
                        if (ret) {
-                               printk("nf_ct_tftp: failed to register helper "
-                                      "for pf: %u port: %u\n",
+                               printk(KERN_ERR "nf_ct_tftp: failed to register"
+                                      " helper for pf: %u port: %u\n",
                                        tftp[i][j].tuple.src.l3num, ports[i]);
                                nf_conntrack_tftp_fini();
                                return ret;
index bf6609978af7ae3a1f961fe170684909b7453d2b..770f76432ad02b89904646d80ed7c03571bccc16 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/netdevice.h>
 
 #ifdef CONFIG_NETFILTER_DEBUG
-#define NFDEBUG(format, args...)  printk(format , ## args)
+#define NFDEBUG(format, args...)  printk(KERN_DEBUG format , ## args)
 #else
 #define NFDEBUG(format, args...)
 #endif
index 015725a5cd5082162d2e7a029f523e17056ee139..7df37fd786bc19406a5ed8a8558df95cd26d93be 100644 (file)
@@ -52,7 +52,8 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger)
        } else {
                /* register at end of list to honor first register win */
                list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
-               llog = rcu_dereference(nf_loggers[pf]);
+               llog = rcu_dereference_protected(nf_loggers[pf],
+                                                lockdep_is_held(&nf_log_mutex));
                if (llog == NULL)
                        rcu_assign_pointer(nf_loggers[pf], logger);
        }
@@ -70,7 +71,8 @@ void nf_log_unregister(struct nf_logger *logger)
 
        mutex_lock(&nf_log_mutex);
        for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
-               c_logger = rcu_dereference(nf_loggers[i]);
+               c_logger = rcu_dereference_protected(nf_loggers[i],
+                                                    lockdep_is_held(&nf_log_mutex));
                if (c_logger == logger)
                        rcu_assign_pointer(nf_loggers[i], NULL);
                list_del(&logger->list[i]);
index c49ef219899edd130cad88524bf7efdf73efe916..78b3cf9c519ca86e66b0ba4ae88c6797a7518c3f 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/rcupdate.h>
 #include <net/protocol.h>
 #include <net/netfilter/nf_queue.h>
+#include <net/dst.h>
 
 #include "nf_internals.h"
 
@@ -170,6 +171,7 @@ static int __nf_queue(struct sk_buff *skb,
                        dev_hold(physoutdev);
        }
 #endif
+       skb_dst_force(skb);
        afinfo->saveroute(skb, entry);
        status = qh->outfn(entry, queuenum);
 
@@ -279,7 +281,6 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict)
        }
        rcu_read_unlock();
        kfree(entry);
-       return;
 }
 EXPORT_SYMBOL(nf_reinject);
 
index 6afa3d52ea5f1d7af8d2be47db8ece008429eeb6..b4a4532823e84ed8fb93fd0e9deceb8cdc07ec96 100644 (file)
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
-#include <linux/fcntl.h>
 #include <linux/skbuff.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -215,13 +212,13 @@ static struct pernet_operations nfnetlink_net_ops = {
 
 static int __init nfnetlink_init(void)
 {
-       printk("Netfilter messages via NETLINK v%s.\n", nfversion);
+       pr_info("Netfilter messages via NETLINK v%s.\n", nfversion);
        return register_pernet_subsys(&nfnetlink_net_ops);
 }
 
 static void __exit nfnetlink_exit(void)
 {
-       printk("Removing netfilter NETLINK layer.\n");
+       pr_info("Removing netfilter NETLINK layer.\n");
        unregister_pernet_subsys(&nfnetlink_net_ops);
 }
 module_init(nfnetlink_init);
index 203643fb2c524ade67aedd22bc5f3ee8221ee884..fc9a211e629e499bbc15eed8f593157a284cc1b7 100644 (file)
@@ -297,7 +297,7 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)
        n = max(inst_size, pkt_size);
        skb = alloc_skb(n, GFP_ATOMIC);
        if (!skb) {
-               PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",
+               pr_notice("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",
                        inst_size);
 
                if (n > pkt_size) {
@@ -306,7 +306,7 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size)
 
                        skb = alloc_skb(pkt_size, GFP_ATOMIC);
                        if (!skb)
-                               PRINTR("nfnetlink_log: can't even alloc %u "
+                               pr_err("nfnetlink_log: can't even alloc %u "
                                       "bytes\n", pkt_size);
                }
        }
index e70a6ef1f4f2dfa81cc6e4121d429771933f4bc5..12e1ab37fcd8f400151f8bced1b13a873b328e77 100644 (file)
@@ -246,8 +246,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
                break;
 
        case NFQNL_COPY_PACKET:
-               if ((entskb->ip_summed == CHECKSUM_PARTIAL ||
-                    entskb->ip_summed == CHECKSUM_COMPLETE) &&
+               if (entskb->ip_summed == CHECKSUM_PARTIAL &&
                    skb_checksum_help(entskb)) {
                        spin_unlock_bh(&queue->lock);
                        return NULL;
index 665f5beef6ad73d2caee6cd882611b4ce5dfee61..445de702b8b75a2dad66d96cf757a9f392ed7d80 100644 (file)
@@ -12,7 +12,7 @@
  * published by the Free Software Foundation.
  *
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/kernel.h>
 #include <linux/socket.h>
 #include <linux/net.h>
@@ -55,12 +55,6 @@ struct xt_af {
 
 static struct xt_af *xt;
 
-#ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
 static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
        [NFPROTO_UNSPEC] = "x",
        [NFPROTO_IPV4]   = "ip",
@@ -69,6 +63,9 @@ static const char *const xt_prefix[NFPROTO_NUMPROTO] = {
        [NFPROTO_IPV6]   = "ip6",
 };
 
+/* Allow this many total (re)entries. */
+static const unsigned int xt_jumpstack_multiplier = 2;
+
 /* Registration hooks for targets. */
 int
 xt_register_target(struct xt_target *target)
@@ -221,6 +218,17 @@ struct xt_match *xt_find_match(u8 af, const char *name, u8 revision)
 }
 EXPORT_SYMBOL(xt_find_match);
 
+struct xt_match *
+xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision)
+{
+       struct xt_match *match;
+
+       match = try_then_request_module(xt_find_match(nfproto, name, revision),
+                                       "%st_%s", xt_prefix[nfproto], name);
+       return (match != NULL) ? match : ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL_GPL(xt_request_find_match);
+
 /* Find target, grabs ref.  Returns ERR_PTR() on error. */
 struct xt_target *xt_find_target(u8 af, const char *name, u8 revision)
 {
@@ -257,9 +265,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision)
 
        target = try_then_request_module(xt_find_target(af, name, revision),
                                         "%st_%s", xt_prefix[af], name);
-       if (IS_ERR(target) || !target)
-               return NULL;
-       return target;
+       return (target != NULL) ? target : ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL_GPL(xt_request_find_target);
 
@@ -361,6 +367,8 @@ static char *textify_hooks(char *buf, size_t size, unsigned int mask)
 int xt_check_match(struct xt_mtchk_param *par,
                   unsigned int size, u_int8_t proto, bool inv_proto)
 {
+       int ret;
+
        if (XT_ALIGN(par->match->matchsize) != size &&
            par->match->matchsize != -1) {
                /*
@@ -397,8 +405,14 @@ int xt_check_match(struct xt_mtchk_param *par,
                       par->match->proto);
                return -EINVAL;
        }
-       if (par->match->checkentry != NULL && !par->match->checkentry(par))
-               return -EINVAL;
+       if (par->match->checkentry != NULL) {
+               ret = par->match->checkentry(par);
+               if (ret < 0)
+                       return ret;
+               else if (ret > 0)
+                       /* Flag up potential errors. */
+                       return -EIO;
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_match);
@@ -518,6 +532,8 @@ EXPORT_SYMBOL_GPL(xt_compat_match_to_user);
 int xt_check_target(struct xt_tgchk_param *par,
                    unsigned int size, u_int8_t proto, bool inv_proto)
 {
+       int ret;
+
        if (XT_ALIGN(par->target->targetsize) != size) {
                pr_err("%s_tables: %s.%u target: invalid size "
                       "%u (kernel) != (user) %u\n",
@@ -549,8 +565,14 @@ int xt_check_target(struct xt_tgchk_param *par,
                       par->target->proto);
                return -EINVAL;
        }
-       if (par->target->checkentry != NULL && !par->target->checkentry(par))
-               return -EINVAL;
+       if (par->target->checkentry != NULL) {
+               ret = par->target->checkentry(par);
+               if (ret < 0)
+                       return ret;
+               else if (ret > 0)
+                       /* Flag up potential errors. */
+                       return -EIO;
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(xt_check_target);
@@ -662,6 +684,26 @@ void xt_free_table_info(struct xt_table_info *info)
                else
                        vfree(info->entries[cpu]);
        }
+
+       if (info->jumpstack != NULL) {
+               if (sizeof(void *) * info->stacksize > PAGE_SIZE) {
+                       for_each_possible_cpu(cpu)
+                               vfree(info->jumpstack[cpu]);
+               } else {
+                       for_each_possible_cpu(cpu)
+                               kfree(info->jumpstack[cpu]);
+               }
+       }
+
+       if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE)
+               vfree(info->jumpstack);
+       else
+               kfree(info->jumpstack);
+       if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE)
+               vfree(info->stackptr);
+       else
+               kfree(info->stackptr);
+
        kfree(info);
 }
 EXPORT_SYMBOL(xt_free_table_info);
@@ -706,6 +748,49 @@ EXPORT_SYMBOL_GPL(xt_compat_unlock);
 DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
 EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
 
+static int xt_jumpstack_alloc(struct xt_table_info *i)
+{
+       unsigned int size;
+       int cpu;
+
+       size = sizeof(unsigned int) * nr_cpu_ids;
+       if (size > PAGE_SIZE)
+               i->stackptr = vmalloc(size);
+       else
+               i->stackptr = kmalloc(size, GFP_KERNEL);
+       if (i->stackptr == NULL)
+               return -ENOMEM;
+       memset(i->stackptr, 0, size);
+
+       size = sizeof(void **) * nr_cpu_ids;
+       if (size > PAGE_SIZE)
+               i->jumpstack = vmalloc(size);
+       else
+               i->jumpstack = kmalloc(size, GFP_KERNEL);
+       if (i->jumpstack == NULL)
+               return -ENOMEM;
+       memset(i->jumpstack, 0, size);
+
+       i->stacksize *= xt_jumpstack_multiplier;
+       size = sizeof(void *) * i->stacksize;
+       for_each_possible_cpu(cpu) {
+               if (size > PAGE_SIZE)
+                       i->jumpstack[cpu] = vmalloc_node(size,
+                               cpu_to_node(cpu));
+               else
+                       i->jumpstack[cpu] = kmalloc_node(size,
+                               GFP_KERNEL, cpu_to_node(cpu));
+               if (i->jumpstack[cpu] == NULL)
+                       /*
+                        * Freeing will be done later on by the callers. The
+                        * chain is: xt_replace_table -> __do_replace ->
+                        * do_replace -> xt_free_table_info.
+                        */
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
 
 struct xt_table_info *
 xt_replace_table(struct xt_table *table,
@@ -714,6 +799,13 @@ xt_replace_table(struct xt_table *table,
              int *error)
 {
        struct xt_table_info *private;
+       int ret;
+
+       ret = xt_jumpstack_alloc(newinfo);
+       if (ret < 0) {
+               *error = ret;
+               return NULL;
+       }
 
        /* Do the substitution. */
        local_bh_disable();
@@ -721,7 +813,7 @@ xt_replace_table(struct xt_table *table,
 
        /* Check inside lock: is the old number correct? */
        if (num_counters != private->number) {
-               duprintf("num_counters != table->private->number (%u/%u)\n",
+               pr_debug("num_counters != table->private->number (%u/%u)\n",
                         num_counters, private->number);
                local_bh_enable();
                *error = -EAGAIN;
@@ -752,6 +844,10 @@ struct xt_table *xt_register_table(struct net *net,
        struct xt_table_info *private;
        struct xt_table *t, *table;
 
+       ret = xt_jumpstack_alloc(newinfo);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
        /* Don't add one object to multiple lists. */
        table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
        if (!table) {
@@ -778,7 +874,7 @@ struct xt_table *xt_register_table(struct net *net,
                goto unlock;
 
        private = table->private;
-       duprintf("table->private->number = %u\n", private->number);
+       pr_debug("table->private->number = %u\n", private->number);
 
        /* save number of initial entries */
        private->initial_entries = private->number;
index 011bc80dd2a176715cb66311cee1cf0e2aa1f40b..c2c0e4abeb996fe689ebac8e964a9aa11163ce9f 100644 (file)
@@ -27,7 +27,7 @@ MODULE_ALIAS("ipt_CLASSIFY");
 MODULE_ALIAS("ip6t_CLASSIFY");
 
 static unsigned int
-classify_tg(struct sk_buff *skb, const struct xt_target_param *par)
+classify_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_classify_target_info *clinfo = par->targinfo;
 
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
deleted file mode 100644 (file)
index 5934570..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *     xt_CONNMARK - Netfilter module to modify the connection mark values
- *
- *     Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
- *     by Henrik Nordstrom <hno@marasystems.com>
- *     Copyright Â© CC Computer Consultants GmbH, 2007 - 2008
- *     Jan Engelhardt <jengelh@computergmbh.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
-MODULE_DESCRIPTION("Xtables: connection mark modification");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("ipt_CONNMARK");
-MODULE_ALIAS("ip6t_CONNMARK");
-
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_CONNMARK.h>
-#include <net/netfilter/nf_conntrack_ecache.h>
-
-static unsigned int
-connmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
-{
-       const struct xt_connmark_tginfo1 *info = par->targinfo;
-       enum ip_conntrack_info ctinfo;
-       struct nf_conn *ct;
-       u_int32_t newmark;
-
-       ct = nf_ct_get(skb, &ctinfo);
-       if (ct == NULL)
-               return XT_CONTINUE;
-
-       switch (info->mode) {
-       case XT_CONNMARK_SET:
-               newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
-               if (ct->mark != newmark) {
-                       ct->mark = newmark;
-                       nf_conntrack_event_cache(IPCT_MARK, ct);
-               }
-               break;
-       case XT_CONNMARK_SAVE:
-               newmark = (ct->mark & ~info->ctmask) ^
-                         (skb->mark & info->nfmask);
-               if (ct->mark != newmark) {
-                       ct->mark = newmark;
-                       nf_conntrack_event_cache(IPCT_MARK, ct);
-               }
-               break;
-       case XT_CONNMARK_RESTORE:
-               newmark = (skb->mark & ~info->nfmask) ^
-                         (ct->mark & info->ctmask);
-               skb->mark = newmark;
-               break;
-       }
-
-       return XT_CONTINUE;
-}
-
-static bool connmark_tg_check(const struct xt_tgchk_param *par)
-{
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "cannot load conntrack support for "
-                      "proto=%u\n", par->family);
-               return false;
-       }
-       return true;
-}
-
-static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
-{
-       nf_ct_l3proto_module_put(par->family);
-}
-
-static struct xt_target connmark_tg_reg __read_mostly = {
-       .name           = "CONNMARK",
-       .revision       = 1,
-       .family         = NFPROTO_UNSPEC,
-       .checkentry     = connmark_tg_check,
-       .target         = connmark_tg,
-       .targetsize     = sizeof(struct xt_connmark_tginfo1),
-       .destroy        = connmark_tg_destroy,
-       .me             = THIS_MODULE,
-};
-
-static int __init connmark_tg_init(void)
-{
-       return xt_register_target(&connmark_tg_reg);
-}
-
-static void __exit connmark_tg_exit(void)
-{
-       xt_unregister_target(&connmark_tg_reg);
-}
-
-module_init(connmark_tg_init);
-module_exit(connmark_tg_exit);
index b54c3756fdc3b942be616d6905b2ca62cb4cc0b4..e04dc282e3bba104d361cbc07e450ffdf3c2c3a0 100644 (file)
@@ -15,6 +15,7 @@
  * published by the Free Software Foundation.
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter/x_tables.h>
@@ -22,8 +23,6 @@
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
 
-#define PFX "CONNSECMARK: "
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
 MODULE_DESCRIPTION("Xtables: target for copying between connection and security mark");
@@ -65,7 +64,7 @@ static void secmark_restore(struct sk_buff *skb)
 }
 
 static unsigned int
-connsecmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
+connsecmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_connsecmark_target_info *info = par->targinfo;
 
@@ -85,15 +84,16 @@ connsecmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool connsecmark_tg_check(const struct xt_tgchk_param *par)
+static int connsecmark_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_connsecmark_target_info *info = par->targinfo;
+       int ret;
 
        if (strcmp(par->table, "mangle") != 0 &&
            strcmp(par->table, "security") != 0) {
-               printk(KERN_INFO PFX "target only valid in the \'mangle\' "
-                      "or \'security\' tables, not \'%s\'.\n", par->table);
-               return false;
+               pr_info("target only valid in the \'mangle\' "
+                       "or \'security\' tables, not \'%s\'.\n", par->table);
+               return -EINVAL;
        }
 
        switch (info->mode) {
@@ -102,16 +102,15 @@ static bool connsecmark_tg_check(const struct xt_tgchk_param *par)
                break;
 
        default:
-               printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
-               return false;
+               pr_info("invalid mode: %hu\n", info->mode);
+               return -EINVAL;
        }
 
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "can't load conntrack support for "
-                                   "proto=%u\n", par->family);
-               return false;
-       }
-       return true;
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
 }
 
 static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
index ee18b231b9508826af1fd70e6003c4b22d695ec9..562bf3266e043d421621ee7472aad72b50b0da51 100644 (file)
@@ -20,7 +20,7 @@
 #include <net/netfilter/nf_conntrack_zones.h>
 
 static unsigned int xt_ct_target(struct sk_buff *skb,
-                                const struct xt_target_param *par)
+                                const struct xt_action_param *par)
 {
        const struct xt_ct_target_info *info = par->targinfo;
        struct nf_conn *ct = info->ct;
@@ -38,13 +38,13 @@ static unsigned int xt_ct_target(struct sk_buff *skb,
 
 static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
 {
-       if (par->family == AF_INET) {
+       if (par->family == NFPROTO_IPV4) {
                const struct ipt_entry *e = par->entryinfo;
 
                if (e->ip.invflags & IPT_INV_PROTO)
                        return 0;
                return e->ip.proto;
-       } else if (par->family == AF_INET6) {
+       } else if (par->family == NFPROTO_IPV6) {
                const struct ip6t_entry *e = par->entryinfo;
 
                if (e->ipv6.invflags & IP6T_INV_PROTO)
@@ -54,16 +54,17 @@ static u8 xt_ct_find_proto(const struct xt_tgchk_param *par)
                return 0;
 }
 
-static bool xt_ct_tg_check(const struct xt_tgchk_param *par)
+static int xt_ct_tg_check(const struct xt_tgchk_param *par)
 {
        struct xt_ct_target_info *info = par->targinfo;
        struct nf_conntrack_tuple t;
        struct nf_conn_help *help;
        struct nf_conn *ct;
+       int ret = 0;
        u8 proto;
 
        if (info->flags & ~XT_CT_NOTRACK)
-               return false;
+               return -EINVAL;
 
        if (info->flags & XT_CT_NOTRACK) {
                ct = &nf_conntrack_untracked;
@@ -76,28 +77,34 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par)
                goto err1;
 #endif
 
-       if (nf_ct_l3proto_try_module_get(par->family) < 0)
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
                goto err1;
 
        memset(&t, 0, sizeof(t));
        ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
+       ret = PTR_ERR(ct);
        if (IS_ERR(ct))
                goto err2;
 
+       ret = 0;
        if ((info->ct_events || info->exp_events) &&
            !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events,
                                  GFP_KERNEL))
                goto err3;
 
        if (info->helper[0]) {
+               ret = -ENOENT;
                proto = xt_ct_find_proto(par);
                if (!proto)
                        goto err3;
 
+               ret = -ENOMEM;
                help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
                if (help == NULL)
                        goto err3;
 
+               ret = -ENOENT;
                help->helper = nf_conntrack_helper_try_module_get(info->helper,
                                                                  par->family,
                                                                  proto);
@@ -109,14 +116,14 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par)
        __set_bit(IPS_CONFIRMED_BIT, &ct->status);
 out:
        info->ct = ct;
-       return true;
+       return 0;
 
 err3:
        nf_conntrack_free(ct);
 err2:
        nf_ct_l3proto_module_put(par->family);
 err1:
-       return false;
+       return ret;
 }
 
 static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
@@ -138,7 +145,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par)
 static struct xt_target xt_ct_tg __read_mostly = {
        .name           = "CT",
        .family         = NFPROTO_UNSPEC,
-       .targetsize     = XT_ALIGN(sizeof(struct xt_ct_target_info)),
+       .targetsize     = sizeof(struct xt_ct_target_info),
        .checkentry     = xt_ct_tg_check,
        .destroy        = xt_ct_tg_destroy,
        .target         = xt_ct_target,
index 74ce892600569020fe077b8e0de83f948d981dc9..0a229191e55b2f8e15e00e459b2ceb20fe226893 100644 (file)
@@ -9,7 +9,7 @@
  *
  * See RFC2474 for a description of the DSCP field within the IP Header.
 */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -28,7 +28,7 @@ MODULE_ALIAS("ipt_TOS");
 MODULE_ALIAS("ip6t_TOS");
 
 static unsigned int
-dscp_tg(struct sk_buff *skb, const struct xt_target_param *par)
+dscp_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_DSCP_info *dinfo = par->targinfo;
        u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
@@ -45,7 +45,7 @@ dscp_tg(struct sk_buff *skb, const struct xt_target_param *par)
 }
 
 static unsigned int
-dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_DSCP_info *dinfo = par->targinfo;
        u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
@@ -60,19 +60,19 @@ dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool dscp_tg_check(const struct xt_tgchk_param *par)
+static int dscp_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_DSCP_info *info = par->targinfo;
 
        if (info->dscp > XT_DSCP_MAX) {
-               printk(KERN_WARNING "DSCP: dscp %x out of range\n", info->dscp);
-               return false;
+               pr_info("dscp %x out of range\n", info->dscp);
+               return -EDOM;
        }
-       return true;
+       return 0;
 }
 
 static unsigned int
-tos_tg(struct sk_buff *skb, const struct xt_target_param *par)
+tos_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_tos_target_info *info = par->targinfo;
        struct iphdr *iph = ip_hdr(skb);
@@ -92,7 +92,7 @@ tos_tg(struct sk_buff *skb, const struct xt_target_param *par)
 }
 
 static unsigned int
-tos_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+tos_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_tos_target_info *info = par->targinfo;
        struct ipv6hdr *iph = ipv6_hdr(skb);
index 10e789e2d12af24d5f526e0feea8c6414d7069bc..95b084800fcc7ca5672b817167528a0334c2246f 100644 (file)
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -26,7 +26,7 @@ MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target");
 MODULE_LICENSE("GPL");
 
 static unsigned int
-ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
+ttl_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct iphdr *iph;
        const struct ipt_TTL_info *info = par->targinfo;
@@ -66,7 +66,7 @@ ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
 }
 
 static unsigned int
-hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+hl_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct ipv6hdr *ip6h;
        const struct ip6t_HL_info *info = par->targinfo;
@@ -101,35 +101,33 @@ hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool ttl_tg_check(const struct xt_tgchk_param *par)
+static int ttl_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_TTL_info *info = par->targinfo;
 
        if (info->mode > IPT_TTL_MAXMODE) {
-               printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
-                       info->mode);
-               return false;
+               pr_info("TTL: invalid or unknown mode %u\n", info->mode);
+               return -EINVAL;
        }
        if (info->mode != IPT_TTL_SET && info->ttl == 0)
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
-static bool hl_tg6_check(const struct xt_tgchk_param *par)
+static int hl_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_HL_info *info = par->targinfo;
 
        if (info->mode > IP6T_HL_MAXMODE) {
-               printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
-                       info->mode);
-               return false;
+               pr_info("invalid or unknown mode %u\n", info->mode);
+               return -EINVAL;
        }
        if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
-               printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
+               pr_info("increment/decrement does not "
                        "make sense with value 0\n");
-               return false;
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target hl_tg_reg[] __read_mostly = {
index 3271c8e52153c929f0d1da15dcff7d6ba6f70f87..a4140509eea1f3e821bd6ffb56b5b747dfd8c9fc 100644 (file)
@@ -18,7 +18,7 @@
  * 02110-1301 USA.
  *
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter/x_tables.h>
@@ -32,18 +32,24 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
 MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
 
+static LIST_HEAD(xt_led_triggers);
+static DEFINE_MUTEX(xt_led_mutex);
+
 /*
  * This is declared in here (the kernel module) only, to avoid having these
  * dependencies in userspace code.  This is what xt_led_info.internal_data
  * points to.
  */
 struct xt_led_info_internal {
+       struct list_head list;
+       int refcnt;
+       char *trigger_id;
        struct led_trigger netfilter_led_trigger;
        struct timer_list timer;
 };
 
 static unsigned int
-led_tg(struct sk_buff *skb, const struct xt_target_param *par)
+led_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_led_info *ledinfo = par->targinfo;
        struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
@@ -54,7 +60,7 @@ led_tg(struct sk_buff *skb, const struct xt_target_param *par)
         */
        if ((ledinfo->delay > 0) && ledinfo->always_blink &&
            timer_pending(&ledinternal->timer))
-               led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF);
+               led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
 
        led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
 
@@ -75,54 +81,86 @@ led_tg(struct sk_buff *skb, const struct xt_target_param *par)
 
 static void led_timeout_callback(unsigned long data)
 {
-       struct xt_led_info *ledinfo = (struct xt_led_info *)data;
-       struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
+       struct xt_led_info_internal *ledinternal = (struct xt_led_info_internal *)data;
 
        led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
 }
 
-static bool led_tg_check(const struct xt_tgchk_param *par)
+static struct xt_led_info_internal *led_trigger_lookup(const char *name)
+{
+       struct xt_led_info_internal *ledinternal;
+
+       list_for_each_entry(ledinternal, &xt_led_triggers, list) {
+               if (!strcmp(name, ledinternal->netfilter_led_trigger.name)) {
+                       return ledinternal;
+               }
+       }
+       return NULL;
+}
+
+static int led_tg_check(const struct xt_tgchk_param *par)
 {
        struct xt_led_info *ledinfo = par->targinfo;
        struct xt_led_info_internal *ledinternal;
        int err;
 
        if (ledinfo->id[0] == '\0') {
-               printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n");
-               return false;
+               pr_info("No 'id' parameter given.\n");
+               return -EINVAL;
        }
 
-       ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
-       if (!ledinternal) {
-               printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n");
-               return false;
+       mutex_lock(&xt_led_mutex);
+
+       ledinternal = led_trigger_lookup(ledinfo->id);
+       if (ledinternal) {
+               ledinternal->refcnt++;
+               goto out;
        }
 
-       ledinternal->netfilter_led_trigger.name = ledinfo->id;
+       err = -ENOMEM;
+       ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
+       if (!ledinternal)
+               goto exit_mutex_only;
+
+       ledinternal->trigger_id = kstrdup(ledinfo->id, GFP_KERNEL);
+       if (!ledinternal->trigger_id)
+               goto exit_internal_alloc;
+
+       ledinternal->refcnt = 1;
+       ledinternal->netfilter_led_trigger.name = ledinternal->trigger_id;
 
        err = led_trigger_register(&ledinternal->netfilter_led_trigger);
        if (err) {
-               printk(KERN_CRIT KBUILD_MODNAME
-                       ": led_trigger_register() failed\n");
+               pr_warning("led_trigger_register() failed\n");
                if (err == -EEXIST)
-                       printk(KERN_ERR KBUILD_MODNAME
-                               ": Trigger name is already in use.\n");
+                       pr_warning("Trigger name is already in use.\n");
                goto exit_alloc;
        }
 
        /* See if we need to set up a timer */
        if (ledinfo->delay > 0)
                setup_timer(&ledinternal->timer, led_timeout_callback,
-                           (unsigned long)ledinfo);
+                           (unsigned long)ledinternal);
+
+       list_add_tail(&ledinternal->list, &xt_led_triggers);
+
+out:
+       mutex_unlock(&xt_led_mutex);
 
        ledinfo->internal_data = ledinternal;
 
-       return true;
+       return 0;
 
 exit_alloc:
+       kfree(ledinternal->trigger_id);
+
+exit_internal_alloc:
        kfree(ledinternal);
 
-       return false;
+exit_mutex_only:
+       mutex_unlock(&xt_led_mutex);
+
+       return err;
 }
 
 static void led_tg_destroy(const struct xt_tgdtor_param *par)
@@ -130,10 +168,23 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par)
        const struct xt_led_info *ledinfo = par->targinfo;
        struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
 
+       mutex_lock(&xt_led_mutex);
+
+       if (--ledinternal->refcnt) {
+               mutex_unlock(&xt_led_mutex);
+               return;
+       }
+
+       list_del(&ledinternal->list);
+
        if (ledinfo->delay > 0)
                del_timer_sync(&ledinternal->timer);
 
        led_trigger_unregister(&ledinternal->netfilter_led_trigger);
+
+       mutex_unlock(&xt_led_mutex);
+
+       kfree(ledinternal->trigger_id);
        kfree(ledinternal);
 }
 
@@ -142,7 +193,7 @@ static struct xt_target led_tg_reg __read_mostly = {
        .revision       = 0,
        .family         = NFPROTO_UNSPEC,
        .target         = led_tg,
-       .targetsize     = XT_ALIGN(sizeof(struct xt_led_info)),
+       .targetsize     = sizeof(struct xt_led_info),
        .checkentry     = led_tg_check,
        .destroy        = led_tg_destroy,
        .me             = THIS_MODULE,
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
deleted file mode 100644 (file)
index 225f8d1..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *     xt_MARK - Netfilter module to modify the NFMARK field of an skb
- *
- *     (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
- *     Copyright Â© CC Computer Consultants GmbH, 2007 - 2008
- *     Jan Engelhardt <jengelh@computergmbh.de>
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License version 2 as
- *     published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <net/checksum.h>
-
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter/xt_MARK.h>
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("Xtables: packet mark modification");
-MODULE_ALIAS("ipt_MARK");
-MODULE_ALIAS("ip6t_MARK");
-
-static unsigned int
-mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
-{
-       const struct xt_mark_tginfo2 *info = par->targinfo;
-
-       skb->mark = (skb->mark & ~info->mask) ^ info->mark;
-       return XT_CONTINUE;
-}
-
-static struct xt_target mark_tg_reg __read_mostly = {
-       .name           = "MARK",
-       .revision       = 2,
-       .family         = NFPROTO_UNSPEC,
-       .target         = mark_tg,
-       .targetsize     = sizeof(struct xt_mark_tginfo2),
-       .me             = THIS_MODULE,
-};
-
-static int __init mark_tg_init(void)
-{
-       return xt_register_target(&mark_tg_reg);
-}
-
-static void __exit mark_tg_exit(void)
-{
-       xt_unregister_target(&mark_tg_reg);
-}
-
-module_init(mark_tg_init);
-module_exit(mark_tg_exit);
index a57c5cf018ec04871d07a4f4c948c78b08ddb443..a17dd0f589b22d3ffce573177414c4afa0790c1d 100644 (file)
@@ -22,7 +22,7 @@ MODULE_ALIAS("ipt_NFLOG");
 MODULE_ALIAS("ip6t_NFLOG");
 
 static unsigned int
-nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
+nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_nflog_info *info = par->targinfo;
        struct nf_loginfo li;
@@ -37,15 +37,15 @@ nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool nflog_tg_check(const struct xt_tgchk_param *par)
+static int nflog_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_nflog_info *info = par->targinfo;
 
        if (info->flags & ~XT_NFLOG_MASK)
-               return false;
+               return -EINVAL;
        if (info->prefix[sizeof(info->prefix) - 1] != '\0')
-               return false;
-       return true;
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_target nflog_tg_reg __read_mostly = {
index 12dcd7007c3e4f6b8713752d7e2a49faeafb2ad5..039cce1bde3dc60ccdbb3e6857bb2685dc123079 100644 (file)
@@ -31,7 +31,7 @@ static u32 jhash_initval __read_mostly;
 static bool rnd_inited __read_mostly;
 
 static unsigned int
-nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par)
+nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_NFQ_info *tinfo = par->targinfo;
 
@@ -49,17 +49,6 @@ static u32 hash_v4(const struct sk_buff *skb)
        return jhash_2words((__force u32)ipaddr, iph->protocol, jhash_initval);
 }
 
-static unsigned int
-nfqueue_tg4_v1(struct sk_buff *skb, const struct xt_target_param *par)
-{
-       const struct xt_NFQ_info_v1 *info = par->targinfo;
-       u32 queue = info->queuenum;
-
-       if (info->queues_total > 1)
-               queue = hash_v4(skb) % info->queues_total + queue;
-       return NF_QUEUE_NR(queue);
-}
-
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 static u32 hash_v6(const struct sk_buff *skb)
 {
@@ -73,20 +62,26 @@ static u32 hash_v6(const struct sk_buff *skb)
 
        return jhash2((__force u32 *)addr, ARRAY_SIZE(addr), jhash_initval);
 }
+#endif
 
 static unsigned int
-nfqueue_tg6_v1(struct sk_buff *skb, const struct xt_target_param *par)
+nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_NFQ_info_v1 *info = par->targinfo;
        u32 queue = info->queuenum;
 
-       if (info->queues_total > 1)
-               queue = hash_v6(skb) % info->queues_total + queue;
+       if (info->queues_total > 1) {
+               if (par->family == NFPROTO_IPV4)
+                       queue = hash_v4(skb) % info->queues_total + queue;
+#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
+               else if (par->family == NFPROTO_IPV6)
+                       queue = hash_v6(skb) % info->queues_total + queue;
+#endif
+       }
        return NF_QUEUE_NR(queue);
 }
-#endif
 
-static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par)
+static int nfqueue_tg_v1_check(const struct xt_tgchk_param *par)
 {
        const struct xt_NFQ_info_v1 *info = par->targinfo;
        u32 maxid;
@@ -97,15 +92,15 @@ static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par)
        }
        if (info->queues_total == 0) {
                pr_err("NFQUEUE: number of total queues is 0\n");
-               return false;
+               return -EINVAL;
        }
        maxid = info->queues_total - 1 + info->queuenum;
        if (maxid > 0xffff) {
                pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n",
                       info->queues_total, maxid);
-               return false;
+               return -ERANGE;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_target nfqueue_tg_reg[] __read_mostly = {
@@ -119,23 +114,12 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = {
        {
                .name           = "NFQUEUE",
                .revision       = 1,
-               .family         = NFPROTO_IPV4,
-               .checkentry     = nfqueue_tg_v1_check,
-               .target         = nfqueue_tg4_v1,
-               .targetsize     = sizeof(struct xt_NFQ_info_v1),
-               .me             = THIS_MODULE,
-       },
-#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-       {
-               .name           = "NFQUEUE",
-               .revision       = 1,
-               .family         = NFPROTO_IPV6,
+               .family         = NFPROTO_UNSPEC,
                .checkentry     = nfqueue_tg_v1_check,
-               .target         = nfqueue_tg6_v1,
+               .target         = nfqueue_tg_v1,
                .targetsize     = sizeof(struct xt_NFQ_info_v1),
                .me             = THIS_MODULE,
        },
-#endif
 };
 
 static int __init nfqueue_tg_init(void)
index e7a0a54fd4eae42f268ee91262532e00fa84199b..512b9123252f0a0caa625a0a43cead965865864c 100644 (file)
@@ -13,7 +13,7 @@ MODULE_ALIAS("ipt_NOTRACK");
 MODULE_ALIAS("ip6t_NOTRACK");
 
 static unsigned int
-notrack_tg(struct sk_buff *skb, const struct xt_target_param *par)
+notrack_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        /* Previously seen (loopback)? Ignore. */
        if (skb->nfct != NULL)
index d16d55df4f616444b3fb7368cf0c91a1a2021459..69c01e10f8afe00ebcdefd1becdec4875fa84a06 100644 (file)
@@ -73,7 +73,7 @@ void xt_rateest_put(struct xt_rateest *est)
 EXPORT_SYMBOL_GPL(xt_rateest_put);
 
 static unsigned int
-xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
+xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_rateest_target_info *info = par->targinfo;
        struct gnet_stats_basic_packed *stats = &info->est->bstats;
@@ -86,7 +86,7 @@ xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
+static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
 {
        struct xt_rateest_target_info *info = par->targinfo;
        struct xt_rateest *est;
@@ -94,6 +94,7 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
                struct nlattr           opt;
                struct gnet_estimator   est;
        } cfg;
+       int ret;
 
        if (unlikely(!rnd_inited)) {
                get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
@@ -110,12 +111,13 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
                    (info->interval != est->params.interval ||
                     info->ewma_log != est->params.ewma_log)) {
                        xt_rateest_put(est);
-                       return false;
+                       return -EINVAL;
                }
                info->est = est;
-               return true;
+               return 0;
        }
 
+       ret = -ENOMEM;
        est = kzalloc(sizeof(*est), GFP_KERNEL);
        if (!est)
                goto err1;
@@ -131,19 +133,19 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
        cfg.est.interval        = info->interval;
        cfg.est.ewma_log        = info->ewma_log;
 
-       if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock,
-                             &cfg.opt) < 0)
+       ret = gen_new_estimator(&est->bstats, &est->rstats,
+                               &est->lock, &cfg.opt);
+       if (ret < 0)
                goto err2;
 
        info->est = est;
        xt_rateest_hash_insert(est);
-
-       return true;
+       return 0;
 
 err2:
        kfree(est);
 err1:
-       return false;
+       return ret;
 }
 
 static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
index 7a6f9e6f5dfaa6b7e4e5eb57890542a99065b0e3..23b2d6c486b573927dcefd00b575546b35376bfa 100644 (file)
@@ -12,6 +12,7 @@
  * published by the Free Software Foundation.
  *
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/selinux.h>
@@ -29,7 +30,7 @@ MODULE_ALIAS("ip6t_SECMARK");
 static u8 mode;
 
 static unsigned int
-secmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
+secmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        u32 secmark = 0;
        const struct xt_secmark_target_info *info = par->targinfo;
@@ -49,7 +50,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return XT_CONTINUE;
 }
 
-static bool checkentry_selinux(struct xt_secmark_target_info *info)
+static int checkentry_selinux(struct xt_secmark_target_info *info)
 {
        int err;
        struct xt_secmark_target_selinux_info *sel = &info->u.sel;
@@ -59,58 +60,59 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info)
        err = selinux_string_to_sid(sel->selctx, &sel->selsid);
        if (err) {
                if (err == -EINVAL)
-                       printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n",
-                              sel->selctx);
-               return false;
+                       pr_info("invalid SELinux context \'%s\'\n",
+                               sel->selctx);
+               return err;
        }
 
        if (!sel->selsid) {
-               printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n",
-                      sel->selctx);
-               return false;
+               pr_info("unable to map SELinux context \'%s\'\n", sel->selctx);
+               return -ENOENT;
        }
 
        err = selinux_secmark_relabel_packet_permission(sel->selsid);
        if (err) {
-               printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
-               return false;
+               pr_info("unable to obtain relabeling permission\n");
+               return err;
        }
 
        selinux_secmark_refcount_inc();
-       return true;
+       return 0;
 }
 
-static bool secmark_tg_check(const struct xt_tgchk_param *par)
+static int secmark_tg_check(const struct xt_tgchk_param *par)
 {
        struct xt_secmark_target_info *info = par->targinfo;
+       int err;
 
        if (strcmp(par->table, "mangle") != 0 &&
            strcmp(par->table, "security") != 0) {
-               printk(KERN_INFO PFX "target only valid in the \'mangle\' "
-                      "or \'security\' tables, not \'%s\'.\n", par->table);
-               return false;
+               pr_info("target only valid in the \'mangle\' "
+                       "or \'security\' tables, not \'%s\'.\n", par->table);
+               return -EINVAL;
        }
 
        if (mode && mode != info->mode) {
-               printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
-                      "rules for mode %hu\n", mode, info->mode);
-               return false;
+               pr_info("mode already set to %hu cannot mix with "
+                       "rules for mode %hu\n", mode, info->mode);
+               return -EINVAL;
        }
 
        switch (info->mode) {
        case SECMARK_MODE_SEL:
-               if (!checkentry_selinux(info))
-                       return false;
+               err = checkentry_selinux(info);
+               if (err <= 0)
+                       return err;
                break;
 
        default:
-               printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
-               return false;
+               pr_info("invalid mode: %hu\n", info->mode);
+               return -EINVAL;
        }
 
        if (!mode)
                mode = info->mode;
-       return true;
+       return 0;
 }
 
 static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
index c5f4b9919e9a016ef3f3428440e2446571293920..62ec021fbd50ddd278da5f9f53756587d83fb786 100644 (file)
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -68,15 +68,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
                if (dst_mtu(skb_dst(skb)) <= minlen) {
                        if (net_ratelimit())
-                               printk(KERN_ERR "xt_TCPMSS: "
-                                      "unknown or invalid path-MTU (%u)\n",
+                               pr_err("unknown or invalid path-MTU (%u)\n",
                                       dst_mtu(skb_dst(skb)));
                        return -1;
                }
                if (in_mtu <= minlen) {
                        if (net_ratelimit())
-                               printk(KERN_ERR "xt_TCPMSS: unknown or "
-                                      "invalid path-MTU (%u)\n", in_mtu);
+                               pr_err("unknown or invalid path-MTU (%u)\n",
+                                      in_mtu);
                        return -1;
                }
                newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
@@ -173,7 +172,7 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
 }
 
 static unsigned int
-tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par)
+tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct iphdr *iph = ip_hdr(skb);
        __be16 newlen;
@@ -196,7 +195,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par)
 
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
 static unsigned int
-tcpmss_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct ipv6hdr *ipv6h = ipv6_hdr(skb);
        u8 nexthdr;
@@ -236,7 +235,7 @@ static inline bool find_syn_match(const struct xt_entry_match *m)
        return false;
 }
 
-static bool tcpmss_tg4_check(const struct xt_tgchk_param *par)
+static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
 {
        const struct xt_tcpmss_info *info = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
@@ -246,19 +245,19 @@ static bool tcpmss_tg4_check(const struct xt_tgchk_param *par)
            (par->hook_mask & ~((1 << NF_INET_FORWARD) |
                           (1 << NF_INET_LOCAL_OUT) |
                           (1 << NF_INET_POST_ROUTING))) != 0) {
-               printk("xt_TCPMSS: path-MTU clamping only supported in "
-                      "FORWARD, OUTPUT and POSTROUTING hooks\n");
-               return false;
+               pr_info("path-MTU clamping only supported in "
+                       "FORWARD, OUTPUT and POSTROUTING hooks\n");
+               return -EINVAL;
        }
        xt_ematch_foreach(ematch, e)
                if (find_syn_match(ematch))
-                       return true;
-       printk("xt_TCPMSS: Only works on TCP SYN packets\n");
-       return false;
+                       return 0;
+       pr_info("Only works on TCP SYN packets\n");
+       return -EINVAL;
 }
 
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-static bool tcpmss_tg6_check(const struct xt_tgchk_param *par)
+static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct xt_tcpmss_info *info = par->targinfo;
        const struct ip6t_entry *e = par->entryinfo;
@@ -268,15 +267,15 @@ static bool tcpmss_tg6_check(const struct xt_tgchk_param *par)
            (par->hook_mask & ~((1 << NF_INET_FORWARD) |
                           (1 << NF_INET_LOCAL_OUT) |
                           (1 << NF_INET_POST_ROUTING))) != 0) {
-               printk("xt_TCPMSS: path-MTU clamping only supported in "
-                      "FORWARD, OUTPUT and POSTROUTING hooks\n");
-               return false;
+               pr_info("path-MTU clamping only supported in "
+                       "FORWARD, OUTPUT and POSTROUTING hooks\n");
+               return -EINVAL;
        }
        xt_ematch_foreach(ematch, e)
                if (find_syn_match(ematch))
-                       return true;
-       printk("xt_TCPMSS: Only works on TCP SYN packets\n");
-       return false;
+                       return 0;
+       pr_info("Only works on TCP SYN packets\n");
+       return -EINVAL;
 }
 #endif
 
index 9dd8c8ef63eb302acaf81320988766919e82dfe4..9dc9ecfdd546298e4bc6dca11a20844367562416 100644 (file)
@@ -3,7 +3,6 @@
  *
  * Copyright (C) 2007 Sven Schnelle <svens@bitebene.org>
  * Copyright Â© CC Computer Consultants GmbH, 2007
- * Contact: Jan Engelhardt <jengelh@computergmbh.de>
  *
  * 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
@@ -75,7 +74,7 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
 }
 
 static unsigned int
-tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_target_param *par)
+tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par)
 {
        return tcpoptstrip_mangle_packet(skb, par->targinfo, ip_hdrlen(skb),
               sizeof(struct iphdr) + sizeof(struct tcphdr));
@@ -83,7 +82,7 @@ tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_target_param *par)
 
 #if defined(CONFIG_IP6_NF_MANGLE) || defined(CONFIG_IP6_NF_MANGLE_MODULE)
 static unsigned int
-tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_target_param *par)
+tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
        struct ipv6hdr *ipv6h = ipv6_hdr(skb);
        int tcphoff;
@@ -136,7 +135,7 @@ static void __exit tcpoptstrip_tg_exit(void)
 
 module_init(tcpoptstrip_tg_init);
 module_exit(tcpoptstrip_tg_exit);
-MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: TCP option stripping");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_TCPOPTSTRIP");
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
new file mode 100644 (file)
index 0000000..d7920d9
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *     "TEE" target extension for Xtables
+ *     Copyright Â© Sebastian Claßen, 2007
+ *     Jan Engelhardt, 2007-2010
+ *
+ *     based on ipt_ROUTE.c from Cédric de Launois
+ *     <delaunois@info.ucl.be>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     version 2 or later, as published by the Free Software Foundation.
+ */
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/route.h>
+#include <linux/skbuff.h>
+#include <linux/notifier.h>
+#include <net/checksum.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/route.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_TEE.h>
+
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#      define WITH_CONNTRACK 1
+#      include <net/netfilter/nf_conntrack.h>
+#endif
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#      define WITH_IPV6 1
+#endif
+
+struct xt_tee_priv {
+       struct notifier_block   notifier;
+       struct xt_tee_tginfo    *tginfo;
+       int                     oif;
+};
+
+static const union nf_inet_addr tee_zero_address;
+static DEFINE_PER_CPU(bool, tee_active);
+
+static struct net *pick_net(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_NS
+       const struct dst_entry *dst;
+
+       if (skb->dev != NULL)
+               return dev_net(skb->dev);
+       dst = skb_dst(skb);
+       if (dst != NULL && dst->dev != NULL)
+               return dev_net(dst->dev);
+#endif
+       return &init_net;
+}
+
+static bool
+tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
+{
+       const struct iphdr *iph = ip_hdr(skb);
+       struct net *net = pick_net(skb);
+       struct rtable *rt;
+       struct flowi fl;
+
+       memset(&fl, 0, sizeof(fl));
+       if (info->priv) {
+               if (info->priv->oif == -1)
+                       return false;
+               fl.oif = info->priv->oif;
+       }
+       fl.nl_u.ip4_u.daddr = info->gw.ip;
+       fl.nl_u.ip4_u.tos   = RT_TOS(iph->tos);
+       fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE;
+       if (ip_route_output_key(net, &rt, &fl) != 0)
+               return false;
+
+       dst_release(skb_dst(skb));
+       skb_dst_set(skb, &rt->u.dst);
+       skb->dev      = rt->u.dst.dev;
+       skb->protocol = htons(ETH_P_IP);
+       return true;
+}
+
+static unsigned int
+tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       const struct xt_tee_tginfo *info = par->targinfo;
+       struct iphdr *iph;
+
+       if (percpu_read(tee_active))
+               return XT_CONTINUE;
+       /*
+        * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
+        * the original skb, which should continue on its way as if nothing has
+        * happened. The copy should be independently delivered to the TEE
+        * --gateway.
+        */
+       skb = pskb_copy(skb, GFP_ATOMIC);
+       if (skb == NULL)
+               return XT_CONTINUE;
+
+#ifdef WITH_CONNTRACK
+       /* Avoid counting cloned packets towards the original connection. */
+       nf_conntrack_put(skb->nfct);
+       skb->nfct     = &nf_conntrack_untracked.ct_general;
+       skb->nfctinfo = IP_CT_NEW;
+       nf_conntrack_get(skb->nfct);
+#endif
+       /*
+        * If we are in PREROUTING/INPUT, the checksum must be recalculated
+        * since the length could have changed as a result of defragmentation.
+        *
+        * We also decrease the TTL to mitigate potential TEE loops
+        * between two hosts.
+        *
+        * Set %IP_DF so that the original source is notified of a potentially
+        * decreased MTU on the clone route. IPv6 does this too.
+        */
+       iph = ip_hdr(skb);
+       iph->frag_off |= htons(IP_DF);
+       if (par->hooknum == NF_INET_PRE_ROUTING ||
+           par->hooknum == NF_INET_LOCAL_IN)
+               --iph->ttl;
+       ip_send_check(iph);
+
+       if (tee_tg_route4(skb, info)) {
+               percpu_write(tee_active, true);
+               ip_local_out(skb);
+               percpu_write(tee_active, false);
+       } else {
+               kfree_skb(skb);
+       }
+       return XT_CONTINUE;
+}
+
+#ifdef WITH_IPV6
+static bool
+tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
+{
+       const struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct net *net = pick_net(skb);
+       struct dst_entry *dst;
+       struct flowi fl;
+
+       memset(&fl, 0, sizeof(fl));
+       if (info->priv) {
+               if (info->priv->oif == -1)
+                       return false;
+               fl.oif = info->priv->oif;
+       }
+       fl.nl_u.ip6_u.daddr = info->gw.in6;
+       fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
+                                 (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
+       dst = ip6_route_output(net, NULL, &fl);
+       if (dst == NULL)
+               return false;
+
+       dst_release(skb_dst(skb));
+       skb_dst_set(skb, dst);
+       skb->dev      = dst->dev;
+       skb->protocol = htons(ETH_P_IPV6);
+       return true;
+}
+
+static unsigned int
+tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       const struct xt_tee_tginfo *info = par->targinfo;
+
+       if (percpu_read(tee_active))
+               return XT_CONTINUE;
+       skb = pskb_copy(skb, GFP_ATOMIC);
+       if (skb == NULL)
+               return XT_CONTINUE;
+
+#ifdef WITH_CONNTRACK
+       nf_conntrack_put(skb->nfct);
+       skb->nfct     = &nf_conntrack_untracked.ct_general;
+       skb->nfctinfo = IP_CT_NEW;
+       nf_conntrack_get(skb->nfct);
+#endif
+       if (par->hooknum == NF_INET_PRE_ROUTING ||
+           par->hooknum == NF_INET_LOCAL_IN) {
+               struct ipv6hdr *iph = ipv6_hdr(skb);
+               --iph->hop_limit;
+       }
+       if (tee_tg_route6(skb, info)) {
+               percpu_write(tee_active, true);
+               ip6_local_out(skb);
+               percpu_write(tee_active, false);
+       } else {
+               kfree_skb(skb);
+       }
+       return XT_CONTINUE;
+}
+#endif /* WITH_IPV6 */
+
+static int tee_netdev_event(struct notifier_block *this, unsigned long event,
+                           void *ptr)
+{
+       struct net_device *dev = ptr;
+       struct xt_tee_priv *priv;
+
+       priv = container_of(this, struct xt_tee_priv, notifier);
+       switch (event) {
+       case NETDEV_REGISTER:
+               if (!strcmp(dev->name, priv->tginfo->oif))
+                       priv->oif = dev->ifindex;
+               break;
+       case NETDEV_UNREGISTER:
+               if (dev->ifindex == priv->oif)
+                       priv->oif = -1;
+               break;
+       case NETDEV_CHANGENAME:
+               if (!strcmp(dev->name, priv->tginfo->oif))
+                       priv->oif = dev->ifindex;
+               else if (dev->ifindex == priv->oif)
+                       priv->oif = -1;
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static int tee_tg_check(const struct xt_tgchk_param *par)
+{
+       struct xt_tee_tginfo *info = par->targinfo;
+       struct xt_tee_priv *priv;
+
+       /* 0.0.0.0 and :: not allowed */
+       if (memcmp(&info->gw, &tee_zero_address,
+                  sizeof(tee_zero_address)) == 0)
+               return -EINVAL;
+
+       if (info->oif[0]) {
+               if (info->oif[sizeof(info->oif)-1] != '\0')
+                       return -EINVAL;
+
+               priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+               if (priv == NULL)
+                       return -ENOMEM;
+
+               priv->tginfo  = info;
+               priv->oif     = -1;
+               priv->notifier.notifier_call = tee_netdev_event;
+               info->priv    = priv;
+
+               register_netdevice_notifier(&priv->notifier);
+       } else
+               info->priv = NULL;
+
+       return 0;
+}
+
+static void tee_tg_destroy(const struct xt_tgdtor_param *par)
+{
+       struct xt_tee_tginfo *info = par->targinfo;
+
+       if (info->priv) {
+               unregister_netdevice_notifier(&info->priv->notifier);
+               kfree(info->priv);
+       }
+}
+
+static struct xt_target tee_tg_reg[] __read_mostly = {
+       {
+               .name       = "TEE",
+               .revision   = 1,
+               .family     = NFPROTO_IPV4,
+               .target     = tee_tg4,
+               .targetsize = sizeof(struct xt_tee_tginfo),
+               .checkentry = tee_tg_check,
+               .destroy    = tee_tg_destroy,
+               .me         = THIS_MODULE,
+       },
+#ifdef WITH_IPV6
+       {
+               .name       = "TEE",
+               .revision   = 1,
+               .family     = NFPROTO_IPV6,
+               .target     = tee_tg6,
+               .targetsize = sizeof(struct xt_tee_tginfo),
+               .checkentry = tee_tg_check,
+               .destroy    = tee_tg_destroy,
+               .me         = THIS_MODULE,
+       },
+#endif
+};
+
+static int __init tee_tg_init(void)
+{
+       return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
+}
+
+static void __exit tee_tg_exit(void)
+{
+       xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
+}
+
+module_init(tee_tg_init);
+module_exit(tee_tg_exit);
+MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
+MODULE_DESCRIPTION("Xtables: Reroute packet copy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_TEE");
+MODULE_ALIAS("ip6t_TEE");
index 1340c2fa3621e54f651d4a66b25edd79007e93c2..e1a0dedac2580b1aeb5fe1d52d6e5f60f082005b 100644 (file)
@@ -9,7 +9,7 @@
  * published by the Free Software Foundation.
  *
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -25,7 +25,7 @@
 #include <net/netfilter/nf_tproxy_core.h>
 
 static unsigned int
-tproxy_tg(struct sk_buff *skb, const struct xt_target_param *par)
+tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct iphdr *iph = ip_hdr(skb);
        const struct xt_tproxy_target_info *tgi = par->targinfo;
@@ -59,17 +59,17 @@ tproxy_tg(struct sk_buff *skb, const struct xt_target_param *par)
        return NF_DROP;
 }
 
-static bool tproxy_tg_check(const struct xt_tgchk_param *par)
+static int tproxy_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_ip *i = par->entryinfo;
 
        if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
            && !(i->invflags & IPT_INV_PROTO))
-               return true;
+               return 0;
 
-       pr_info("xt_TPROXY: Can be used only in combination with "
+       pr_info("Can be used only in combination with "
                "either -p tcp or -p udp\n");
-       return false;
+       return -EINVAL;
 }
 
 static struct xt_target tproxy_tg_reg __read_mostly = {
index fbb04b86c46b8c96b7d933d7bd11ff7bbd8b5fca..df48967af38210e766f2bb85568f4d5ddb67bbfa 100644 (file)
@@ -11,7 +11,7 @@ MODULE_ALIAS("ipt_TRACE");
 MODULE_ALIAS("ip6t_TRACE");
 
 static unsigned int
-trace_tg(struct sk_buff *skb, const struct xt_target_param *par)
+trace_tg(struct sk_buff *skb, const struct xt_action_param *par)
 {
        skb->nf_trace = 1;
        return XT_CONTINUE;
index 225ee3ecd69d63152489a0f47ae76d5cbacb7b8f..30b95a1c1c892da3018bbf9084e4fe3a8d59b4b1 100644 (file)
@@ -5,6 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/jhash.h>
@@ -85,7 +86,7 @@ xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
 }
 
 static bool
-xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct sk_buff *pskb = (struct sk_buff *)skb;
        const struct xt_cluster_match_info *info = par->matchinfo;
@@ -131,22 +132,22 @@ xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par)
               !!(info->flags & XT_CLUSTER_F_INV);
 }
 
-static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
+static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
 {
        struct xt_cluster_match_info *info = par->matchinfo;
 
        if (info->total_nodes > XT_CLUSTER_NODES_MAX) {
-               printk(KERN_ERR "xt_cluster: you have exceeded the maximum "
-                               "number of cluster nodes (%u > %u)\n",
-                               info->total_nodes, XT_CLUSTER_NODES_MAX);
-               return false;
+               pr_info("you have exceeded the maximum "
+                       "number of cluster nodes (%u > %u)\n",
+                       info->total_nodes, XT_CLUSTER_NODES_MAX);
+               return -EINVAL;
        }
        if (info->node_mask >= (1ULL << info->total_nodes)) {
-               printk(KERN_ERR "xt_cluster: this node mask cannot be "
-                               "higher than the total number of nodes\n");
-               return false;
+               pr_info("this node mask cannot be "
+                       "higher than the total number of nodes\n");
+               return -EDOM;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match xt_cluster_match __read_mostly = {
index e82179832acd252bd6595b940fb97388612cad0d..5c861d2f21ca6feb528355e209ab679fd749a638 100644 (file)
@@ -16,7 +16,7 @@ MODULE_ALIAS("ipt_comment");
 MODULE_ALIAS("ip6t_comment");
 
 static bool
-comment_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+comment_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        /* We always match */
        return true;
index 955e6598a7f0a9fc02d4ed2f52425178a1706cb2..73517835303d4fa68b2b34247d3907e2a7f4c3ca 100644 (file)
@@ -1,6 +1,7 @@
 /* Kernel module to match connection tracking byte counter.
  * GPL (C) 2002 Martin Devera (devik@cdi.cz).
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/bitops.h>
 #include <linux/skbuff.h>
@@ -17,7 +18,7 @@ MODULE_ALIAS("ipt_connbytes");
 MODULE_ALIAS("ip6t_connbytes");
 
 static bool
-connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_connbytes_info *sinfo = par->matchinfo;
        const struct nf_conn *ct;
@@ -92,27 +93,26 @@ connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                return what >= sinfo->count.from;
 }
 
-static bool connbytes_mt_check(const struct xt_mtchk_param *par)
+static int connbytes_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_connbytes_info *sinfo = par->matchinfo;
+       int ret;
 
        if (sinfo->what != XT_CONNBYTES_PKTS &&
            sinfo->what != XT_CONNBYTES_BYTES &&
            sinfo->what != XT_CONNBYTES_AVGPKT)
-               return false;
+               return -EINVAL;
 
        if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
            sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
            sinfo->direction != XT_CONNBYTES_DIR_BOTH)
-               return false;
-
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "can't load conntrack support for "
-                                   "proto=%u\n", par->family);
-               return false;
-       }
+               return -EINVAL;
 
-       return true;
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
 }
 
 static void connbytes_mt_destroy(const struct xt_mtdtor_param *par)
index 388ca459609846e9f0f92b84771331c1e58bd206..5c5b6b921b845b2fe1ba438ef9c13a2161e5b0ea 100644 (file)
@@ -5,13 +5,13 @@
  *   Nov 2002: Martin Bene <martin.bene@icomedias.com>:
  *             only ignore TIME_WAIT or gone connections
  *   (C) CC Computer Consultants GmbH, 2007
- *   Contact: <jengelh@computergmbh.de>
  *
  * based on ...
  *
  * Kernel module to match connection tracking information.
  * GPL (C) 1999  Rusty Russell (rusty@rustcorp.com.au).
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/ip.h>
@@ -173,7 +173,7 @@ static int count_them(struct net *net,
 }
 
 static bool
-connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct net *net = dev_net(par->in ? par->in : par->out);
        const struct xt_connlimit_info *info = par->matchinfo;
@@ -206,44 +206,46 @@ connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 
        if (connections < 0) {
                /* kmalloc failed, drop it entirely */
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
        return (connections > info->limit) ^ info->inverse;
 
  hotdrop:
-       *par->hotdrop = true;
+       par->hotdrop = true;
        return false;
 }
 
-static bool connlimit_mt_check(const struct xt_mtchk_param *par)
+static int connlimit_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_connlimit_info *info = par->matchinfo;
        unsigned int i;
+       int ret;
 
        if (unlikely(!connlimit_rnd_inited)) {
                get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd));
                connlimit_rnd_inited = true;
        }
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "cannot load conntrack support for "
-                      "address family %u\n", par->family);
-               return false;
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0) {
+               pr_info("cannot load conntrack support for "
+                       "address family %u\n", par->family);
+               return ret;
        }
 
        /* init private data */
        info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL);
        if (info->data == NULL) {
                nf_ct_l3proto_module_put(par->family);
-               return false;
+               return -ENOMEM;
        }
 
        spin_lock_init(&info->data->lock);
        for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i)
                INIT_LIST_HEAD(&info->data->iphash[i]);
 
-       return true;
+       return 0;
 }
 
 static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
index 122aa8b0147b7360a65a90648603b45fd555d84e..7278145e6a68385c71b1d64efccc3aee71cb2412 100644 (file)
@@ -1,10 +1,10 @@
 /*
- *     xt_connmark - Netfilter module to match connection mark values
+ *     xt_connmark - Netfilter module to operate on connection marks
  *
  *     Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
  *     by Henrik Nordstrom <hno@marasystems.com>
  *     Copyright Â© CC Computer Consultants GmbH, 2007 - 2008
- *     Jan Engelhardt <jengelh@computergmbh.de>
+ *     Jan Engelhardt <jengelh@medozas.de>
  *
  * 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
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_connmark.h>
 
 MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
-MODULE_DESCRIPTION("Xtables: connection mark match");
+MODULE_DESCRIPTION("Xtables: connection mark operations");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_CONNMARK");
+MODULE_ALIAS("ip6t_CONNMARK");
 MODULE_ALIAS("ipt_connmark");
 MODULE_ALIAS("ip6t_connmark");
 
+static unsigned int
+connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       const struct xt_connmark_tginfo1 *info = par->targinfo;
+       enum ip_conntrack_info ctinfo;
+       struct nf_conn *ct;
+       u_int32_t newmark;
+
+       ct = nf_ct_get(skb, &ctinfo);
+       if (ct == NULL)
+               return XT_CONTINUE;
+
+       switch (info->mode) {
+       case XT_CONNMARK_SET:
+               newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
+               if (ct->mark != newmark) {
+                       ct->mark = newmark;
+                       nf_conntrack_event_cache(IPCT_MARK, ct);
+               }
+               break;
+       case XT_CONNMARK_SAVE:
+               newmark = (ct->mark & ~info->ctmask) ^
+                         (skb->mark & info->nfmask);
+               if (ct->mark != newmark) {
+                       ct->mark = newmark;
+                       nf_conntrack_event_cache(IPCT_MARK, ct);
+               }
+               break;
+       case XT_CONNMARK_RESTORE:
+               newmark = (skb->mark & ~info->nfmask) ^
+                         (ct->mark & info->ctmask);
+               skb->mark = newmark;
+               break;
+       }
+
+       return XT_CONTINUE;
+}
+
+static int connmark_tg_check(const struct xt_tgchk_param *par)
+{
+       int ret;
+
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
+}
+
+static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
+{
+       nf_ct_l3proto_module_put(par->family);
+}
+
 static bool
-connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+connmark_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_connmark_mtinfo1 *info = par->matchinfo;
        enum ip_conntrack_info ctinfo;
@@ -47,14 +104,15 @@ connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ((ct->mark & info->mask) == info->mark) ^ info->invert;
 }
 
-static bool connmark_mt_check(const struct xt_mtchk_param *par)
+static int connmark_mt_check(const struct xt_mtchk_param *par)
 {
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "cannot load conntrack support for "
-                      "proto=%u\n", par->family);
-               return false;
-       }
-       return true;
+       int ret;
+
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
 }
 
 static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
@@ -62,6 +120,17 @@ static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
        nf_ct_l3proto_module_put(par->family);
 }
 
+static struct xt_target connmark_tg_reg __read_mostly = {
+       .name           = "CONNMARK",
+       .revision       = 1,
+       .family         = NFPROTO_UNSPEC,
+       .checkentry     = connmark_tg_check,
+       .target         = connmark_tg,
+       .targetsize     = sizeof(struct xt_connmark_tginfo1),
+       .destroy        = connmark_tg_destroy,
+       .me             = THIS_MODULE,
+};
+
 static struct xt_match connmark_mt_reg __read_mostly = {
        .name           = "connmark",
        .revision       = 1,
@@ -75,12 +144,23 @@ static struct xt_match connmark_mt_reg __read_mostly = {
 
 static int __init connmark_mt_init(void)
 {
-       return xt_register_match(&connmark_mt_reg);
+       int ret;
+
+       ret = xt_register_target(&connmark_tg_reg);
+       if (ret < 0)
+               return ret;
+       ret = xt_register_match(&connmark_mt_reg);
+       if (ret < 0) {
+               xt_unregister_target(&connmark_tg_reg);
+               return ret;
+       }
+       return 0;
 }
 
 static void __exit connmark_mt_exit(void)
 {
        xt_unregister_match(&connmark_mt_reg);
+       xt_unregister_target(&connmark_tg_reg);
 }
 
 module_init(connmark_mt_init);
index ae66305f0fe5c088861fedb6c08d16af4c2438cd..39681f10291c13a8a72efbfebad857ca10a7d750 100644 (file)
@@ -9,7 +9,7 @@
  *     it under the terms of the GNU General Public License version 2 as
  *     published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <net/ipv6.h>
@@ -113,7 +113,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
 }
 
 static bool
-conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par,
+conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
              u16 state_mask, u16 status_mask)
 {
        const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
@@ -191,7 +191,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par,
 }
 
 static bool
-conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
+conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
 
@@ -199,21 +199,22 @@ conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
 }
 
 static bool
-conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par)
+conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
 
        return conntrack_mt(skb, par, info->state_mask, info->status_mask);
 }
 
-static bool conntrack_mt_check(const struct xt_mtchk_param *par)
+static int conntrack_mt_check(const struct xt_mtchk_param *par)
 {
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "can't load conntrack support for "
-                                   "proto=%u\n", par->family);
-               return false;
-       }
-       return true;
+       int ret;
+
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
 }
 
 static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
index 395af5943ffdef6c888bbe5e87fb225e60ec02cd..b63d2a3d80ba5f6a601b23a031f7a4889978dd01 100644 (file)
@@ -96,7 +96,7 @@ match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
 }
 
 static bool
-dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+dccp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_dccp_info *info = par->matchinfo;
        const struct dccp_hdr *dh;
@@ -107,7 +107,7 @@ dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 
        dh = skb_header_pointer(skb, par->thoff, sizeof(_dh), &_dh);
        if (dh == NULL) {
-               *par->hotdrop = true;
+               par->hotdrop = true;
                return false;
        }
 
@@ -120,17 +120,21 @@ dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                && DCCHECK(match_types(dh, info->typemask),
                           XT_DCCP_TYPE, info->flags, info->invflags)
                && DCCHECK(match_option(info->option, skb, par->thoff, dh,
-                                       par->hotdrop),
+                                       &par->hotdrop),
                           XT_DCCP_OPTION, info->flags, info->invflags);
 }
 
-static bool dccp_mt_check(const struct xt_mtchk_param *par)
+static int dccp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_dccp_info *info = par->matchinfo;
 
-       return !(info->flags & ~XT_DCCP_VALID_FLAGS)
-               && !(info->invflags & ~XT_DCCP_VALID_FLAGS)
-               && !(info->invflags & ~info->flags);
+       if (info->flags & ~XT_DCCP_VALID_FLAGS)
+               return -EINVAL;
+       if (info->invflags & ~XT_DCCP_VALID_FLAGS)
+               return -EINVAL;
+       if (info->invflags & ~info->flags)
+               return -EINVAL;
+       return 0;
 }
 
 static struct xt_match dccp_mt_reg[] __read_mostly = {
index 0280d3a8c16172bc924f53b233c4527fe6b1e7b0..64670fc5d0e1a581f4e3b3885d8117c7a70b0edb 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -25,7 +25,7 @@ MODULE_ALIAS("ipt_tos");
 MODULE_ALIAS("ip6t_tos");
 
 static bool
-dscp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+dscp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_dscp_info *info = par->matchinfo;
        u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
@@ -34,7 +34,7 @@ dscp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 }
 
 static bool
-dscp_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+dscp_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_dscp_info *info = par->matchinfo;
        u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
@@ -42,23 +42,23 @@ dscp_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        return (dscp == info->dscp) ^ !!info->invert;
 }
 
-static bool dscp_mt_check(const struct xt_mtchk_param *par)
+static int dscp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_dscp_info *info = par->matchinfo;
 
        if (info->dscp > XT_DSCP_MAX) {
-               printk(KERN_ERR "xt_dscp: dscp %x out of range\n", info->dscp);
-               return false;
+               pr_info("dscp %x out of range\n", info->dscp);
+               return -EDOM;
        }
 
-       return true;
+       return 0;
 }
 
-static bool tos_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool tos_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_tos_match_info *info = par->matchinfo;
 
-       if (par->match->family == NFPROTO_IPV4)
+       if (par->family == NFPROTO_IPV4)
                return ((ip_hdr(skb)->tos & info->tos_mask) ==
                       info->tos_value) ^ !!info->invert;
        else
index 609439967c2c67579d299e9e43218a7c362da8a8..171ba82b5902095202d72705fd0ec00906e241b8 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/in.h>
@@ -24,25 +24,19 @@ MODULE_DESCRIPTION("Xtables: IPsec-ESP packet match");
 MODULE_ALIAS("ipt_esp");
 MODULE_ALIAS("ip6t_esp");
 
-#if 0
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline bool
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
 {
        bool r;
-       duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
-                min, spi, max);
+       pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n",
+                invert ? '!' : ' ', min, spi, max);
        r = (spi >= min && spi <= max) ^ invert;
-       duprintf(" result %s\n", r ? "PASS" : "FAILED");
+       pr_debug(" result %s\n", r ? "PASS" : "FAILED");
        return r;
 }
 
-static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool esp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ip_esp_hdr *eh;
        struct ip_esp_hdr _esp;
@@ -57,8 +51,8 @@ static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                /* We've been asked to examine this packet, and we
                 * can't.  Hence, no choice but to drop.
                 */
-               duprintf("Dropping evil ESP tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil ESP tinygram.\n");
+               par->hotdrop = true;
                return false;
        }
 
@@ -66,16 +60,16 @@ static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                         !!(espinfo->invflags & XT_ESP_INV_SPI));
 }
 
-static bool esp_mt_check(const struct xt_mtchk_param *par)
+static int esp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_esp *espinfo = par->matchinfo;
 
        if (espinfo->invflags & ~XT_ESP_INV_MASK) {
-               duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
-               return false;
+               pr_debug("unknown flags %X\n", espinfo->invflags);
+               return -EINVAL;
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match esp_mt_reg[] __read_mostly = {
index 215a64835de82748af7db9682ba69aa3104fde39..b46a8390896d012dc4524e220a14d817d378dfd7 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Development of this code was funded by Astaro AG, http://www.astaro.com/
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/random.h>
@@ -36,7 +37,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match");
 MODULE_ALIAS("ipt_hashlimit");
 MODULE_ALIAS("ip6t_hashlimit");
@@ -80,12 +81,14 @@ struct dsthash_ent {
        struct dsthash_dst dst;
 
        /* modified structure members in the end */
+       spinlock_t lock;
        unsigned long expires;          /* precalculated expiry time */
        struct {
                unsigned long prev;     /* last modification */
                u_int32_t credit;
                u_int32_t credit_cap, cost;
        } rateinfo;
+       struct rcu_head rcu;
 };
 
 struct xt_hashlimit_htable {
@@ -142,9 +145,11 @@ dsthash_find(const struct xt_hashlimit_htable *ht,
        u_int32_t hash = hash_dst(ht, dst);
 
        if (!hlist_empty(&ht->hash[hash])) {
-               hlist_for_each_entry(ent, pos, &ht->hash[hash], node)
-                       if (dst_cmp(ent, dst))
+               hlist_for_each_entry_rcu(ent, pos, &ht->hash[hash], node)
+                       if (dst_cmp(ent, dst)) {
+                               spin_lock(&ent->lock);
                                return ent;
+                       }
        }
        return NULL;
 }
@@ -156,9 +161,10 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht,
 {
        struct dsthash_ent *ent;
 
+       spin_lock(&ht->lock);
        /* initialize hash with random val at the time we allocate
         * the first hashtable entry */
-       if (!ht->rnd_initialized) {
+       if (unlikely(!ht->rnd_initialized)) {
                get_random_bytes(&ht->rnd, sizeof(ht->rnd));
                ht->rnd_initialized = true;
        }
@@ -166,106 +172,40 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht,
        if (ht->cfg.max && ht->count >= ht->cfg.max) {
                /* FIXME: do something. question is what.. */
                if (net_ratelimit())
-                       printk(KERN_WARNING
-                               "xt_hashlimit: max count of %u reached\n",
-                               ht->cfg.max);
-               return NULL;
-       }
-
-       ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC);
+                       pr_err("max count of %u reached\n", ht->cfg.max);
+               ent = NULL;
+       } else
+               ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC);
        if (!ent) {
                if (net_ratelimit())
-                       printk(KERN_ERR
-                               "xt_hashlimit: can't allocate dsthash_ent\n");
-               return NULL;
-       }
-       memcpy(&ent->dst, dst, sizeof(ent->dst));
+                       pr_err("cannot allocate dsthash_ent\n");
+       } else {
+               memcpy(&ent->dst, dst, sizeof(ent->dst));
+               spin_lock_init(&ent->lock);
 
-       hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]);
-       ht->count++;
+               spin_lock(&ent->lock);
+               hlist_add_head_rcu(&ent->node, &ht->hash[hash_dst(ht, dst)]);
+               ht->count++;
+       }
+       spin_unlock(&ht->lock);
        return ent;
 }
 
-static inline void
-dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
+static void dsthash_free_rcu(struct rcu_head *head)
 {
-       hlist_del(&ent->node);
+       struct dsthash_ent *ent = container_of(head, struct dsthash_ent, rcu);
+
        kmem_cache_free(hashlimit_cachep, ent);
-       ht->count--;
 }
-static void htable_gc(unsigned long htlong);
 
-static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_int8_t family)
+static inline void
+dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent)
 {
-       struct hashlimit_net *hashlimit_net = hashlimit_pernet(net);
-       struct xt_hashlimit_htable *hinfo;
-       unsigned int size;
-       unsigned int i;
-
-       if (minfo->cfg.size)
-               size = minfo->cfg.size;
-       else {
-               size = ((totalram_pages << PAGE_SHIFT) / 16384) /
-                      sizeof(struct list_head);
-               if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE))
-                       size = 8192;
-               if (size < 16)
-                       size = 16;
-       }
-       /* FIXME: don't use vmalloc() here or anywhere else -HW */
-       hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
-                       sizeof(struct list_head) * size);
-       if (!hinfo) {
-               printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n");
-               return -1;
-       }
-       minfo->hinfo = hinfo;
-
-       /* copy match config into hashtable config */
-       hinfo->cfg.mode        = minfo->cfg.mode;
-       hinfo->cfg.avg         = minfo->cfg.avg;
-       hinfo->cfg.burst       = minfo->cfg.burst;
-       hinfo->cfg.max         = minfo->cfg.max;
-       hinfo->cfg.gc_interval = minfo->cfg.gc_interval;
-       hinfo->cfg.expire      = minfo->cfg.expire;
-
-       if (family == NFPROTO_IPV4)
-               hinfo->cfg.srcmask = hinfo->cfg.dstmask = 32;
-       else
-               hinfo->cfg.srcmask = hinfo->cfg.dstmask = 128;
-
-       hinfo->cfg.size = size;
-       if (!hinfo->cfg.max)
-               hinfo->cfg.max = 8 * hinfo->cfg.size;
-       else if (hinfo->cfg.max < hinfo->cfg.size)
-               hinfo->cfg.max = hinfo->cfg.size;
-
-       for (i = 0; i < hinfo->cfg.size; i++)
-               INIT_HLIST_HEAD(&hinfo->hash[i]);
-
-       hinfo->use = 1;
-       hinfo->count = 0;
-       hinfo->family = family;
-       hinfo->rnd_initialized = false;
-       spin_lock_init(&hinfo->lock);
-       hinfo->pde = proc_create_data(minfo->name, 0,
-               (family == NFPROTO_IPV4) ?
-               hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit,
-               &dl_file_ops, hinfo);
-       if (!hinfo->pde) {
-               vfree(hinfo);
-               return -1;
-       }
-       hinfo->net = net;
-
-       setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo);
-       hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
-       add_timer(&hinfo->timer);
-
-       hlist_add_head(&hinfo->node, &hashlimit_net->htables);
-
-       return 0;
+       hlist_del_rcu(&ent->node);
+       call_rcu_bh(&ent->rcu, dsthash_free_rcu);
+       ht->count--;
 }
+static void htable_gc(unsigned long htlong);
 
 static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
                         u_int8_t family)
@@ -288,10 +228,8 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
        /* FIXME: don't use vmalloc() here or anywhere else -HW */
        hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) +
                        sizeof(struct list_head) * size);
-       if (hinfo == NULL) {
-               printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n");
-               return -1;
-       }
+       if (hinfo == NULL)
+               return -ENOMEM;
        minfo->hinfo = hinfo;
 
        /* copy match config into hashtable config */
@@ -317,7 +255,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo,
                &dl_file_ops, hinfo);
        if (hinfo->pde == NULL) {
                vfree(hinfo);
-               return -1;
+               return -ENOMEM;
        }
        hinfo->net = net;
 
@@ -578,58 +516,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 }
 
 static bool
-hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
-{
-       const struct xt_hashlimit_info *r = par->matchinfo;
-       struct xt_hashlimit_htable *hinfo = r->hinfo;
-       unsigned long now = jiffies;
-       struct dsthash_ent *dh;
-       struct dsthash_dst dst;
-
-       if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
-               goto hotdrop;
-
-       spin_lock_bh(&hinfo->lock);
-       dh = dsthash_find(hinfo, &dst);
-       if (!dh) {
-               dh = dsthash_alloc_init(hinfo, &dst);
-               if (!dh) {
-                       spin_unlock_bh(&hinfo->lock);
-                       goto hotdrop;
-               }
-
-               dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
-               dh->rateinfo.prev = jiffies;
-               dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
-                                                  hinfo->cfg.burst);
-               dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
-                                                      hinfo->cfg.burst);
-               dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
-       } else {
-               /* update expiration timeout */
-               dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
-               rateinfo_recalc(dh, now);
-       }
-
-       if (dh->rateinfo.credit >= dh->rateinfo.cost) {
-               /* We're underlimit. */
-               dh->rateinfo.credit -= dh->rateinfo.cost;
-               spin_unlock_bh(&hinfo->lock);
-               return true;
-       }
-
-       spin_unlock_bh(&hinfo->lock);
-
-       /* default case: we're overlimit, thus don't match */
-       return false;
-
-hotdrop:
-       *par->hotdrop = true;
-       return false;
-}
-
-static bool
-hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
        struct xt_hashlimit_htable *hinfo = info->hinfo;
@@ -640,15 +527,14 @@ hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0)
                goto hotdrop;
 
-       spin_lock_bh(&hinfo->lock);
+       rcu_read_lock_bh();
        dh = dsthash_find(hinfo, &dst);
        if (dh == NULL) {
                dh = dsthash_alloc_init(hinfo, &dst);
                if (dh == NULL) {
-                       spin_unlock_bh(&hinfo->lock);
+                       rcu_read_unlock_bh();
                        goto hotdrop;
                }
-
                dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
                dh->rateinfo.prev = jiffies;
                dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
@@ -665,96 +551,58 @@ hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        if (dh->rateinfo.credit >= dh->rateinfo.cost) {
                /* below the limit */
                dh->rateinfo.credit -= dh->rateinfo.cost;
-               spin_unlock_bh(&hinfo->lock);
+               spin_unlock(&dh->lock);
+               rcu_read_unlock_bh();
                return !(info->cfg.mode & XT_HASHLIMIT_INVERT);
        }
 
-       spin_unlock_bh(&hinfo->lock);
+       spin_unlock(&dh->lock);
+       rcu_read_unlock_bh();
        /* default match is underlimit - so over the limit, we need to invert */
        return info->cfg.mode & XT_HASHLIMIT_INVERT;
 
  hotdrop:
-       *par->hotdrop = true;
+       par->hotdrop = true;
        return false;
 }
 
-static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
-{
-       struct net *net = par->net;
-       struct xt_hashlimit_info *r = par->matchinfo;
-
-       /* Check for overflow. */
-       if (r->cfg.burst == 0 ||
-           user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) {
-               printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",
-                      r->cfg.avg, r->cfg.burst);
-               return false;
-       }
-       if (r->cfg.mode == 0 ||
-           r->cfg.mode > (XT_HASHLIMIT_HASH_DPT |
-                          XT_HASHLIMIT_HASH_DIP |
-                          XT_HASHLIMIT_HASH_SIP |
-                          XT_HASHLIMIT_HASH_SPT))
-               return false;
-       if (!r->cfg.gc_interval)
-               return false;
-       if (!r->cfg.expire)
-               return false;
-       if (r->name[sizeof(r->name) - 1] != '\0')
-               return false;
-
-       mutex_lock(&hashlimit_mutex);
-       r->hinfo = htable_find_get(net, r->name, par->match->family);
-       if (!r->hinfo && htable_create_v0(net, r, par->match->family) != 0) {
-               mutex_unlock(&hashlimit_mutex);
-               return false;
-       }
-       mutex_unlock(&hashlimit_mutex);
-
-       return true;
-}
-
-static bool hashlimit_mt_check(const struct xt_mtchk_param *par)
+static int hashlimit_mt_check(const struct xt_mtchk_param *par)
 {
        struct net *net = par->net;
        struct xt_hashlimit_mtinfo1 *info = par->matchinfo;
+       int ret;
 
        /* Check for overflow. */
        if (info->cfg.burst == 0 ||
            user2credits(info->cfg.avg * info->cfg.burst) <
            user2credits(info->cfg.avg)) {
-               printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",
-                      info->cfg.avg, info->cfg.burst);
-               return false;
+               pr_info("overflow, try lower: %u/%u\n",
+                       info->cfg.avg, info->cfg.burst);
+               return -ERANGE;
        }
        if (info->cfg.gc_interval == 0 || info->cfg.expire == 0)
-               return false;
+               return -EINVAL;
        if (info->name[sizeof(info->name)-1] != '\0')
-               return false;
-       if (par->match->family == NFPROTO_IPV4) {
+               return -EINVAL;
+       if (par->family == NFPROTO_IPV4) {
                if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32)
-                       return false;
+                       return -EINVAL;
        } else {
                if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128)
-                       return false;
+                       return -EINVAL;
        }
 
        mutex_lock(&hashlimit_mutex);
-       info->hinfo = htable_find_get(net, info->name, par->match->family);
-       if (!info->hinfo && htable_create(net, info, par->match->family) != 0) {
-               mutex_unlock(&hashlimit_mutex);
-               return false;
+       info->hinfo = htable_find_get(net, info->name, par->family);
+       if (info->hinfo == NULL) {
+               ret = htable_create(net, info, par->family);
+               if (ret < 0) {
+                       mutex_unlock(&hashlimit_mutex);
+                       return ret;
+               }
        }
        mutex_unlock(&hashlimit_mutex);
-       return true;
-}
-
-static void
-hashlimit_mt_destroy_v0(const struct xt_mtdtor_param *par)
-{
-       const struct xt_hashlimit_info *r = par->matchinfo;
-
-       htable_put(r->hinfo);
+       return 0;
 }
 
 static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par)
@@ -764,46 +612,7 @@ static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par)
        htable_put(info->hinfo);
 }
 
-#ifdef CONFIG_COMPAT
-struct compat_xt_hashlimit_info {
-       char name[IFNAMSIZ];
-       struct hashlimit_cfg cfg;
-       compat_uptr_t hinfo;
-       compat_uptr_t master;
-};
-
-static void hashlimit_mt_compat_from_user(void *dst, const void *src)
-{
-       int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
-
-       memcpy(dst, src, off);
-       memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off);
-}
-
-static int hashlimit_mt_compat_to_user(void __user *dst, const void *src)
-{
-       int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
-
-       return copy_to_user(dst, src, off) ? -EFAULT : 0;
-}
-#endif
-
 static struct xt_match hashlimit_mt_reg[] __read_mostly = {
-       {
-               .name           = "hashlimit",
-               .revision       = 0,
-               .family         = NFPROTO_IPV4,
-               .match          = hashlimit_mt_v0,
-               .matchsize      = sizeof(struct xt_hashlimit_info),
-#ifdef CONFIG_COMPAT
-               .compatsize     = sizeof(struct compat_xt_hashlimit_info),
-               .compat_from_user = hashlimit_mt_compat_from_user,
-               .compat_to_user = hashlimit_mt_compat_to_user,
-#endif
-               .checkentry     = hashlimit_mt_check_v0,
-               .destroy        = hashlimit_mt_destroy_v0,
-               .me             = THIS_MODULE
-       },
        {
                .name           = "hashlimit",
                .revision       = 1,
@@ -815,20 +624,6 @@ static struct xt_match hashlimit_mt_reg[] __read_mostly = {
                .me             = THIS_MODULE,
        },
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-       {
-               .name           = "hashlimit",
-               .family         = NFPROTO_IPV6,
-               .match          = hashlimit_mt_v0,
-               .matchsize      = sizeof(struct xt_hashlimit_info),
-#ifdef CONFIG_COMPAT
-               .compatsize     = sizeof(struct compat_xt_hashlimit_info),
-               .compat_from_user = hashlimit_mt_compat_from_user,
-               .compat_to_user = hashlimit_mt_compat_to_user,
-#endif
-               .checkentry     = hashlimit_mt_check_v0,
-               .destroy        = hashlimit_mt_destroy_v0,
-               .me             = THIS_MODULE
-       },
        {
                .name           = "hashlimit",
                .revision       = 1,
@@ -888,12 +683,15 @@ static void dl_seq_stop(struct seq_file *s, void *v)
 static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
                                   struct seq_file *s)
 {
+       int res;
+
+       spin_lock(&ent->lock);
        /* recalculate to show accurate numbers */
        rateinfo_recalc(ent, jiffies);
 
        switch (family) {
        case NFPROTO_IPV4:
-               return seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n",
+               res = seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n",
                                 (long)(ent->expires - jiffies)/HZ,
                                 &ent->dst.ip.src,
                                 ntohs(ent->dst.src_port),
@@ -901,9 +699,10 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
                                 ntohs(ent->dst.dst_port),
                                 ent->rateinfo.credit, ent->rateinfo.credit_cap,
                                 ent->rateinfo.cost);
+               break;
 #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
        case NFPROTO_IPV6:
-               return seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n",
+               res = seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n",
                                 (long)(ent->expires - jiffies)/HZ,
                                 &ent->dst.ip6.src,
                                 ntohs(ent->dst.src_port),
@@ -911,11 +710,14 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
                                 ntohs(ent->dst.dst_port),
                                 ent->rateinfo.credit, ent->rateinfo.credit_cap,
                                 ent->rateinfo.cost);
+               break;
 #endif
        default:
                BUG();
-               return 0;
+               res = 0;
        }
+       spin_unlock(&ent->lock);
+       return res;
 }
 
 static int dl_seq_show(struct seq_file *s, void *v)
@@ -1024,7 +826,7 @@ static int __init hashlimit_mt_init(void)
                                            sizeof(struct dsthash_ent), 0, 0,
                                            NULL);
        if (!hashlimit_cachep) {
-               printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n");
+               pr_warning("unable to create slab cache\n");
                goto err2;
        }
        return 0;
@@ -1039,9 +841,11 @@ err1:
 
 static void __exit hashlimit_mt_exit(void)
 {
-       kmem_cache_destroy(hashlimit_cachep);
        xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
        unregister_pernet_subsys(&hashlimit_net_ops);
+
+       rcu_barrier_bh();
+       kmem_cache_destroy(hashlimit_cachep);
 }
 
 module_init(hashlimit_mt_init);
index 64fc7f277221b67c9e77ac0dd2addc2004192863..9f4ab00c80500635e8015b2384d25dea98641c56 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
@@ -24,7 +24,7 @@ MODULE_ALIAS("ip6t_helper");
 
 
 static bool
-helper_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+helper_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_helper_info *info = par->matchinfo;
        const struct nf_conn *ct;
@@ -54,17 +54,19 @@ helper_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ret;
 }
 
-static bool helper_mt_check(const struct xt_mtchk_param *par)
+static int helper_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_helper_info *info = par->matchinfo;
+       int ret;
 
-       if (nf_ct_l3proto_try_module_get(par->family) < 0) {
-               printk(KERN_WARNING "can't load conntrack support for "
-                                   "proto=%u\n", par->family);
-               return false;
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0) {
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+               return ret;
        }
        info->name[29] = '\0';
-       return true;
+       return 0;
 }
 
 static void helper_mt_destroy(const struct xt_mtdtor_param *par)
index 7726154c87b25c919a1ff5a870d5659649c6bcf6..7d12221ead8966136fc84b5a8ddce158a212258b 100644 (file)
@@ -25,7 +25,7 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_ttl");
 MODULE_ALIAS("ip6t_hl");
 
-static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool ttl_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ipt_ttl_info *info = par->matchinfo;
        const u8 ttl = ip_hdr(skb)->ttl;
@@ -39,16 +39,12 @@ static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                        return ttl < info->ttl;
                case IPT_TTL_GT:
                        return ttl > info->ttl;
-               default:
-                       printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
-                               info->mode);
-                       return false;
        }
 
        return false;
 }
 
-static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool hl_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct ip6t_hl_info *info = par->matchinfo;
        const struct ipv6hdr *ip6h = ipv6_hdr(skb);
@@ -56,20 +52,12 @@ static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
        switch (info->mode) {
                case IP6T_HL_EQ:
                        return ip6h->hop_limit == info->hop_limit;
-                       break;
                case IP6T_HL_NE:
                        return ip6h->hop_limit != info->hop_limit;
-                       break;
                case IP6T_HL_LT:
                        return ip6h->hop_limit < info->hop_limit;
-                       break;
                case IP6T_HL_GT:
                        return ip6h->hop_limit > info->hop_limit;
-                       break;
-               default:
-                       printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
-                               info->mode);
-                       return false;
        }
 
        return false;
index ffc96387d5565fa43286739d82902a37e7a9aa83..88f7c3511c72c2554de292e97c844cc934367c9e 100644 (file)
@@ -8,6 +8,7 @@
  *     it under the terms of the GNU General Public License version 2 as
  *     published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
@@ -16,7 +17,7 @@
 #include <linux/netfilter/xt_iprange.h>
 
 static bool
-iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par)
+iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_iprange_mtinfo *info = par->matchinfo;
        const struct iphdr *iph = ip_hdr(skb);
@@ -67,7 +68,7 @@ iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b)
 }
 
 static bool
-iprange_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_iprange_mtinfo *info = par->matchinfo;
        const struct ipv6hdr *iph = ipv6_hdr(skb);
index c4871ca6c86da8874545fe9b517b33511ee80450..176e5570a9991727c8613de3bd8fe3341a852501 100644 (file)
@@ -21,7 +21,7 @@ MODULE_ALIAS("ipt_length");
 MODULE_ALIAS("ip6t_length");
 
 static bool
-length_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+length_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_length_info *info = par->matchinfo;
        u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len);
@@ -30,7 +30,7 @@ length_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 }
 
 static bool
-length_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
+length_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_length_info *info = par->matchinfo;
        const u_int16_t pktlen = ntohs(ipv6_hdr(skb)->payload_len) +
index e5d7e1ffb1a46be8b7a0a21897f4da1a3e1df6cd..32b7a579a032cde09c831f47c5ee8eae83adbd41 100644 (file)
@@ -5,6 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -64,7 +65,7 @@ static DEFINE_SPINLOCK(limit_lock);
 #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
 
 static bool
-limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_rateinfo *r = par->matchinfo;
        struct xt_limit_priv *priv = r->master;
@@ -98,7 +99,7 @@ user2credits(u_int32_t user)
        return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
 }
 
-static bool limit_mt_check(const struct xt_mtchk_param *par)
+static int limit_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_rateinfo *r = par->matchinfo;
        struct xt_limit_priv *priv;
@@ -106,14 +107,14 @@ static bool limit_mt_check(const struct xt_mtchk_param *par)
        /* Check for overflow. */
        if (r->burst == 0
            || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-               printk("Overflow in xt_limit, try lower: %u/%u\n",
-                      r->avg, r->burst);
-               return false;
+               pr_info("Overflow, try lower: %u/%u\n",
+                       r->avg, r->burst);
+               return -ERANGE;
        }
 
        priv = kmalloc(sizeof(*priv), GFP_KERNEL);
        if (priv == NULL)
-               return false;
+               return -ENOMEM;
 
        /* For SMP, we only want to use one set of state. */
        r->master = priv;
@@ -125,7 +126,7 @@ static bool limit_mt_check(const struct xt_mtchk_param *par)
                r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
                r->cost = user2credits(r->avg);
        }
-       return true;
+       return 0;
 }
 
 static void limit_mt_destroy(const struct xt_mtdtor_param *par)
index c2007116ce5bb66db44ae43590e8ba94330d03ea..8160f6b1435d699371af378f3a5c90c2530161b5 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
+#include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/etherdevice.h>
 
@@ -24,16 +25,20 @@ MODULE_DESCRIPTION("Xtables: MAC address match");
 MODULE_ALIAS("ipt_mac");
 MODULE_ALIAS("ip6t_mac");
 
-static bool mac_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
-    const struct xt_mac_info *info = par->matchinfo;
-
-    /* Is mac pointer valid? */
-    return skb_mac_header(skb) >= skb->head &&
-          skb_mac_header(skb) + ETH_HLEN <= skb->data
-          /* If so, compare... */
-          && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
-               ^ info->invert);
+       const struct xt_mac_info *info = par->matchinfo;
+       bool ret;
+
+       if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER)
+               return false;
+       if (skb_mac_header(skb) < skb->head)
+               return false;
+       if (skb_mac_header(skb) + ETH_HLEN > skb->data)
+               return false;
+       ret  = compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr) == 0;
+       ret ^= info->invert;
+       return ret;
 }
 
 static struct xt_match mac_mt_reg __read_mostly = {
index 1db07d8125f81c71c13bf0bb587c6ca4f6e82854..23345238711b515805a63687b774cdb4b6d788f4 100644 (file)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
-MODULE_DESCRIPTION("Xtables: packet mark match");
+MODULE_DESCRIPTION("Xtables: packet mark operations");
 MODULE_ALIAS("ipt_mark");
 MODULE_ALIAS("ip6t_mark");
+MODULE_ALIAS("ipt_MARK");
+MODULE_ALIAS("ip6t_MARK");
+
+static unsigned int
+mark_tg(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       const struct xt_mark_tginfo2 *info = par->targinfo;
+
+       skb->mark = (skb->mark & ~info->mask) ^ info->mark;
+       return XT_CONTINUE;
+}
 
 static bool
-mark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+mark_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_mark_mtinfo1 *info = par->matchinfo;
 
        return ((skb->mark & info->mask) == info->mark) ^ info->invert;
 }
 
+static struct xt_target mark_tg_reg __read_mostly = {
+       .name           = "MARK",
+       .revision       = 2,
+       .family         = NFPROTO_UNSPEC,
+       .target         = mark_tg,
+       .targetsize     = sizeof(struct xt_mark_tginfo2),
+       .me             = THIS_MODULE,
+};
+
 static struct xt_match mark_mt_reg __read_mostly = {
        .name           = "mark",
        .revision       = 1,
@@ -41,12 +61,23 @@ static struct xt_match mark_mt_reg __read_mostly = {
 
 static int __init mark_mt_init(void)
 {
-       return xt_register_match(&mark_mt_reg);
+       int ret;
+
+       ret = xt_register_target(&mark_tg_reg);
+       if (ret < 0)
+               return ret;
+       ret = xt_register_match(&mark_mt_reg);
+       if (ret < 0) {
+               xt_unregister_target(&mark_tg_reg);
+               return ret;
+       }
+       return 0;
 }
 
 static void __exit mark_mt_exit(void)
 {
        xt_unregister_match(&mark_mt_reg);
+       xt_unregister_target(&mark_tg_reg);
 }
 
 module_init(mark_mt_init);
index d06bb2dd39002171c5aa8f99f8500cd1f15b7eca..ac1d3c3d09e72dbbfbf49f4dcdad6fc7600dcded 100644 (file)
@@ -8,7 +8,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/udp.h>
@@ -26,29 +26,6 @@ MODULE_DESCRIPTION("Xtables: multiple port matching for TCP, UDP, UDP-Lite, SCTP
 MODULE_ALIAS("ipt_multiport");
 MODULE_ALIAS("ip6t_multiport");
 
-#if 0
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
-/* Returns 1 if the port is matched by the test, 0 otherwise. */
-static inline bool
-ports_match_v0(const u_int16_t *portlist, enum xt_multiport_flags flags,
-              u_int8_t count, u_int16_t src, u_int16_t dst)
-{
-       unsigned int i;
-       for (i = 0; i < count; i++) {
-               if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
-                       return true;
-
-               if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
-                       return true;
-       }
-
-       return false;
-}
-
 /* Returns 1 if the port is matched by the test, 0 otherwise. */
 static inline bool
 ports_match_v1(const struct xt_multiport_v1 *minfo,
@@ -63,7 +40,7 @@ ports_match_v1(const struct xt_multiport_v1 *minfo,
                if (minfo->pflags[i]) {
                        /* range port matching */
                        e = minfo->ports[++i];
-                       duprintf("src or dst matches with %d-%d?\n", s, e);
+                       pr_debug("src or dst matches with %d-%d?\n", s, e);
 
                        if (minfo->flags == XT_MULTIPORT_SOURCE
                            && src >= s && src <= e)
@@ -77,7 +54,7 @@ ports_match_v1(const struct xt_multiport_v1 *minfo,
                                return true ^ minfo->invert;
                } else {
                        /* exact port matching */
-                       duprintf("src or dst matches with %d?\n", s);
+                       pr_debug("src or dst matches with %d?\n", s);
 
                        if (minfo->flags == XT_MULTIPORT_SOURCE
                            && src == s)
@@ -95,31 +72,7 @@ ports_match_v1(const struct xt_multiport_v1 *minfo,
 }
 
 static bool
-multiport_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
-{
-       const __be16 *pptr;
-       __be16 _ports[2];
-       const struct xt_multiport *multiinfo = par->matchinfo;
-
-       if (par->fragoff != 0)
-               return false;
-
-       pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports);
-       if (pptr == NULL) {
-               /* We've been asked to examine this packet, and we
-                * can't.  Hence, no choice but to drop.
-                */
-               duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
-               *par->hotdrop = true;
-               return false;
-       }
-
-       return ports_match_v0(multiinfo->ports, multiinfo->flags,
-              multiinfo->count, ntohs(pptr[0]), ntohs(pptr[1]));
-}
-
-static bool
-multiport_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+multiport_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const __be16 *pptr;
        __be16 _ports[2];
@@ -133,8 +86,8 @@ multiport_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                /* We've been asked to examine this packet, and we
                 * can't.  Hence, no choice but to drop.
                 */
-               duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil offset=0 tinygram.\n");
+               par->hotdrop = true;
                return false;
        }
 
@@ -158,52 +111,25 @@ check(u_int16_t proto,
                && count <= XT_MULTI_PORTS;
 }
 
-static bool multiport_mt_check_v0(const struct xt_mtchk_param *par)
-{
-       const struct ipt_ip *ip = par->entryinfo;
-       const struct xt_multiport *multiinfo = par->matchinfo;
-
-       return check(ip->proto, ip->invflags, multiinfo->flags,
-                    multiinfo->count);
-}
-
-static bool multiport_mt_check(const struct xt_mtchk_param *par)
+static int multiport_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ipt_ip *ip = par->entryinfo;
        const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 
        return check(ip->proto, ip->invflags, multiinfo->flags,
-                    multiinfo->count);
+                    multiinfo->count) ? 0 : -EINVAL;
 }
 
-static bool multiport_mt6_check_v0(const struct xt_mtchk_param *par)
-{
-       const struct ip6t_ip6 *ip = par->entryinfo;
-       const struct xt_multiport *multiinfo = par->matchinfo;
-
-       return check(ip->proto, ip->invflags, multiinfo->flags,
-                    multiinfo->count);
-}
-
-static bool multiport_mt6_check(const struct xt_mtchk_param *par)
+static int multiport_mt6_check(const struct xt_mtchk_param *par)
 {
        const struct ip6t_ip6 *ip = par->entryinfo;
        const struct xt_multiport_v1 *multiinfo = par->matchinfo;
 
        return check(ip->proto, ip->invflags, multiinfo->flags,
-                    multiinfo->count);
+                    multiinfo->count) ? 0 : -EINVAL;
 }
 
 static struct xt_match multiport_mt_reg[] __read_mostly = {
-       {
-               .name           = "multiport",
-               .family         = NFPROTO_IPV4,
-               .revision       = 0,
-               .checkentry     = multiport_mt_check_v0,
-               .match          = multiport_mt_v0,
-               .matchsize      = sizeof(struct xt_multiport),
-               .me             = THIS_MODULE,
-       },
        {
                .name           = "multiport",
                .family         = NFPROTO_IPV4,
@@ -213,15 +139,6 @@ static struct xt_match multiport_mt_reg[] __read_mostly = {
                .matchsize      = sizeof(struct xt_multiport_v1),
                .me             = THIS_MODULE,
        },
-       {
-               .name           = "multiport",
-               .family         = NFPROTO_IPV6,
-               .revision       = 0,
-               .checkentry     = multiport_mt6_check_v0,
-               .match          = multiport_mt_v0,
-               .matchsize      = sizeof(struct xt_multiport),
-               .me             = THIS_MODULE,
-       },
        {
                .name           = "multiport",
                .family         = NFPROTO_IPV6,
index 4169e200588dc6c0dbc112826d2a4484cfd22065..4327e101c047ff1f9c1469a1cfa1dc544dbda5b8 100644 (file)
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/kernel.h>
 
@@ -193,8 +193,8 @@ static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info
        return ip->ttl == f_ttl;
 }
 
-static bool xt_osf_match_packet(const struct sk_buff *skb,
-               const struct xt_match_param *p)
+static bool
+xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p)
 {
        const struct xt_osf_info *info = p->matchinfo;
        const struct iphdr *ip = ip_hdr(skb);
@@ -382,14 +382,14 @@ static int __init xt_osf_init(void)
 
        err = nfnetlink_subsys_register(&xt_osf_nfnetlink);
        if (err < 0) {
-               printk(KERN_ERR "Failed (%d) to register OSF nsfnetlink helper.\n", err);
+               pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err);
                goto err_out_exit;
        }
 
        err = xt_register_match(&xt_osf_match);
        if (err) {
-               printk(KERN_ERR "Failed (%d) to register OS fingerprint "
-                               "matching module.\n", err);
+               pr_err("Failed to register OS fingerprint "
+                      "matching module (%d)\n", err);
                goto err_out_remove;
        }
 
index d24c76dffee298a01a11126fe0fad2bb54301712..772d7389b3376d623c9ab3a6ce71883619e356e1 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/netfilter/xt_owner.h>
 
 static bool
-owner_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_owner_match_info *info = par->matchinfo;
        const struct file *filp;
index 8d28ca5848bc6a57d6363023683d8c3d6daaddc3..d7ca16b8b8dfbcd8dec7c7ab67f9d6e5c3f957d9 100644 (file)
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter_bridge.h>
@@ -22,7 +22,7 @@ MODULE_ALIAS("ip6t_physdev");
 
 
 static bool
-physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+physdev_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
        const struct xt_physdev_info *info = par->matchinfo;
@@ -83,25 +83,25 @@ match_outdev:
        return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
 }
 
-static bool physdev_mt_check(const struct xt_mtchk_param *par)
+static int physdev_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_physdev_info *info = par->matchinfo;
 
        if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
            info->bitmask & ~XT_PHYSDEV_OP_MASK)
-               return false;
+               return -EINVAL;
        if (info->bitmask & XT_PHYSDEV_OP_OUT &&
            (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
             info->invert & XT_PHYSDEV_OP_BRIDGED) &&
            par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
            (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
-               printk(KERN_WARNING "physdev match: using --physdev-out in the "
-                      "OUTPUT, FORWARD and POSTROUTING chains for non-bridged "
-                      "traffic is not supported anymore.\n");
+               pr_info("using --physdev-out in the OUTPUT, FORWARD and "
+                       "POSTROUTING chains for non-bridged traffic is not "
+                       "supported anymore.\n");
                if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
-                       return false;
+                       return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match physdev_mt_reg __read_mostly = {
index 69da1d3a1d85974a66c13c060078aa205a610963..5b645cb598fc261d52d8b44c6acc63ac8d388dea 100644 (file)
@@ -23,7 +23,7 @@ MODULE_ALIAS("ipt_pkttype");
 MODULE_ALIAS("ip6t_pkttype");
 
 static bool
-pkttype_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+pkttype_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_pkttype_info *info = par->matchinfo;
        u_int8_t type;
index 4cbfebda8fa11795af6887e33761a374b50857ce..f23e97bb42d7c0f860cdf15258e530a11bb54bef 100644 (file)
@@ -6,7 +6,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
@@ -110,15 +110,15 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
 }
 
 static bool
-policy_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+policy_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_policy_info *info = par->matchinfo;
        int ret;
 
        if (info->flags & XT_POLICY_MATCH_IN)
-               ret = match_policy_in(skb, info, par->match->family);
+               ret = match_policy_in(skb, info, par->family);
        else
-               ret = match_policy_out(skb, info, par->match->family);
+               ret = match_policy_out(skb, info, par->family);
 
        if (ret < 0)
                ret = info->flags & XT_POLICY_MATCH_NONE ? true : false;
@@ -128,32 +128,29 @@ policy_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ret;
 }
 
-static bool policy_mt_check(const struct xt_mtchk_param *par)
+static int policy_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_policy_info *info = par->matchinfo;
 
        if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
-               printk(KERN_ERR "xt_policy: neither incoming nor "
-                               "outgoing policy selected\n");
-               return false;
+               pr_info("neither incoming nor outgoing policy selected\n");
+               return -EINVAL;
        }
        if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
            (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) {
-               printk(KERN_ERR "xt_policy: output policy not valid in "
-                               "PRE_ROUTING and INPUT\n");
-               return false;
+               pr_info("output policy not valid in PREROUTING and INPUT\n");
+               return -EINVAL;
        }
        if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
            (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) {
-               printk(KERN_ERR "xt_policy: input policy not valid in "
-                               "POST_ROUTING and OUTPUT\n");
-               return false;
+               pr_info("input policy not valid in POSTROUTING and OUTPUT\n");
+               return -EINVAL;
        }
        if (info->len > XT_POLICY_MAX_ELEM) {
-               printk(KERN_ERR "xt_policy: too many policy elements\n");
-               return false;
+               pr_info("too many policy elements\n");
+               return -EINVAL;
        }
-       return true;
+       return 0;
 }
 
 static struct xt_match policy_mt_reg[] __read_mostly = {
index 2d5562498c435007efec01d0bc8fd82fe074d63b..b4f7dfea59805f3c705859163bfcf57fcb6b4da8 100644 (file)
@@ -23,7 +23,7 @@ MODULE_ALIAS("ip6t_quota");
 static DEFINE_SPINLOCK(quota_lock);
 
 static bool
-quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct xt_quota_info *q = (void *)par->matchinfo;
        struct xt_quota_priv *priv = q->master;
@@ -44,19 +44,19 @@ quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ret;
 }
 
-static bool quota_mt_check(const struct xt_mtchk_param *par)
+static int quota_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_quota_info *q = par->matchinfo;
 
        if (q->flags & ~XT_QUOTA_MASK)
-               return false;
+               return -EINVAL;
 
        q->master = kmalloc(sizeof(*q->master), GFP_KERNEL);
        if (q->master == NULL)
-               return false;
+               return -ENOMEM;
 
        q->master->quota = q->quota;
-       return true;
+       return 0;
 }
 
 static void quota_mt_destroy(const struct xt_mtdtor_param *par)
index 4fc6a917f6de5b30d55de8dba82531be03e67826..76a083184d8e6991b0e49e4fb77db3e78d47488b 100644 (file)
@@ -15,7 +15,7 @@
 
 
 static bool
-xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_rateest_match_info *info = par->matchinfo;
        struct gnet_stats_rate_est *r;
@@ -74,10 +74,11 @@ xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ret;
 }
 
-static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
+static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
 {
        struct xt_rateest_match_info *info = par->matchinfo;
        struct xt_rateest *est1, *est2;
+       int ret = false;
 
        if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS |
                                     XT_RATEEST_MATCH_REL)) != 1)
@@ -95,6 +96,7 @@ static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
                goto err1;
        }
 
+       ret  = -ENOENT;
        est1 = xt_rateest_lookup(info->name1);
        if (!est1)
                goto err1;
@@ -109,12 +111,12 @@ static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
 
        info->est1 = est1;
        info->est2 = est2;
-       return true;
+       return 0;
 
 err2:
        xt_rateest_put(est1);
 err1:
-       return false;
+       return -EINVAL;
 }
 
 static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
index 484d1689bfde167d43474b3eeb35947b073e026c..459a7b256eb2592c31d6150be137e08ed3f18079 100644 (file)
@@ -22,7 +22,7 @@ MODULE_DESCRIPTION("Xtables: Routing realm match");
 MODULE_ALIAS("ipt_realm");
 
 static bool
-realm_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+realm_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_realm_info *info = par->matchinfo;
        const struct dst_entry *dst = skb_dst(skb);
index 834b736857cb2160b54951234b7f62609903f6fc..76aec6a44762df7de9a371ea61bab9925c933be8 100644 (file)
@@ -12,6 +12,7 @@
  * Author: Stephen Frost <sfrost@snowman.net>
  * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/init.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
@@ -35,8 +36,8 @@
 #include <linux/netfilter/xt_recent.h>
 
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
-MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching for IPv4");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
+MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_recent");
 MODULE_ALIAS("ip6t_recent");
@@ -51,14 +52,14 @@ module_param(ip_list_tot, uint, 0400);
 module_param(ip_pkt_list_tot, uint, 0400);
 module_param(ip_list_hash_size, uint, 0400);
 module_param(ip_list_perms, uint, 0400);
-module_param(ip_list_uid, uint, 0400);
-module_param(ip_list_gid, uint, 0400);
+module_param(ip_list_uid, uint, S_IRUGO | S_IWUSR);
+module_param(ip_list_gid, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
 MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)");
 MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
 MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files");
-MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/xt_recent/* files");
-MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/xt_recent/* files");
+MODULE_PARM_DESC(ip_list_uid, "default owner of /proc/net/xt_recent/* files");
+MODULE_PARM_DESC(ip_list_gid, "default owning group of /proc/net/xt_recent/* files");
 
 struct recent_entry {
        struct list_head        list;
@@ -84,9 +85,6 @@ struct recent_net {
        struct list_head        tables;
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry   *xt_recent;
-#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-       struct proc_dir_entry   *ipt_recent;
-#endif
 #endif
 };
 
@@ -147,6 +145,25 @@ static void recent_entry_remove(struct recent_table *t, struct recent_entry *e)
        t->entries--;
 }
 
+/*
+ * Drop entries with timestamps older then 'time'.
+ */
+static void recent_entry_reap(struct recent_table *t, unsigned long time)
+{
+       struct recent_entry *e;
+
+       /*
+        * The head of the LRU list is always the oldest entry.
+        */
+       e = list_entry(t->lru_list.next, struct recent_entry, lru_list);
+
+       /*
+        * The last time stamp is the most recent.
+        */
+       if (time_after(time, e->stamps[e->index-1]))
+               recent_entry_remove(t, e);
+}
+
 static struct recent_entry *
 recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr,
                  u_int16_t family, u_int8_t ttl)
@@ -207,7 +224,7 @@ static void recent_table_flush(struct recent_table *t)
 }
 
 static bool
-recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct net *net = dev_net(par->in ? par->in : par->out);
        struct recent_net *recent_net = recent_pernet(net);
@@ -218,7 +235,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        u_int8_t ttl;
        bool ret = info->invert;
 
-       if (par->match->family == NFPROTO_IPV4) {
+       if (par->family == NFPROTO_IPV4) {
                const struct iphdr *iph = ip_hdr(skb);
 
                if (info->side == XT_RECENT_DEST)
@@ -244,14 +261,14 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 
        spin_lock_bh(&recent_lock);
        t = recent_table_lookup(recent_net, info->name);
-       e = recent_entry_lookup(t, &addr, par->match->family,
+       e = recent_entry_lookup(t, &addr, par->family,
                                (info->check_set & XT_RECENT_TTL) ? ttl : 0);
        if (e == NULL) {
                if (!(info->check_set & XT_RECENT_SET))
                        goto out;
-               e = recent_entry_init(t, &addr, par->match->family, ttl);
+               e = recent_entry_init(t, &addr, par->family, ttl);
                if (e == NULL)
-                       *par->hotdrop = true;
+                       par->hotdrop = true;
                ret = !ret;
                goto out;
        }
@@ -273,6 +290,10 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                                break;
                        }
                }
+
+               /* info->seconds must be non-zero */
+               if (info->check_set & XT_RECENT_REAP)
+                       recent_entry_reap(t, time);
        }
 
        if (info->check_set & XT_RECENT_SET ||
@@ -285,7 +306,7 @@ out:
        return ret;
 }
 
-static bool recent_mt_check(const struct xt_mtchk_param *par)
+static int recent_mt_check(const struct xt_mtchk_param *par)
 {
        struct recent_net *recent_net = recent_pernet(par->net);
        const struct xt_recent_mtinfo *info = par->matchinfo;
@@ -294,41 +315,51 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
        struct proc_dir_entry *pde;
 #endif
        unsigned i;
-       bool ret = false;
+       int ret = -EINVAL;
 
        if (unlikely(!hash_rnd_inited)) {
                get_random_bytes(&hash_rnd, sizeof(hash_rnd));
                hash_rnd_inited = true;
        }
+       if (info->check_set & ~XT_RECENT_VALID_FLAGS) {
+               pr_info("Unsupported user space flags (%08x)\n",
+                       info->check_set);
+               return -EINVAL;
+       }
        if (hweight8(info->check_set &
                     (XT_RECENT_SET | XT_RECENT_REMOVE |
                      XT_RECENT_CHECK | XT_RECENT_UPDATE)) != 1)
-               return false;
+               return -EINVAL;
        if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) &&
-           (info->seconds || info->hit_count))
-               return false;
+           (info->seconds || info->hit_count ||
+           (info->check_set & XT_RECENT_MODIFIERS)))
+               return -EINVAL;
+       if ((info->check_set & XT_RECENT_REAP) && !info->seconds)
+               return -EINVAL;
        if (info->hit_count > ip_pkt_list_tot) {
-               pr_info(KBUILD_MODNAME ": hitcount (%u) is larger than "
+               pr_info("hitcount (%u) is larger than "
                        "packets to be remembered (%u)\n",
                        info->hit_count, ip_pkt_list_tot);
-               return false;
+               return -EINVAL;
        }
        if (info->name[0] == '\0' ||
            strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
-               return false;
+               return -EINVAL;
 
        mutex_lock(&recent_mutex);
        t = recent_table_lookup(recent_net, info->name);
        if (t != NULL) {
                t->refcnt++;
-               ret = true;
+               ret = 0;
                goto out;
        }
 
        t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size,
                    GFP_KERNEL);
-       if (t == NULL)
+       if (t == NULL) {
+               ret = -ENOMEM;
                goto out;
+       }
        t->refcnt = 1;
        strcpy(t->name, info->name);
        INIT_LIST_HEAD(&t->lru_list);
@@ -339,26 +370,16 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
                  &recent_mt_fops, t);
        if (pde == NULL) {
                kfree(t);
-               goto out;
-       }
-       pde->uid = ip_list_uid;
-       pde->gid = ip_list_gid;
-#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-       pde = proc_create_data(t->name, ip_list_perms, recent_net->ipt_recent,
-                     &recent_old_fops, t);
-       if (pde == NULL) {
-               remove_proc_entry(t->name, recent_net->xt_recent);
-               kfree(t);
+               ret = -ENOMEM;
                goto out;
        }
        pde->uid = ip_list_uid;
        pde->gid = ip_list_gid;
-#endif
 #endif
        spin_lock_bh(&recent_lock);
        list_add_tail(&t->list, &recent_net->tables);
        spin_unlock_bh(&recent_lock);
-       ret = true;
+       ret = 0;
 out:
        mutex_unlock(&recent_mutex);
        return ret;
@@ -377,9 +398,6 @@ static void recent_mt_destroy(const struct xt_mtdtor_param *par)
                list_del(&t->list);
                spin_unlock_bh(&recent_lock);
 #ifdef CONFIG_PROC_FS
-#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-               remove_proc_entry(t->name, recent_net->ipt_recent);
-#endif
                remove_proc_entry(t->name, recent_net->xt_recent);
 #endif
                recent_table_flush(t);
@@ -471,84 +489,6 @@ static int recent_seq_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-static int recent_old_seq_open(struct inode *inode, struct file *filp)
-{
-       static bool warned_of_old;
-
-       if (unlikely(!warned_of_old)) {
-               printk(KERN_INFO KBUILD_MODNAME ": Use of /proc/net/ipt_recent"
-                      " is deprecated; use /proc/net/xt_recent.\n");
-               warned_of_old = true;
-       }
-       return recent_seq_open(inode, filp);
-}
-
-static ssize_t recent_old_proc_write(struct file *file,
-                                    const char __user *input,
-                                    size_t size, loff_t *loff)
-{
-       const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
-       struct recent_table *t = pde->data;
-       struct recent_entry *e;
-       char buf[sizeof("+255.255.255.255")], *c = buf;
-       union nf_inet_addr addr = {};
-       int add;
-
-       if (size > sizeof(buf))
-               size = sizeof(buf);
-       if (copy_from_user(buf, input, size))
-               return -EFAULT;
-
-       c = skip_spaces(c);
-
-       if (size - (c - buf) < 5)
-               return c - buf;
-       if (!strncmp(c, "clear", 5)) {
-               c += 5;
-               spin_lock_bh(&recent_lock);
-               recent_table_flush(t);
-               spin_unlock_bh(&recent_lock);
-               return c - buf;
-       }
-
-       switch (*c) {
-       case '-':
-               add = 0;
-               c++;
-               break;
-       case '+':
-               c++;
-       default:
-               add = 1;
-               break;
-       }
-       addr.ip = in_aton(c);
-
-       spin_lock_bh(&recent_lock);
-       e = recent_entry_lookup(t, &addr, NFPROTO_IPV4, 0);
-       if (e == NULL) {
-               if (add)
-                       recent_entry_init(t, &addr, NFPROTO_IPV4, 0);
-       } else {
-               if (add)
-                       recent_entry_update(t, e);
-               else
-                       recent_entry_remove(t, e);
-       }
-       spin_unlock_bh(&recent_lock);
-       return size;
-}
-
-static const struct file_operations recent_old_fops = {
-       .open           = recent_old_seq_open,
-       .read           = seq_read,
-       .write          = recent_old_proc_write,
-       .release        = seq_release_private,
-       .owner          = THIS_MODULE,
-};
-#endif
-
 static ssize_t
 recent_mt_proc_write(struct file *file, const char __user *input,
                     size_t size, loff_t *loff)
@@ -585,7 +525,7 @@ recent_mt_proc_write(struct file *file, const char __user *input,
                add = true;
                break;
        default:
-               printk(KERN_INFO KBUILD_MODNAME ": Need +ip, -ip or /\n");
+               pr_info("Need \"+ip\", \"-ip\" or \"/\"\n");
                return -EINVAL;
        }
 
@@ -600,8 +540,7 @@ recent_mt_proc_write(struct file *file, const char __user *input,
        }
 
        if (!succ) {
-               printk(KERN_INFO KBUILD_MODNAME ": illegal address written "
-                      "to procfs\n");
+               pr_info("illegal address written to procfs\n");
                return -EINVAL;
        }
 
@@ -637,21 +576,11 @@ static int __net_init recent_proc_net_init(struct net *net)
        recent_net->xt_recent = proc_mkdir("xt_recent", net->proc_net);
        if (!recent_net->xt_recent)
                return -ENOMEM;
-#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-       recent_net->ipt_recent = proc_mkdir("ipt_recent", net->proc_net);
-       if (!recent_net->ipt_recent) {
-               proc_net_remove(net, "xt_recent");
-               return -ENOMEM;
-       }
-#endif
        return 0;
 }
 
 static void __net_exit recent_proc_net_exit(struct net *net)
 {
-#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
-       proc_net_remove(net, "ipt_recent");
-#endif
        proc_net_remove(net, "xt_recent");
 }
 #else
index a189ada9128f523e9481f5c4d9c6c993c9574bad..c04fcf385c591875ec45f2f50812b9c564657869 100644 (file)
@@ -1,3 +1,4 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <net/ip.h>
@@ -15,12 +16,6 @@ MODULE_DESCRIPTION("Xtables: SCTP protocol packet match");
 MODULE_ALIAS("ipt_sctp");
 MODULE_ALIAS("ip6t_sctp");
 
-#ifdef DEBUG_SCTP
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
 #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
                                              || (!!((invflag) & (option)) ^ (cond)))
 
@@ -52,7 +47,7 @@ match_packet(const struct sk_buff *skb,
        const struct xt_sctp_flag_info *flag_info = info->flag_info;
        int flag_count = info->flag_count;
 
-#ifdef DEBUG_SCTP
+#ifdef DEBUG
        int i = 0;
 #endif
 
@@ -62,17 +57,19 @@ match_packet(const struct sk_buff *skb,
        do {
                sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
                if (sch == NULL || sch->length == 0) {
-                       duprintf("Dropping invalid SCTP packet.\n");
+                       pr_debug("Dropping invalid SCTP packet.\n");
                        *hotdrop = true;
                        return false;
                }
-
-               duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
-                               ++i, offset, sch->type, htons(sch->length), sch->flags);
-
+#ifdef DEBUG
+               pr_debug("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d"
+                        "\tflags: %x\n",
+                        ++i, offset, sch->type, htons(sch->length),
+                        sch->flags);
+#endif
                offset += (ntohs(sch->length) + 3) & ~3;
 
-               duprintf("skb->len: %d\toffset: %d\n", skb->len, offset);
+               pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset);
 
                if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) {
                        switch (chunk_match_type) {
@@ -117,24 +114,24 @@ match_packet(const struct sk_buff *skb,
 }
 
 static bool
-sctp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+sctp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_sctp_info *info = par->matchinfo;
        const sctp_sctphdr_t *sh;
        sctp_sctphdr_t _sh;
 
        if (par->fragoff != 0) {
-               duprintf("Dropping non-first fragment.. FIXME\n");
+               pr_debug("Dropping non-first fragment.. FIXME\n");
                return false;
        }
 
        sh = skb_header_pointer(skb, par->thoff, sizeof(_sh), &_sh);
        if (sh == NULL) {
-               duprintf("Dropping evil TCP offset=0 tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil TCP offset=0 tinygram.\n");
+               par->hotdrop = true;
                return false;
        }
-       duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
+       pr_debug("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
 
        return  SCCHECK(ntohs(sh->source) >= info->spts[0]
                        && ntohs(sh->source) <= info->spts[1],
@@ -143,22 +140,26 @@ sctp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                        && ntohs(sh->dest) <= info->dpts[1],
                        XT_SCTP_DEST_PORTS, info->flags, info->invflags)
                && SCCHECK(match_packet(skb, par->thoff + sizeof(sctp_sctphdr_t),
-                                       info, par->hotdrop),
+                                       info, &par->hotdrop),
                           XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
 }
 
-static bool sctp_mt_check(const struct xt_mtchk_param *par)
+static int sctp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_sctp_info *info = par->matchinfo;
 
-       return !(info->flags & ~XT_SCTP_VALID_FLAGS)
-               && !(info->invflags & ~XT_SCTP_VALID_FLAGS)
-               && !(info->invflags & ~info->flags)
-               && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) ||
-                       (info->chunk_match_type &
-                               (SCTP_CHUNK_MATCH_ALL
-                               | SCTP_CHUNK_MATCH_ANY
-                               | SCTP_CHUNK_MATCH_ONLY)));
+       if (info->flags & ~XT_SCTP_VALID_FLAGS)
+               return -EINVAL;
+       if (info->invflags & ~XT_SCTP_VALID_FLAGS)
+               return -EINVAL;
+       if (info->invflags & ~info->flags)
+               return -EINVAL;
+       if (!(info->flags & XT_SCTP_CHUNK_TYPES))
+               return 0;
+       if (info->chunk_match_type & (SCTP_CHUNK_MATCH_ALL |
+           SCTP_CHUNK_MATCH_ANY | SCTP_CHUNK_MATCH_ONLY))
+               return 0;
+       return -EINVAL;
 }
 
 static struct xt_match sctp_mt_reg[] __read_mostly = {
index 6a902564d24f7e44233bc51cd8933d9971d0f4ad..3d54c236a1ba0643ba0077eee8caf4f93078155f 100644 (file)
@@ -9,7 +9,7 @@
  * published by the Free Software Foundation.
  *
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter/x_tables.h>
@@ -88,7 +88,7 @@ extract_icmp_fields(const struct sk_buff *skb,
 
 
 static bool
-socket_match(const struct sk_buff *skb, const struct xt_match_param *par,
+socket_match(const struct sk_buff *skb, struct xt_action_param *par,
             const struct xt_socket_mtinfo1 *info)
 {
        const struct iphdr *iph = ip_hdr(skb);
@@ -165,8 +165,7 @@ socket_match(const struct sk_buff *skb, const struct xt_match_param *par,
                        sk = NULL;
        }
 
-       pr_debug("socket match: proto %u %08x:%u -> %08x:%u "
-                "(orig %08x:%u) sock %p\n",
+       pr_debug("proto %u %08x:%u -> %08x:%u (orig %08x:%u) sock %p\n",
                 protocol, ntohl(saddr), ntohs(sport),
                 ntohl(daddr), ntohs(dport),
                 ntohl(iph->daddr), hp ? ntohs(hp->dest) : 0, sk);
@@ -175,13 +174,13 @@ socket_match(const struct sk_buff *skb, const struct xt_match_param *par,
 }
 
 static bool
-socket_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
+socket_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
 {
        return socket_match(skb, par, NULL);
 }
 
 static bool
-socket_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
+socket_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 {
        return socket_match(skb, par, par->matchinfo);
 }
index 4c946cbd731f7cfe47b9333b13c7e861906f9298..e12e053d3782ba8f9252a5b5b8a2d3085b2345c3 100644 (file)
@@ -21,7 +21,7 @@ MODULE_ALIAS("ipt_state");
 MODULE_ALIAS("ip6t_state");
 
 static bool
-state_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+state_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_state_info *sinfo = par->matchinfo;
        enum ip_conntrack_info ctinfo;
@@ -37,50 +37,40 @@ state_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return (sinfo->statemask & statebit);
 }
 
-static bool state_mt_check(const struct xt_mtchk_param *par)
+static int state_mt_check(const struct xt_mtchk_param *par)
 {
-       if (nf_ct_l3proto_try_module_get(par->match->family) < 0) {
-               printk(KERN_WARNING "can't load conntrack support for "
-                                   "proto=%u\n", par->match->family);
-               return false;
-       }
-       return true;
+       int ret;
+
+       ret = nf_ct_l3proto_try_module_get(par->family);
+       if (ret < 0)
+               pr_info("cannot load conntrack support for proto=%u\n",
+                       par->family);
+       return ret;
 }
 
 static void state_mt_destroy(const struct xt_mtdtor_param *par)
 {
-       nf_ct_l3proto_module_put(par->match->family);
+       nf_ct_l3proto_module_put(par->family);
 }
 
-static struct xt_match state_mt_reg[] __read_mostly = {
-       {
-               .name           = "state",
-               .family         = NFPROTO_IPV4,
-               .checkentry     = state_mt_check,
-               .match          = state_mt,
-               .destroy        = state_mt_destroy,
-               .matchsize      = sizeof(struct xt_state_info),
-               .me             = THIS_MODULE,
-       },
-       {
-               .name           = "state",
-               .family         = NFPROTO_IPV6,
-               .checkentry     = state_mt_check,
-               .match          = state_mt,
-               .destroy        = state_mt_destroy,
-               .matchsize      = sizeof(struct xt_state_info),
-               .me             = THIS_MODULE,
-       },
+static struct xt_match state_mt_reg __read_mostly = {
+       .name       = "state",
+       .family     = NFPROTO_UNSPEC,
+       .checkentry = state_mt_check,
+       .match      = state_mt,
+       .destroy    = state_mt_destroy,
+       .matchsize  = sizeof(struct xt_state_info),
+       .me         = THIS_MODULE,
 };
 
 static int __init state_mt_init(void)
 {
-       return xt_register_matches(state_mt_reg, ARRAY_SIZE(state_mt_reg));
+       return xt_register_match(&state_mt_reg);
 }
 
 static void __exit state_mt_exit(void)
 {
-       xt_unregister_matches(state_mt_reg, ARRAY_SIZE(state_mt_reg));
+       xt_unregister_match(&state_mt_reg);
 }
 
 module_init(state_mt_init);
index 937ce0633e99c7c926144a882fea550d2b232a3a..96e62b8fd6b10d063f7bdc4cc2ee0ba28ed9991a 100644 (file)
@@ -30,7 +30,7 @@ MODULE_ALIAS("ip6t_statistic");
 static DEFINE_SPINLOCK(nth_lock);
 
 static bool
-statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+statistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_statistic_info *info = par->matchinfo;
        bool ret = info->flags & XT_STATISTIC_INVERT;
@@ -53,22 +53,20 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return ret;
 }
 
-static bool statistic_mt_check(const struct xt_mtchk_param *par)
+static int statistic_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_statistic_info *info = par->matchinfo;
 
        if (info->mode > XT_STATISTIC_MODE_MAX ||
            info->flags & ~XT_STATISTIC_MASK)
-               return false;
+               return -EINVAL;
 
        info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
-       if (info->master == NULL) {
-               printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n");
-               return false;
-       }
+       if (info->master == NULL)
+               return -ENOMEM;
        info->master->count = info->u.nth.count;
 
-       return true;
+       return 0;
 }
 
 static void statistic_mt_destroy(const struct xt_mtdtor_param *par)
index 96801ffd8af8d79c33e2d30fdd62c39ade795265..d3c48b14ab94c09d74f0c74e62b94ed5fcb58af7 100644 (file)
@@ -23,16 +23,14 @@ MODULE_ALIAS("ipt_string");
 MODULE_ALIAS("ip6t_string");
 
 static bool
-string_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+string_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_string_info *conf = par->matchinfo;
        struct ts_state state;
-       int invert;
+       bool invert;
 
        memset(&state, 0, sizeof(struct ts_state));
-
-       invert = (par->match->revision == 0 ? conf->u.v0.invert :
-                                   conf->u.v1.flags & XT_STRING_FLAG_INVERT);
+       invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT;
 
        return (skb_find_text((struct sk_buff *)skb, conf->from_offset,
                             conf->to_offset, conf->config, &state)
@@ -41,7 +39,7 @@ string_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 
 #define STRING_TEXT_PRIV(m) ((struct xt_string_info *)(m))
 
-static bool string_mt_check(const struct xt_mtchk_param *par)
+static int string_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_string_info *conf = par->matchinfo;
        struct ts_config *ts_conf;
@@ -49,26 +47,23 @@ static bool string_mt_check(const struct xt_mtchk_param *par)
 
        /* Damn, can't handle this case properly with iptables... */
        if (conf->from_offset > conf->to_offset)
-               return false;
+               return -EINVAL;
        if (conf->algo[XT_STRING_MAX_ALGO_NAME_SIZE - 1] != '\0')
-               return false;
+               return -EINVAL;
        if (conf->patlen > XT_STRING_MAX_PATTERN_SIZE)
-               return false;
-       if (par->match->revision == 1) {
-               if (conf->u.v1.flags &
-                   ~(XT_STRING_FLAG_IGNORECASE | XT_STRING_FLAG_INVERT))
-                       return false;
-               if (conf->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
-                       flags |= TS_IGNORECASE;
-       }
+               return -EINVAL;
+       if (conf->u.v1.flags &
+           ~(XT_STRING_FLAG_IGNORECASE | XT_STRING_FLAG_INVERT))
+               return -EINVAL;
+       if (conf->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
+               flags |= TS_IGNORECASE;
        ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
                                     GFP_KERNEL, flags);
        if (IS_ERR(ts_conf))
-               return false;
+               return PTR_ERR(ts_conf);
 
        conf->config = ts_conf;
-
-       return true;
+       return 0;
 }
 
 static void string_mt_destroy(const struct xt_mtdtor_param *par)
@@ -76,38 +71,25 @@ static void string_mt_destroy(const struct xt_mtdtor_param *par)
        textsearch_destroy(STRING_TEXT_PRIV(par->matchinfo)->config);
 }
 
-static struct xt_match xt_string_mt_reg[] __read_mostly = {
-       {
-               .name           = "string",
-               .revision       = 0,
-               .family         = NFPROTO_UNSPEC,
-               .checkentry     = string_mt_check,
-               .match          = string_mt,
-               .destroy        = string_mt_destroy,
-               .matchsize      = sizeof(struct xt_string_info),
-               .me             = THIS_MODULE
-       },
-       {
-               .name           = "string",
-               .revision       = 1,
-               .family         = NFPROTO_UNSPEC,
-               .checkentry     = string_mt_check,
-               .match          = string_mt,
-               .destroy        = string_mt_destroy,
-               .matchsize      = sizeof(struct xt_string_info),
-               .me             = THIS_MODULE
-       },
+static struct xt_match xt_string_mt_reg __read_mostly = {
+       .name       = "string",
+       .revision   = 1,
+       .family     = NFPROTO_UNSPEC,
+       .checkentry = string_mt_check,
+       .match      = string_mt,
+       .destroy    = string_mt_destroy,
+       .matchsize  = sizeof(struct xt_string_info),
+       .me         = THIS_MODULE,
 };
 
 static int __init string_mt_init(void)
 {
-       return xt_register_matches(xt_string_mt_reg,
-                                  ARRAY_SIZE(xt_string_mt_reg));
+       return xt_register_match(&xt_string_mt_reg);
 }
 
 static void __exit string_mt_exit(void)
 {
-       xt_unregister_matches(xt_string_mt_reg, ARRAY_SIZE(xt_string_mt_reg));
+       xt_unregister_match(&xt_string_mt_reg);
 }
 
 module_init(string_mt_init);
index 4809b34b10f823f6f8fb62b6ed7f9e9335400dce..c53d4d18eadf7176754dbcd6e99cea8f12639786 100644 (file)
@@ -25,7 +25,7 @@ MODULE_ALIAS("ipt_tcpmss");
 MODULE_ALIAS("ip6t_tcpmss");
 
 static bool
-tcpmss_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_tcpmss_match_info *info = par->matchinfo;
        const struct tcphdr *th;
@@ -73,7 +73,7 @@ out:
        return info->invert;
 
 dropit:
-       *par->hotdrop = true;
+       par->hotdrop = true;
        return false;
 }
 
index 1ebdc4934eed531b4f55f419779e8ce243979d64..c14d4645daa3525d3ce45548344e4973763cd599 100644 (file)
@@ -1,3 +1,4 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/types.h>
 #include <linux/module.h>
 #include <net/ip.h>
@@ -19,13 +20,6 @@ MODULE_ALIAS("ipt_tcp");
 MODULE_ALIAS("ip6t_udp");
 MODULE_ALIAS("ip6t_tcp");
 
-#ifdef DEBUG_IP_FIREWALL_USER
-#define duprintf(format, args...) printk(format , ## args)
-#else
-#define duprintf(format, args...)
-#endif
-
-
 /* Returns 1 if the port is matched by the range, 0 otherwise */
 static inline bool
 port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert)
@@ -46,7 +40,7 @@ tcp_find_option(u_int8_t option,
        u_int8_t _opt[60 - sizeof(struct tcphdr)];
        unsigned int i;
 
-       duprintf("tcp_match: finding option\n");
+       pr_debug("finding option\n");
 
        if (!optlen)
                return invert;
@@ -68,7 +62,7 @@ tcp_find_option(u_int8_t option,
        return invert;
 }
 
-static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct tcphdr *th;
        struct tcphdr _tcph;
@@ -82,8 +76,8 @@ static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                   flag overwrite to pass the direction checks.
                */
                if (par->fragoff == 1) {
-                       duprintf("Dropping evil TCP offset=1 frag.\n");
-                       *par->hotdrop = true;
+                       pr_debug("Dropping evil TCP offset=1 frag.\n");
+                       par->hotdrop = true;
                }
                /* Must not be a fragment. */
                return false;
@@ -95,8 +89,8 @@ static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        if (th == NULL) {
                /* We've been asked to examine this packet, and we
                   can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil TCP offset=0 tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil TCP offset=0 tinygram.\n");
+               par->hotdrop = true;
                return false;
        }
 
@@ -114,27 +108,27 @@ static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                return false;
        if (tcpinfo->option) {
                if (th->doff * 4 < sizeof(_tcph)) {
-                       *par->hotdrop = true;
+                       par->hotdrop = true;
                        return false;
                }
                if (!tcp_find_option(tcpinfo->option, skb, par->thoff,
                                     th->doff*4 - sizeof(_tcph),
                                     tcpinfo->invflags & XT_TCP_INV_OPTION,
-                                    par->hotdrop))
+                                    &par->hotdrop))
                        return false;
        }
        return true;
 }
 
-static bool tcp_mt_check(const struct xt_mtchk_param *par)
+static int tcp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_tcp *tcpinfo = par->matchinfo;
 
        /* Must specify no unknown invflags */
-       return !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
+       return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0;
 }
 
-static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct udphdr *uh;
        struct udphdr _udph;
@@ -148,8 +142,8 @@ static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        if (uh == NULL) {
                /* We've been asked to examine this packet, and we
                   can't.  Hence, no choice but to drop. */
-               duprintf("Dropping evil UDP tinygram.\n");
-               *par->hotdrop = true;
+               pr_debug("Dropping evil UDP tinygram.\n");
+               par->hotdrop = true;
                return false;
        }
 
@@ -161,12 +155,12 @@ static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
                              !!(udpinfo->invflags & XT_UDP_INV_DSTPT));
 }
 
-static bool udp_mt_check(const struct xt_mtchk_param *par)
+static int udp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_udp *udpinfo = par->matchinfo;
 
        /* Must specify no unknown invflags */
-       return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
+       return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0;
 }
 
 static struct xt_match tcpudp_mt_reg[] __read_mostly = {
index 93acaa59d1089909378d2c6768942345e197217e..c48975ff8ea27c4d1e7d99ae60f67f1da94d8003 100644 (file)
@@ -1,7 +1,6 @@
 /*
  *     xt_time
  *     Copyright Â© CC Computer Consultants GmbH, 2007
- *     Contact: <jengelh@computergmbh.de>
  *
  *     based on ipt_time by Fabrice MARIE <fabrice@netfilter.org>
  *     This is a module which is used for time matching
@@ -149,11 +148,10 @@ static void localtime_3(struct xtm *r, time_t time)
        }
 
        r->month    = i + 1;
-       return;
 }
 
 static bool
-time_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+time_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_time_info *info = par->matchinfo;
        unsigned int packet_time;
@@ -218,18 +216,18 @@ time_mt(const struct sk_buff *skb, const struct xt_match_param *par)
        return true;
 }
 
-static bool time_mt_check(const struct xt_mtchk_param *par)
+static int time_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_time_info *info = par->matchinfo;
 
        if (info->daytime_start > XT_TIME_MAX_DAYTIME ||
            info->daytime_stop > XT_TIME_MAX_DAYTIME) {
-               printk(KERN_WARNING "xt_time: invalid argument - start or "
-                      "stop time greater than 23:59:59\n");
-               return false;
+               pr_info("invalid argument - start or "
+                       "stop time greater than 23:59:59\n");
+               return -EDOM;
        }
 
-       return true;
+       return 0;
 }
 
 static struct xt_match xt_time_mt_reg __read_mostly = {
@@ -264,7 +262,7 @@ static void __exit time_mt_exit(void)
 
 module_init(time_mt_init);
 module_exit(time_mt_exit);
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: time-based matching");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_time");
index 24a5276245006e68d7d0fa2cc33138cd38617702..a95b50342dbb1d1f1a43663e46104e031f4f295a 100644 (file)
@@ -3,7 +3,6 @@
  *
  *     Original author: Don Cohen <don@isis.cs3-inc.com>
  *     (C) CC Computer Consultants GmbH, 2007
- *     Contact: <jengelh@computergmbh.de>
  */
 
 #include <linux/module.h>
@@ -87,7 +86,7 @@ static bool u32_match_it(const struct xt_u32 *data,
        return true;
 }
 
-static bool u32_mt(const struct sk_buff *skb, const struct xt_match_param *par)
+static bool u32_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        const struct xt_u32 *data = par->matchinfo;
        bool ret;
@@ -117,7 +116,7 @@ static void __exit u32_mt_exit(void)
 
 module_init(u32_mt_init);
 module_exit(u32_mt_exit);
-MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 MODULE_DESCRIPTION("Xtables: arbitrary byte matching");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("ipt_u32");
index 07ae7fd82be1ee2531eb8bc015d2be42653e701c..1c1c093cf279caf9786456e0967cc7547b053276 100644 (file)
@@ -130,7 +130,6 @@ static inline void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
                                             int src, const char *dev,
                                             __be32 addr, __be32 mask)
 {
-       return;
 }
 #endif
 
@@ -203,7 +202,6 @@ static inline void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
                                             const struct in6_addr *addr,
                                             const struct in6_addr *mask)
 {
-       return;
 }
 #endif
 #endif /* IPV6 */
index a3d64aabe2f73d6bbd90b12fbbdb6ae908d34447..e2b0a680dd562912e3f1540d64d669147b2b11f1 100644 (file)
@@ -670,7 +670,6 @@ static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
 
 unlhsh_condremove_failure:
        spin_unlock(&netlbl_unlhsh_lock);
-       return;
 }
 
 /**
index 795424396aff62fba6971aaff0eb6631965ce481..6464a1972a69dc649099fbd05a7ca5d56708b790 100644 (file)
@@ -545,7 +545,7 @@ static int netlink_autobind(struct socket *sock)
        struct hlist_head *head;
        struct sock *osk;
        struct hlist_node *node;
-       s32 pid = current->tgid;
+       s32 pid = task_tgid_vnr(current);
        int err;
        static s32 rover = -4097;
 
index 06438fa2b1e5d1bfcef02b274941e0553a533bd2..aa4308afcc7f07168d9317235e795218d878acdd 100644 (file)
 
 static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 
-static inline void genl_lock(void)
+void genl_lock(void)
 {
        mutex_lock(&genl_mutex);
 }
+EXPORT_SYMBOL(genl_lock);
 
-static inline void genl_unlock(void)
+void genl_unlock(void)
 {
        mutex_unlock(&genl_mutex);
 }
+EXPORT_SYMBOL(genl_unlock);
 
 #define GENL_FAM_TAB_SIZE      16
 #define GENL_FAM_TAB_MASK      (GENL_FAM_TAB_SIZE - 1)
index fa07f044b59977af946049b8a03fe64be5994966..06cb02796a0ef827775a0d4a756e5e8198114000 100644 (file)
@@ -739,7 +739,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
                DEFINE_WAIT(wait);
 
                for (;;) {
-                       prepare_to_wait(sk->sk_sleep, &wait,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
@@ -752,7 +752,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
                        err = -ERESTARTSYS;
                        break;
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
                if (err)
                        goto out_release;
        }
@@ -798,7 +798,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
         *      hooked into the SABM we saved
         */
        for (;;) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                skb = skb_dequeue(&sk->sk_receive_queue);
                if (skb)
                        break;
@@ -816,7 +816,7 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
                err = -ERESTARTSYS;
                break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (err)
                goto out_release;
 
index 243946d4809d04584a8388c8183aaa4cb608d049..2078a277e06b53f4e89181f8f4bb6bca21f7264a 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/mutex.h>
 #include <linux/if_vlan.h>
 #include <linux/virtio_net.h>
+#include <linux/errqueue.h>
 
 #ifdef CONFIG_INET
 #include <net/inet_common.h>
@@ -315,6 +316,8 @@ static inline struct packet_sock *pkt_sk(struct sock *sk)
 
 static void packet_sock_destruct(struct sock *sk)
 {
+       skb_queue_purge(&sk->sk_error_queue);
+
        WARN_ON(atomic_read(&sk->sk_rmem_alloc));
        WARN_ON(atomic_read(&sk->sk_wmem_alloc));
 
@@ -483,6 +486,9 @@ retry:
        skb->dev = dev;
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
+       err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+       if (err < 0)
+               goto out_unlock;
 
        dev_queue_xmit(skb);
        rcu_read_unlock();
@@ -1188,6 +1194,9 @@ static int packet_snd(struct socket *sock,
        err = skb_copy_datagram_from_iovec(skb, offset, msg->msg_iov, 0, len);
        if (err)
                goto out_free;
+       err = sock_tx_timestamp(msg, sk, skb_tx(skb));
+       if (err < 0)
+               goto out_free;
 
        skb->protocol = proto;
        skb->dev = dev;
@@ -1487,6 +1496,51 @@ out:
        return err;
 }
 
+static int packet_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+       struct sock_exterr_skb *serr;
+       struct sk_buff *skb, *skb2;
+       int copied, err;
+
+       err = -EAGAIN;
+       skb = skb_dequeue(&sk->sk_error_queue);
+       if (skb == NULL)
+               goto out;
+
+       copied = skb->len;
+       if (copied > len) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+       err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+       if (err)
+               goto out_free_skb;
+
+       sock_recv_timestamp(msg, sk, skb);
+
+       serr = SKB_EXT_ERR(skb);
+       put_cmsg(msg, SOL_PACKET, PACKET_TX_TIMESTAMP,
+                sizeof(serr->ee), &serr->ee);
+
+       msg->msg_flags |= MSG_ERRQUEUE;
+       err = copied;
+
+       /* Reset and regenerate socket error */
+       spin_lock_bh(&sk->sk_error_queue.lock);
+       sk->sk_err = 0;
+       if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
+               sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+               spin_unlock_bh(&sk->sk_error_queue.lock);
+               sk->sk_error_report(sk);
+       } else
+               spin_unlock_bh(&sk->sk_error_queue.lock);
+
+out_free_skb:
+       kfree_skb(skb);
+out:
+       return err;
+}
+
 /*
  *     Pull a packet from our receive queue and hand it to the user.
  *     If necessary we block.
@@ -1502,7 +1556,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
        int vnet_hdr_len = 0;
 
        err = -EINVAL;
-       if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT))
+       if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT|MSG_ERRQUEUE))
                goto out;
 
 #if 0
@@ -1511,6 +1565,11 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                return -ENODEV;
 #endif
 
+       if (flags & MSG_ERRQUEUE) {
+               err = packet_recv_error(sk, msg, len);
+               goto out;
+       }
+
        /*
         *      Call the generic datagram receiver. This handles all sorts
         *      of horrible races and re-entrancy so we can forget about it
@@ -1692,9 +1751,9 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
                if (i->alen != dev->addr_len)
                        return -EINVAL;
                if (what > 0)
-                       return dev_mc_add(dev, i->addr, i->alen, 0);
+                       return dev_mc_add(dev, i->addr);
                else
-                       return dev_mc_delete(dev, i->addr, i->alen, 0);
+                       return dev_mc_del(dev, i->addr);
                break;
        case PACKET_MR_PROMISC:
                return dev_set_promiscuity(dev, what);
@@ -1706,9 +1765,9 @@ static int packet_dev_mc(struct net_device *dev, struct packet_mclist *i,
                if (i->alen != dev->addr_len)
                        return -EINVAL;
                if (what > 0)
-                       return dev_unicast_add(dev, i->addr);
+                       return dev_uc_add(dev, i->addr);
                else
-                       return dev_unicast_delete(dev, i->addr);
+                       return dev_uc_del(dev, i->addr);
                break;
        default:
                break;
index e2a95762abd37685c6b10a63795df539ffe0b295..af4d38bc3b2231135a60974a53038d306b110961 100644 (file)
@@ -664,12 +664,12 @@ static int pep_wait_connreq(struct sock *sk, int noblock)
                if (signal_pending(tsk))
                        return sock_intr_errno(timeo);
 
-               prepare_to_wait_exclusive(&sk->sk_socket->wait, &wait,
+               prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                                TASK_INTERRUPTIBLE);
                release_sock(sk);
                timeo = schedule_timeout(timeo);
                lock_sock(sk);
-               finish_wait(&sk->sk_socket->wait, &wait);
+               finish_wait(sk_sleep(sk), &wait);
        }
 
        return 0;
@@ -910,10 +910,10 @@ disabled:
                        goto out;
                }
 
-               prepare_to_wait(&sk->sk_socket->wait, &wait,
+               prepare_to_wait(sk_sleep(sk), &wait,
                                TASK_INTERRUPTIBLE);
                done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits));
-               finish_wait(&sk->sk_socket->wait, &wait);
+               finish_wait(sk_sleep(sk), &wait);
 
                if (sk->sk_state != TCP_ESTABLISHED)
                        goto disabled;
index 9b4ced6e0968dc99ecf198bbdfba1b4201aed0a4..c33da65769420555a4a3cb60c0d5585519111f11 100644 (file)
@@ -46,9 +46,16 @@ struct phonet_net {
 
 int phonet_net_id __read_mostly;
 
+static struct phonet_net *phonet_pernet(struct net *net)
+{
+       BUG_ON(!net);
+
+       return net_generic(net, phonet_net_id);
+}
+
 struct phonet_device_list *phonet_device_list(struct net *net)
 {
-       struct phonet_net *pnn = net_generic(net, phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(net);
        return &pnn->pndevs;
 }
 
@@ -261,7 +268,7 @@ static int phonet_device_autoconf(struct net_device *dev)
 
 static void phonet_route_autodel(struct net_device *dev)
 {
-       struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(dev_net(dev));
        unsigned i;
        DECLARE_BITMAP(deleted, 64);
 
@@ -313,7 +320,7 @@ static struct notifier_block phonet_device_notifier = {
 /* Per-namespace Phonet devices handling */
 static int __net_init phonet_init_net(struct net *net)
 {
-       struct phonet_net *pnn = net_generic(net, phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(net);
 
        if (!proc_net_fops_create(net, "phonet", 0, &pn_sock_seq_fops))
                return -ENOMEM;
@@ -326,7 +333,7 @@ static int __net_init phonet_init_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 phonet_net *pnn = phonet_pernet(net);
        struct net_device *dev;
        unsigned i;
 
@@ -376,7 +383,7 @@ void phonet_device_exit(void)
 
 int phonet_route_add(struct net_device *dev, u8 daddr)
 {
-       struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(dev_net(dev));
        struct phonet_routes *routes = &pnn->routes;
        int err = -EEXIST;
 
@@ -393,7 +400,7 @@ int phonet_route_add(struct net_device *dev, u8 daddr)
 
 int phonet_route_del(struct net_device *dev, u8 daddr)
 {
-       struct phonet_net *pnn = net_generic(dev_net(dev), phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(dev_net(dev));
        struct phonet_routes *routes = &pnn->routes;
 
        daddr = daddr >> 2;
@@ -413,7 +420,7 @@ int phonet_route_del(struct net_device *dev, u8 daddr)
 
 struct net_device *phonet_route_get(struct net *net, u8 daddr)
 {
-       struct phonet_net *pnn = net_generic(net, phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(net);
        struct phonet_routes *routes = &pnn->routes;
        struct net_device *dev;
 
@@ -428,7 +435,7 @@ struct net_device *phonet_route_get(struct net *net, u8 daddr)
 
 struct net_device *phonet_route_output(struct net *net, u8 daddr)
 {
-       struct phonet_net *pnn = net_generic(net, phonet_net_id);
+       struct phonet_net *pnn = phonet_pernet(net);
        struct phonet_routes *routes = &pnn->routes;
        struct net_device *dev;
 
index c785bfd0744f149b753506f8f2f754329410f8ad..6e9848bf0370dff4a78827839a9a1057e52fb2b0 100644 (file)
@@ -265,7 +265,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
        struct pep_sock *pn = pep_sk(sk);
        unsigned int mask = 0;
 
-       poll_wait(file, &sock->wait, wait);
+       poll_wait(file, sk_sleep(sk), wait);
 
        switch (sk->sk_state) {
        case TCP_LISTEN:
index f81862baf4d080be3aa507e21e96fba2edd90a7a..aebfecbdb8417cfa3bd3196e2c22f18433a7b08b 100644 (file)
@@ -158,9 +158,10 @@ static unsigned int rds_poll(struct file *file, struct socket *sock,
        unsigned int mask = 0;
        unsigned long flags;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       poll_wait(file, sk_sleep(sk), wait);
 
-       poll_wait(file, &rds_poll_waitq, wait);
+       if (rs->rs_seen_congestion)
+               poll_wait(file, &rds_poll_waitq, wait);
 
        read_lock_irqsave(&rs->rs_recv_lock, flags);
        if (!rs->rs_cong_monitor) {
@@ -182,6 +183,10 @@ static unsigned int rds_poll(struct file *file, struct socket *sock,
                mask |= (POLLOUT | POLLWRNORM);
        read_unlock_irqrestore(&rs->rs_recv_lock, flags);
 
+       /* clear state any time we wake a seen-congested socket */
+       if (mask)
+               rs->rs_seen_congestion = 0;
+
        return mask;
 }
 
@@ -447,7 +452,6 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len,
                              struct rds_info_lengths *lens)
 {
        struct rds_sock *rs;
-       struct sock *sk;
        struct rds_incoming *inc;
        unsigned long flags;
        unsigned int total = 0;
@@ -457,7 +461,6 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len,
        spin_lock_irqsave(&rds_sock_lock, flags);
 
        list_for_each_entry(rs, &rds_sock_list, rs_item) {
-               sk = rds_rs_to_sk(rs);
                read_lock(&rs->rs_recv_lock);
 
                /* XXX too lazy to maintain counts.. */
index f1da27ceb064e5a2d4095414c65e1fbf547d063e..0871a29f078000ee79370fd20e6d94ca46ba3efd 100644 (file)
@@ -219,8 +219,6 @@ void rds_cong_queue_updates(struct rds_cong_map *map)
        spin_lock_irqsave(&rds_cong_lock, flags);
 
        list_for_each_entry(conn, &map->m_conn_list, c_map_item) {
-               if (conn->c_loopback)
-                       continue;
                if (!test_and_set_bit(0, &conn->c_map_queued)) {
                        rds_stats_inc(s_cong_update_queued);
                        queue_delayed_work(rds_wq, &conn->c_send_w, 0);
index 88d0856cb797d3bd41ffc0fc29f0b51618424d6d..10ed0d55f75948702837e2154327876a521d3d8b 100644 (file)
@@ -204,9 +204,10 @@ static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
                rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
                break;
        default:
-               rds_ib_conn_error(conn, "RDS/IB: Fatal QP Event %u "
+               rdsdebug("Fatal QP Event %u "
                        "- connection %pI4->%pI4, reconnecting\n",
                        event->event, &conn->c_laddr, &conn->c_faddr);
+               rds_conn_drop(conn);
                break;
        }
 }
index 059989fdb7d784592eef3f873b808d1b88a16afa..a54cd63f9e35bd0f3e33a80d9ac06801fb3e0122 100644 (file)
@@ -235,8 +235,8 @@ void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
 {
        flush_workqueue(rds_wq);
        rds_ib_flush_mr_pool(pool, 1);
-       BUG_ON(atomic_read(&pool->item_count));
-       BUG_ON(atomic_read(&pool->free_pinned));
+       WARN_ON(atomic_read(&pool->item_count));
+       WARN_ON(atomic_read(&pool->free_pinned));
        kfree(pool);
 }
 
@@ -441,6 +441,7 @@ static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
 
                        /* FIXME we need a way to tell a r/w MR
                         * from a r/o MR */
+                       BUG_ON(in_interrupt());
                        set_page_dirty(page);
                        put_page(page);
                }
index c7dd11b835f04447cb2e63d013e0b49fd9a384b2..c74e9904a6b2c20872917c79bf06a905c1ecd403 100644 (file)
@@ -469,8 +469,8 @@ static void rds_ib_send_ack(struct rds_ib_connection *ic, unsigned int adv_credi
                set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
 
                rds_ib_stats_inc(s_ib_ack_send_failure);
-               /* Need to finesse this later. */
-               BUG();
+
+               rds_ib_conn_error(ic->conn, "sending ack failed\n");
        } else
                rds_ib_stats_inc(s_ib_ack_sent);
 }
index a10fab6886d18a033749cce366494bbbac7c7d12..17fa80803ab01ccbd0fa1279ed448c1bd51d501d 100644 (file)
@@ -243,8 +243,12 @@ void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
                                struct rds_message *rm;
 
                                rm = rds_send_get_message(conn, send->s_op);
-                               if (rm)
+                               if (rm) {
+                                       if (rm->m_rdma_op)
+                                               rds_ib_send_unmap_rdma(ic, rm->m_rdma_op);
                                        rds_ib_send_rdma_complete(rm, wc.status);
+                                       rds_message_put(rm);
+                               }
                        }
 
                        oldest = (oldest + 1) % ic->i_send_ring.w_nr;
@@ -482,6 +486,13 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
        BUG_ON(off % RDS_FRAG_SIZE);
        BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
 
+       /* Do not send cong updates to IB loopback */
+       if (conn->c_loopback
+           && rm->m_inc.i_hdr.h_flags & RDS_FLAG_CONG_BITMAP) {
+               rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
+               return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+       }
+
        /* FIXME we may overallocate here */
        if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0)
                i = 1;
@@ -574,8 +585,7 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
                rds_ib_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
                adv_credits += posted;
                BUG_ON(adv_credits > 255);
-       } else if (ic->i_rm != rm)
-               BUG();
+       }
 
        send = &ic->i_sends[pos];
        first = send;
@@ -714,8 +724,8 @@ add_header:
                        ic->i_rm = prev->s_rm;
                        prev->s_rm = NULL;
                }
-               /* Finesse this later */
-               BUG();
+
+               rds_ib_conn_error(ic->conn, "ib_post_send failed\n");
                goto out;
        }
 
index 3e9460f935d84f6ebafca6d5592b8f8527185fb7..a9d951b4fbaec49dfea00dc6494639b0d32403ac 100644 (file)
@@ -157,9 +157,11 @@ static void rds_iw_qp_event_handler(struct ib_event *event, void *data)
        case IB_EVENT_QP_REQ_ERR:
        case IB_EVENT_QP_FATAL:
        default:
-               rds_iw_conn_error(conn, "RDS/IW: Fatal QP Event %u - connection %pI4->%pI4...reconnecting\n",
+               rdsdebug("Fatal QP Event %u "
+                       "- connection %pI4->%pI4, reconnecting\n",
                        event->event, &conn->c_laddr,
                        &conn->c_faddr);
+               rds_conn_drop(conn);
                break;
        }
 }
index da43ee840ca3bb89d44d5031b5acf5887fcf1069..3d479067d54dbd02810f9c6b1bf2d373d9388cbf 100644 (file)
@@ -469,8 +469,8 @@ static void rds_iw_send_ack(struct rds_iw_connection *ic, unsigned int adv_credi
                set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
 
                rds_iw_stats_inc(s_iw_ack_send_failure);
-               /* Need to finesse this later. */
-               BUG();
+
+               rds_iw_conn_error(ic->conn, "sending ack failed\n");
        } else
                rds_iw_stats_inc(s_iw_ack_sent);
 }
index 1379e9d66a789934ae8d7d649066c1e5d5463ef0..52182ff7519edcde8b7dee746b72282fe6eb832f 100644 (file)
@@ -616,8 +616,7 @@ int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
                rds_iw_send_grab_credits(ic, 0, &posted, 1, RDS_MAX_ADV_CREDIT - adv_credits);
                adv_credits += posted;
                BUG_ON(adv_credits > 255);
-       } else if (ic->i_rm != rm)
-               BUG();
+       }
 
        send = &ic->i_sends[pos];
        first = send;
index 0d7a159158b81c0b18af5df5f37a7c2356f9a6eb..dd9879379457e29bc9afcb45bacbb58b4ffd092e 100644 (file)
@@ -81,16 +81,9 @@ static int rds_loop_xmit_cong_map(struct rds_connection *conn,
                                  struct rds_cong_map *map,
                                  unsigned long offset)
 {
-       unsigned long i;
-
        BUG_ON(offset);
        BUG_ON(map != conn->c_lcong);
 
-       for (i = 0; i < RDS_CONG_MAP_PAGES; i++) {
-               memcpy((void *)conn->c_fcong->m_page_addrs[i],
-                      (void *)map->m_page_addrs[i], PAGE_SIZE);
-       }
-
        rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
 
        return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
index 5ce9437cad672168825e78f43fb1fe38e8ce2b20..75fd13bb631bbc06bf8493c06c266951b6e47c95 100644 (file)
@@ -439,8 +439,10 @@ void rds_rdma_free_op(struct rds_rdma_op *ro)
                /* Mark page dirty if it was possibly modified, which
                 * is the case for a RDMA_READ which copies from remote
                 * to local memory */
-               if (!ro->r_write)
+               if (!ro->r_write) {
+                       BUG_ON(in_interrupt());
                        set_page_dirty(page);
+               }
                put_page(page);
        }
 
index 7b155081b4dc59ba8a8565396ff01e78cb7cde21..e599ba2f950d72e03c4bc98f7b1a9b86742134e7 100644 (file)
@@ -101,7 +101,7 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
                break;
 
        case RDMA_CM_EVENT_DISCONNECTED:
-               printk(KERN_WARNING "RDS/RDMA: DISCONNECT event - dropping connection "
+               rdsdebug("DISCONNECT event - dropping connection "
                        "%pI4->%pI4\n", &conn->c_laddr,
                         &conn->c_faddr);
                rds_conn_drop(conn);
@@ -109,8 +109,7 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
 
        default:
                /* things like device disconnect? */
-               printk(KERN_ERR "unknown event %u\n", event->event);
-               BUG();
+               printk(KERN_ERR "RDS: unknown event %u!\n", event->event);
                break;
        }
 
index 85d6f897ecc76af06cfbc028636901a4be5dc365..c224b5bb3ba9368fd00fad5f6a25f90d68364ebd 100644 (file)
@@ -388,6 +388,8 @@ struct rds_sock {
 
        /* flag indicating we were congested or not */
        int                     rs_congested;
+       /* seen congestion (ENOBUFS) when sending? */
+       int                     rs_seen_congestion;
 
        /* rs_lock protects all these adjacent members before the newline */
        spinlock_t              rs_lock;
@@ -490,7 +492,7 @@ void rds_sock_put(struct rds_sock *rs);
 void rds_wake_sk_sleep(struct rds_sock *rs);
 static inline void __rds_wake_sk_sleep(struct sock *sk)
 {
-       wait_queue_head_t *waitq = sk->sk_sleep;
+       wait_queue_head_t *waitq = sk_sleep(sk);
 
        if (!sock_flag(sk, SOCK_DEAD) && waitq)
                wake_up(waitq);
index e2a2b9344f7b576be4d06ca02f23c072acd9f904..795a00b7f2cb7aa6a539adb3c86a2cad180575f1 100644 (file)
@@ -432,7 +432,7 @@ int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                                break;
                        }
 
-                       timeo = wait_event_interruptible_timeout(*sk->sk_sleep,
+                       timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
                                        (!list_empty(&rs->rs_notify_queue) ||
                                         rs->rs_cong_notify ||
                                         rds_next_incoming(rs, &inc)), timeo);
index f04b929ded926d48b0fd326f5c5d916895b3f9b5..9c1c6bcaa6c9532e9abdbbd198b8ab6e6c7b9400 100644 (file)
@@ -508,12 +508,13 @@ EXPORT_SYMBOL_GPL(rds_send_get_message);
  */
 void rds_send_remove_from_sock(struct list_head *messages, int status)
 {
-       unsigned long flags = 0; /* silence gcc :P */
+       unsigned long flags;
        struct rds_sock *rs = NULL;
        struct rds_message *rm;
 
-       local_irq_save(flags);
        while (!list_empty(messages)) {
+               int was_on_sock = 0;
+
                rm = list_entry(messages->next, struct rds_message,
                                m_conn_item);
                list_del_init(&rm->m_conn_item);
@@ -528,20 +529,19 @@ void rds_send_remove_from_sock(struct list_head *messages, int status)
                 * while we're messing with it. It does not prevent the
                 * message from being removed from the socket, though.
                 */
-               spin_lock(&rm->m_rs_lock);
+               spin_lock_irqsave(&rm->m_rs_lock, flags);
                if (!test_bit(RDS_MSG_ON_SOCK, &rm->m_flags))
                        goto unlock_and_drop;
 
                if (rs != rm->m_rs) {
                        if (rs) {
-                               spin_unlock(&rs->rs_lock);
                                rds_wake_sk_sleep(rs);
                                sock_put(rds_rs_to_sk(rs));
                        }
                        rs = rm->m_rs;
-                       spin_lock(&rs->rs_lock);
                        sock_hold(rds_rs_to_sk(rs));
                }
+               spin_lock(&rs->rs_lock);
 
                if (test_and_clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags)) {
                        struct rds_rdma_op *ro = rm->m_rdma_op;
@@ -558,21 +558,22 @@ void rds_send_remove_from_sock(struct list_head *messages, int status)
                                        notifier->n_status = status;
                                rm->m_rdma_op->r_notifier = NULL;
                        }
-                       rds_message_put(rm);
+                       was_on_sock = 1;
                        rm->m_rs = NULL;
                }
+               spin_unlock(&rs->rs_lock);
 
 unlock_and_drop:
-               spin_unlock(&rm->m_rs_lock);
+               spin_unlock_irqrestore(&rm->m_rs_lock, flags);
                rds_message_put(rm);
+               if (was_on_sock)
+                       rds_message_put(rm);
        }
 
        if (rs) {
-               spin_unlock(&rs->rs_lock);
                rds_wake_sk_sleep(rs);
                sock_put(rds_rs_to_sk(rs));
        }
-       local_irq_restore(flags);
 }
 
 /*
@@ -634,9 +635,6 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
                list_move(&rm->m_sock_item, &list);
                rds_send_sndbuf_remove(rs, rm);
                clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags);
-
-               /* If this is a RDMA operation, notify the app. */
-               __rds_rdma_send_complete(rs, rm, RDS_RDMA_CANCELED);
        }
 
        /* order flag updates with the rs lock */
@@ -645,9 +643,6 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
 
        spin_unlock_irqrestore(&rs->rs_lock, flags);
 
-       if (wake)
-               rds_wake_sk_sleep(rs);
-
        conn = NULL;
 
        /* now remove the messages from the conn list as needed */
@@ -655,6 +650,10 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
                /* We do this here rather than in the loop above, so that
                 * we don't have to nest m_rs_lock under rs->rs_lock */
                spin_lock_irqsave(&rm->m_rs_lock, flags2);
+               /* If this is a RDMA operation, notify the app. */
+               spin_lock(&rs->rs_lock);
+               __rds_rdma_send_complete(rs, rm, RDS_RDMA_CANCELED);
+               spin_unlock(&rs->rs_lock);
                rm->m_rs = NULL;
                spin_unlock_irqrestore(&rm->m_rs_lock, flags2);
 
@@ -683,6 +682,9 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
        if (conn)
                spin_unlock_irqrestore(&conn->c_lock, flags);
 
+       if (wake)
+               rds_wake_sk_sleep(rs);
+
        while (!list_empty(&list)) {
                rm = list_entry(list.next, struct rds_message, m_sock_item);
                list_del_init(&rm->m_sock_item);
@@ -816,7 +818,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        int ret = 0;
        int queued = 0, allocated_mr = 0;
        int nonblock = msg->msg_flags & MSG_DONTWAIT;
-       long timeo = sock_rcvtimeo(sk, nonblock);
+       long timeo = sock_sndtimeo(sk, nonblock);
 
        /* Mirror Linux UDP mirror of BSD error message compatibility */
        /* XXX: Perhaps MSG_MORE someday */
@@ -895,8 +897,10 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
 
        ret = rds_cong_wait(conn->c_fcong, dport, nonblock, rs);
-       if (ret)
+       if (ret) {
+               rs->rs_seen_congestion = 1;
                goto out;
+       }
 
        while (!rds_send_queue_rm(rs, conn, rm, rs->rs_bound_port,
                                  dport, &queued)) {
@@ -911,7 +915,7 @@ int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
                        goto out;
                }
 
-               timeo = wait_event_interruptible_timeout(*sk->sk_sleep,
+               timeo = wait_event_interruptible_timeout(*sk_sleep(sk),
                                        rds_send_queue_rm(rs, conn, rm,
                                                          rs->rs_bound_port,
                                                          dport,
index 056256285987dea30ffcb2a93b71bf5af8b904c1..c397524c039cdb28140ff5f6c0fe2359cebfa3b5 100644 (file)
@@ -141,7 +141,7 @@ void rds_tcp_conn_shutdown(struct rds_connection *conn)
 
                release_sock(sock->sk);
                sock_release(sock);
-       };
+       }
 
        if (tc->t_tinc) {
                rds_inc_put(&tc->t_tinc->ti_inc);
index e08ec912d8b0f3f3181e32365a567abb2d916ebe..1aba6878fa5dc42d4c54473350fde61d714a184c 100644 (file)
@@ -98,6 +98,7 @@ int rds_tcp_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
                                goto out;
                        }
 
+                       rds_stats_add(s_copy_to_user, to_copy);
                        size -= to_copy;
                        ret += to_copy;
                        skb_off += to_copy;
index 34fdcc059e543271e3a47b07980184351f5e588a..a28b895ff0d10194730463b218e3ccb526cdea50 100644 (file)
@@ -240,7 +240,9 @@ void rds_tcp_write_space(struct sock *sk)
        tc->t_last_seen_una = rds_tcp_snd_una(tc);
        rds_send_drop_acked(conn, rds_tcp_snd_una(tc), rds_tcp_is_acked);
 
-       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+        if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf)
+               queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+
 out:
        read_unlock(&sk->sk_callback_lock);
 
index 00fa10e59af8a735cd95a5b7c3562d68a676ba05..786c20eaaf5e44a1cb1a2d7bdd284c7ad2cedf53 100644 (file)
@@ -259,7 +259,7 @@ void rds_threads_exit(void)
 
 int __init rds_threads_init(void)
 {
-       rds_wq = create_singlethread_workqueue("krdsd");
+       rds_wq = create_workqueue("krdsd");
        if (rds_wq == NULL)
                return -ENOMEM;
 
index a9fa86f65983a65ebbcc9a04e65f053df2f70afc..51875a0c5d48c489899e1bcb71c3fd2a2fd3c91c 100644 (file)
@@ -629,6 +629,49 @@ static ssize_t rfkill_persistent_show(struct device *dev,
        return sprintf(buf, "%d\n", rfkill->persistent);
 }
 
+static ssize_t rfkill_hard_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       return sprintf(buf, "%d\n", (rfkill->state & RFKILL_BLOCK_HW) ? 1 : 0 );
+}
+
+static ssize_t rfkill_soft_show(struct device *dev,
+                                struct device_attribute *attr,
+                                char *buf)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+
+       return sprintf(buf, "%d\n", (rfkill->state & RFKILL_BLOCK_SW) ? 1 : 0 );
+}
+
+static ssize_t rfkill_soft_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct rfkill *rfkill = to_rfkill(dev);
+       unsigned long state;
+       int err;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       err = strict_strtoul(buf, 0, &state);
+       if (err)
+               return err;
+
+       if (state > 1 )
+               return -EINVAL;
+
+       mutex_lock(&rfkill_global_mutex);
+       rfkill_set_block(rfkill, state);
+       mutex_unlock(&rfkill_global_mutex);
+
+       return err ?: count;
+}
+
 static u8 user_state_from_blocked(unsigned long state)
 {
        if (state & RFKILL_BLOCK_HW)
@@ -644,14 +687,8 @@ static ssize_t rfkill_state_show(struct device *dev,
                                 char *buf)
 {
        struct rfkill *rfkill = to_rfkill(dev);
-       unsigned long flags;
-       u32 state;
-
-       spin_lock_irqsave(&rfkill->lock, flags);
-       state = rfkill->state;
-       spin_unlock_irqrestore(&rfkill->lock, flags);
 
-       return sprintf(buf, "%d\n", user_state_from_blocked(state));
+       return sprintf(buf, "%d\n", user_state_from_blocked(rfkill->state));
 }
 
 static ssize_t rfkill_state_store(struct device *dev,
@@ -701,6 +738,8 @@ static struct device_attribute rfkill_dev_attrs[] = {
        __ATTR(persistent, S_IRUGO, rfkill_persistent_show, NULL),
        __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
        __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
+       __ATTR(soft, S_IRUGO|S_IWUSR, rfkill_soft_show, rfkill_soft_store),
+       __ATTR(hard, S_IRUGO, rfkill_hard_show, NULL),
        __ATTR_NULL
 };
 
index 4fb711a035f43f34ee5490fb5ab9ed17e93a98af..8e45e76a95f51cdca332263ee7e32108f0beb95c 100644 (file)
@@ -845,7 +845,7 @@ rose_try_next_neigh:
                DEFINE_WAIT(wait);
 
                for (;;) {
-                       prepare_to_wait(sk->sk_sleep, &wait,
+                       prepare_to_wait(sk_sleep(sk), &wait,
                                        TASK_INTERRUPTIBLE);
                        if (sk->sk_state != TCP_SYN_SENT)
                                break;
@@ -858,7 +858,7 @@ rose_try_next_neigh:
                        err = -ERESTARTSYS;
                        break;
                }
-               finish_wait(sk->sk_sleep, &wait);
+               finish_wait(sk_sleep(sk), &wait);
 
                if (err)
                        goto out_release;
@@ -911,7 +911,7 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
         *      hooked into the SABM we saved
         */
        for (;;) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
                skb = skb_dequeue(&sk->sk_receive_queue);
                if (skb)
@@ -930,7 +930,7 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
                err = -ERESTARTSYS;
                break;
        }
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        if (err)
                goto out_release;
 
index c060095b27ce9c6b1f565461345836d38a154f6c..0b9bb2085ce4ac5f8d22ada9ba0132235c02fbf9 100644 (file)
@@ -62,13 +62,15 @@ static inline int rxrpc_writable(struct sock *sk)
 static void rxrpc_write_space(struct sock *sk)
 {
        _enter("%p", sk);
-       read_lock(&sk->sk_callback_lock);
+       rcu_read_lock();
        if (rxrpc_writable(sk)) {
-               if (sk_has_sleeper(sk))
-                       wake_up_interruptible(sk->sk_sleep);
+               struct socket_wq *wq = rcu_dereference(sk->sk_wq);
+
+               if (wq_has_sleeper(wq))
+                       wake_up_interruptible(&wq->wait);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 /*
@@ -589,7 +591,7 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock,
        unsigned int mask;
        struct sock *sk = sock->sk;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* the socket is readable if there are any messages waiting on the Rx
index 60c2b94e6b547855e52c92f21046e9786b767e59..0c65013e3bfee6395a3cd70846416ff03dfad4f3 100644 (file)
@@ -91,7 +91,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
 
                        /* wait for a message to turn up */
                        release_sock(&rx->sk);
-                       prepare_to_wait_exclusive(rx->sk.sk_sleep, &wait,
+                       prepare_to_wait_exclusive(sk_sleep(&rx->sk), &wait,
                                                  TASK_INTERRUPTIBLE);
                        ret = sock_error(&rx->sk);
                        if (ret)
@@ -102,7 +102,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                                        goto wait_interrupted;
                                timeo = schedule_timeout(timeo);
                        }
-                       finish_wait(rx->sk.sk_sleep, &wait);
+                       finish_wait(sk_sleep(&rx->sk), &wait);
                        lock_sock(&rx->sk);
                        continue;
                }
@@ -356,7 +356,7 @@ csum_copy_error:
 wait_interrupted:
        ret = sock_intr_errno(timeo);
 wait_error:
-       finish_wait(rx->sk.sk_sleep, &wait);
+       finish_wait(sk_sleep(&rx->sk), &wait);
        if (continue_call)
                rxrpc_put_call(continue_call);
        if (copied)
index d8e0171d9a4b8a14cd2c7241c173d3647164430e..972378f47f3cfd2ef03b33ac3a3a5ea7801e7afe 100644 (file)
@@ -153,7 +153,7 @@ int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
        } else if (type == RTM_GETACTION) {
                return tcf_dump_walker(skb, cb, a, hinfo);
        } else {
-               printk("tcf_generic_walker: unknown action %d\n", type);
+               WARN(1, "tcf_generic_walker: unknown action %d\n", type);
                return -EINVAL;
        }
 }
@@ -403,8 +403,9 @@ void tcf_action_destroy(struct tc_action *act, int bind)
                                module_put(a->ops->owner);
                        act = act->next;
                        kfree(a);
-               } else { /*FIXME: Remove later - catch insertion bugs*/
-                       printk("tcf_action_destroy: BUG? destroying NULL ops\n");
+               } else {
+                       /*FIXME: Remove later - catch insertion bugs*/
+                       WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
                        act = act->next;
                        kfree(a);
                }
@@ -668,7 +669,8 @@ nlmsg_failure:
 }
 
 static int
-act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event)
+act_get_notify(struct net *net, u32 pid, struct nlmsghdr *n,
+              struct tc_action *a, int event)
 {
        struct sk_buff *skb;
 
@@ -680,7 +682,7 @@ act_get_notify(u32 pid, struct nlmsghdr *n, struct tc_action *a, int event)
                return -EINVAL;
        }
 
-       return rtnl_unicast(skb, &init_net, pid);
+       return rtnl_unicast(skb, net, pid);
 }
 
 static struct tc_action *
@@ -743,14 +745,15 @@ static struct tc_action *create_a(int i)
 
        act = kzalloc(sizeof(*act), GFP_KERNEL);
        if (act == NULL) {
-               printk("create_a: failed to alloc!\n");
+               pr_debug("create_a: failed to alloc!\n");
                return NULL;
        }
        act->order = i;
        return act;
 }
 
-static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
+static int tca_action_flush(struct net *net, struct nlattr *nla,
+                           struct nlmsghdr *n, u32 pid)
 {
        struct sk_buff *skb;
        unsigned char *b;
@@ -764,13 +767,13 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
        int err = -ENOMEM;
 
        if (a == NULL) {
-               printk("tca_action_flush: couldnt create tc_action\n");
+               pr_debug("tca_action_flush: couldnt create tc_action\n");
                return err;
        }
 
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!skb) {
-               printk("tca_action_flush: failed skb alloc\n");
+               pr_debug("tca_action_flush: failed skb alloc\n");
                kfree(a);
                return err;
        }
@@ -809,7 +812,7 @@ static int tca_action_flush(struct nlattr *nla, struct nlmsghdr *n, u32 pid)
        nlh->nlmsg_flags |= NLM_F_ROOT;
        module_put(a->ops->owner);
        kfree(a);
-       err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+       err = rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
        if (err > 0)
                return 0;
 
@@ -826,7 +829,8 @@ noflush_out:
 }
 
 static int
-tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event)
+tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
+             u32 pid, int event)
 {
        int i, ret;
        struct nlattr *tb[TCA_ACT_MAX_PRIO+1];
@@ -838,7 +842,7 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event)
 
        if (event == RTM_DELACTION && n->nlmsg_flags&NLM_F_ROOT) {
                if (tb[1] != NULL)
-                       return tca_action_flush(tb[1], n, pid);
+                       return tca_action_flush(net, tb[1], n, pid);
                else
                        return -EINVAL;
        }
@@ -859,7 +863,7 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event)
        }
 
        if (event == RTM_GETACTION)
-               ret = act_get_notify(pid, n, head, event);
+               ret = act_get_notify(net, pid, n, head, event);
        else { /* delete */
                struct sk_buff *skb;
 
@@ -878,7 +882,7 @@ tca_action_gd(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int event)
 
                /* now do the delete */
                tcf_action_destroy(head, 0);
-               ret = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC,
+               ret = rtnetlink_send(skb, net, pid, RTNLGRP_TC,
                                     n->nlmsg_flags&NLM_F_ECHO);
                if (ret > 0)
                        return 0;
@@ -889,8 +893,8 @@ err:
        return ret;
 }
 
-static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,
-                         u16 flags)
+static int tcf_add_notify(struct net *net, struct tc_action *a,
+                         u32 pid, u32 seq, int event, u16 flags)
 {
        struct tcamsg *t;
        struct nlmsghdr *nlh;
@@ -923,7 +927,7 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,
        nlh->nlmsg_len = skb_tail_pointer(skb) - b;
        NETLINK_CB(skb).dst_group = RTNLGRP_TC;
 
-       err = rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, flags&NLM_F_ECHO);
+       err = rtnetlink_send(skb, net, pid, RTNLGRP_TC, flags&NLM_F_ECHO);
        if (err > 0)
                err = 0;
        return err;
@@ -936,7 +940,8 @@ nlmsg_failure:
 
 
 static int
-tcf_action_add(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int ovr)
+tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
+              u32 pid, int ovr)
 {
        int ret = 0;
        struct tc_action *act;
@@ -954,7 +959,7 @@ tcf_action_add(struct nlattr *nla, struct nlmsghdr *n, u32 pid, int ovr)
        /* dump then free all the actions after update; inserted policy
         * stays intact
         * */
-       ret = tcf_add_notify(act, pid, seq, RTM_NEWACTION, n->nlmsg_flags);
+       ret = tcf_add_notify(net, act, pid, seq, RTM_NEWACTION, n->nlmsg_flags);
        for (a = act; a; a = act) {
                act = a->next;
                kfree(a);
@@ -970,15 +975,12 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        u32 pid = skb ? NETLINK_CB(skb).pid : 0;
        int ret = 0, ovr = 0;
 
-       if (!net_eq(net, &init_net))
-               return -EINVAL;
-
        ret = nlmsg_parse(n, sizeof(struct tcamsg), tca, TCA_ACT_MAX, NULL);
        if (ret < 0)
                return ret;
 
        if (tca[TCA_ACT_TAB] == NULL) {
-               printk("tc_ctl_action: received NO action attribs\n");
+               pr_notice("tc_ctl_action: received NO action attribs\n");
                return -EINVAL;
        }
 
@@ -995,15 +997,17 @@ static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
                if (n->nlmsg_flags&NLM_F_REPLACE)
                        ovr = 1;
 replay:
-               ret = tcf_action_add(tca[TCA_ACT_TAB], n, pid, ovr);
+               ret = tcf_action_add(net, tca[TCA_ACT_TAB], n, pid, ovr);
                if (ret == -EAGAIN)
                        goto replay;
                break;
        case RTM_DELACTION:
-               ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_DELACTION);
+               ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
+                                   pid, RTM_DELACTION);
                break;
        case RTM_GETACTION:
-               ret = tca_action_gd(tca[TCA_ACT_TAB], n, pid, RTM_GETACTION);
+               ret = tca_action_gd(net, tca[TCA_ACT_TAB], n,
+                                   pid, RTM_GETACTION);
                break;
        default:
                BUG();
@@ -1043,7 +1047,6 @@ find_dump_kind(const struct nlmsghdr *n)
 static int
 tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
        struct nlmsghdr *nlh;
        unsigned char *b = skb_tail_pointer(skb);
        struct nlattr *nest;
@@ -1053,11 +1056,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
        struct tcamsg *t = (struct tcamsg *) NLMSG_DATA(cb->nlh);
        struct nlattr *kind = find_dump_kind(cb->nlh);
 
-       if (!net_eq(net, &init_net))
-               return 0;
-
        if (kind == NULL) {
-               printk("tc_dump_action: action bad kind\n");
+               pr_info("tc_dump_action: action bad kind\n");
                return 0;
        }
 
@@ -1070,7 +1070,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
        a.ops = a_o;
 
        if (a_o->walk == NULL) {
-               printk("tc_dump_action: %s !capable of dumping table\n", a_o->kind);
+               WARN(1, "tc_dump_action: %s !capable of dumping table\n",
+                    a_o->kind);
                goto nla_put_failure;
        }
 
index e7f796aec657f90089a4872ab79c831b62bde467..8406c66549909c763a6b2ae3d7594ea5aeceb361 100644 (file)
@@ -202,9 +202,9 @@ MODULE_LICENSE("GPL");
 static int __init gact_init_module(void)
 {
 #ifdef CONFIG_GACT_PROB
-       printk("GACT probability on\n");
+       printk(KERN_INFO "GACT probability on\n");
 #else
-       printk("GACT probability NOT on\n");
+       printk(KERN_INFO "GACT probability NOT on\n");
 #endif
        return tcf_register_action(&act_gact_ops);
 }
index da27a170b6b7bcd42372a651668cba3f72034ab0..c7e59e6ec34938a3762fead555fc6748ab5d0e09 100644 (file)
@@ -47,8 +47,8 @@ static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int
 
        target = xt_request_find_target(AF_INET, t->u.user.name,
                                        t->u.user.revision);
-       if (!target)
-               return -ENOENT;
+       if (IS_ERR(target))
+               return PTR_ERR(target);
 
        t->u.kernel.target = target;
        par.table     = table;
@@ -199,7 +199,7 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
 {
        int ret = 0, result = 0;
        struct tcf_ipt *ipt = a->priv;
-       struct xt_target_param par;
+       struct xt_action_param par;
 
        if (skb_cloned(skb)) {
                if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
@@ -235,7 +235,8 @@ static int tcf_ipt(struct sk_buff *skb, struct tc_action *a,
                break;
        default:
                if (net_ratelimit())
-                       printk("Bogus netfilter code %d assume ACCEPT\n", ret);
+                       pr_notice("tc filter: Bogus netfilter code"
+                                 " %d assume ACCEPT\n", ret);
                result = TC_POLICE_OK;
                break;
        }
index c046682054ebdffbba3f71e439d140ac5c3155c1..c0b6863e3b87dbe91679638b83a169f099ab887f 100644 (file)
@@ -164,8 +164,8 @@ static int tcf_mirred(struct sk_buff *skb, struct tc_action *a,
        dev = m->tcfm_dev;
        if (!(dev->flags & IFF_UP)) {
                if (net_ratelimit())
-                       printk("mirred to Houston: device %s is gone!\n",
-                              dev->name);
+                       pr_notice("tc mirred to Houston: device %s is gone!\n",
+                                 dev->name);
                goto out;
        }
 
@@ -252,7 +252,7 @@ MODULE_LICENSE("GPL");
 
 static int __init mirred_init_module(void)
 {
-       printk("Mirror/redirect action on\n");
+       pr_info("Mirror/redirect action on\n");
        return tcf_register_action(&act_mirred_ops);
 }
 
index b7dcfedc802ea5c54a096efe3921f1fe4dd30aa5..fdbd0b7bd840715c41626abfa74831ddcd9ef2fb 100644 (file)
@@ -158,11 +158,13 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
                        }
 
                        if (offset % 4) {
-                               printk("offset must be on 32 bit boundaries\n");
+                               pr_info("tc filter pedit"
+                                       " offset must be on 32 bit boundaries\n");
                                goto bad;
                        }
                        if (offset > 0 && offset > skb->len) {
-                               printk("offset %d cant exceed pkt length %d\n",
+                               pr_info("tc filter pedit"
+                                       " offset %d cant exceed pkt length %d\n",
                                       offset, skb->len);
                                goto bad;
                        }
@@ -176,9 +178,8 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
                if (munged)
                        skb->tc_verd = SET_TC_MUNGED(skb->tc_verd);
                goto done;
-       } else {
-               printk("pedit BUG: index %d\n", p->tcf_index);
-       }
+       } else
+               WARN(1, "pedit BUG: index %d\n", p->tcf_index);
 
 bad:
        p->tcf_qstats.overlimits++;
index 622ca809c15ca3cf595e0d721e1d70171c3c2fbe..1b4bc691d7d1d0b5d716ddc681f319e23c19c98c 100644 (file)
@@ -49,7 +49,7 @@ static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result
         * Example if this was the 3rd packet and the string was "hello"
         * then it would look like "hello_3" (without quotes)
         **/
-       printk("simple: %s_%d\n",
+       pr_info("simple: %s_%d\n",
               (char *)d->tcfd_defdata, d->tcf_bstats.packets);
        spin_unlock(&d->tcf_lock);
        return d->tcf_action;
@@ -205,7 +205,7 @@ static int __init simp_init_module(void)
 {
        int ret = tcf_register_action(&act_simp_ops);
        if (!ret)
-               printk("Simple TC action Loaded\n");
+               pr_info("Simple TC action Loaded\n");
        return ret;
 }
 
index f082b27ff46d90fe80d85ab051511e43acb915c1..5fd0c28ef79a319ef1ab54474f6db98eb3b274cd 100644 (file)
@@ -99,8 +99,9 @@ out:
 }
 EXPORT_SYMBOL(unregister_tcf_proto_ops);
 
-static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
-                         struct tcf_proto *tp, unsigned long fh, int event);
+static int tfilter_notify(struct net *net, struct sk_buff *oskb,
+                         struct nlmsghdr *n, struct tcf_proto *tp,
+                         unsigned long fh, int event);
 
 
 /* Select new prio value from the range, managed by kernel. */
@@ -138,9 +139,6 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        int err;
        int tp_created = 0;
 
-       if (!net_eq(net, &init_net))
-               return -EINVAL;
-
 replay:
        t = NLMSG_DATA(n);
        protocol = TC_H_MIN(t->tcm_info);
@@ -159,7 +157,7 @@ replay:
        /* Find head of filter chain. */
 
        /* Find link */
-       dev = __dev_get_by_index(&init_net, t->tcm_ifindex);
+       dev = __dev_get_by_index(net, t->tcm_ifindex);
        if (dev == NULL)
                return -ENODEV;
 
@@ -283,7 +281,7 @@ replay:
                        *back = tp->next;
                        spin_unlock_bh(root_lock);
 
-                       tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER);
+                       tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
                        tcf_destroy(tp);
                        err = 0;
                        goto errout;
@@ -306,10 +304,10 @@ replay:
                case RTM_DELTFILTER:
                        err = tp->ops->delete(tp, fh);
                        if (err == 0)
-                               tfilter_notify(skb, n, tp, fh, RTM_DELTFILTER);
+                               tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER);
                        goto errout;
                case RTM_GETTFILTER:
-                       err = tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER);
+                       err = tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
                        goto errout;
                default:
                        err = -EINVAL;
@@ -325,7 +323,7 @@ replay:
                        *back = tp;
                        spin_unlock_bh(root_lock);
                }
-               tfilter_notify(skb, n, tp, fh, RTM_NEWTFILTER);
+               tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER);
        } else {
                if (tp_created)
                        tcf_destroy(tp);
@@ -371,8 +369,9 @@ nla_put_failure:
        return -1;
 }
 
-static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
-                         struct tcf_proto *tp, unsigned long fh, int event)
+static int tfilter_notify(struct net *net, struct sk_buff *oskb,
+                         struct nlmsghdr *n, struct tcf_proto *tp,
+                         unsigned long fh, int event)
 {
        struct sk_buff *skb;
        u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
@@ -386,7 +385,7 @@ static int tfilter_notify(struct sk_buff *oskb, struct nlmsghdr *n,
                return -EINVAL;
        }
 
-       return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC,
+       return rtnetlink_send(skb, net, pid, RTNLGRP_TC,
                              n->nlmsg_flags & NLM_F_ECHO);
 }
 
@@ -419,12 +418,9 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
        const struct Qdisc_class_ops *cops;
        struct tcf_dump_args arg;
 
-       if (!net_eq(net, &init_net))
-               return 0;
-
        if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
                return skb->len;
-       if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
+       if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
                return skb->len;
 
        if (!tcm->tcm_parent)
index 6ed61b10e0020d657c4531d501adf155292c486a..f73542d2cdd0640d3f6ef7900cc44987e1be3544 100644 (file)
@@ -602,7 +602,6 @@ static unsigned long flow_get(struct tcf_proto *tp, u32 handle)
 
 static void flow_put(struct tcf_proto *tp, unsigned long f)
 {
-       return;
 }
 
 static int flow_dump(struct tcf_proto *tp, unsigned long fh,
index 17c5dfc673209d68670aee8bfb5cbf099a4f0a51..96275422c619e9d2a4e5eecd4fa8b433a526c8ab 100644 (file)
@@ -211,7 +211,7 @@ check_terminal:
 
 deadloop:
        if (net_ratelimit())
-               printk("cls_u32: dead loop\n");
+               printk(KERN_WARNING "cls_u32: dead loop\n");
        return -1;
 }
 
@@ -768,15 +768,15 @@ static struct tcf_proto_ops cls_u32_ops __read_mostly = {
 
 static int __init init_u32(void)
 {
-       printk("u32 classifier\n");
+       pr_info("u32 classifier\n");
 #ifdef CONFIG_CLS_U32_PERF
-       printk("    Performance counters on\n");
+       pr_info("    Performance counters on\n");
 #endif
 #ifdef CONFIG_NET_CLS_IND
-       printk("    input device check on \n");
+       pr_info("    input device check on\n");
 #endif
 #ifdef CONFIG_NET_CLS_ACT
-       printk("    Actions configured \n");
+       pr_info("    Actions configured\n");
 #endif
        return register_tcf_proto_ops(&cls_u32_ops);
 }
index e782bdeedc584254ecf8b544d85a449039016a92..5e37da961f804cfdf17fa30d6434332e32dc1332 100644 (file)
@@ -527,7 +527,8 @@ pop_stack:
 
 stack_overflow:
        if (net_ratelimit())
-               printk("Local stack overflow, increase NET_EMATCH_STACK\n");
+               printk(KERN_WARNING "tc ematch: local stack overflow,"
+                       " increase NET_EMATCH_STACK\n");
        return -1;
 }
 EXPORT_SYMBOL(__tcf_em_tree_match);
index 145268ca57cfeffdfea5751e19c738964b2637db..fe35c1f338c2b25d7c2a4e4ae19123bf4023f6b5 100644 (file)
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 
-static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
+static int qdisc_notify(struct net *net, struct sk_buff *oskb,
+                       struct nlmsghdr *n, u32 clid,
                        struct Qdisc *old, struct Qdisc *new);
-static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
-                        struct Qdisc *q, unsigned long cl, int event);
+static int tclass_notify(struct net *net, struct sk_buff *oskb,
+                        struct nlmsghdr *n, struct Qdisc *q,
+                        unsigned long cl, int event);
 
 /*
 
@@ -639,11 +641,12 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
 }
 EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
 
-static void notify_and_destroy(struct sk_buff *skb, struct nlmsghdr *n, u32 clid,
+static void notify_and_destroy(struct net *net, struct sk_buff *skb,
+                              struct nlmsghdr *n, u32 clid,
                               struct Qdisc *old, struct Qdisc *new)
 {
        if (new || old)
-               qdisc_notify(skb, n, clid, old, new);
+               qdisc_notify(net, skb, n, clid, old, new);
 
        if (old)
                qdisc_destroy(old);
@@ -663,6 +666,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
                       struct Qdisc *new, struct Qdisc *old)
 {
        struct Qdisc *q = old;
+       struct net *net = dev_net(dev);
        int err = 0;
 
        if (parent == NULL) {
@@ -699,12 +703,13 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
                }
 
                if (!ingress) {
-                       notify_and_destroy(skb, n, classid, dev->qdisc, new);
+                       notify_and_destroy(net, skb, n, classid,
+                                          dev->qdisc, new);
                        if (new && !new->ops->attach)
                                atomic_inc(&new->refcnt);
                        dev->qdisc = new ? : &noop_qdisc;
                } else {
-                       notify_and_destroy(skb, n, classid, old, new);
+                       notify_and_destroy(net, skb, n, classid, old, new);
                }
 
                if (dev->flags & IFF_UP)
@@ -722,7 +727,7 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
                                err = -ENOENT;
                }
                if (!err)
-                       notify_and_destroy(skb, n, classid, old, new);
+                       notify_and_destroy(net, skb, n, classid, old, new);
        }
        return err;
 }
@@ -948,10 +953,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        struct Qdisc *p = NULL;
        int err;
 
-       if (!net_eq(net, &init_net))
-               return -EINVAL;
-
-       if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
+       if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
                return -ENODEV;
 
        err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -991,7 +993,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
                if ((err = qdisc_graft(dev, p, skb, n, clid, NULL, q)) != 0)
                        return err;
        } else {
-               qdisc_notify(skb, n, clid, NULL, q);
+               qdisc_notify(net, skb, n, clid, NULL, q);
        }
        return 0;
 }
@@ -1010,16 +1012,13 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        struct Qdisc *q, *p;
        int err;
 
-       if (!net_eq(net, &init_net))
-               return -EINVAL;
-
 replay:
        /* Reinit, just in case something touches this. */
        tcm = NLMSG_DATA(n);
        clid = tcm->tcm_parent;
        q = p = NULL;
 
-       if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
+       if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
                return -ENODEV;
 
        err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -1106,7 +1105,7 @@ replay:
                return -EINVAL;
        err = qdisc_change(q, tca);
        if (err == 0)
-               qdisc_notify(skb, n, clid, NULL, q);
+               qdisc_notify(net, skb, n, clid, NULL, q);
        return err;
 
 create_n_graft:
@@ -1196,8 +1195,9 @@ nla_put_failure:
        return -1;
 }
 
-static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
-                       u32 clid, struct Qdisc *old, struct Qdisc *new)
+static int qdisc_notify(struct net *net, struct sk_buff *oskb,
+                       struct nlmsghdr *n, u32 clid,
+                       struct Qdisc *old, struct Qdisc *new)
 {
        struct sk_buff *skb;
        u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
@@ -1216,7 +1216,7 @@ static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
        }
 
        if (skb->len)
-               return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+               return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
 
 err_out:
        kfree_skb(skb);
@@ -1275,15 +1275,12 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
        int s_idx, s_q_idx;
        struct net_device *dev;
 
-       if (!net_eq(net, &init_net))
-               return 0;
-
        s_idx = cb->args[0];
        s_q_idx = q_idx = cb->args[1];
 
        rcu_read_lock();
        idx = 0;
-       for_each_netdev_rcu(&init_net, dev) {
+       for_each_netdev_rcu(net, dev) {
                struct netdev_queue *dev_queue;
 
                if (idx < s_idx)
@@ -1335,10 +1332,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        u32 qid = TC_H_MAJ(clid);
        int err;
 
-       if (!net_eq(net, &init_net))
-               return -EINVAL;
-
-       if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
+       if ((dev = __dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
                return -ENODEV;
 
        err = nlmsg_parse(n, sizeof(*tcm), tca, TCA_MAX, NULL);
@@ -1419,10 +1413,10 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
                        if (cops->delete)
                                err = cops->delete(q, cl);
                        if (err == 0)
-                               tclass_notify(skb, n, q, cl, RTM_DELTCLASS);
+                               tclass_notify(net, skb, n, q, cl, RTM_DELTCLASS);
                        goto out;
                case RTM_GETTCLASS:
-                       err = tclass_notify(skb, n, q, cl, RTM_NEWTCLASS);
+                       err = tclass_notify(net, skb, n, q, cl, RTM_NEWTCLASS);
                        goto out;
                default:
                        err = -EINVAL;
@@ -1435,7 +1429,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
        if (cops->change)
                err = cops->change(q, clid, pid, tca, &new_cl);
        if (err == 0)
-               tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);
+               tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS);
 
 out:
        if (cl)
@@ -1487,8 +1481,9 @@ nla_put_failure:
        return -1;
 }
 
-static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
-                         struct Qdisc *q, unsigned long cl, int event)
+static int tclass_notify(struct net *net, struct sk_buff *oskb,
+                        struct nlmsghdr *n, struct Qdisc *q,
+                        unsigned long cl, int event)
 {
        struct sk_buff *skb;
        u32 pid = oskb ? NETLINK_CB(oskb).pid : 0;
@@ -1502,7 +1497,7 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
                return -EINVAL;
        }
 
-       return rtnetlink_send(skb, &init_net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
+       return rtnetlink_send(skb, net, pid, RTNLGRP_TC, n->nlmsg_flags&NLM_F_ECHO);
 }
 
 struct qdisc_dump_args
@@ -1577,12 +1572,9 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
        struct net_device *dev;
        int t, s_t;
 
-       if (!net_eq(net, &init_net))
-               return 0;
-
        if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
                return 0;
-       if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
+       if ((dev = dev_get_by_index(net, tcm->tcm_ifindex)) == NULL)
                return 0;
 
        s_t = cb->args[0];
@@ -1645,9 +1637,12 @@ reclassify:
                tp = otp;
 
                if (verd++ >= MAX_REC_LOOP) {
-                       printk("rule prio %u protocol %02x reclassify loop, "
-                              "packet dropped\n",
-                              tp->prio&0xffff, ntohs(tp->protocol));
+                       if (net_ratelimit())
+                               printk(KERN_NOTICE
+                                      "%s: packet reclassify loop"
+                                         " rule prio %u protocol %02x\n",
+                                      tp->q->ops->id,
+                                      tp->prio & 0xffff, ntohs(tp->protocol));
                        return TC_ACT_SHOT;
                }
                skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
@@ -1692,7 +1687,7 @@ static int psched_show(struct seq_file *seq, void *v)
 
 static int psched_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, psched_show, PDE(inode)->data);
+       return single_open(file, psched_show, NULL);
 }
 
 static const struct file_operations psched_fops = {
@@ -1702,15 +1697,53 @@ static const struct file_operations psched_fops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
+
+static int __net_init psched_net_init(struct net *net)
+{
+       struct proc_dir_entry *e;
+
+       e = proc_net_fops_create(net, "psched", 0, &psched_fops);
+       if (e == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void __net_exit psched_net_exit(struct net *net)
+{
+       proc_net_remove(net, "psched");
+}
+#else
+static int __net_init psched_net_init(struct net *net)
+{
+       return 0;
+}
+
+static void __net_exit psched_net_exit(struct net *net)
+{
+}
 #endif
 
+static struct pernet_operations psched_net_ops = {
+       .init = psched_net_init,
+       .exit = psched_net_exit,
+};
+
 static int __init pktsched_init(void)
 {
+       int err;
+
+       err = register_pernet_subsys(&psched_net_ops);
+       if (err) {
+               printk(KERN_ERR "pktsched_init: "
+                      "cannot initialize per netns operations\n");
+               return err;
+       }
+
        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);
 
        rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL);
        rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL);
index ff4dd53eeff013f875330d8fbeb24e3a6e299e5a..a63029ef3eddc9e1bc19cbc552f327e6fdafa8aa 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <net/pkt_sched.h>
+#include <net/dst.h>
 
 /* Main transmission queue. */
 
@@ -40,6 +41,7 @@
 
 static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
 {
+       skb_dst_force(skb);
        q->gso_skb = skb;
        q->qstats.requeues++;
        q->q.qlen++;    /* it's still part of the queue */
@@ -94,7 +96,7 @@ static inline int handle_dev_cpu_collision(struct sk_buff *skb,
                 * Another cpu is holding lock, requeue & delay xmits for
                 * some time.
                 */
-               __get_cpu_var(netdev_rx_stat).cpu_collision++;
+               __get_cpu_var(softnet_data).cpu_collision++;
                ret = dev_requeue_skb(skb, q);
        }
 
@@ -179,7 +181,7 @@ static inline int qdisc_restart(struct Qdisc *q)
        skb = dequeue_skb(q);
        if (unlikely(!skb))
                return 0;
-
+       WARN_ON_ONCE(skb_dst_is_noref(skb));
        root_lock = qdisc_lock(q);
        dev = qdisc_dev(q);
        txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
@@ -529,7 +531,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
        unsigned int size;
        int err = -ENOBUFS;
 
-       /* ensure that the Qdisc and the private data are 32-byte aligned */
+       /* ensure that the Qdisc and the private data are 64-byte aligned */
        size = QDISC_ALIGN(sizeof(*sch));
        size += ops->priv_size + (QDISC_ALIGNTO - 1);
 
@@ -591,6 +593,13 @@ void qdisc_reset(struct Qdisc *qdisc)
 }
 EXPORT_SYMBOL(qdisc_reset);
 
+static void qdisc_rcu_free(struct rcu_head *head)
+{
+       struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head);
+
+       kfree((char *) qdisc - qdisc->padded);
+}
+
 void qdisc_destroy(struct Qdisc *qdisc)
 {
        const struct Qdisc_ops  *ops = qdisc->ops;
@@ -614,7 +623,11 @@ void qdisc_destroy(struct Qdisc *qdisc)
        dev_put(qdisc_dev(qdisc));
 
        kfree_skb(qdisc->gso_skb);
-       kfree((char *) qdisc - qdisc->padded);
+       /*
+        * gen_estimator est_timer() might access qdisc->q.lock,
+        * wait a RCU grace period before freeing qdisc.
+        */
+       call_rcu(&qdisc->rcu_head, qdisc_rcu_free);
 }
 EXPORT_SYMBOL(qdisc_destroy);
 
index b38b39c60752a90a1713c22b9f4d9e0917d11955..abd904be428717462395d62adb682023e64e17a5 100644 (file)
@@ -617,7 +617,6 @@ rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
        rtsc->y = y;
        rtsc->dx = dx;
        rtsc->dy = dy;
-       return;
 }
 
 static void
@@ -1155,7 +1154,7 @@ static struct hfsc_class *
 hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 {
        struct hfsc_sched *q = qdisc_priv(sch);
-       struct hfsc_class *cl;
+       struct hfsc_class *head, *cl;
        struct tcf_result res;
        struct tcf_proto *tcf;
        int result;
@@ -1166,6 +1165,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
                        return cl;
 
        *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
+       head = &q->root;
        tcf = q->root.filter_list;
        while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
 #ifdef CONFIG_NET_CLS_ACT
@@ -1180,6 +1180,8 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
                if ((cl = (struct hfsc_class *)res.class) == NULL) {
                        if ((cl = hfsc_find_class(res.classid, sch)) == NULL)
                                break; /* filter selected invalid classid */
+                       if (cl->level >= head->level)
+                               break; /* filter may only point downwards */
                }
 
                if (cl->level == 0)
@@ -1187,6 +1189,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 
                /* apply inner filter chain */
                tcf = cl->filter_list;
+               head = cl;
        }
 
        /* classification failed, try default class */
index a9e646bdb605138ce8d5ec1435c8acb36c1c4667..f10e34a6844516db924303b29ade38f9f7e8f49d 100644 (file)
@@ -44,7 +44,6 @@ static void ingress_put(struct Qdisc *sch, unsigned long cl)
 
 static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
 {
-       return;
 }
 
 static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch, unsigned long cl)
index b2aba3f5e6fa5cd8bdf127c86d96fd7ab21ebf32..fe91e50f9d98e7f2819242fc5a3b68ff905219a2 100644 (file)
@@ -174,7 +174,6 @@ static unsigned long mq_get(struct Qdisc *sch, u32 classid)
 
 static void mq_put(struct Qdisc *sch, unsigned long cl)
 {
-       return;
 }
 
 static int mq_dump_class(struct Qdisc *sch, unsigned long cl,
index c50876cd87047bace522be68375d193687108ade..6ae251279fc2f53c86aa339d39bff13b71c79991 100644 (file)
@@ -340,7 +340,6 @@ static unsigned long multiq_bind(struct Qdisc *sch, unsigned long parent,
 
 static void multiq_put(struct Qdisc *q, unsigned long cl)
 {
-       return;
 }
 
 static int multiq_dump_class(struct Qdisc *sch, unsigned long cl,
index 81672e0c1b253558a77f6ead32dfd6bfbb995c4e..0748fb1e3a49b397e87d5f1c13169f4b3eb5a980 100644 (file)
@@ -303,7 +303,6 @@ static unsigned long prio_bind(struct Qdisc *sch, unsigned long parent, u32 clas
 
 static void prio_put(struct Qdisc *q, unsigned long cl)
 {
-       return;
 }
 
 static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb,
index 072cdf442f8eeb8ecad1a7b146c93653b25f6964..8d42bb3ba5406b225b7ec209a1fa9eb50a1c101b 100644 (file)
@@ -303,7 +303,6 @@ static unsigned long red_get(struct Qdisc *sch, u32 classid)
 
 static void red_put(struct Qdisc *sch, unsigned long arg)
 {
-       return;
 }
 
 static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
index c5a9ac5660079581ad81b61bef4039da621cf2ad..c65762823f5ee58f8992b494d741ba667c190fad 100644 (file)
@@ -123,8 +123,8 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
        case htons(ETH_P_IP):
        {
                const struct iphdr *iph = ip_hdr(skb);
-               h = iph->daddr;
-               h2 = iph->saddr ^ iph->protocol;
+               h = (__force u32)iph->daddr;
+               h2 = (__force u32)iph->saddr ^ iph->protocol;
                if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
                    (iph->protocol == IPPROTO_TCP ||
                     iph->protocol == IPPROTO_UDP ||
@@ -138,8 +138,8 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
        case htons(ETH_P_IPV6):
        {
                struct ipv6hdr *iph = ipv6_hdr(skb);
-               h = iph->daddr.s6_addr32[3];
-               h2 = iph->saddr.s6_addr32[3] ^ iph->nexthdr;
+               h = (__force u32)iph->daddr.s6_addr32[3];
+               h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr;
                if (iph->nexthdr == IPPROTO_TCP ||
                    iph->nexthdr == IPPROTO_UDP ||
                    iph->nexthdr == IPPROTO_UDPLITE ||
@@ -150,7 +150,7 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
                break;
        }
        default:
-               h = (unsigned long)skb_dst(skb) ^ skb->protocol;
+               h = (unsigned long)skb_dst(skb) ^ (__force u32)skb->protocol;
                h2 = (unsigned long)skb->sk;
        }
 
index 8fb8107ab18847402b94278ee420f9623ed40b8c..0991c640cd3e8f3e5ae836c44b16b9e27f743c7e 100644 (file)
@@ -273,7 +273,11 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt)
        if (max_size < 0)
                goto done;
 
-       if (qopt->limit > 0) {
+       if (q->qdisc != &noop_qdisc) {
+               err = fifo_set_limit(q->qdisc, qopt->limit);
+               if (err)
+                       goto done;
+       } else if (qopt->limit > 0) {
                child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
                if (IS_ERR(child)) {
                        err = PTR_ERR(child);
index 58b3e882a187a1ff3205efa5de37fd9d15c758a8..126b014eb79b495dff682943bb49e151a3faf677 100644 (file)
@@ -37,6 +37,18 @@ menuconfig IP_SCTP
 
 if IP_SCTP
 
+config NET_SCTPPROBE
+       tristate "SCTP: Association probing"
+        depends on PROC_FS && KPROBES
+        ---help---
+        This module allows for capturing the changes to SCTP association
+        state in response to incoming packets. It is used for debugging
+        SCTP congestion control algorithms. If you don't understand
+        what was just said, you don't need it: say N.
+
+        To compile this code as a module, choose M here: the
+        module will be called sctp_probe.
+
 config SCTP_DBG_MSG
        bool "SCTP: Debug messages"
        help
index 6b794734380a805d8a6558d9d5fd5b9458646894..5c30b7a873dfc3eeccf841e2486c7866d26024c9 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_IP_SCTP) += sctp.o
+obj-$(CONFIG_NET_SCTPPROBE) += sctp_probe.o
 
 sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
          protocol.o endpointola.o associola.o \
@@ -11,6 +12,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
          tsnmap.o bind_addr.o socket.o primitive.o \
          output.o input.o debug.o ssnmap.o auth.o
 
+sctp_probe-y := probe.o
+
 sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o
 sctp-$(CONFIG_PROC_FS) += proc.o
 sctp-$(CONFIG_SYSCTL) += sysctl.o
index 99c93ee98ad9dd0317c236e561e25fef069297d0..e41feff19e43690b3ea84f6498d9319dfee02c52 100644 (file)
@@ -87,9 +87,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
        /* Retrieve the SCTP per socket area.  */
        sp = sctp_sk((struct sock *)sk);
 
-       /* Init all variables to a known value.  */
-       memset(asoc, 0, sizeof(struct sctp_association));
-
        /* Discarding const is appropriate here.  */
        asoc->ep = (struct sctp_endpoint *)ep;
        sctp_endpoint_hold(asoc->ep);
@@ -762,7 +759,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
                asoc->peer.retran_path = peer;
        }
 
-       if (asoc->peer.active_path == asoc->peer.retran_path) {
+       if (asoc->peer.active_path == asoc->peer.retran_path &&
+           peer->state != SCTP_UNCONFIRMED) {
                asoc->peer.retran_path = peer;
        }
 
@@ -818,8 +816,6 @@ void sctp_assoc_del_nonprimary_peers(struct sctp_association *asoc,
                if (t != primary)
                        sctp_assoc_rm_peer(asoc, t);
        }
-
-       return;
 }
 
 /* Engage in transport control operations.
@@ -1320,12 +1316,13 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc)
                        /* Keep track of the next transport in case
                         * we don't find any active transport.
                         */
-                       if (!next)
+                       if (t->state != SCTP_UNCONFIRMED && !next)
                                next = t;
                }
        }
 
-       asoc->peer.retran_path = t;
+       if (t)
+               asoc->peer.retran_path = t;
 
        SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_update_retran_path:association"
                                 " %p addr: ",
@@ -1485,7 +1482,7 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len)
        if (asoc->rwnd >= len) {
                asoc->rwnd -= len;
                if (over) {
-                       asoc->rwnd_press = asoc->rwnd;
+                       asoc->rwnd_press += asoc->rwnd;
                        asoc->rwnd = 0;
                }
        } else {
index 3eab6db59a37e5e5a9d40b6afabac39d421af2e3..476caaf100ed740e0b72138721f1baf6ff90f584 100644 (file)
@@ -58,9 +58,9 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
        msg->send_failed = 0;
        msg->send_error = 0;
        msg->can_abandon = 0;
+       msg->can_delay = 1;
        msg->expires_at = 0;
        INIT_LIST_HEAD(&msg->chunks);
-       msg->msg_size = 0;
 }
 
 /* Allocate and initialize datamsg. */
@@ -157,7 +157,6 @@ static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chu
 {
        sctp_datamsg_hold(msg);
        chunk->msg = msg;
-       msg->msg_size += chunk->skb->len;
 }
 
 
@@ -247,6 +246,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
        if (msg_len >= first_len) {
                msg_len -= first_len;
                whole = 1;
+               msg->can_delay = 0;
        }
 
        /* How many full sized?  How many bytes leftover? */
index 7ec09ba03a1cec9e82d6251d9becccf8a8a42a1b..e10acc01c75f90600f6c1cbb59a2e4610977fc96 100644 (file)
@@ -70,8 +70,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
        struct sctp_shared_key *null_key;
        int err;
 
-       memset(ep, 0, sizeof(struct sctp_endpoint));
-
        ep->digest = kzalloc(SCTP_SIGNATURE_SIZE, gfp);
        if (!ep->digest)
                return NULL;
index 9fb5d37c37ad0785fcd2e56b3912baa1a9087de3..732689140fb864d40f0cd109e92288bb74373a4c 100644 (file)
@@ -232,7 +232,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
        if (!(transport->param_flags & SPP_PMTUD_ENABLE))
                skb->local_df = 1;
 
-       return ip6_xmit(sk, skb, &fl, np->opt, 0);
+       return ip6_xmit(sk, skb, &fl, np->opt);
 }
 
 /* Returns the dst cache entry for the given source and destination ip
@@ -277,20 +277,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
                                         union sctp_addr *s2)
 {
-       struct in6_addr *a1 = &s1->v6.sin6_addr;
-       struct in6_addr *a2 = &s2->v6.sin6_addr;
-       int i, j;
-
-       for (i = 0; i < 4 ; i++) {
-               __be32 a1xora2;
-
-               a1xora2 = a1->s6_addr32[i] ^ a2->s6_addr32[i];
-
-               if ((j = fls(ntohl(a1xora2))))
-                       return (i * 32 + 32 - j);
-       }
-
-       return (i*32);
+       return ipv6_addr_diff(&s1->v6.sin6_addr, &s2->v6.sin6_addr);
 }
 
 /* Fills in the source address(saddr) based on the destination address(daddr)
@@ -372,13 +359,13 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
        }
 
        read_lock_bh(&in6_dev->lock);
-       for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
+       list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
                /* Add the address to the local list.  */
                addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
                if (addr) {
                        addr->a.v6.sin6_family = AF_INET6;
                        addr->a.v6.sin6_port = 0;
-                       addr->a.v6.sin6_addr = ifp->addr;
+                       ipv6_addr_copy(&addr->a.v6.sin6_addr, &ifp->addr);
                        addr->a.v6.sin6_scope_id = dev->ifindex;
                        addr->valid = 1;
                        INIT_LIST_HEAD(&addr->list);
@@ -419,7 +406,7 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 {
        addr->v6.sin6_family = AF_INET6;
        addr->v6.sin6_port = 0;
-       addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
+       ipv6_addr_copy(&addr->v6.sin6_addr, &inet6_sk(sk)->rcv_saddr);
 }
 
 /* Initialize sk->sk_rcv_saddr from sctp_addr. */
@@ -432,7 +419,7 @@ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
                inet6_sk(sk)->rcv_saddr.s6_addr32[3] =
                        addr->v4.sin_addr.s_addr;
        } else {
-               inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
+               ipv6_addr_copy(&inet6_sk(sk)->rcv_saddr, &addr->v6.sin6_addr);
        }
 }
 
@@ -445,7 +432,7 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
                inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff);
                inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
        } else {
-               inet6_sk(sk)->daddr = addr->v6.sin6_addr;
+               ipv6_addr_copy(&inet6_sk(sk)->daddr, &addr->v6.sin6_addr);
        }
 }
 
index fad261d41ec2f6fdbb1eb3d323b1a0445f29305a..a646681f5acdffe30cd7b5b2f06c3bbf413609a6 100644 (file)
@@ -429,24 +429,17 @@ int sctp_packet_transmit(struct sctp_packet *packet)
        list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
                list_del_init(&chunk->list);
                if (sctp_chunk_is_data(chunk)) {
+                       /* 6.3.1 C4) When data is in flight and when allowed
+                        * by rule C5, a new RTT measurement MUST be made each
+                        * round trip.  Furthermore, new RTT measurements
+                        * SHOULD be made no more than once per round-trip
+                        * for a given destination transport address.
+                        */
 
-                       if (!chunk->resent) {
-
-                               /* 6.3.1 C4) When data is in flight and when allowed
-                                * by rule C5, a new RTT measurement MUST be made each
-                                * round trip.  Furthermore, new RTT measurements
-                                * SHOULD be made no more than once per round-trip
-                                * for a given destination transport address.
-                                */
-
-                               if (!tp->rto_pending) {
-                                       chunk->rtt_in_progress = 1;
-                                       tp->rto_pending = 1;
-                               }
+                       if (!tp->rto_pending) {
+                               chunk->rtt_in_progress = 1;
+                               tp->rto_pending = 1;
                        }
-
-                       chunk->resent = 1;
-
                        has_data = 1;
                }
 
@@ -681,7 +674,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet,
                 * Don't delay large message writes that may have been
                 * fragmeneted into small peices.
                 */
-               if ((len < max) && (chunk->msg->msg_size < max)) {
+               if ((len < max) && chunk->msg->can_delay) {
                        retval = SCTP_XMIT_NAGLE_DELAY;
                        goto finish;
                }
index abfc0b8dee74ea171c9f974e7a10fe4b9c66b2b9..c04b2eb591868627280269fd5379d2307f9802f7 100644 (file)
@@ -62,7 +62,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                   struct list_head *transmitted_queue,
                                   struct sctp_transport *transport,
                                   struct sctp_sackhdr *sack,
-                                  __u32 highest_new_tsn);
+                                  __u32 *highest_new_tsn);
 
 static void sctp_mark_missing(struct sctp_outq *q,
                              struct list_head *transmitted_queue,
@@ -80,7 +80,6 @@ static inline void sctp_outq_head_data(struct sctp_outq *q,
 {
        list_add(&ch->list, &q->out_chunk_list);
        q->out_qlen += ch->skb->len;
-       return;
 }
 
 /* Take data from the front of the queue. */
@@ -103,7 +102,6 @@ static inline void sctp_outq_tail_data(struct sctp_outq *q,
 {
        list_add_tail(&ch->list, &q->out_chunk_list);
        q->out_qlen += ch->skb->len;
-       return;
 }
 
 /*
@@ -308,7 +306,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
        /* If it is data, queue it up, otherwise, send it
         * immediately.
         */
-       if (SCTP_CID_DATA == chunk->chunk_hdr->type) {
+       if (sctp_chunk_is_data(chunk)) {
                /* Is it OK to queue data chunks?  */
                /* From 9. Termination of Association
                 *
@@ -598,11 +596,23 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                if (fast_rtx && !chunk->fast_retransmit)
                        continue;
 
+redo:
                /* Attempt to append this chunk to the packet. */
                status = sctp_packet_append_chunk(pkt, chunk);
 
                switch (status) {
                case SCTP_XMIT_PMTU_FULL:
+                       if (!pkt->has_data && !pkt->has_cookie_echo) {
+                               /* If this packet did not contain DATA then
+                                * retransmission did not happen, so do it
+                                * again.  We'll ignore the error here since
+                                * control chunks are already freed so there
+                                * is nothing we can do.
+                                */
+                               sctp_packet_transmit(pkt);
+                               goto redo;
+                       }
+
                        /* Send this packet.  */
                        error = sctp_packet_transmit(pkt);
 
@@ -647,14 +657,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
                        if (chunk->fast_retransmit == SCTP_NEED_FRTX)
                                chunk->fast_retransmit = SCTP_DONT_FRTX;
 
-                       /* Force start T3-rtx timer when fast retransmitting
-                        * the earliest outstanding TSN
-                        */
-                       if (!timer && fast_rtx &&
-                           ntohl(chunk->subh.data_hdr->tsn) ==
-                                            asoc->ctsn_ack_point + 1)
-                               timer = 2;
-
                        q->empty = 0;
                        break;
                }
@@ -854,6 +856,12 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                        if (status  != SCTP_XMIT_OK) {
                                /* put the chunk back */
                                list_add(&chunk->list, &q->control_chunk_list);
+                       } else if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) {
+                               /* PR-SCTP C5) If a FORWARD TSN is sent, the
+                                * sender MUST assure that at least one T3-rtx
+                                * timer is running.
+                                */
+                               sctp_transport_reset_timers(transport);
                        }
                        break;
 
@@ -906,8 +914,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                                                    rtx_timeout, &start_timer);
 
                        if (start_timer)
-                               sctp_transport_reset_timers(transport,
-                                                           start_timer-1);
+                               sctp_transport_reset_timers(transport);
 
                        /* This can happen on COOKIE-ECHO resend.  Only
                         * one chunk can get bundled with a COOKIE-ECHO.
@@ -1040,7 +1047,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                        list_add_tail(&chunk->transmitted_list,
                                      &transport->transmitted);
 
-                       sctp_transport_reset_timers(transport, 0);
+                       sctp_transport_reset_timers(transport);
 
                        q->empty = 0;
 
@@ -1100,32 +1107,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc,
        assoc->unack_data = unack_data;
 }
 
-/* Return the highest new tsn that is acknowledged by the given SACK chunk. */
-static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
-                                 struct sctp_association *asoc)
-{
-       struct sctp_transport *transport;
-       struct sctp_chunk *chunk;
-       __u32 highest_new_tsn, tsn;
-       struct list_head *transport_list = &asoc->peer.transport_addr_list;
-
-       highest_new_tsn = ntohl(sack->cum_tsn_ack);
-
-       list_for_each_entry(transport, transport_list, transports) {
-               list_for_each_entry(chunk, &transport->transmitted,
-                               transmitted_list) {
-                       tsn = ntohl(chunk->subh.data_hdr->tsn);
-
-                       if (!chunk->tsn_gap_acked &&
-                           TSN_lt(highest_new_tsn, tsn) &&
-                           sctp_acked(sack, tsn))
-                               highest_new_tsn = tsn;
-               }
-       }
-
-       return highest_new_tsn;
-}
-
 /* This is where we REALLY process a SACK.
  *
  * Process the SACK against the outqueue.  Mostly, this just frees
@@ -1145,6 +1126,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        struct sctp_transport *primary = asoc->peer.primary_path;
        int count_of_newacks = 0;
        int gap_ack_blocks;
+       u8 accum_moved = 0;
 
        /* Grab the association's destination address list. */
        transport_list = &asoc->peer.transport_addr_list;
@@ -1193,18 +1175,15 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
        if (gap_ack_blocks)
                highest_tsn += ntohs(frags[gap_ack_blocks - 1].gab.end);
 
-       if (TSN_lt(asoc->highest_sacked, highest_tsn)) {
-               highest_new_tsn = highest_tsn;
+       if (TSN_lt(asoc->highest_sacked, highest_tsn))
                asoc->highest_sacked = highest_tsn;
-       } else {
-               highest_new_tsn = sctp_highest_new_tsn(sack, asoc);
-       }
 
+       highest_new_tsn = sack_ctsn;
 
        /* Run through the retransmit queue.  Credit bytes received
         * and free those chunks that we can.
         */
-       sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn);
+       sctp_check_transmitted(q, &q->retransmit, NULL, sack, &highest_new_tsn);
 
        /* Run through the transmitted queue.
         * Credit bytes received and free those chunks which we can.
@@ -1213,7 +1192,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
         */
        list_for_each_entry(transport, transport_list, transports) {
                sctp_check_transmitted(q, &transport->transmitted,
-                                      transport, sack, highest_new_tsn);
+                                      transport, sack, &highest_new_tsn);
                /*
                 * SFR-CACC algorithm:
                 * C) Let count_of_newacks be the number of
@@ -1223,16 +1202,22 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
                        count_of_newacks ++;
        }
 
+       /* Move the Cumulative TSN Ack Point if appropriate.  */
+       if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn)) {
+               asoc->ctsn_ack_point = sack_ctsn;
+               accum_moved = 1;
+       }
+
        if (gap_ack_blocks) {
+
+               if (asoc->fast_recovery && accum_moved)
+                       highest_new_tsn = highest_tsn;
+
                list_for_each_entry(transport, transport_list, transports)
                        sctp_mark_missing(q, &transport->transmitted, transport,
                                          highest_new_tsn, count_of_newacks);
        }
 
-       /* Move the Cumulative TSN Ack Point if appropriate.  */
-       if (TSN_lt(asoc->ctsn_ack_point, sack_ctsn))
-               asoc->ctsn_ack_point = sack_ctsn;
-
        /* Update unack_data field in the assoc. */
        sctp_sack_update_unack_data(asoc, sack);
 
@@ -1315,7 +1300,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                   struct list_head *transmitted_queue,
                                   struct sctp_transport *transport,
                                   struct sctp_sackhdr *sack,
-                                  __u32 highest_new_tsn_in_sack)
+                                  __u32 *highest_new_tsn_in_sack)
 {
        struct list_head *lchunk;
        struct sctp_chunk *tchunk;
@@ -1387,7 +1372,6 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                                 * instance).
                                 */
                                if (!tchunk->tsn_gap_acked &&
-                                   !tchunk->resent &&
                                    tchunk->rtt_in_progress) {
                                        tchunk->rtt_in_progress = 0;
                                        rtt = jiffies - tchunk->sent_at;
@@ -1404,6 +1388,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
                         */
                        if (!tchunk->tsn_gap_acked) {
                                tchunk->tsn_gap_acked = 1;
+                               *highest_new_tsn_in_sack = tsn;
                                bytes_acked += sctp_data_size(tchunk);
                                if (!tchunk->transport)
                                        migrate_bytes += sctp_data_size(tchunk);
@@ -1677,7 +1662,8 @@ static void sctp_mark_missing(struct sctp_outq *q,
        struct sctp_chunk *chunk;
        __u32 tsn;
        char do_fast_retransmit = 0;
-       struct sctp_transport *primary = q->asoc->peer.primary_path;
+       struct sctp_association *asoc = q->asoc;
+       struct sctp_transport *primary = asoc->peer.primary_path;
 
        list_for_each_entry(chunk, transmitted_queue, transmitted_list) {
 
diff --git a/net/sctp/probe.c b/net/sctp/probe.c
new file mode 100644 (file)
index 0000000..db3a42b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * sctp_probe - Observe the SCTP flow with kprobes.
+ *
+ * The idea for this came from Werner Almesberger's umlsim
+ * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+ *
+ * Modified for SCTP from Stephen Hemminger's code
+ * Copyright (C) 2010, Wei Yongjun <yjwei@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/socket.h>
+#include <linux/sctp.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/kfifo.h>
+#include <linux/time.h>
+#include <net/net_namespace.h>
+
+#include <net/sctp/sctp.h>
+#include <net/sctp/sm.h>
+
+MODULE_AUTHOR("Wei Yongjun <yjwei@cn.fujitsu.com>");
+MODULE_DESCRIPTION("SCTP snooper");
+MODULE_LICENSE("GPL");
+
+static int port __read_mostly = 0;
+MODULE_PARM_DESC(port, "Port to match (0=all)");
+module_param(port, int, 0);
+
+static int bufsize __read_mostly = 64 * 1024;
+MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
+module_param(bufsize, int, 0);
+
+static int full __read_mostly = 1;
+MODULE_PARM_DESC(full, "Full log (1=every ack packet received,  0=only cwnd changes)");
+module_param(full, int, 0);
+
+static const char procname[] = "sctpprobe";
+
+static struct {
+       struct kfifo      fifo;
+       spinlock_t        lock;
+       wait_queue_head_t wait;
+       struct timespec   tstart;
+} sctpw;
+
+static void printl(const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       char tbuf[256];
+
+       va_start(args, fmt);
+       len = vscnprintf(tbuf, sizeof(tbuf), fmt, args);
+       va_end(args);
+
+       kfifo_in_locked(&sctpw.fifo, tbuf, len, &sctpw.lock);
+       wake_up(&sctpw.wait);
+}
+
+static int sctpprobe_open(struct inode *inode, struct file *file)
+{
+       kfifo_reset(&sctpw.fifo);
+       getnstimeofday(&sctpw.tstart);
+
+       return 0;
+}
+
+static ssize_t sctpprobe_read(struct file *file, char __user *buf,
+                             size_t len, loff_t *ppos)
+{
+       int error = 0, cnt = 0;
+       unsigned char *tbuf;
+
+       if (!buf)
+               return -EINVAL;
+
+       if (len == 0)
+               return 0;
+
+       tbuf = vmalloc(len);
+       if (!tbuf)
+               return -ENOMEM;
+
+       error = wait_event_interruptible(sctpw.wait,
+                                        kfifo_len(&sctpw.fifo) != 0);
+       if (error)
+               goto out_free;
+
+       cnt = kfifo_out_locked(&sctpw.fifo, tbuf, len, &sctpw.lock);
+       error = copy_to_user(buf, tbuf, cnt) ? -EFAULT : 0;
+
+out_free:
+       vfree(tbuf);
+
+       return error ? error : cnt;
+}
+
+static const struct file_operations sctpprobe_fops = {
+       .owner  = THIS_MODULE,
+       .open   = sctpprobe_open,
+       .read   = sctpprobe_read,
+};
+
+sctp_disposition_t jsctp_sf_eat_sack(const struct sctp_endpoint *ep,
+                                    const struct sctp_association *asoc,
+                                    const sctp_subtype_t type,
+                                    void *arg,
+                                    sctp_cmd_seq_t *commands)
+{
+       struct sctp_transport *sp;
+       static __u32 lcwnd = 0;
+       struct timespec now;
+
+       sp = asoc->peer.primary_path;
+
+       if ((full || sp->cwnd != lcwnd) &&
+           (!port || asoc->peer.port == port ||
+            ep->base.bind_addr.port == port)) {
+               lcwnd = sp->cwnd;
+
+               getnstimeofday(&now);
+               now = timespec_sub(now, sctpw.tstart);
+
+               printl("%lu.%06lu ", (unsigned long) now.tv_sec,
+                      (unsigned long) now.tv_nsec / NSEC_PER_USEC);
+
+               printl("%p %5d %5d %5d %8d %5d ", asoc,
+                      ep->base.bind_addr.port, asoc->peer.port,
+                      asoc->pathmtu, asoc->peer.rwnd, asoc->unack_data);
+
+               list_for_each_entry(sp, &asoc->peer.transport_addr_list,
+                                       transports) {
+                       if (sp == asoc->peer.primary_path)
+                               printl("*");
+
+                       if (sp->ipaddr.sa.sa_family == AF_INET)
+                               printl("%pI4 ", &sp->ipaddr.v4.sin_addr);
+                       else
+                               printl("%pI6 ", &sp->ipaddr.v6.sin6_addr);
+
+                       printl("%2u %8u %8u %8u %8u %8u ",
+                              sp->state, sp->cwnd, sp->ssthresh,
+                              sp->flight_size, sp->partial_bytes_acked,
+                              sp->pathmtu);
+               }
+               printl("\n");
+       }
+
+       jprobe_return();
+       return 0;
+}
+
+static struct jprobe sctp_recv_probe = {
+       .kp     = {
+               .symbol_name = "sctp_sf_eat_sack_6_2",
+       },
+       .entry  = jsctp_sf_eat_sack,
+};
+
+static __init int sctpprobe_init(void)
+{
+       int ret = -ENOMEM;
+
+       init_waitqueue_head(&sctpw.wait);
+       spin_lock_init(&sctpw.lock);
+       if (kfifo_alloc(&sctpw.fifo, bufsize, GFP_KERNEL))
+               return ret;
+
+       if (!proc_net_fops_create(&init_net, procname, S_IRUSR,
+                                 &sctpprobe_fops))
+               goto free_kfifo;
+
+       ret = register_jprobe(&sctp_recv_probe);
+       if (ret)
+               goto remove_proc;
+
+       pr_info("SCTP probe registered (port=%d)\n", port);
+
+       return 0;
+
+remove_proc:
+       proc_net_remove(&init_net, procname);
+free_kfifo:
+       kfifo_free(&sctpw.fifo);
+       return ret;
+}
+
+static __exit void sctpprobe_exit(void)
+{
+       kfifo_free(&sctpw.fifo);
+       proc_net_remove(&init_net, procname);
+       unregister_jprobe(&sctp_recv_probe);
+}
+
+module_init(sctpprobe_init);
+module_exit(sctpprobe_exit);
index 784bcc9a979d22b284f4638b3fbf3a9a555b963d..61aacfbbaa92f55829730687fdf0026d123301d1 100644 (file)
@@ -181,7 +181,6 @@ static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
 
 static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
 {
-       return;
 }
 
 
@@ -286,7 +285,6 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
 
 static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
 {
-       return;
 }
 
 
@@ -409,7 +407,6 @@ static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
 static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v)
 {
-       return;
 }
 
 static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
index a56f98e82f92f0a0dbd53d2045ab7d8053ab1454..182749867c72a4c2b629d8675e1ad2de6340a536 100644 (file)
@@ -474,13 +474,17 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
 
        memset(&fl, 0x0, sizeof(struct flowi));
        fl.fl4_dst  = daddr->v4.sin_addr.s_addr;
+       fl.fl_ip_dport = daddr->v4.sin_port;
        fl.proto = IPPROTO_SCTP;
        if (asoc) {
                fl.fl4_tos = RT_CONN_FLAGS(asoc->base.sk);
                fl.oif = asoc->base.sk->sk_bound_dev_if;
+               fl.fl_ip_sport = htons(asoc->base.bind_addr.port);
        }
-       if (saddr)
+       if (saddr) {
                fl.fl4_src = saddr->v4.sin_addr.s_addr;
+               fl.fl_ip_sport = saddr->v4.sin_port;
+       }
 
        SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
                          __func__, &fl.fl4_dst, &fl.fl4_src);
@@ -528,6 +532,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
                if ((laddr->state == SCTP_ADDR_SRC) &&
                    (AF_INET == laddr->a.sa.sa_family)) {
                        fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
+                       fl.fl_ip_sport = laddr->a.v4.sin_port;
                        if (!ip_route_output_key(&init_net, &rt, &fl)) {
                                dst = &rt->u.dst;
                                goto out_unlock;
@@ -854,7 +859,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
                         IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
 
        SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
-       return ip_queue_xmit(skb, 0);
+       return ip_queue_xmit(skb);
 }
 
 static struct sctp_af sctp_af_inet;
index 30c1767186b8af2d6091eaab4e9b77ee1f831215..bd2a50b482ace5089f4857b6aa56a6f066e0f683 100644 (file)
@@ -141,7 +141,7 @@ int sctp_init_cause_fixed(struct sctp_chunk *chunk, __be16 cause_code,
        len = sizeof(sctp_errhdr_t) + paylen;
        err.length  = htons(len);
 
-       if (skb_tailroom(chunk->skb)  len)
+       if (skb_tailroom(chunk->skb) < len)
                return -ENOSPC;
        chunk->subh.err_hdr = sctp_addto_chunk_fixed(chunk,
                                                     sizeof(sctp_errhdr_t),
@@ -445,10 +445,17 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (!retval)
                goto nomem_chunk;
 
-       /* Per the advice in RFC 2960 6.4, send this reply to
-        * the source of the INIT packet.
+       /* RFC 2960 6.4 Multi-homed SCTP Endpoints
+        *
+        * An endpoint SHOULD transmit reply chunks (e.g., SACK,
+        * HEARTBEAT ACK, * etc.) to the same destination transport
+        * address from which it received the DATA or control chunk
+        * to which it is replying.
+        *
+        * [INIT ACK back to where the INIT came from.]
         */
        retval->transport = chunk->transport;
+
        retval->subh.init_hdr =
                sctp_addto_chunk(retval, sizeof(initack), &initack);
        retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v);
@@ -487,18 +494,6 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        /* We need to remove the const qualifier at this point.  */
        retval->asoc = (struct sctp_association *) asoc;
 
-       /* RFC 2960 6.4 Multi-homed SCTP Endpoints
-        *
-        * An endpoint SHOULD transmit reply chunks (e.g., SACK,
-        * HEARTBEAT ACK, * etc.) to the same destination transport
-        * address from which it received the DATA or control chunk
-        * to which it is replying.
-        *
-        * [INIT ACK back to where the INIT came from.]
-        */
-       if (chunk)
-               retval->transport = chunk->transport;
-
 nomem_chunk:
        kfree(cookie);
 nomem_cookie:
@@ -1254,7 +1249,6 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
        INIT_LIST_HEAD(&retval->list);
        retval->skb             = skb;
        retval->asoc            = (struct sctp_association *)asoc;
-       retval->resent          = 0;
        retval->has_tsn         = 0;
        retval->has_ssn         = 0;
        retval->rtt_in_progress = 0;
@@ -1421,7 +1415,7 @@ void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
 void *sctp_addto_chunk_fixed(struct sctp_chunk *chunk,
                             int len, const void *data)
 {
-       if (skb_tailroom(chunk->skb) > len)
+       if (skb_tailroom(chunk->skb) >= len)
                return sctp_addto_chunk(chunk, len, data);
        else
                return NULL;
index eb1f42f45fdde604512f1eefcced4041843e51f8..f5e5e27cac5ee5918f815fecf1cebbbc6be3203e 100644 (file)
@@ -732,11 +732,15 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds,
 {
        struct sctp_transport *t;
 
-       t = sctp_assoc_choose_alter_transport(asoc,
+       if (chunk->transport)
+               t = chunk->transport;
+       else {
+               t = sctp_assoc_choose_alter_transport(asoc,
                                              asoc->shutdown_last_sent_to);
+               chunk->transport = t;
+       }
        asoc->shutdown_last_sent_to = t;
        asoc->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = t->rto;
-       chunk->transport = t;
 }
 
 /* Helper function to change the state of an association. */
@@ -888,8 +892,6 @@ static void sctp_cmd_process_fwdtsn(struct sctp_ulpq *ulpq,
        sctp_walk_fwdtsn(skip, chunk) {
                sctp_ulpq_skip(ulpq, ntohs(skip->stream), ntohs(skip->ssn));
        }
-
-       return;
 }
 
 /* Helper function to remove the association non-primary peer
@@ -908,8 +910,6 @@ static void sctp_cmd_del_non_primary(struct sctp_association *asoc)
                        sctp_assoc_del_peer(asoc, &t->ipaddr);
                }
        }
-
-       return;
 }
 
 /* Helper function to set sk_err on a 1-1 style socket. */
index 44a1ab03a3f0124ac33c63aa62f54b5663b52914..ca44917872d2553b98f4e2f3601f95fe0f2c414f 100644 (file)
@@ -3720,9 +3720,6 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
 
        SCTP_DBG_OBJCNT_INC(sock);
 
-       /* Set socket backlog limit. */
-       sk->sk_backlog.limit = sysctl_sctp_rmem[1];
-
        local_bh_disable();
        percpu_counter_inc(&sctp_sockets_allocated);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
@@ -4387,7 +4384,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
                                transports) {
                memcpy(&temp, &from->ipaddr, sizeof(temp));
                sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
-               addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
+               addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
                if (space_left < addrlen)
                        return -ENOMEM;
                if (copy_to_user(to, &temp, addrlen))
@@ -5436,6 +5433,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                        rover++;
                        if ((rover < low) || (rover > high))
                                rover = low;
+                       if (inet_is_reserved_local_port(rover))
+                               continue;
                        index = sctp_phashfn(rover);
                        head = &sctp_port_hashtable[index];
                        sctp_spin_lock(&head->lock);
@@ -5482,7 +5481,6 @@ pp_found:
                 */
                int reuse = sk->sk_reuse;
                struct sock *sk2;
-               struct hlist_node *node;
 
                SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
                if (pp->fastreuse && sk->sk_reuse &&
@@ -5703,7 +5701,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        struct sctp_sock *sp = sctp_sk(sk);
        unsigned int mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       poll_wait(file, sk_sleep(sk), wait);
 
        /* A TCP-style listening socket becomes readable when the accept queue
         * is not empty.
@@ -5944,7 +5942,7 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
        int error;
        DEFINE_WAIT(wait);
 
-       prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+       prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
        /* Socket errors? */
        error = sock_error(sk);
@@ -5981,14 +5979,14 @@ static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
        sctp_lock_sock(sk);
 
 ready:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        return 0;
 
 interrupted:
        error = sock_intr_errno(*timeo_p);
 
 out:
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        *err = error;
        return error;
 }
@@ -6062,14 +6060,14 @@ static void __sctp_write_space(struct sctp_association *asoc)
                        wake_up_interruptible(&asoc->wait);
 
                if (sctp_writeable(sk)) {
-                       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-                               wake_up_interruptible(sk->sk_sleep);
+                       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+                               wake_up_interruptible(sk_sleep(sk));
 
                        /* Note that we try to include the Async I/O support
                         * here by modeling from the current TCP/UDP code.
                         * We have not tested with it yet.
                         */
-                       if (sock->fasync_list &&
+                       if (sock->wq->fasync_list &&
                            !(sk->sk_shutdown & SEND_SHUTDOWN))
                                sock_wake_async(sock,
                                                SOCK_WAKE_SPACE, POLL_OUT);
@@ -6191,12 +6189,15 @@ do_nonblock:
 
 void sctp_data_ready(struct sock *sk, int len)
 {
-       read_lock_bh(&sk->sk_callback_lock);
-       if (sk_has_sleeper(sk))
-               wake_up_interruptible_sync_poll(sk->sk_sleep, POLLIN |
+       struct socket_wq *wq;
+
+       rcu_read_lock();
+       wq = rcu_dereference(sk->sk_wq);
+       if (wq_has_sleeper(wq))
+               wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
                                                POLLRDNORM | POLLRDBAND);
        sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
-       read_unlock_bh(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 /* If socket sndbuf has changed, wake up all per association waiters.  */
@@ -6307,7 +6308,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
 
 
        for (;;) {
-               prepare_to_wait_exclusive(sk->sk_sleep, &wait,
+               prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                          TASK_INTERRUPTIBLE);
 
                if (list_empty(&ep->asocs)) {
@@ -6333,7 +6334,7 @@ static int sctp_wait_for_accept(struct sock *sk, long timeo)
                        break;
        }
 
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
 
        return err;
 }
@@ -6343,7 +6344,7 @@ static void sctp_wait_for_close(struct sock *sk, long timeout)
        DEFINE_WAIT(wait);
 
        do {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (list_empty(&sctp_sk(sk)->ep->asocs))
                        break;
                sctp_release_sock(sk);
@@ -6351,7 +6352,7 @@ static void sctp_wait_for_close(struct sock *sk, long timeout)
                sctp_lock_sock(sk);
        } while (!signal_pending(current) && timeout);
 
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
 }
 
 static void sctp_skb_set_owner_r_frag(struct sk_buff *skb, struct sock *sk)
index 165d54e07fcd4bc571642fff9ad020411e417c00..132046cb82fc764ae758a0535aad8816946ae1d2 100644 (file)
@@ -64,9 +64,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
        /* Copy in the address.  */
        peer->ipaddr = *addr;
        peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
-       peer->asoc = NULL;
-
-       peer->dst = NULL;
        memset(&peer->saddr, 0, sizeof(union sctp_addr));
 
        /* From 6.3.1 RTO Calculation:
@@ -76,34 +73,21 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
         * parameter 'RTO.Initial'.
         */
        peer->rto = msecs_to_jiffies(sctp_rto_initial);
-       peer->rtt = 0;
-       peer->rttvar = 0;
-       peer->srtt = 0;
-       peer->rto_pending = 0;
-       peer->hb_sent = 0;
-       peer->fast_recovery = 0;
 
        peer->last_time_heard = jiffies;
        peer->last_time_ecne_reduced = jiffies;
 
-       peer->init_sent_count = 0;
-
        peer->param_flags = SPP_HB_DISABLE |
                            SPP_PMTUD_ENABLE |
                            SPP_SACKDELAY_ENABLE;
-       peer->hbinterval  = 0;
 
        /* Initialize the default path max_retrans.  */
        peer->pathmaxrxt  = sctp_max_retrans_path;
-       peer->error_count = 0;
 
        INIT_LIST_HEAD(&peer->transmitted);
        INIT_LIST_HEAD(&peer->send_ready);
        INIT_LIST_HEAD(&peer->transports);
 
-       peer->T3_rtx_timer.expires = 0;
-       peer->hb_timer.expires = 0;
-
        setup_timer(&peer->T3_rtx_timer, sctp_generate_t3_rtx_event,
                        (unsigned long)peer);
        setup_timer(&peer->hb_timer, sctp_generate_heartbeat_event,
@@ -115,15 +99,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
        get_random_bytes(&peer->hb_nonce, sizeof(peer->hb_nonce));
 
        atomic_set(&peer->refcnt, 1);
-       peer->dead = 0;
-
-       peer->malloced = 0;
-
-       /* Initialize the state information for SFR-CACC */
-       peer->cacc.changeover_active = 0;
-       peer->cacc.cycling_changeover = 0;
-       peer->cacc.next_tsn_at_change = 0;
-       peer->cacc.cacc_saw_newack = 0;
 
        return peer;
 }
@@ -201,7 +176,7 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
 /* Start T3_rtx timer if it is not already running and update the heartbeat
  * timer.  This routine is called every time a DATA chunk is sent.
  */
-void sctp_transport_reset_timers(struct sctp_transport *transport, int force)
+void sctp_transport_reset_timers(struct sctp_transport *transport)
 {
        /* RFC 2960 6.3.2 Retransmission Timer Rules
         *
@@ -211,7 +186,7 @@ void sctp_transport_reset_timers(struct sctp_transport *transport, int force)
         * address.
         */
 
-       if (force || !timer_pending(&transport->T3_rtx_timer))
+       if (!timer_pending(&transport->T3_rtx_timer))
                if (!mod_timer(&transport->T3_rtx_timer,
                               jiffies + transport->rto))
                        sctp_transport_hold(transport);
@@ -409,15 +384,16 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
 void sctp_transport_raise_cwnd(struct sctp_transport *transport,
                               __u32 sack_ctsn, __u32 bytes_acked)
 {
+       struct sctp_association *asoc = transport->asoc;
        __u32 cwnd, ssthresh, flight_size, pba, pmtu;
 
        cwnd = transport->cwnd;
        flight_size = transport->flight_size;
 
        /* See if we need to exit Fast Recovery first */
-       if (transport->fast_recovery &&
-           TSN_lte(transport->fast_recovery_exit, sack_ctsn))
-               transport->fast_recovery = 0;
+       if (asoc->fast_recovery &&
+           TSN_lte(asoc->fast_recovery_exit, sack_ctsn))
+               asoc->fast_recovery = 0;
 
        /* The appropriate cwnd increase algorithm is performed if, and only
         * if the cumulative TSN whould advanced and the congestion window is
@@ -446,7 +422,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
                 *    2) the destination's path MTU.  This upper bound protects
                 *    against the ACK-Splitting attack outlined in [SAVAGE99].
                 */
-               if (transport->fast_recovery)
+               if (asoc->fast_recovery)
                        return;
 
                if (bytes_acked > pmtu)
@@ -497,6 +473,8 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
 void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                               sctp_lower_cwnd_t reason)
 {
+       struct sctp_association *asoc = transport->asoc;
+
        switch (reason) {
        case SCTP_LOWER_CWND_T3_RTX:
                /* RFC 2960 Section 7.2.3, sctpimpguide
@@ -507,11 +485,11 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 *      partial_bytes_acked = 0
                 */
                transport->ssthresh = max(transport->cwnd/2,
-                                         4*transport->asoc->pathmtu);
-               transport->cwnd = transport->asoc->pathmtu;
+                                         4*asoc->pathmtu);
+               transport->cwnd = asoc->pathmtu;
 
-               /* T3-rtx also clears fast recovery on the transport */
-               transport->fast_recovery = 0;
+               /* T3-rtx also clears fast recovery */
+               asoc->fast_recovery = 0;
                break;
 
        case SCTP_LOWER_CWND_FAST_RTX:
@@ -527,15 +505,15 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 *      cwnd = ssthresh
                 *      partial_bytes_acked = 0
                 */
-               if (transport->fast_recovery)
+               if (asoc->fast_recovery)
                        return;
 
                /* Mark Fast recovery */
-               transport->fast_recovery = 1;
-               transport->fast_recovery_exit = transport->asoc->next_tsn - 1;
+               asoc->fast_recovery = 1;
+               asoc->fast_recovery_exit = asoc->next_tsn - 1;
 
                transport->ssthresh = max(transport->cwnd/2,
-                                         4*transport->asoc->pathmtu);
+                                         4*asoc->pathmtu);
                transport->cwnd = transport->ssthresh;
                break;
 
@@ -555,7 +533,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                if (time_after(jiffies, transport->last_time_ecne_reduced +
                                        transport->rtt)) {
                        transport->ssthresh = max(transport->cwnd/2,
-                                                 4*transport->asoc->pathmtu);
+                                                 4*asoc->pathmtu);
                        transport->cwnd = transport->ssthresh;
                        transport->last_time_ecne_reduced = jiffies;
                }
@@ -571,7 +549,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 * interval.
                 */
                transport->cwnd = max(transport->cwnd/2,
-                                        4*transport->asoc->pathmtu);
+                                        4*asoc->pathmtu);
                break;
        }
 
@@ -656,7 +634,6 @@ void sctp_transport_reset(struct sctp_transport *t)
        t->error_count = 0;
        t->rto_pending = 0;
        t->hb_sent = 0;
-       t->fast_recovery = 0;
 
        /* Initialize the state information for SFR-CACC */
        t->cacc.changeover_active = 0;
index 3a448536f0b6b4c98d3ae2966c51f686ee068760..c7f7e49609cbf4e1732a99b51686f73f03616f45 100644 (file)
@@ -955,7 +955,6 @@ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
         * ordering and deliver them if needed.
         */
        sctp_ulpq_reap_ordered(ulpq, sid);
-       return;
 }
 
 static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
@@ -1064,7 +1063,6 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
        }
 
        sk_mem_reclaim(asoc->base.sk);
-       return;
 }
 
 
index 5e8d0af3c0e73b3537c1852eee2c15a917e4a605..f9f7d0872cacf96cb7e5d4716b5b4c2358b13dae 100644 (file)
@@ -252,9 +252,14 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
-       init_waitqueue_head(&ei->socket.wait);
+       ei->socket.wq = kmalloc(sizeof(struct socket_wq), GFP_KERNEL);
+       if (!ei->socket.wq) {
+               kmem_cache_free(sock_inode_cachep, ei);
+               return NULL;
+       }
+       init_waitqueue_head(&ei->socket.wq->wait);
+       ei->socket.wq->fasync_list = NULL;
 
-       ei->socket.fasync_list = NULL;
        ei->socket.state = SS_UNCONNECTED;
        ei->socket.flags = 0;
        ei->socket.ops = NULL;
@@ -264,10 +269,21 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        return &ei->vfs_inode;
 }
 
+
+static void wq_free_rcu(struct rcu_head *head)
+{
+       struct socket_wq *wq = container_of(head, struct socket_wq, rcu);
+
+       kfree(wq);
+}
+
 static void sock_destroy_inode(struct inode *inode)
 {
-       kmem_cache_free(sock_inode_cachep,
-                       container_of(inode, struct socket_alloc, vfs_inode));
+       struct socket_alloc *ei;
+
+       ei = container_of(inode, struct socket_alloc, vfs_inode);
+       call_rcu(&ei->socket.wq->rcu, wq_free_rcu);
+       kmem_cache_free(sock_inode_cachep, ei);
 }
 
 static void init_once(void *foo)
@@ -513,7 +529,7 @@ void sock_release(struct socket *sock)
                module_put(owner);
        }
 
-       if (sock->fasync_list)
+       if (sock->wq->fasync_list)
                printk(KERN_ERR "sock_release: fasync list not empty!\n");
 
        percpu_sub(sockets_in_use, 1);
@@ -620,10 +636,9 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
                                 sizeof(tv), &tv);
                } else {
-                       struct timespec ts;
-                       skb_get_timestampns(skb, &ts);
+                       skb_get_timestampns(skb, &ts[0]);
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
-                                sizeof(ts), &ts);
+                                sizeof(ts[0]), &ts[0]);
                }
        }
 
@@ -656,13 +671,13 @@ inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff
                        sizeof(__u32), &skb->dropcount);
 }
 
-void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb)
 {
        sock_recv_timestamp(msg, sk, skb);
        sock_recv_drops(msg, sk, skb);
 }
-EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops);
+EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops);
 
 static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
                                       struct msghdr *msg, size_t size, int flags)
@@ -1068,87 +1083,44 @@ static int sock_close(struct inode *inode, struct file *filp)
  *     1. fasync_list is modified only under process context socket lock
  *        i.e. under semaphore.
  *     2. fasync_list is used under read_lock(&sk->sk_callback_lock)
- *        or under socket lock.
- *     3. fasync_list can be used from softirq context, so that
- *        modification under socket lock have to be enhanced with
- *        write_lock_bh(&sk->sk_callback_lock).
- *                                                     --ANK (990710)
+ *        or under socket lock
  */
 
 static int sock_fasync(int fd, struct file *filp, int on)
 {
-       struct fasync_struct *fa, *fna = NULL, **prev;
-       struct socket *sock;
-       struct sock *sk;
-
-       if (on) {
-               fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
-               if (fna == NULL)
-                       return -ENOMEM;
-       }
-
-       sock = filp->private_data;
+       struct socket *sock = filp->private_data;
+       struct sock *sk = sock->sk;
 
-       sk = sock->sk;
-       if (sk == NULL) {
-               kfree(fna);
+       if (sk == NULL)
                return -EINVAL;
-       }
 
        lock_sock(sk);
 
-       spin_lock(&filp->f_lock);
-       if (on)
-               filp->f_flags |= FASYNC;
-       else
-               filp->f_flags &= ~FASYNC;
-       spin_unlock(&filp->f_lock);
+       fasync_helper(fd, filp, on, &sock->wq->fasync_list);
 
-       prev = &(sock->fasync_list);
-
-       for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev)
-               if (fa->fa_file == filp)
-                       break;
-
-       if (on) {
-               if (fa != NULL) {
-                       write_lock_bh(&sk->sk_callback_lock);
-                       fa->fa_fd = fd;
-                       write_unlock_bh(&sk->sk_callback_lock);
-
-                       kfree(fna);
-                       goto out;
-               }
-               fna->fa_file = filp;
-               fna->fa_fd = fd;
-               fna->magic = FASYNC_MAGIC;
-               fna->fa_next = sock->fasync_list;
-               write_lock_bh(&sk->sk_callback_lock);
-               sock->fasync_list = fna;
+       if (!sock->wq->fasync_list)
+               sock_reset_flag(sk, SOCK_FASYNC);
+       else
                sock_set_flag(sk, SOCK_FASYNC);
-               write_unlock_bh(&sk->sk_callback_lock);
-       } else {
-               if (fa != NULL) {
-                       write_lock_bh(&sk->sk_callback_lock);
-                       *prev = fa->fa_next;
-                       if (!sock->fasync_list)
-                               sock_reset_flag(sk, SOCK_FASYNC);
-                       write_unlock_bh(&sk->sk_callback_lock);
-                       kfree(fa);
-               }
-       }
 
-out:
-       release_sock(sock->sk);
+       release_sock(sk);
        return 0;
 }
 
-/* This function may be called only under socket lock or callback_lock */
+/* This function may be called only under socket lock or callback_lock or rcu_lock */
 
 int sock_wake_async(struct socket *sock, int how, int band)
 {
-       if (!sock || !sock->fasync_list)
+       struct socket_wq *wq;
+
+       if (!sock)
                return -1;
+       rcu_read_lock();
+       wq = rcu_dereference(sock->wq);
+       if (!wq || !wq->fasync_list) {
+               rcu_read_unlock();
+               return -1;
+       }
        switch (how) {
        case SOCK_WAKE_WAITD:
                if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
@@ -1160,11 +1132,12 @@ int sock_wake_async(struct socket *sock, int how, int band)
                /* fall through */
        case SOCK_WAKE_IO:
 call_kill:
-               __kill_fasync(sock->fasync_list, SIGIO, band);
+               kill_fasync(&wq->fasync_list, SIGIO, band);
                break;
        case SOCK_WAKE_URG:
-               __kill_fasync(sock->fasync_list, SIGURG, band);
+               kill_fasync(&wq->fasync_list, SIGURG, band);
        }
+       rcu_read_unlock();
        return 0;
 }
 
@@ -2642,7 +2615,7 @@ static int bond_ioctl(struct net *net, unsigned int cmd,
                return dev_ioctl(net, cmd, uifr);
        default:
                return -EINVAL;
-       };
+       }
 }
 
 static int siocdevprivate_ioctl(struct net *net, unsigned int cmd,
index 3308157436d2931dcef73de989a7ed85ae8824da..a99825d7caa04ef60df696971858dfbaa1bf46b5 100644 (file)
@@ -223,7 +223,7 @@ spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **ck
 
        /* only support SPKM_MIC_TOK */
        if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
-               dprintk("RPC:       ERROR unsupported SPKM3 token \n");
+               dprintk("RPC:       ERROR unsupported SPKM3 token\n");
                goto out;
        }
 
index f0c05d3311c1a1ac3dca0d19ab701cd5e00a9559..7dcfe0cc350087d652be6e04a6680a586d6f5603 100644 (file)
@@ -60,7 +60,7 @@ int bc_send(struct rpc_rqst *req)
                rpc_put_task(task);
        }
        return ret;
-       dprintk("RPC:       bc_send ret= %d \n", ret);
+       dprintk("RPC:       bc_send ret= %d\n", ret);
 }
 
 #endif /* CONFIG_NFS_V4_1 */
index 8c7b5433022a24a33afdb8c5add46725a15b2850..756fc324db9ec5dc37870c8f0a2c1e6b2f4d2573 100644 (file)
@@ -1507,7 +1507,6 @@ call_refreshresult(struct rpc_task *task)
        task->tk_action = call_refresh;
        if (status != -ETIMEDOUT)
                rpc_delay(task, 3*HZ);
-       return;
 }
 
 static __be32 *
index a338927336437f4040064ce536ef243c21010e2f..7e534dd0907720073171365cc218b25e012b4c0c 100644 (file)
@@ -150,7 +150,6 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
                }
                break;
        }
-       return;
 }
 
 /*
@@ -419,8 +418,8 @@ static void svc_udp_data_ready(struct sock *sk, int count)
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible(sk_sleep(sk));
 }
 
 /*
@@ -436,10 +435,10 @@ static void svc_write_space(struct sock *sk)
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) {
+       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk))) {
                dprintk("RPC svc_write_space: someone sleeping on %p\n",
                       svsk);
-               wake_up_interruptible(sk->sk_sleep);
+               wake_up_interruptible(sk_sleep(sk));
        }
 }
 
@@ -751,8 +750,8 @@ static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused)
                        printk("svc: socket %p: no user data\n", sk);
        }
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_all(sk->sk_sleep);
+       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible_all(sk_sleep(sk));
 }
 
 /*
@@ -771,8 +770,8 @@ static void svc_tcp_state_change(struct sock *sk)
                set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible_all(sk->sk_sleep);
+       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible_all(sk_sleep(sk));
 }
 
 static void svc_tcp_data_ready(struct sock *sk, int count)
@@ -785,8 +784,8 @@ static void svc_tcp_data_ready(struct sock *sk, int count)
                set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible(sk_sleep(sk));
 }
 
 /*
@@ -1481,8 +1480,8 @@ static void svc_sock_detach(struct svc_xprt *xprt)
        sk->sk_data_ready = svsk->sk_odata;
        sk->sk_write_space = svsk->sk_owspace;
 
-       if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+       if (sk_sleep(sk) && waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible(sk_sleep(sk));
 }
 
 /*
index 65fe2e4e7cbfcbed9aaf267af0927e1c68b79483..3fc325399ee4da4eaf77d19ace55717e34639798 100644 (file)
@@ -984,7 +984,7 @@ void xprt_reserve(struct rpc_task *task)
 
 static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
 {
-       return xprt->xid++;
+       return (__force __be32)xprt->xid++;
 }
 
 static inline void xprt_init_xid(struct rpc_xprt *xprt)
index 02fc7f04dd17afbd036dafe5e81234adab364d16..b7cd8cccbe72c3dc12320e65af18f22104d5df5d 100644 (file)
@@ -1035,8 +1035,6 @@ static inline void xs_tcp_read_common(struct rpc_xprt *xprt,
                if (transport->tcp_flags & TCP_RCV_LAST_FRAG)
                        transport->tcp_flags &= ~TCP_RCV_COPY_DATA;
        }
-
-       return;
 }
 
 /*
@@ -2182,7 +2180,6 @@ static int bc_send_request(struct rpc_task *task)
 
 static void bc_close(struct rpc_xprt *xprt)
 {
-       return;
 }
 
 /*
@@ -2192,7 +2189,6 @@ static void bc_close(struct rpc_xprt *xprt)
 
 static void bc_destroy(struct rpc_xprt *xprt)
 {
-       return;
 }
 
 static struct rpc_xprt_ops xs_udp_ops = {
index 53196009160a031ae4909fc5bc65e8ad098ef22c..ca84212cfbfede9c42f4b99cdd484149b6bc0471 100644 (file)
@@ -82,7 +82,6 @@ static int __net_init sysctl_net_init(struct net *net)
 static void __net_exit sysctl_net_exit(struct net *net)
 {
        WARN_ON(!list_empty(&net->sysctls.list));
-       return;
 }
 
 static struct pernet_operations sysctl_pernet_ops = {
index e5207a11edf64d36fd4a44bc8e9212425b1bf57f..c048543ffbebbb6ce37f8b57c8c6a758e4c629a9 100644 (file)
@@ -92,3 +92,35 @@ int tipc_addr_node_valid(u32 addr)
        return (tipc_addr_domain_valid(addr) && tipc_node(addr));
 }
 
+int tipc_in_scope(u32 domain, u32 addr)
+{
+       if (!domain || (domain == addr))
+               return 1;
+       if (domain == (addr & 0xfffff000u)) /* domain <Z.C.0> */
+               return 1;
+       if (domain == (addr & 0xff000000u)) /* domain <Z.0.0> */
+               return 1;
+       return 0;
+}
+
+/**
+ * tipc_addr_scope - convert message lookup domain to a 2-bit scope value
+ */
+
+int tipc_addr_scope(u32 domain)
+{
+       if (likely(!domain))
+               return TIPC_ZONE_SCOPE;
+       if (tipc_node(domain))
+               return TIPC_NODE_SCOPE;
+       if (tipc_cluster(domain))
+               return TIPC_CLUSTER_SCOPE;
+       return TIPC_ZONE_SCOPE;
+}
+
+char *tipc_addr_string_fill(char *string, u32 addr)
+{
+       snprintf(string, 16, "<%u.%u.%u>",
+                tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
+       return string;
+}
index 3ba67e6ce03e284ed27b87f4b6916f465dbf084b..c1cc5724d8cc85f546cdb21eb2de110fd4c660e4 100644 (file)
@@ -67,32 +67,6 @@ static inline int may_route(u32 addr)
        return(addr ^ tipc_own_addr) >> 11;
 }
 
-static inline int in_scope(u32 domain, u32 addr)
-{
-       if (!domain || (domain == addr))
-               return 1;
-       if (domain == (addr & 0xfffff000u)) /* domain <Z.C.0> */
-               return 1;
-       if (domain == (addr & 0xff000000u)) /* domain <Z.0.0> */
-               return 1;
-       return 0;
-}
-
-/**
- * addr_scope - convert message lookup domain to equivalent 2-bit scope value
- */
-
-static inline int addr_scope(u32 domain)
-{
-       if (likely(!domain))
-               return TIPC_ZONE_SCOPE;
-       if (tipc_node(domain))
-               return TIPC_NODE_SCOPE;
-       if (tipc_cluster(domain))
-               return TIPC_CLUSTER_SCOPE;
-       return TIPC_ZONE_SCOPE;
-}
-
 /**
  * addr_domain - convert 2-bit scope value to equivalent message lookup domain
  *
@@ -110,14 +84,9 @@ static inline int addr_domain(int sc)
        return tipc_addr(tipc_zone(tipc_own_addr), 0, 0);
 }
 
-static inline char *addr_string_fill(char *string, u32 addr)
-{
-       snprintf(string, 16, "<%u.%u.%u>",
-                tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
-       return string;
-}
-
 int tipc_addr_domain_valid(u32);
 int tipc_addr_node_valid(u32 addr);
-
+int tipc_in_scope(u32 domain, u32 addr);
+int tipc_addr_scope(u32 domain);
+char *tipc_addr_string_fill(char *string, u32 addr);
 #endif
index a3bfd40649125721809b51ca419770d6321dd8ad..a008c6689305bd7b037a5226f1107a878c943060 100644 (file)
@@ -119,7 +119,7 @@ static struct bclink *bclink = NULL;
 static struct link *bcl = NULL;
 static DEFINE_SPINLOCK(bc_lock);
 
-const char tipc_bclink_name[] = "multicast-link";
+const char tipc_bclink_name[] = "broadcast-link";
 
 
 static u32 buf_seqno(struct sk_buff *buf)
@@ -275,7 +275,7 @@ static void bclink_send_nack(struct tipc_node *n_ptr)
        buf = buf_acquire(INT_H_SIZE);
        if (buf) {
                msg = buf_msg(buf);
-               msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
+               tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
                         INT_H_SIZE, n_ptr->addr);
                msg_set_mc_netid(msg, tipc_net_id);
                msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in));
@@ -558,10 +558,7 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
                              struct tipc_bearer *unused1,
                              struct tipc_media_addr *unused2)
 {
-       static int send_count = 0;
-
        int bp_index;
-       int swap_time;
 
        /* Prepare buffer for broadcasting (if first time trying to send it) */
 
@@ -575,11 +572,6 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
                msg_set_mc_netid(msg, tipc_net_id);
        }
 
-       /* Determine if bearer pairs should be swapped following this attempt */
-
-       if ((swap_time = (++send_count >= 10)))
-               send_count = 0;
-
        /* Send buffer over bearers until all targets reached */
 
        bcbearer->remains = tipc_cltr_bcast_nodes;
@@ -595,21 +587,22 @@ static int tipc_bcbearer_send(struct sk_buff *buf,
                if (bcbearer->remains_new.count == bcbearer->remains.count)
                        continue;       /* bearer pair doesn't add anything */
 
-               if (!p->publ.blocked &&
-                   !p->media->send_msg(buf, &p->publ, &p->media->bcast_addr)) {
-                       if (swap_time && s && !s->publ.blocked)
-                               goto swap;
-                       else
-                               goto update;
+               if (p->publ.blocked ||
+                   p->media->send_msg(buf, &p->publ, &p->media->bcast_addr)) {
+                       /* unable to send on primary bearer */
+                       if (!s || s->publ.blocked ||
+                           s->media->send_msg(buf, &s->publ,
+                                              &s->media->bcast_addr)) {
+                               /* unable to send on either bearer */
+                               continue;
+                       }
+               }
+
+               if (s) {
+                       bcbearer->bpairs[bp_index].primary = s;
+                       bcbearer->bpairs[bp_index].secondary = p;
                }
 
-               if (!s || s->publ.blocked ||
-                   s->media->send_msg(buf, &s->publ, &s->media->bcast_addr))
-                       continue;       /* unable to send using bearer pair */
-swap:
-               bcbearer->bpairs[bp_index].primary = s;
-               bcbearer->bpairs[bp_index].secondary = p;
-update:
                if (bcbearer->remains_new.count == 0)
                        return 0;
 
@@ -829,3 +822,113 @@ void tipc_bclink_stop(void)
        spin_unlock_bh(&bc_lock);
 }
 
+
+/**
+ * tipc_nmap_add - add a node to a node map
+ */
+
+void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
+{
+       int n = tipc_node(node);
+       int w = n / WSIZE;
+       u32 mask = (1 << (n % WSIZE));
+
+       if ((nm_ptr->map[w] & mask) == 0) {
+               nm_ptr->count++;
+               nm_ptr->map[w] |= mask;
+       }
+}
+
+/**
+ * tipc_nmap_remove - remove a node from a node map
+ */
+
+void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
+{
+       int n = tipc_node(node);
+       int w = n / WSIZE;
+       u32 mask = (1 << (n % WSIZE));
+
+       if ((nm_ptr->map[w] & mask) != 0) {
+               nm_ptr->map[w] &= ~mask;
+               nm_ptr->count--;
+       }
+}
+
+/**
+ * tipc_nmap_diff - find differences between node maps
+ * @nm_a: input node map A
+ * @nm_b: input node map B
+ * @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
+ */
+
+void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
+                                 struct tipc_node_map *nm_diff)
+{
+       int stop = ARRAY_SIZE(nm_a->map);
+       int w;
+       int b;
+       u32 map;
+
+       memset(nm_diff, 0, sizeof(*nm_diff));
+       for (w = 0; w < stop; w++) {
+               map = nm_a->map[w] ^ (nm_a->map[w] & nm_b->map[w]);
+               nm_diff->map[w] = map;
+               if (map != 0) {
+                       for (b = 0 ; b < WSIZE; b++) {
+                               if (map & (1 << b))
+                                       nm_diff->count++;
+                       }
+               }
+       }
+}
+
+/**
+ * tipc_port_list_add - add a port to a port list, ensuring no duplicates
+ */
+
+void tipc_port_list_add(struct port_list *pl_ptr, u32 port)
+{
+       struct port_list *item = pl_ptr;
+       int i;
+       int item_sz = PLSIZE;
+       int cnt = pl_ptr->count;
+
+       for (; ; cnt -= item_sz, item = item->next) {
+               if (cnt < PLSIZE)
+                       item_sz = cnt;
+               for (i = 0; i < item_sz; i++)
+                       if (item->ports[i] == port)
+                               return;
+               if (i < PLSIZE) {
+                       item->ports[i] = port;
+                       pl_ptr->count++;
+                       return;
+               }
+               if (!item->next) {
+                       item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
+                       if (!item->next) {
+                               warn("Incomplete multicast delivery, no memory\n");
+                               return;
+                       }
+                       item->next->next = NULL;
+               }
+       }
+}
+
+/**
+ * tipc_port_list_free - free dynamically created entries in port_list chain
+ *
+ */
+
+void tipc_port_list_free(struct port_list *pl_ptr)
+{
+       struct port_list *item;
+       struct port_list *next;
+
+       for (item = pl_ptr->next; item; item = next) {
+               next = item->next;
+               kfree(item);
+       }
+}
+
index 4c1771e95c99ed2ad0b43a07f2690fa69d043af0..e8c2b81658c7513c1a49e8bf0c3d57a99348e0ea 100644 (file)
@@ -72,41 +72,11 @@ struct tipc_node;
 
 extern const char tipc_bclink_name[];
 
+void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node);
+void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node);
 
 /**
- * nmap_add - add a node to a node map
- */
-
-static inline void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
-{
-       int n = tipc_node(node);
-       int w = n / WSIZE;
-       u32 mask = (1 << (n % WSIZE));
-
-       if ((nm_ptr->map[w] & mask) == 0) {
-               nm_ptr->count++;
-               nm_ptr->map[w] |= mask;
-       }
-}
-
-/**
- * nmap_remove - remove a node from a node map
- */
-
-static inline void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
-{
-       int n = tipc_node(node);
-       int w = n / WSIZE;
-       u32 mask = (1 << (n % WSIZE));
-
-       if ((nm_ptr->map[w] & mask) != 0) {
-               nm_ptr->map[w] &= ~mask;
-               nm_ptr->count--;
-       }
-}
-
-/**
- * nmap_equal - test for equality of node maps
+ * tipc_nmap_equal - test for equality of node maps
  */
 
 static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b)
@@ -114,84 +84,11 @@ static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_m
        return !memcmp(nm_a, nm_b, sizeof(*nm_a));
 }
 
-/**
- * nmap_diff - find differences between node maps
- * @nm_a: input node map A
- * @nm_b: input node map B
- * @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
- */
-
-static inline void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
-                                 struct tipc_node_map *nm_diff)
-{
-       int stop = ARRAY_SIZE(nm_a->map);
-       int w;
-       int b;
-       u32 map;
-
-       memset(nm_diff, 0, sizeof(*nm_diff));
-       for (w = 0; w < stop; w++) {
-               map = nm_a->map[w] ^ (nm_a->map[w] & nm_b->map[w]);
-               nm_diff->map[w] = map;
-               if (map != 0) {
-                       for (b = 0 ; b < WSIZE; b++) {
-                               if (map & (1 << b))
-                                       nm_diff->count++;
-                       }
-               }
-       }
-}
-
-/**
- * port_list_add - add a port to a port list, ensuring no duplicates
- */
-
-static inline void tipc_port_list_add(struct port_list *pl_ptr, u32 port)
-{
-       struct port_list *item = pl_ptr;
-       int i;
-       int item_sz = PLSIZE;
-       int cnt = pl_ptr->count;
-
-       for (; ; cnt -= item_sz, item = item->next) {
-               if (cnt < PLSIZE)
-                       item_sz = cnt;
-               for (i = 0; i < item_sz; i++)
-                       if (item->ports[i] == port)
-                               return;
-               if (i < PLSIZE) {
-                       item->ports[i] = port;
-                       pl_ptr->count++;
-                       return;
-               }
-               if (!item->next) {
-                       item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
-                       if (!item->next) {
-                               warn("Incomplete multicast delivery, no memory\n");
-                               return;
-                       }
-                       item->next->next = NULL;
-               }
-       }
-}
-
-/**
- * port_list_free - free dynamically created entries in port_list chain
- *
- * Note: First item is on stack, so it doesn't need to be released
- */
-
-static inline void tipc_port_list_free(struct port_list *pl_ptr)
-{
-       struct port_list *item;
-       struct port_list *next;
-
-       for (item = pl_ptr->next; item; item = next) {
-               next = item->next;
-               kfree(item);
-       }
-}
+void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
+                                 struct tipc_node_map *nm_diff);
 
+void tipc_port_list_add(struct port_list *pl_ptr, u32 port);
+void tipc_port_list_free(struct port_list *pl_ptr);
 
 int  tipc_bclink_init(void);
 void tipc_bclink_stop(void);
index 78091375ca120988ee81e4a1841bc4176103837f..52ae17b2583e3457c77652a9f842ed2aba237916 100644 (file)
@@ -467,6 +467,18 @@ int tipc_bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr)
        return res;
 }
 
+/**
+ * tipc_bearer_congested - determines if bearer is currently congested
+ */
+
+int tipc_bearer_congested(struct bearer *b_ptr, struct link *l_ptr)
+{
+       if (unlikely(b_ptr->publ.blocked))
+               return 1;
+       if (likely(list_empty(&b_ptr->cong_links)))
+               return 0;
+       return !tipc_bearer_resolve_congestion(b_ptr, l_ptr);
+}
 
 /**
  * tipc_enable_bearer - enable bearer with the given name
@@ -493,7 +505,7 @@ int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
                return -EINVAL;
        }
        if (!tipc_addr_domain_valid(bcast_scope) ||
-           !in_scope(bcast_scope, tipc_own_addr)) {
+           !tipc_in_scope(bcast_scope, tipc_own_addr)) {
                warn("Bearer <%s> rejected, illegal broadcast scope\n", name);
                return -EINVAL;
        }
@@ -571,7 +583,7 @@ restart:
        spin_lock_init(&b_ptr->publ.lock);
        write_unlock_bh(&tipc_net_lock);
        info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
-            name, addr_string_fill(addr_string, bcast_scope), priority);
+            name, tipc_addr_string_fill(addr_string, bcast_scope), priority);
        return 0;
 failed:
        write_unlock_bh(&tipc_net_lock);
index 000228e93f9ef75e3dd008b4b76b4a9f56b963c6..a850b389663ede225780911d0f539501b2148280 100644 (file)
@@ -125,6 +125,7 @@ void tipc_bearer_remove_dest(struct bearer *b_ptr, u32 dest);
 void tipc_bearer_schedule(struct bearer *b_ptr, struct link *l_ptr);
 struct bearer *tipc_bearer_find_interface(const char *if_name);
 int tipc_bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr);
+int tipc_bearer_congested(struct bearer *b_ptr, struct link *l_ptr);
 int tipc_bearer_init(void);
 void tipc_bearer_stop(void);
 void tipc_bearer_lock_push(struct bearer *b_ptr);
@@ -154,17 +155,4 @@ static inline int tipc_bearer_send(struct bearer *b_ptr, struct sk_buff *buf,
        return !b_ptr->media->send_msg(buf, &b_ptr->publ, dest);
 }
 
-/**
- * tipc_bearer_congested - determines if bearer is currently congested
- */
-
-static inline int tipc_bearer_congested(struct bearer *b_ptr, struct link *l_ptr)
-{
-       if (unlikely(b_ptr->publ.blocked))
-               return 1;
-       if (likely(list_empty(&b_ptr->cong_links)))
-               return 0;
-       return !tipc_bearer_resolve_congestion(b_ptr, l_ptr);
-}
-
-#endif
+#endif /* _TIPC_BEARER_H */
index a7eac00cd363298ff75e4fc57819ef66d8c41432..e68f705381bc345a75283dc69074c737fba26f7a 100644 (file)
@@ -238,7 +238,7 @@ static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
        if (buf) {
                msg = buf_msg(buf);
                memset((char *)msg, 0, size);
-               msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest);
+               tipc_msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest);
        }
        return buf;
 }
index ca3544d030c7f9177fbe426e9f955c4655c157cc..961d1b097146d99dd90f45721937668f22b5d7f6 100644 (file)
@@ -56,9 +56,6 @@ struct subscr_data {
 struct manager {
        u32 user_ref;
        u32 port_ref;
-       u32 subscr_ref;
-       u32 link_subscriptions;
-       struct list_head link_subscribers;
 };
 
 static struct manager mng = { 0};
@@ -70,12 +67,6 @@ static int req_tlv_space;            /* request message TLV area size */
 static int rep_headroom;               /* reply message headroom to use */
 
 
-void tipc_cfg_link_event(u32 addr, char *name, int up)
-{
-       /* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
-}
-
-
 struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
 {
        struct sk_buff *buf;
@@ -130,12 +121,24 @@ struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
 }
 
 
-
-
 #if 0
 
 /* Now obsolete code for handling commands not yet implemented the new way */
 
+/*
+ * Some of this code assumed that the manager structure contains two added
+ * fields:
+ *     u32 link_subscriptions;
+ *     struct list_head link_subscribers;
+ * which are currently not present.  These fields may need to be re-introduced
+ * if and when support for link subscriptions is added.
+ */
+
+void tipc_cfg_link_event(u32 addr, char *name, int up)
+{
+       /* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
+}
+
 int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
                 char *data,
                 u32 sz,
@@ -243,13 +246,48 @@ static void cfg_cmd_event(struct tipc_cmd_msg *msg,
        default:
                rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
        }
-       exit:
+exit:
        rmsg.result_len = htonl(msg_sect[1].iov_len);
        rmsg.retval = htonl(rv);
        tipc_cfg_respond(msg_sect, 2u, orig);
 }
 #endif
 
+#define MAX_STATS_INFO 2000
+
+static struct sk_buff *tipc_show_stats(void)
+{
+       struct sk_buff *buf;
+       struct tlv_desc *rep_tlv;
+       struct print_buf pb;
+       int str_len;
+       u32 value;
+
+       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
+               return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
+
+       value = ntohl(*(u32 *)TLV_DATA(req_tlv_area));
+       if (value != 0)
+               return tipc_cfg_reply_error_string("unsupported argument");
+
+       buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_STATS_INFO));
+       if (buf == NULL)
+               return NULL;
+
+       rep_tlv = (struct tlv_desc *)buf->data;
+       tipc_printbuf_init(&pb, (char *)TLV_DATA(rep_tlv), MAX_STATS_INFO);
+
+       tipc_printf(&pb, "TIPC version " TIPC_MOD_VER "\n");
+
+       /* Use additional tipc_printf()'s to return more info ... */
+
+       str_len = tipc_printbuf_validate(&pb);
+       skb_put(buf, TLV_SPACE(str_len));
+       TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
+
+       return buf;
+}
+
 static struct sk_buff *cfg_enable_bearer(void)
 {
        struct tipc_bearer_config *args;
@@ -533,6 +571,9 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
        case TIPC_CMD_DUMP_LOG:
                rep_tlv_buf = tipc_log_dump();
                break;
+       case TIPC_CMD_SHOW_STATS:
+               rep_tlv_buf = tipc_show_stats();
+               break;
        case TIPC_CMD_SET_LINK_TOL:
        case TIPC_CMD_SET_LINK_PRI:
        case TIPC_CMD_SET_LINK_WINDOW:
@@ -667,9 +708,6 @@ int tipc_cfg_init(void)
        struct tipc_name_seq seq;
        int res;
 
-       memset(&mng, 0, sizeof(mng));
-       INIT_LIST_HEAD(&mng.link_subscribers);
-
        res = tipc_attach(&mng.user_ref, NULL, NULL);
        if (res)
                goto failed;
index 52c571fedbe05892ed9e7690e68063af7aabf1e6..69646811798542cb29b37e66dd424679464a30a9 100644 (file)
@@ -49,8 +49,6 @@
 #include "config.h"
 
 
-#define TIPC_MOD_VER "1.6.4"
-
 #ifndef CONFIG_TIPC_ZONES
 #define CONFIG_TIPC_ZONES 3
 #endif
@@ -103,6 +101,30 @@ int tipc_get_mode(void)
        return tipc_mode;
 }
 
+/**
+ * buf_acquire - creates a TIPC message buffer
+ * @size: message size (including TIPC header)
+ *
+ * Returns a new buffer with data pointers set to the specified size.
+ *
+ * NOTE: Headroom is reserved to allow prepending of a data link header.
+ *       There may also be unrequested tailroom present at the buffer's end.
+ */
+
+struct sk_buff *buf_acquire(u32 size)
+{
+       struct sk_buff *skb;
+       unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
+
+       skb = alloc_skb_fclone(buf_size, GFP_ATOMIC);
+       if (skb) {
+               skb_reserve(skb, BUF_HEADROOM);
+               skb_put(skb, size);
+               skb->next = NULL;
+       }
+       return skb;
+}
+
 /**
  * tipc_core_stop_net - shut down TIPC networking sub-systems
  */
index c58a1d16563a6ab3bd9b51740a8520cef997bf45..188799017abdb35aa5416862539395dbb412974b 100644 (file)
@@ -59,6 +59,9 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 
+
+#define TIPC_MOD_VER "2.0.0"
+
 /*
  * TIPC sanity test macros
  */
@@ -325,29 +328,7 @@ static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
        return (struct tipc_msg *)skb->data;
 }
 
-/**
- * buf_acquire - creates a TIPC message buffer
- * @size: message size (including TIPC header)
- *
- * Returns a new buffer with data pointers set to the specified size.
- *
- * NOTE: Headroom is reserved to allow prepending of a data link header.
- *       There may also be unrequested tailroom present at the buffer's end.
- */
-
-static inline struct sk_buff *buf_acquire(u32 size)
-{
-       struct sk_buff *skb;
-       unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
-
-       skb = alloc_skb_fclone(buf_size, GFP_ATOMIC);
-       if (skb) {
-               skb_reserve(skb, BUF_HEADROOM);
-               skb_put(skb, size);
-               skb->next = NULL;
-       }
-       return skb;
-}
+extern struct sk_buff *buf_acquire(u32 size);
 
 /**
  * buf_discard - frees a TIPC message buffer
index 74b7d1e28aec0205bbb405185bc5cba4e179d285..fc1fcf5e6b53625e4bc22ad29228af151de6288f 100644 (file)
@@ -120,7 +120,7 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
 
        if (buf) {
                msg = buf_msg(buf);
-               msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain);
+               tipc_msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain);
                msg_set_non_seq(msg, 1);
                msg_set_req_links(msg, req_links);
                msg_set_dest_domain(msg, dest_domain);
@@ -144,7 +144,7 @@ static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
        char media_addr_str[64];
        struct print_buf pb;
 
-       addr_string_fill(node_addr_str, node_addr);
+       tipc_addr_string_fill(node_addr_str, node_addr);
        tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str));
        tipc_media_addr_printf(&pb, media_addr);
        tipc_printbuf_validate(&pb);
@@ -183,7 +183,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
                        disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
                return;
        }
-       if (!in_scope(dest, tipc_own_addr))
+       if (!tipc_in_scope(dest, tipc_own_addr))
                return;
        if (is_slave(tipc_own_addr) && is_slave(orig))
                return;
@@ -224,7 +224,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
                        memcpy(addr, &media_addr, sizeof(*addr));
                        tipc_link_reset(link);
                }
-               link_fully_up = (link->state == WORKING_WORKING);
+               link_fully_up = link_working_working(link);
                spin_unlock_bh(&n_ptr->lock);
                if ((type == DSC_RESP_MSG) || link_fully_up)
                        return;
index 1a7e4665af8009759156193b08bf23d768130679..a3616b99529b72ef1085fe95c99fd972e95e6b93 100644 (file)
@@ -202,41 +202,6 @@ static unsigned int align(unsigned int i)
        return (i + 3) & ~3u;
 }
 
-static int link_working_working(struct link *l_ptr)
-{
-       return (l_ptr->state == WORKING_WORKING);
-}
-
-static int link_working_unknown(struct link *l_ptr)
-{
-       return (l_ptr->state == WORKING_UNKNOWN);
-}
-
-static int link_reset_unknown(struct link *l_ptr)
-{
-       return (l_ptr->state == RESET_UNKNOWN);
-}
-
-static int link_reset_reset(struct link *l_ptr)
-{
-       return (l_ptr->state == RESET_RESET);
-}
-
-static int link_blocked(struct link *l_ptr)
-{
-       return (l_ptr->exp_msg_count || l_ptr->blocked);
-}
-
-static int link_congested(struct link *l_ptr)
-{
-       return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
-}
-
-static u32 link_max_pkt(struct link *l_ptr)
-{
-       return l_ptr->max_pkt;
-}
-
 static void link_init_max_pkt(struct link *l_ptr)
 {
        u32 max_pkt;
@@ -468,7 +433,7 @@ struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
 
        l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
        msg = l_ptr->pmsg;
-       msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
+       tipc_msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
        msg_set_size(msg, sizeof(l_ptr->proto_msg));
        msg_set_session(msg, (tipc_random & 0xffff));
        msg_set_bearer_id(msg, b_ptr->identity);
@@ -561,9 +526,8 @@ static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz)
                        goto exit;
                if (!list_empty(&p_ptr->wait_list))
                        goto exit;
-               p_ptr->congested_link = l_ptr;
                p_ptr->publ.congested = 1;
-               p_ptr->waiting_pkts = 1 + ((sz - 1) / link_max_pkt(l_ptr));
+               p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt);
                list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
                l_ptr->stats.link_congs++;
 exit:
@@ -592,7 +556,6 @@ void tipc_link_wakeup_ports(struct link *l_ptr, int all)
                if (win <= 0)
                        break;
                list_del_init(&p_ptr->wait_list);
-               p_ptr->congested_link = NULL;
                spin_lock_bh(p_ptr->publ.lock);
                p_ptr->publ.congested = 0;
                p_ptr->wakeup(&p_ptr->publ);
@@ -877,7 +840,7 @@ static void link_state_event(struct link *l_ptr, unsigned event)
                case TIMEOUT_EVT:
                        dbg_link("TIM ");
                        if (l_ptr->next_in_no != l_ptr->checkpoint) {
-                               dbg_link("-> WW \n");
+                               dbg_link("-> WW\n");
                                l_ptr->state = WORKING_WORKING;
                                l_ptr->fsm_msg_cnt = 0;
                                l_ptr->checkpoint = l_ptr->next_in_no;
@@ -934,7 +897,7 @@ static void link_state_event(struct link *l_ptr, unsigned event)
                        link_set_timer(l_ptr, cont_intv);
                        break;
                case RESET_MSG:
-                       dbg_link("RES \n");
+                       dbg_link("RES\n");
                        dbg_link(" -> RR\n");
                        l_ptr->state = RESET_RESET;
                        l_ptr->fsm_msg_cnt = 0;
@@ -947,7 +910,7 @@ static void link_state_event(struct link *l_ptr, unsigned event)
                        l_ptr->started = 1;
                        /* fall through */
                case TIMEOUT_EVT:
-                       dbg_link("TIM \n");
+                       dbg_link("TIM\n");
                        tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv);
@@ -1017,7 +980,7 @@ static int link_bundle_buf(struct link *l_ptr,
                return 0;
        if (skb_tailroom(bundler) < (pad + size))
                return 0;
-       if (link_max_pkt(l_ptr) < (to_pos + size))
+       if (l_ptr->max_pkt < (to_pos + size))
                return 0;
 
        skb_put(bundler, pad + size);
@@ -1062,9 +1025,9 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
        u32 size = msg_size(msg);
        u32 dsz = msg_data_sz(msg);
        u32 queue_size = l_ptr->out_queue_size;
-       u32 imp = msg_tot_importance(msg);
+       u32 imp = tipc_msg_tot_importance(msg);
        u32 queue_limit = l_ptr->queue_limit[imp];
-       u32 max_packet = link_max_pkt(l_ptr);
+       u32 max_packet = l_ptr->max_pkt;
 
        msg_set_prevnode(msg, tipc_own_addr);   /* If routed message */
 
@@ -1127,7 +1090,7 @@ int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
                        struct tipc_msg bundler_hdr;
 
                        if (bundler) {
-                               msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
+                               tipc_msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
                                         INT_H_SIZE, l_ptr->addr);
                                skb_copy_to_linear_data(bundler, &bundler_hdr,
                                                        INT_H_SIZE);
@@ -1195,7 +1158,7 @@ static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
        int res = msg_data_sz(msg);
 
        if (likely(!link_congested(l_ptr))) {
-               if (likely(msg_size(msg) <= link_max_pkt(l_ptr))) {
+               if (likely(msg_size(msg) <= l_ptr->max_pkt)) {
                        if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
                                link_add_to_outqueue(l_ptr, buf, msg);
                                if (likely(tipc_bearer_send(l_ptr->b_ptr, buf,
@@ -1212,7 +1175,7 @@ static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
                        }
                }
                else
-                       *used_max_pkt = link_max_pkt(l_ptr);
+                       *used_max_pkt = l_ptr->max_pkt;
        }
        return tipc_link_send_buf(l_ptr, buf);  /* All other cases */
 }
@@ -1280,7 +1243,7 @@ again:
         * (Must not hold any locks while building message.)
         */
 
-       res = msg_build(hdr, msg_sect, num_sect, sender->publ.max_pkt,
+       res = tipc_msg_build(hdr, msg_sect, num_sect, sender->publ.max_pkt,
                        !sender->user_port, &buf);
 
        read_lock_bh(&tipc_net_lock);
@@ -1319,7 +1282,7 @@ exit:
                         * then re-try fast path or fragment the message
                         */
 
-                       sender->publ.max_pkt = link_max_pkt(l_ptr);
+                       sender->publ.max_pkt = l_ptr->max_pkt;
                        tipc_node_unlock(node);
                        read_unlock_bh(&tipc_net_lock);
 
@@ -1391,7 +1354,7 @@ again:
        /* Prepare reusable fragment header: */
 
        msg_dbg(hdr, ">FRAGMENTING>");
-       msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
+       tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
                 INT_H_SIZE, msg_destnode(hdr));
        msg_set_link_selector(&fragm_hdr, sender->publ.ref);
        msg_set_size(&fragm_hdr, max_pkt);
@@ -1482,8 +1445,8 @@ error:
                        tipc_node_unlock(node);
                        goto reject;
                }
-               if (link_max_pkt(l_ptr) < max_pkt) {
-                       sender->publ.max_pkt = link_max_pkt(l_ptr);
+               if (l_ptr->max_pkt < max_pkt) {
+                       sender->publ.max_pkt = l_ptr->max_pkt;
                        tipc_node_unlock(node);
                        for (; buf_chain; buf_chain = buf) {
                                buf = buf_chain->next;
@@ -1553,7 +1516,7 @@ u32 tipc_link_push_packet(struct link *l_ptr)
 
        /* Continue retransmission now, if there is anything: */
 
-       if (r_q_size && buf && !skb_cloned(buf)) {
+       if (r_q_size && buf) {
                msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
                msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);
                if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
@@ -1650,7 +1613,7 @@ static void link_reset_all(unsigned long addr)
        tipc_node_lock(n_ptr);
 
        warn("Resetting all links to %s\n",
-            addr_string_fill(addr_string, n_ptr->addr));
+            tipc_addr_string_fill(addr_string, n_ptr->addr));
 
        for (i = 0; i < MAX_BEARERS; i++) {
                if (n_ptr->links[i]) {
@@ -1692,7 +1655,7 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
                n_ptr = l_ptr->owner->next;
                tipc_node_lock(n_ptr);
 
-               addr_string_fill(addr_string, n_ptr->addr);
+               tipc_addr_string_fill(addr_string, n_ptr->addr);
                tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string);
                tipc_printf(TIPC_OUTPUT, "Supported: %d,  ", n_ptr->bclink.supported);
                tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked);
@@ -1722,15 +1685,16 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
        dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
 
        if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
-               if (!skb_cloned(buf)) {
+               if (l_ptr->retransm_queue_size == 0) {
                        msg_dbg(msg, ">NO_RETR->BCONG>");
                        dbg_print_link(l_ptr, "   ");
                        l_ptr->retransm_queue_head = msg_seqno(msg);
                        l_ptr->retransm_queue_size = retransmits;
-                       return;
                } else {
-                       /* Don't retransmit if driver already has the buffer */
+                       err("Unexpected retransmit on link %s (qsize=%d)\n",
+                           l_ptr->name, l_ptr->retransm_queue_size);
                }
+               return;
        } else {
                /* Detect repeated retransmit failures on uncongested bearer */
 
@@ -1745,7 +1709,7 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
                }
        }
 
-       while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
+       while (retransmits && (buf != l_ptr->next_out) && buf) {
                msg = buf_msg(buf);
                msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
                msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
@@ -2434,7 +2398,7 @@ void tipc_link_changeover(struct link *l_ptr)
                return;
        }
 
-       msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
+       tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
                 ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
        msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
        msg_set_msgcnt(&tunnel_hdr, msgcount);
@@ -2489,7 +2453,7 @@ void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
        struct sk_buff *iter;
        struct tipc_msg tunnel_hdr;
 
-       msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
+       tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
                 DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
        msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
        msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
@@ -2680,7 +2644,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
        u32 dsz = msg_data_sz(inmsg);
        unchar *crs = buf->data;
        u32 rest = insize;
-       u32 pack_sz = link_max_pkt(l_ptr);
+       u32 pack_sz = l_ptr->max_pkt;
        u32 fragm_sz = pack_sz - INT_H_SIZE;
        u32 fragm_no = 1;
        u32 destaddr;
@@ -2695,7 +2659,7 @@ int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
 
        /* Prepare reusable fragment header: */
 
-       msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
+       tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
                 INT_H_SIZE, destaddr);
        msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
        msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
@@ -3126,7 +3090,7 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
        tipc_printf(&pb, "Link <%s>\n"
                         "  %s  MTU:%u  Priority:%u  Tolerance:%u ms"
                         "  Window:%u packets\n",
-                   l_ptr->name, status, link_max_pkt(l_ptr),
+                   l_ptr->name, status, l_ptr->max_pkt,
                    l_ptr->priority, l_ptr->tolerance, l_ptr->queue_limit[0]);
        tipc_printf(&pb, "  RX packets:%u fragments:%u/%u bundles:%u/%u\n",
                    l_ptr->next_in_no - l_ptr->stats.recv_info,
@@ -3271,7 +3235,7 @@ u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
                tipc_node_lock(n_ptr);
                l_ptr = n_ptr->active_links[selector & 1];
                if (l_ptr)
-                       res = link_max_pkt(l_ptr);
+                       res = l_ptr->max_pkt;
                tipc_node_unlock(n_ptr);
        }
        read_unlock_bh(&tipc_net_lock);
@@ -3294,7 +3258,7 @@ static void link_dump_rec_queue(struct link *l_ptr)
                        info("buffer %x invalid\n", crs);
                        return;
                }
-               msg_dbg(buf_msg(crs), "In rec queue: \n");
+               msg_dbg(buf_msg(crs), "In rec queue:\n");
                crs = crs->next;
        }
 }
@@ -3329,9 +3293,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
                if (l_ptr->next_out)
                        tipc_printf(buf, "%u..",
                                    msg_seqno(buf_msg(l_ptr->next_out)));
-               tipc_printf(buf, "%u]",
-                           msg_seqno(buf_msg
-                                     (l_ptr->last_out)), l_ptr->out_queue_size);
+               tipc_printf(buf, "%u]", msg_seqno(buf_msg(l_ptr->last_out)));
                if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) -
                         msg_seqno(buf_msg(l_ptr->first_out)))
                     != (l_ptr->out_queue_size - 1)) ||
index 6a51e38ad25c9b027f9852dd5b5d90b9510c1b9b..2e5385c47d30ccbe67bad535ff21c6f58fe93b0d 100644 (file)
@@ -292,4 +292,39 @@ static inline u32 lesser(u32 left, u32 right)
        return less_eq(left, right) ? left : right;
 }
 
+
+/*
+ * Link status checking routines
+ */
+
+static inline int link_working_working(struct link *l_ptr)
+{
+       return (l_ptr->state == WORKING_WORKING);
+}
+
+static inline int link_working_unknown(struct link *l_ptr)
+{
+       return (l_ptr->state == WORKING_UNKNOWN);
+}
+
+static inline int link_reset_unknown(struct link *l_ptr)
+{
+       return (l_ptr->state == RESET_UNKNOWN);
+}
+
+static inline int link_reset_reset(struct link *l_ptr)
+{
+       return (l_ptr->state == RESET_RESET);
+}
+
+static inline int link_blocked(struct link *l_ptr)
+{
+       return (l_ptr->exp_msg_count || l_ptr->blocked);
+}
+
+static inline int link_congested(struct link *l_ptr)
+{
+       return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
+}
+
 #endif
index 73dcd00d674edc19005b9ab4dd138b611462da29..381063817b41b393069c54945e092540610f047e 100644 (file)
 #include "msg.h"
 #include "bearer.h"
 
+u32 tipc_msg_tot_importance(struct tipc_msg *m)
+{
+       if (likely(msg_isdata(m))) {
+               if (likely(msg_orignode(m) == tipc_own_addr))
+                       return msg_importance(m);
+               return msg_importance(m) + 4;
+       }
+       if ((msg_user(m) == MSG_FRAGMENTER)  &&
+           (msg_type(m) == FIRST_FRAGMENT))
+               return msg_importance(msg_get_wrapped(m));
+       return msg_importance(m);
+}
+
+
+void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type,
+                           u32 hsize, u32 destnode)
+{
+       memset(m, 0, hsize);
+       msg_set_version(m);
+       msg_set_user(m, user);
+       msg_set_hdr_sz(m, hsize);
+       msg_set_size(m, hsize);
+       msg_set_prevnode(m, tipc_own_addr);
+       msg_set_type(m, type);
+       if (!msg_short(m)) {
+               msg_set_orignode(m, tipc_own_addr);
+               msg_set_destnode(m, destnode);
+       }
+}
+
+/**
+ * tipc_msg_calc_data_size - determine total data size for message
+ */
+
+int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
+{
+       int dsz = 0;
+       int i;
+
+       for (i = 0; i < num_sect; i++)
+               dsz += msg_sect[i].iov_len;
+       return dsz;
+}
+
+/**
+ * tipc_msg_build - create message using specified header and data
+ *
+ * Note: Caller must not hold any locks in case copy_from_user() is interrupted!
+ *
+ * Returns message data size or errno
+ */
+
+int tipc_msg_build(struct tipc_msg *hdr,
+                           struct iovec const *msg_sect, u32 num_sect,
+                           int max_size, int usrmem, struct sk_buff** buf)
+{
+       int dsz, sz, hsz, pos, res, cnt;
+
+       dsz = tipc_msg_calc_data_size(msg_sect, num_sect);
+       if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
+               *buf = NULL;
+               return -EINVAL;
+       }
+
+       pos = hsz = msg_hdr_sz(hdr);
+       sz = hsz + dsz;
+       msg_set_size(hdr, sz);
+       if (unlikely(sz > max_size)) {
+               *buf = NULL;
+               return dsz;
+       }
+
+       *buf = buf_acquire(sz);
+       if (!(*buf))
+               return -ENOMEM;
+       skb_copy_to_linear_data(*buf, hdr, hsz);
+       for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
+               if (likely(usrmem))
+                       res = !copy_from_user((*buf)->data + pos,
+                                             msg_sect[cnt].iov_base,
+                                             msg_sect[cnt].iov_len);
+               else
+                       skb_copy_to_linear_data_offset(*buf, pos,
+                                                      msg_sect[cnt].iov_base,
+                                                      msg_sect[cnt].iov_len);
+               pos += msg_sect[cnt].iov_len;
+       }
+       if (likely(res))
+               return dsz;
+
+       buf_discard(*buf);
+       *buf = NULL;
+       return -EFAULT;
+}
 
 #ifdef CONFIG_TIPC_DEBUG
 
index 7ee6ae23814781f8cca8c70015f3236dfec99f90..995d2da35b01d238fe7ad439d8a8d765e94f8c0e 100644 (file)
@@ -708,100 +708,13 @@ static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos)
 #define DSC_REQ_MSG          0
 #define DSC_RESP_MSG         1
 
-static inline u32 msg_tot_importance(struct tipc_msg *m)
-{
-       if (likely(msg_isdata(m))) {
-               if (likely(msg_orignode(m) == tipc_own_addr))
-                       return msg_importance(m);
-               return msg_importance(m) + 4;
-       }
-       if ((msg_user(m) == MSG_FRAGMENTER)  &&
-           (msg_type(m) == FIRST_FRAGMENT))
-               return msg_importance(msg_get_wrapped(m));
-       return msg_importance(m);
-}
-
-
-static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
-                           u32 hsize, u32 destnode)
-{
-       memset(m, 0, hsize);
-       msg_set_version(m);
-       msg_set_user(m, user);
-       msg_set_hdr_sz(m, hsize);
-       msg_set_size(m, hsize);
-       msg_set_prevnode(m, tipc_own_addr);
-       msg_set_type(m, type);
-       if (!msg_short(m)) {
-               msg_set_orignode(m, tipc_own_addr);
-               msg_set_destnode(m, destnode);
-       }
-}
-
-/**
- * msg_calc_data_size - determine total data size for message
- */
-
-static inline int msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
-{
-       int dsz = 0;
-       int i;
-
-       for (i = 0; i < num_sect; i++)
-               dsz += msg_sect[i].iov_len;
-       return dsz;
-}
-
-/**
- * msg_build - create message using specified header and data
- *
- * Note: Caller must not hold any locks in case copy_from_user() is interrupted!
- *
- * Returns message data size or errno
- */
-
-static inline int msg_build(struct tipc_msg *hdr,
+u32 tipc_msg_tot_importance(struct tipc_msg *m);
+void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type,
+                           u32 hsize, u32 destnode);
+int tipc_msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect);
+int tipc_msg_build(struct tipc_msg *hdr,
                            struct iovec const *msg_sect, u32 num_sect,
-                           int max_size, int usrmem, struct sk_buff** buf)
-{
-       int dsz, sz, hsz, pos, res, cnt;
-
-       dsz = msg_calc_data_size(msg_sect, num_sect);
-       if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
-               *buf = NULL;
-               return -EINVAL;
-       }
-
-       pos = hsz = msg_hdr_sz(hdr);
-       sz = hsz + dsz;
-       msg_set_size(hdr, sz);
-       if (unlikely(sz > max_size)) {
-               *buf = NULL;
-               return dsz;
-       }
-
-       *buf = buf_acquire(sz);
-       if (!(*buf))
-               return -ENOMEM;
-       skb_copy_to_linear_data(*buf, hdr, hsz);
-       for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
-               if (likely(usrmem))
-                       res = !copy_from_user((*buf)->data + pos,
-                                             msg_sect[cnt].iov_base,
-                                             msg_sect[cnt].iov_len);
-               else
-                       skb_copy_to_linear_data_offset(*buf, pos,
-                                                      msg_sect[cnt].iov_base,
-                                                      msg_sect[cnt].iov_len);
-               pos += msg_sect[cnt].iov_len;
-       }
-       if (likely(res))
-               return dsz;
-
-       buf_discard(*buf);
-       *buf = NULL;
-       return -EFAULT;
-}
+                           int max_size, int usrmem, struct sk_buff** buf);
 
 static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
 {
index 10a69894e2fd5e9cfc3d22e39518e1f0c82603e0..6ac3c543250bfebc1f7f82d4ea7b516393cbf974 100644 (file)
@@ -103,7 +103,7 @@ static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
 
        if (buf != NULL) {
                msg = buf_msg(buf);
-               msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest);
+               tipc_msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest);
                msg_set_size(msg, LONG_H_SIZE + size);
        }
        return buf;
index acab41a48d675a3f1c3709fb1489c1b433bd5460..8ba79620db3f705941fa04ba25aeda92f1215d98 100644 (file)
@@ -627,7 +627,7 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
        struct name_seq *seq;
        u32 ref;
 
-       if (!in_scope(*destnode, tipc_own_addr))
+       if (!tipc_in_scope(*destnode, tipc_own_addr))
                return 0;
 
        read_lock_bh(&tipc_nametbl_lock);
index f25b1cdb64eb069cba0bf991df72930248ba371c..f61b7694138b5f7c0a208cfd2ce883d7a6c88d4b 100644 (file)
 */
 
 DEFINE_RWLOCK(tipc_net_lock);
-struct _zone *tipc_zones[256] = { NULL, };
+static struct _zone *tipc_zones[256] = { NULL, };
 struct network tipc_net = { tipc_zones };
 
 struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref)
@@ -219,7 +219,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
 
        /* Handle message for this node */
        dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
-       if (in_scope(dnode, tipc_own_addr)) {
+       if (tipc_in_scope(dnode, tipc_own_addr)) {
                if (msg_isdata(msg)) {
                        if (msg_mcast(msg))
                                tipc_port_recv_mcast(buf, NULL);
@@ -277,7 +277,7 @@ int tipc_net_start(u32 addr)
 
        info("Started in network mode\n");
        info("Own node address %s, network identity %u\n",
-            addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
+            tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
        return 0;
 }
 
@@ -291,6 +291,6 @@ void tipc_net_stop(void)
        tipc_bclink_stop();
        net_stop();
        write_unlock_bh(&tipc_net_lock);
-       info("Left network mode \n");
+       info("Left network mode\n");
 }
 
index 2c24e7d6d9506a38a0072c2517da793ed57b81ba..b634942caba5d5ed9204269c327b9fa6fef4512f 100644 (file)
@@ -268,7 +268,7 @@ struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
 
                if (n_ptr->link_cnt >= 2) {
                        err("Attempt to create third link to %s\n",
-                           addr_string_fill(addr_string, n_ptr->addr));
+                           tipc_addr_string_fill(addr_string, n_ptr->addr));
                        return NULL;
                }
 
@@ -278,9 +278,9 @@ struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
                        n_ptr->link_cnt++;
                        return n_ptr;
                }
-               err("Attempt to establish second link on <%s> to %s \n",
+               err("Attempt to establish second link on <%s> to %s\n",
                    l_ptr->b_ptr->publ.name,
-                   addr_string_fill(addr_string, l_ptr->addr));
+                   tipc_addr_string_fill(addr_string, l_ptr->addr));
        }
        return NULL;
 }
@@ -439,7 +439,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
                return;
 
        info("Lost contact with %s\n",
-            addr_string_fill(addr_string, n_ptr->addr));
+            tipc_addr_string_fill(addr_string, n_ptr->addr));
 
        /* Abort link changeover */
        for (i = 0; i < MAX_BEARERS; i++) {
@@ -602,7 +602,7 @@ u32 tipc_available_nodes(const u32 domain)
 
        read_lock_bh(&tipc_net_lock);
        for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
-               if (!in_scope(domain, n_ptr->addr))
+               if (!tipc_in_scope(domain, n_ptr->addr))
                        continue;
                if (tipc_node_is_up(n_ptr))
                        cnt++;
@@ -651,7 +651,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
        /* Add TLVs for all nodes in scope */
 
        for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
-               if (!in_scope(domain, n_ptr->addr))
+               if (!tipc_in_scope(domain, n_ptr->addr))
                        continue;
                node_info.addr = htonl(n_ptr->addr);
                node_info.up = htonl(tipc_node_is_up(n_ptr));
@@ -711,7 +711,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
        for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
                u32 i;
 
-               if (!in_scope(domain, n_ptr->addr))
+               if (!tipc_in_scope(domain, n_ptr->addr))
                        continue;
                tipc_node_lock(n_ptr);
                for (i = 0; i < MAX_BEARERS; i++) {
index e70d27ea6578a3138c34761e5bba9414a2bd6af5..0737680e9266021f528f5addec9ff0acefbec406 100644 (file)
@@ -116,7 +116,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain,
        msg_set_namelower(hdr, seq->lower);
        msg_set_nameupper(hdr, seq->upper);
        msg_set_hdr_sz(hdr, MCAST_H_SIZE);
-       res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
+       res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
                        !oport->user_port, &buf);
        if (unlikely(!buf))
                return res;
@@ -241,13 +241,12 @@ struct tipc_port *tipc_createport_raw(void *usr_handle,
        p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
        p_ptr->publ.ref = ref;
        msg = &p_ptr->publ.phdr;
-       msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
+       tipc_msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
        msg_set_origport(msg, ref);
        p_ptr->last_in_seqno = 41;
        p_ptr->sent = 1;
        INIT_LIST_HEAD(&p_ptr->wait_list);
        INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
-       p_ptr->congested_link = NULL;
        p_ptr->dispatcher = dispatcher;
        p_ptr->wakeup = wakeup;
        p_ptr->user_port = NULL;
@@ -396,7 +395,7 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
        buf = buf_acquire(LONG_H_SIZE);
        if (buf) {
                msg = buf_msg(buf);
-               msg_init(msg, usr, type, LONG_H_SIZE, destnode);
+               tipc_msg_init(msg, usr, type, LONG_H_SIZE, destnode);
                msg_set_errcode(msg, err);
                msg_set_destport(msg, destport);
                msg_set_origport(msg, origport);
@@ -440,7 +439,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
                return data_sz;
        }
        rmsg = buf_msg(rbuf);
-       msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
+       tipc_msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
        msg_set_errcode(rmsg, err);
        msg_set_destport(rmsg, msg_origport(msg));
        msg_set_origport(rmsg, msg_destport(msg));
@@ -481,7 +480,7 @@ int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
        struct sk_buff *buf;
        int res;
 
-       res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
+       res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
                        !p_ptr->user_port, &buf);
        if (!buf)
                return res;
@@ -1344,7 +1343,7 @@ int tipc_port_recv_sections(struct port *sender, unsigned int num_sect,
        struct sk_buff *buf;
        int res;
 
-       res = msg_build(&sender->publ.phdr, msg_sect, num_sect,
+       res = tipc_msg_build(&sender->publ.phdr, msg_sect, num_sect,
                        MAX_MSG_SIZE, !sender->user_port, &buf);
        if (likely(buf))
                tipc_port_recv_msg(buf);
@@ -1384,7 +1383,7 @@ int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
        if (port_unreliable(p_ptr)) {
                p_ptr->publ.congested = 0;
                /* Just calculate msg length and return */
-               return msg_calc_data_size(msg_sect, num_sect);
+               return tipc_msg_calc_data_size(msg_sect, num_sect);
        }
        return -ELINKCONG;
 }
@@ -1453,7 +1452,7 @@ int tipc_forward2name(u32 ref,
        struct port *p_ptr;
        struct tipc_msg *msg;
        u32 destnode = domain;
-       u32 destport = 0;
+       u32 destport;
        int res;
 
        p_ptr = tipc_port_deref(ref);
@@ -1467,7 +1466,7 @@ int tipc_forward2name(u32 ref,
        msg_set_hdr_sz(msg, LONG_H_SIZE);
        msg_set_nametype(msg, name->type);
        msg_set_nameinst(msg, name->instance);
-       msg_set_lookup_scope(msg, addr_scope(domain));
+       msg_set_lookup_scope(msg, tipc_addr_scope(domain));
        if (importance <= TIPC_CRITICAL_IMPORTANCE)
                msg_set_importance(msg,importance);
        destport = tipc_nametbl_translate(name->type, name->instance, &destnode);
@@ -1484,7 +1483,7 @@ int tipc_forward2name(u32 ref,
                        return res;
                if (port_unreliable(p_ptr)) {
                        /* Just calculate msg length and return */
-                       return msg_calc_data_size(msg_sect, num_sect);
+                       return tipc_msg_calc_data_size(msg_sect, num_sect);
                }
                return -ELINKCONG;
        }
@@ -1525,7 +1524,7 @@ int tipc_forward_buf2name(u32 ref,
        struct port *p_ptr;
        struct tipc_msg *msg;
        u32 destnode = domain;
-       u32 destport = 0;
+       u32 destport;
        int res;
 
        p_ptr = (struct port *)tipc_ref_deref(ref);
@@ -1540,7 +1539,7 @@ int tipc_forward_buf2name(u32 ref,
        msg_set_origport(msg, orig->ref);
        msg_set_nametype(msg, name->type);
        msg_set_nameinst(msg, name->instance);
-       msg_set_lookup_scope(msg, addr_scope(domain));
+       msg_set_lookup_scope(msg, tipc_addr_scope(domain));
        msg_set_hdr_sz(msg, LONG_H_SIZE);
        msg_set_size(msg, LONG_H_SIZE + dsz);
        destport = tipc_nametbl_translate(name->type, name->instance, &destnode);
@@ -1620,7 +1619,7 @@ int tipc_forward2port(u32 ref,
                return res;
        if (port_unreliable(p_ptr)) {
                /* Just calculate msg length and return */
-               return msg_calc_data_size(msg_sect, num_sect);
+               return tipc_msg_calc_data_size(msg_sect, num_sect);
        }
        return -ELINKCONG;
 }
index ff31ee4a1dc3937d9e878debabbf6f9774bcbc24..8d1652aab298c0ba1132e045b3fb37e66bb14e12 100644 (file)
@@ -75,7 +75,6 @@ struct user_port {
  * @wakeup: ptr to routine to call when port is no longer congested
  * @user_port: ptr to user port associated with port (if any)
  * @wait_list: adjacent ports in list of ports waiting on link congestion
- * @congested_link: ptr to congested link port is waiting on
  * @waiting_pkts:
  * @sent:
  * @acked:
@@ -95,7 +94,6 @@ struct port {
        void (*wakeup)(struct tipc_port *);
        struct user_port *user_port;
        struct list_head wait_list;
-       struct link *congested_link;
        u32 waiting_pkts;
        u32 sent;
        u32 acked;
index cfb20b80b3a1758061d446e60fa92de17299559c..66e889ba48fd4d61088bd6e3f5e0721d7348d20b 100644 (file)
@@ -446,7 +446,7 @@ static unsigned int poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        u32 mask;
 
-       poll_wait(file, sk->sk_sleep, wait);
+       poll_wait(file, sk_sleep(sk), wait);
 
        if (!skb_queue_empty(&sk->sk_receive_queue) ||
            (sock->state == SS_UNCONNECTED) ||
@@ -591,7 +591,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
                        break;
                }
                release_sock(sk);
-               res = wait_event_interruptible(*sk->sk_sleep,
+               res = wait_event_interruptible(*sk_sleep(sk),
                                               !tport->congested);
                lock_sock(sk);
                if (res)
@@ -650,7 +650,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
                        break;
                }
                release_sock(sk);
-               res = wait_event_interruptible(*sk->sk_sleep,
+               res = wait_event_interruptible(*sk_sleep(sk),
                        (!tport->congested || !tport->connected));
                lock_sock(sk);
                if (res)
@@ -931,7 +931,7 @@ restart:
                        goto exit;
                }
                release_sock(sk);
-               res = wait_event_interruptible(*sk->sk_sleep,
+               res = wait_event_interruptible(*sk_sleep(sk),
                        (!skb_queue_empty(&sk->sk_receive_queue) ||
                         (sock->state == SS_DISCONNECTING)));
                lock_sock(sk);
@@ -1064,7 +1064,7 @@ restart:
                        goto exit;
                }
                release_sock(sk);
-               res = wait_event_interruptible(*sk->sk_sleep,
+               res = wait_event_interruptible(*sk_sleep(sk),
                        (!skb_queue_empty(&sk->sk_receive_queue) ||
                         (sock->state == SS_DISCONNECTING)));
                lock_sock(sk);
@@ -1271,8 +1271,8 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
                tipc_disconnect_port(tipc_sk_port(sk));
        }
 
-       if (waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+       if (waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible(sk_sleep(sk));
        return TIPC_OK;
 }
 
@@ -1343,8 +1343,8 @@ static void wakeupdispatch(struct tipc_port *tport)
 {
        struct sock *sk = (struct sock *)tport->usr_handle;
 
-       if (waitqueue_active(sk->sk_sleep))
-               wake_up_interruptible(sk->sk_sleep);
+       if (waitqueue_active(sk_sleep(sk)))
+               wake_up_interruptible(sk_sleep(sk));
 }
 
 /**
@@ -1426,7 +1426,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
        /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */
 
        release_sock(sk);
-       res = wait_event_interruptible_timeout(*sk->sk_sleep,
+       res = wait_event_interruptible_timeout(*sk_sleep(sk),
                        (!skb_queue_empty(&sk->sk_receive_queue) ||
                        (sock->state != SS_CONNECTING)),
                        sk->sk_rcvtimeo);
@@ -1521,7 +1521,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
                        goto exit;
                }
                release_sock(sk);
-               res = wait_event_interruptible(*sk->sk_sleep,
+               res = wait_event_interruptible(*sk_sleep(sk),
                                (!skb_queue_empty(&sk->sk_receive_queue)));
                lock_sock(sk);
                if (res)
@@ -1632,8 +1632,8 @@ restart:
                /* Discard any unreceived messages; wake up sleeping tasks */
 
                discard_rx_queue(sk);
-               if (waitqueue_active(sk->sk_sleep))
-                       wake_up_interruptible(sk->sk_sleep);
+               if (waitqueue_active(sk_sleep(sk)))
+                       wake_up_interruptible(sk_sleep(sk));
                res = 0;
                break;
 
index ff123e56114a14e5e05671ac846d59a4e5555723..ab6eab4c45e2b0ecbbc460ddbed0045d48792f1c 100644 (file)
@@ -274,7 +274,7 @@ static void subscr_cancel(struct tipc_subscr *s,
 {
        struct subscription *sub;
        struct subscription *sub_temp;
-       __u32 type, lower, upper;
+       __u32 type, lower, upper, timeout, filter;
        int found = 0;
 
        /* Find first matching subscription, exit if not found */
@@ -282,12 +282,18 @@ static void subscr_cancel(struct tipc_subscr *s,
        type = ntohl(s->seq.type);
        lower = ntohl(s->seq.lower);
        upper = ntohl(s->seq.upper);
+       timeout = ntohl(s->timeout);
+       filter = ntohl(s->filter) & ~TIPC_SUB_CANCEL;
 
        list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
                                 subscription_list) {
                        if ((type == sub->seq.type) &&
                            (lower == sub->seq.lower) &&
-                           (upper == sub->seq.upper)) {
+                           (upper == sub->seq.upper) &&
+                           (timeout == sub->timeout) &&
+                            (filter == sub->filter) &&
+                             !memcmp(s->usr_handle,sub->evt.s.usr_handle,
+                                    sizeof(s->usr_handle)) ){
                                found = 1;
                                break;
                        }
@@ -304,7 +310,7 @@ static void subscr_cancel(struct tipc_subscr *s,
                k_term_timer(&sub->timer);
                spin_lock_bh(subscriber->lock);
        }
-       dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
+       dbg("Cancel: removing sub %u,%u,%u from subscriber %p list\n",
            sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
        subscr_del(sub);
 }
@@ -352,8 +358,7 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s,
        sub->seq.upper = ntohl(s->seq.upper);
        sub->timeout = ntohl(s->timeout);
        sub->filter = ntohl(s->filter);
-       if ((!(sub->filter & TIPC_SUB_PORTS) ==
-            !(sub->filter & TIPC_SUB_SERVICE)) ||
+       if ((sub->filter && (sub->filter != TIPC_SUB_PORTS)) ||
            (sub->seq.lower > sub->seq.upper)) {
                warn("Subscription rejected, illegal request\n");
                kfree(sub);
index 3d9122e78f41736c7e654cfe7f2482284cdd1dca..fef2cc5e9d2bf48a8a26e32bcb1796a6c0165284 100644 (file)
@@ -313,13 +313,16 @@ static inline int unix_writable(struct sock *sk)
 
 static void unix_write_space(struct sock *sk)
 {
-       read_lock(&sk->sk_callback_lock);
+       struct socket_wq *wq;
+
+       rcu_read_lock();
        if (unix_writable(sk)) {
-               if (sk_has_sleeper(sk))
-                       wake_up_interruptible_sync(sk->sk_sleep);
+               wq = rcu_dereference(sk->sk_wq);
+               if (wq_has_sleeper(wq))
+                       wake_up_interruptible_sync(&wq->wait);
                sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT);
        }
-       read_unlock(&sk->sk_callback_lock);
+       rcu_read_unlock();
 }
 
 /* When dgram socket disconnects (or changes its peer), we clear its receive
@@ -406,9 +409,7 @@ static int unix_release_sock(struct sock *sk, int embrion)
                                skpair->sk_err = ECONNRESET;
                        unix_state_unlock(skpair);
                        skpair->sk_state_change(skpair);
-                       read_lock(&skpair->sk_callback_lock);
                        sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
-                       read_unlock(&skpair->sk_callback_lock);
                }
                sock_put(skpair); /* It may now die */
                unix_peer(sk) = NULL;
@@ -1142,7 +1143,7 @@ restart:
        newsk->sk_peercred.pid  = task_tgid_vnr(current);
        current_euid_egid(&newsk->sk_peercred.uid, &newsk->sk_peercred.gid);
        newu = unix_sk(newsk);
-       newsk->sk_sleep         = &newu->peer_wait;
+       newsk->sk_wq            = &newu->peer_wq;
        otheru = unix_sk(other);
 
        /* copy address information from listening to new sock*/
@@ -1736,7 +1737,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
        unix_state_lock(sk);
 
        for (;;) {
-               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+               prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
                if (!skb_queue_empty(&sk->sk_receive_queue) ||
                    sk->sk_err ||
@@ -1752,7 +1753,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
                clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
        }
 
-       finish_wait(sk->sk_sleep, &wait);
+       finish_wait(sk_sleep(sk), &wait);
        unix_state_unlock(sk);
        return timeo;
 }
@@ -1931,12 +1932,10 @@ static int unix_shutdown(struct socket *sock, int mode)
                        other->sk_shutdown |= peer_mode;
                        unix_state_unlock(other);
                        other->sk_state_change(other);
-                       read_lock(&other->sk_callback_lock);
                        if (peer_mode == SHUTDOWN_MASK)
                                sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP);
                        else if (peer_mode & RCV_SHUTDOWN)
                                sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN);
-                       read_unlock(&other->sk_callback_lock);
                }
                if (other)
                        sock_put(other);
@@ -1991,7 +1990,7 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table
        struct sock *sk = sock->sk;
        unsigned int mask;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* exceptional events? */
@@ -2028,7 +2027,7 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk, *other;
        unsigned int mask, writable;
 
-       sock_poll_wait(file, sk->sk_sleep, wait);
+       sock_poll_wait(file, sk_sleep(sk), wait);
        mask = 0;
 
        /* exceptional events? */
index 14c22c3768da8875955e72836830057eb5f7db13..c8df6fda0b1fcf124b65812f600710a3b3f17069 100644 (file)
@@ -153,15 +153,6 @@ void unix_notinflight(struct file *fp)
        }
 }
 
-static inline struct sk_buff *sock_queue_head(struct sock *sk)
-{
-       return (struct sk_buff *)&sk->sk_receive_queue;
-}
-
-#define receive_queue_for_each_skb(sk, next, skb) \
-       for (skb = sock_queue_head(sk)->next, next = skb->next; \
-            skb != sock_queue_head(sk); skb = next, next = skb->next)
-
 static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
                          struct sk_buff_head *hitlist)
 {
@@ -169,7 +160,7 @@ static void scan_inflight(struct sock *x, void (*func)(struct unix_sock *),
        struct sk_buff *next;
 
        spin_lock(&x->sk_receive_queue.lock);
-       receive_queue_for_each_skb(x, next, skb) {
+       skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
                /*
                 *      Do we have file descriptors ?
                 */
@@ -225,7 +216,7 @@ static void scan_children(struct sock *x, void (*func)(struct unix_sock *),
                 * and perform a scan on them as well.
                 */
                spin_lock(&x->sk_receive_queue.lock);
-               receive_queue_for_each_skb(x, next, skb) {
+               skb_queue_walk_safe(&x->sk_receive_queue, skb, next) {
                        u = unix_sk(skb->sk);
 
                        /*
index 4dc82a54ba3041251c97bd85e03627bbccf53a56..68bedf3e544357f17f51615eb3c99de8024dabe2 100644 (file)
@@ -110,7 +110,6 @@ int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
 {
        int result, ifindex;
        struct wimax_dev *wimax_dev;
-       struct device *dev;
 
        d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
        result = -ENODEV;
@@ -123,7 +122,6 @@ int wimax_gnl_doit_reset(struct sk_buff *skb, struct genl_info *info)
        wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
        if (wimax_dev == NULL)
                goto error_no_wimax_dev;
-       dev = wimax_dev_to_dev(wimax_dev);
        /* Execute the operation and send the result back to user space */
        result = wimax_reset(wimax_dev);
        dev_put(wimax_dev->net_dev);
index 11ad3356eb5645ae62f24e48e7c19370b3c2ee9d..aff8776e2d41a5d4020bdd5f8c937830e6e214a6 100644 (file)
@@ -53,7 +53,6 @@ int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info)
 {
        int result, ifindex;
        struct wimax_dev *wimax_dev;
-       struct device *dev;
 
        d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info);
        result = -ENODEV;
@@ -66,7 +65,6 @@ int wimax_gnl_doit_state_get(struct sk_buff *skb, struct genl_info *info)
        wimax_dev = wimax_dev_get_by_genl_info(info, ifindex);
        if (wimax_dev == NULL)
                goto error_no_wimax_dev;
-       dev = wimax_dev_to_dev(wimax_dev);
        /* Execute the operation and send the result back to user space */
        result = wimax_state_get(wimax_dev);
        dev_put(wimax_dev->net_dev);
index 1ed65dbdab03df1bab0a008a7ca0277ce143bfdb..ee99e7dfcdbaa2a87d81d9044e0c30690013e45d 100644 (file)
@@ -315,12 +315,11 @@ void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
                BUG();
        }
        __wimax_state_set(wimax_dev, new_state);
-       if (stch_skb)
+       if (!IS_ERR(stch_skb))
                wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header);
 out:
        d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n",
                wimax_dev, new_state, old_state);
-       return;
 }
 
 
@@ -362,7 +361,6 @@ void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
        if (wimax_dev->state > __WIMAX_ST_NULL)
                __wimax_state_change(wimax_dev, new_state);
        mutex_unlock(&wimax_dev->mutex);
-       return;
 }
 EXPORT_SYMBOL_GPL(wimax_state_change);
 
index bf1737fc9a7e47fe448e71a058334fb5fdb1b068..d92d088026bf885e30607f81799781a4c94c2794 100644 (file)
@@ -9,38 +9,6 @@
 #include <net/cfg80211.h>
 #include "core.h"
 
-struct ieee80211_channel *
-rdev_fixed_channel(struct cfg80211_registered_device *rdev,
-                  struct wireless_dev *for_wdev)
-{
-       struct wireless_dev *wdev;
-       struct ieee80211_channel *result = NULL;
-
-       WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
-
-       list_for_each_entry(wdev, &rdev->netdev_list, list) {
-               if (wdev == for_wdev)
-                       continue;
-
-               /*
-                * Lock manually to tell lockdep about allowed
-                * nesting here if for_wdev->mtx is held already.
-                * This is ok as it's all under the rdev devlist
-                * mutex and as such can only be done once at any
-                * given time.
-                */
-               mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
-               if (wdev->current_bss)
-                       result = wdev->current_bss->pub.channel;
-               wdev_unlock(wdev);
-
-               if (result)
-                       break;
-       }
-
-       return result;
-}
-
 struct ieee80211_channel *
 rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
                  int freq, enum nl80211_channel_type channel_type)
@@ -75,15 +43,22 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
        return chan;
 }
 
-int rdev_set_freq(struct cfg80211_registered_device *rdev,
-                 struct wireless_dev *for_wdev,
-                 int freq, enum nl80211_channel_type channel_type)
+int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
+                     struct wireless_dev *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 (wdev->iftype == NL80211_IFTYPE_MONITOR)
+               wdev = NULL;
+
+       if (wdev) {
+               ASSERT_WDEV_LOCK(wdev);
+
+               if (!netif_running(wdev->netdev))
+                       return -ENETDOWN;
+       }
 
        if (!rdev->ops->set_channel)
                return -EOPNOTSUPP;
@@ -92,11 +67,14 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
        if (!chan)
                return -EINVAL;
 
-       result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
+       result = rdev->ops->set_channel(&rdev->wiphy,
+                                       wdev ? wdev->netdev : NULL,
+                                       chan, channel_type);
        if (result)
                return result;
 
-       rdev->channel = chan;
+       if (wdev)
+               wdev->channel = chan;
 
        return 0;
 }
index 6ac70c1015235448fe79ebd3b25664b5f47479e3..37d0e0ab4432c7cecac400debdaeee1e1319c94b 100644 (file)
@@ -705,7 +705,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                        wdev->ps = true;
                else
                        wdev->ps = false;
-               wdev->ps_timeout = 100;
+               /* allow mac80211 to determine the timeout */
+               wdev->ps_timeout = -1;
                if (rdev->ops->set_power_mgmt)
                        if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
                                                      wdev->ps,
index d52da913145a82c96c1be83f84a7771909da8763..ae930acf75e9fb45bef945da23a0fdd1690e61f6 100644 (file)
@@ -70,9 +70,6 @@ struct cfg80211_registered_device {
        struct work_struct conn_work;
        struct work_struct event_work;
 
-       /* current channel */
-       struct ieee80211_channel *channel;
-
        /* must be last because of the way we do wiphy_priv(),
         * and it should at least be aligned to NETDEV_ALIGN */
        struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -293,13 +290,15 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx);
+                        const u8 *key, int key_len, int key_idx,
+                        bool local_state_change);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       struct net_device *dev, struct ieee80211_channel *chan,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx);
+                      const u8 *key, int key_len, int key_idx,
+                      bool local_state_change);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
                          struct ieee80211_channel *chan,
@@ -315,13 +314,16 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
                        struct cfg80211_crypto_settings *crypt);
 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason);
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change);
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                         struct net_device *dev, const u8 *bssid,
-                        const u8 *ie, int ie_len, u16 reason);
+                        const u8 *ie, int ie_len, u16 reason,
+                        bool local_state_change);
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason);
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change);
 void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
                        struct net_device *dev);
 void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -382,15 +384,12 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                          u32 *flags, struct vif_params *params);
 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);
+int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
+                     struct wireless_dev *wdev, int freq,
+                     enum nl80211_channel_type channel_type);
 
 u16 cfg80211_calculate_bitrate(struct rate_info *rate);
 
index 6a5acf7501740a1da95520f8f867cd2187b46c18..adcabba02e20c78199d3913a626fe74f209e002d 100644 (file)
@@ -81,15 +81,10 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                         struct cfg80211_cached_keys *connkeys)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct ieee80211_channel *chan;
        int err;
 
        ASSERT_WDEV_LOCK(wdev);
 
-       chan = rdev_fixed_channel(rdev, wdev);
-       if (chan && chan != params->channel)
-               return -EBUSY;
-
        if (wdev->ssid_len)
                return -EALREADY;
 
index 22139fa4611598810ae0d4c4a462996aeaa61583..48ead6f0426dc9763cc49819f7ac6e613aa36a76 100644 (file)
@@ -378,7 +378,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                         const u8 *bssid,
                         const u8 *ssid, int ssid_len,
                         const u8 *ie, int ie_len,
-                        const u8 *key, int key_len, int key_idx)
+                        const u8 *key, int key_len, int key_idx,
+                        bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_auth_request req;
@@ -408,6 +409,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 
        memset(&req, 0, sizeof(req));
 
+       req.local_state_change = local_state_change;
        req.ie = ie;
        req.ie_len = ie_len;
        req.auth_type = auth_type;
@@ -434,12 +436,18 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                goto out;
        }
 
-       wdev->authtry_bsses[slot] = bss;
+       if (local_state_change)
+               wdev->auth_bsses[slot] = bss;
+       else
+               wdev->authtry_bsses[slot] = bss;
        cfg80211_hold_bss(bss);
 
        err = rdev->ops->auth(&rdev->wiphy, dev, &req);
        if (err) {
-               wdev->authtry_bsses[slot] = NULL;
+               if (local_state_change)
+                       wdev->auth_bsses[slot] = NULL;
+               else
+                       wdev->authtry_bsses[slot] = NULL;
                cfg80211_unhold_bss(bss);
        }
 
@@ -454,14 +462,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
                       enum nl80211_auth_type auth_type, const u8 *bssid,
                       const u8 *ssid, int ssid_len,
                       const u8 *ie, int ie_len,
-                      const u8 *key, int key_len, int key_idx)
+                      const u8 *key, int key_len, int key_idx,
+                      bool local_state_change)
 {
        int err;
 
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                   ssid, ssid_len, ie, ie_len,
-                                  key, key_len, key_idx);
+                                  key, key_len, key_idx, local_state_change);
        wdev_unlock(dev->ieee80211_ptr);
 
        return err;
@@ -555,7 +564,8 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 
 int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason)
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_deauth_request req;
@@ -565,6 +575,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
        memset(&req, 0, sizeof(req));
        req.reason_code = reason;
+       req.local_state_change = local_state_change;
        req.ie = ie;
        req.ie_len = ie_len;
        if (wdev->current_bss &&
@@ -591,13 +602,15 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
                         struct net_device *dev, const u8 *bssid,
-                        const u8 *ie, int ie_len, u16 reason)
+                        const u8 *ie, int ie_len, u16 reason,
+                        bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
        wdev_lock(wdev);
-       err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
+       err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason,
+                                    local_state_change);
        wdev_unlock(wdev);
 
        return err;
@@ -605,7 +618,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                                    struct net_device *dev, const u8 *bssid,
-                                   const u8 *ie, int ie_len, u16 reason)
+                                   const u8 *ie, int ie_len, u16 reason,
+                                   bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_disassoc_request req;
@@ -620,6 +634,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
 
        memset(&req, 0, sizeof(req));
        req.reason_code = reason;
+       req.local_state_change = local_state_change;
        req.ie = ie;
        req.ie_len = ie_len;
        if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
@@ -632,13 +647,15 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
 
 int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
                           struct net_device *dev, const u8 *bssid,
-                          const u8 *ie, int ie_len, u16 reason)
+                          const u8 *ie, int ie_len, u16 reason,
+                          bool local_state_change)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        int err;
 
        wdev_lock(wdev);
-       err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
+       err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason,
+                                      local_state_change);
        wdev_unlock(wdev);
 
        return err;
@@ -895,3 +912,16 @@ void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
        nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
 }
 EXPORT_SYMBOL(cfg80211_action_tx_status);
+
+void cfg80211_cqm_rssi_notify(struct net_device *dev,
+                             enum nl80211_cqm_rssi_threshold_event rssi_event,
+                             gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       /* Indicate roaming trigger event to user space */
+       nl80211_send_cqm_rssi_notify(rdev, dev, rssi_event, gfp);
+}
+EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
index 030cf153bea252e28893e7d976f776faa355aa14..aaa1aad566cda4fb16ea866d5a078f8346f33340 100644 (file)
@@ -150,6 +150,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                                 .len = IEEE80211_MAX_DATA_LEN },
        [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
        [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
+       [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
+       [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
+       [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
 };
 
 /* policy for the attributes */
@@ -586,6 +589,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
        }
+       CMD(set_channel, SET_CHANNEL);
 
 #undef CMD
 
@@ -686,10 +690,90 @@ static int parse_txq_params(struct nlattr *tb[],
        return 0;
 }
 
+static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
+{
+       /*
+        * You can only set the channel explicitly for AP, mesh
+        * and WDS type interfaces; all others have their channel
+        * managed via their respective "establish a connection"
+        * command (connect, join, ...)
+        *
+        * Monitors are special as they are normally slaved to
+        * whatever else is going on, so they behave as though
+        * you tried setting the wiphy channel itself.
+        */
+       return !wdev ||
+               wdev->iftype == NL80211_IFTYPE_AP ||
+               wdev->iftype == NL80211_IFTYPE_WDS ||
+               wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
+               wdev->iftype == NL80211_IFTYPE_MONITOR;
+}
+
+static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
+                                struct wireless_dev *wdev,
+                                struct genl_info *info)
+{
+       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+       u32 freq;
+       int result;
+
+       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+               return -EINVAL;
+
+       if (!nl80211_can_set_dev_channel(wdev))
+               return -EOPNOTSUPP;
+
+       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)
+                       return -EINVAL;
+       }
+
+       freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+
+       mutex_lock(&rdev->devlist_mtx);
+       if (wdev) {
+               wdev_lock(wdev);
+               result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
+               wdev_unlock(wdev);
+       } else {
+               result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
+       }
+       mutex_unlock(&rdev->devlist_mtx);
+
+       return result;
+}
+
+static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev;
+       struct net_device *netdev;
+       int result;
+
+       rtnl_lock();
+
+       result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
+       if (result)
+               goto unlock;
+
+       result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
+
+ unlock:
+       rtnl_unlock();
+
+       return result;
+}
+
 static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
-       int result = 0, rem_txq_params = 0;
+       struct net_device *netdev = NULL;
+       struct wireless_dev *wdev;
+       int result, rem_txq_params = 0;
        struct nlattr *nl_txq_params;
        u32 changed;
        u8 retry_short = 0, retry_long = 0;
@@ -698,16 +782,50 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_lock();
 
+       /*
+        * Try to find the wiphy and netdev. Normally this
+        * function shouldn't need the netdev, but this is
+        * done for backward compatibility -- previously
+        * setting the channel was done per wiphy, but now
+        * it is per netdev. Previous userland like hostapd
+        * also passed a netdev to set_wiphy, so that it is
+        * possible to let that go to the right netdev!
+        */
        mutex_lock(&cfg80211_mutex);
 
-       rdev = __cfg80211_rdev_from_info(info);
-       if (IS_ERR(rdev)) {
-               mutex_unlock(&cfg80211_mutex);
-               result = PTR_ERR(rdev);
-               goto unlock;
+       if (info->attrs[NL80211_ATTR_IFINDEX]) {
+               int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
+
+               netdev = dev_get_by_index(genl_info_net(info), ifindex);
+               if (netdev && netdev->ieee80211_ptr) {
+                       rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
+                       mutex_lock(&rdev->mtx);
+               } else
+                       netdev = NULL;
        }
 
-       mutex_lock(&rdev->mtx);
+       if (!netdev) {
+               rdev = __cfg80211_rdev_from_info(info);
+               if (IS_ERR(rdev)) {
+                       mutex_unlock(&cfg80211_mutex);
+                       result = PTR_ERR(rdev);
+                       goto unlock;
+               }
+               wdev = NULL;
+               netdev = NULL;
+               result = 0;
+
+               mutex_lock(&rdev->mtx);
+       } else if (netif_running(netdev) &&
+                  nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+               wdev = netdev->ieee80211_ptr;
+       else
+               wdev = NULL;
+
+       /*
+        * end workaround code, by now the rdev is available
+        * and locked, and wdev may or may not be NULL.
+        */
 
        if (info->attrs[NL80211_ATTR_WIPHY_NAME])
                result = cfg80211_dev_rename(
@@ -746,26 +864,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-               u32 freq;
-
-               result = -EINVAL;
-
-               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)
-                               goto bad_res;
-               }
-
-               freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
-
-               mutex_lock(&rdev->devlist_mtx);
-               result = rdev_set_freq(rdev, NULL, freq, channel_type);
-               mutex_unlock(&rdev->devlist_mtx);
+               result = __nl80211_set_channel(rdev, wdev, info);
                if (result)
                        goto bad_res;
        }
@@ -862,6 +961,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
 
  bad_res:
        mutex_unlock(&rdev->mtx);
+       if (netdev)
+               dev_put(netdev);
  unlock:
        rtnl_unlock();
        return result;
@@ -2096,7 +2197,8 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
                goto out_rtnl;
 
        if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
                err = -EINVAL;
                goto out;
        }
@@ -2439,6 +2541,7 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
        params.use_cts_prot = -1;
        params.use_short_preamble = -1;
        params.use_short_slot_time = -1;
+       params.ap_isolate = -1;
 
        if (info->attrs[NL80211_ATTR_BSS_CTS_PROT])
                params.use_cts_prot =
@@ -2455,6 +2558,8 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info)
                params.basic_rates_len =
                        nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
        }
+       if (info->attrs[NL80211_ATTR_AP_ISOLATE])
+               params.ap_isolate = !!nla_get_u8(info->attrs[NL80211_ATTR_AP_ISOLATE]);
 
        rtnl_lock();
 
@@ -3392,6 +3497,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
        int err, ssid_len, ie_len = 0;
        enum nl80211_auth_type auth_type;
        struct key_parse key;
+       bool local_state_change;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3470,9 +3576,12 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
+       local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+
        err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
                                 ssid, ssid_len, ie, ie_len,
-                                key.p.key, key.p.key_len, key.idx);
+                                key.p.key, key.p.key_len, key.idx,
+                                local_state_change);
 
 out:
        cfg80211_unlock_rdev(rdev);
@@ -3551,9 +3660,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev;
        struct net_device *dev;
-       struct wireless_dev *wdev;
        struct cfg80211_crypto_settings crypto;
-       struct ieee80211_channel *chan, *fixedchan;
+       struct ieee80211_channel *chan;
        const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
        int err, ssid_len, ie_len = 0;
        bool use_mfp = false;
@@ -3596,16 +3704,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
                goto out;
        }
 
-       mutex_lock(&rdev->devlist_mtx);
-       wdev = dev->ieee80211_ptr;
-       fixedchan = rdev_fixed_channel(rdev, wdev);
-       if (fixedchan && chan != fixedchan) {
-               err = -EBUSY;
-               mutex_unlock(&rdev->devlist_mtx);
-               goto out;
-       }
-       mutex_unlock(&rdev->devlist_mtx);
-
        ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
@@ -3649,6 +3747,7 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
        const u8 *ie = NULL, *bssid;
        int err, ie_len = 0;
        u16 reason_code;
+       bool local_state_change;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3694,7 +3793,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code);
+       local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+
+       err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
+                                  local_state_change);
 
 out:
        cfg80211_unlock_rdev(rdev);
@@ -3711,6 +3813,7 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
        const u8 *ie = NULL, *bssid;
        int err, ie_len = 0;
        u16 reason_code;
+       bool local_state_change;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
@@ -3756,7 +3859,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code);
+       local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
+
+       err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
+                                    local_state_change);
 
 out:
        cfg80211_unlock_rdev(rdev);
@@ -4779,6 +4885,84 @@ unlock_rtnl:
        return err;
 }
 
+static struct nla_policy
+nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
+       [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+       [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
+       [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+};
+
+static int nl80211_set_cqm_rssi(struct genl_info *info,
+                               s32 threshold, u32 hysteresis)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wireless_dev *wdev;
+       struct net_device *dev;
+       int err;
+
+       if (threshold > 0)
+               return -EINVAL;
+
+       rtnl_lock();
+
+       err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
+       if (err)
+               goto unlock_rdev;
+
+       wdev = dev->ieee80211_ptr;
+
+       if (!rdev->ops->set_cqm_rssi_config) {
+               err = -EOPNOTSUPP;
+               goto unlock_rdev;
+       }
+
+       if (wdev->iftype != NL80211_IFTYPE_STATION) {
+               err = -EOPNOTSUPP;
+               goto unlock_rdev;
+       }
+
+       err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev,
+                                            threshold, hysteresis);
+
+unlock_rdev:
+       cfg80211_unlock_rdev(rdev);
+       dev_put(dev);
+       rtnl_unlock();
+
+       return err;
+}
+
+static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nlattr *attrs[NL80211_ATTR_CQM_MAX + 1];
+       struct nlattr *cqm;
+       int err;
+
+       cqm = info->attrs[NL80211_ATTR_CQM];
+       if (!cqm) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = nla_parse_nested(attrs, NL80211_ATTR_CQM_MAX, cqm,
+                              nl80211_attr_cqm_policy);
+       if (err)
+               goto out;
+
+       if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
+           attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
+               s32 threshold;
+               u32 hysteresis;
+               threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+               hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
+               err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
+       } else
+               err = -EINVAL;
+
+out:
+       return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_GET_WIPHY,
@@ -5083,6 +5267,18 @@ static struct genl_ops nl80211_ops[] = {
                .policy = nl80211_policy,
                /* can be retrieved by unprivileged users */
        },
+       {
+               .cmd = NL80211_CMD_SET_CQM,
+               .doit = nl80211_set_cqm,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = NL80211_CMD_SET_CHANNEL,
+               .doit = nl80211_set_channel,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5833,6 +6029,52 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
+void
+nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
+                            struct net_device *netdev,
+                            enum nl80211_cqm_rssi_threshold_event rssi_event,
+                            gfp_t gfp)
+{
+       struct sk_buff *msg;
+       struct nlattr *pinfoattr;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
+       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);
+
+       pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
+       if (!pinfoattr)
+               goto nla_put_failure;
+
+       NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
+                   rssi_event);
+
+       nla_nest_end(msg, pinfoattr);
+
+       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);
+}
+
 static int nl80211_netlink_notify(struct notifier_block * nb,
                                  unsigned long state,
                                  void *_notify)
index 4ca511102c6c669ac2b2becb08821a8918e70da4..2ad7fbc7d9f1ad907d3ef7638cb3241c93c622d7 100644 (file)
@@ -82,4 +82,10 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
                                   const u8 *buf, size_t len, bool ack,
                                   gfp_t gfp);
 
+void
+nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
+                            struct net_device *netdev,
+                            enum nl80211_cqm_rssi_threshold_event rssi_event,
+                            gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index 422da20d1e5b8a0bad63c8677b2631612905be9e..8f0d97dd3109c54cd85fe01095308171d34d9f01 100644 (file)
@@ -2356,10 +2356,10 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
                                        rdev->country_ie_alpha2[1]);
                        } else
                                printk(KERN_INFO "cfg80211: Current regulatory "
-                                       "domain intersected: \n");
+                                       "domain intersected:\n");
                } else
-                               printk(KERN_INFO "cfg80211: Current regulatory "
-                                       "domain intersected: \n");
+                       printk(KERN_INFO "cfg80211: Current regulatory "
+                               "domain intersected:\n");
        } else if (is_world_regdom(rd->alpha2))
                printk(KERN_INFO "cfg80211: World regulatory "
                        "domain updated:\n");
index f4dfd5f5f2ea429cb3a6e1d541f419813063ef45..72222f0074dbd4b24914386b85e02257d499941d 100644 (file)
@@ -171,7 +171,7 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                            params->ssid, params->ssid_len,
                                            NULL, 0,
                                            params->key, params->key_len,
-                                           params->key_idx);
+                                           params->key_idx, false);
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -186,12 +186,13 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                if (err)
                        __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                               NULL, 0,
-                                              WLAN_REASON_DEAUTH_LEAVING);
+                                              WLAN_REASON_DEAUTH_LEAVING,
+                                              false);
                return err;
        case CFG80211_CONN_DEAUTH_ASSOC_FAIL:
                __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                       NULL, 0,
-                                      WLAN_REASON_DEAUTH_LEAVING);
+                                      WLAN_REASON_DEAUTH_LEAVING, false);
                /* return an error so that we call __cfg80211_connect_result() */
                return -EINVAL;
        default:
@@ -517,12 +518,16 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        ev->type = EVENT_CONNECT_RESULT;
        if (bssid)
                memcpy(ev->cr.bssid, bssid, ETH_ALEN);
-       ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
-       ev->cr.req_ie_len = req_ie_len;
-       memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
-       ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
-       ev->cr.resp_ie_len = resp_ie_len;
-       memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+       if (req_ie_len) {
+               ev->cr.req_ie = ((u8 *)ev) + sizeof(*ev);
+               ev->cr.req_ie_len = req_ie_len;
+               memcpy((void *)ev->cr.req_ie, req_ie, req_ie_len);
+       }
+       if (resp_ie_len) {
+               ev->cr.resp_ie = ((u8 *)ev) + sizeof(*ev) + req_ie_len;
+               ev->cr.resp_ie_len = resp_ie_len;
+               memcpy((void *)ev->cr.resp_ie, resp_ie, resp_ie_len);
+       }
        ev->cr.status = status;
 
        spin_lock_irqsave(&wdev->event_lock, flags);
@@ -676,7 +681,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                                continue;
                        bssid = wdev->auth_bsses[i]->pub.bssid;
                        ret = __cfg80211_mlme_deauth(rdev, dev, bssid, NULL, 0,
-                                               WLAN_REASON_DEAUTH_LEAVING);
+                                               WLAN_REASON_DEAUTH_LEAVING,
+                                               false);
                        WARN(ret, "deauth failed: %d\n", ret);
                }
        }
@@ -735,7 +741,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
                       const u8 *prev_bssid)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct ieee80211_channel *chan;
        struct cfg80211_bss *bss = NULL;
        int err;
 
@@ -744,10 +749,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
        if (wdev->sme_state != CFG80211_SME_IDLE)
                return -EALREADY;
 
-       chan = rdev_fixed_channel(rdev, wdev);
-       if (chan && chan != connect->channel)
-               return -EBUSY;
-
        if (WARN_ON(wdev->connect_keys)) {
                kfree(wdev->connect_keys);
                wdev->connect_keys = NULL;
@@ -935,7 +936,7 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
                /* wdev->conn->params.bssid must be set if > SCANNING */
                err = __cfg80211_mlme_deauth(rdev, dev,
                                             wdev->conn->params.bssid,
-                                            NULL, 0, reason);
+                                            NULL, 0, reason, false);
                if (err)
                        return err;
        } else {
@@ -991,7 +992,8 @@ void cfg80211_sme_disassoc(struct net_device *dev, int idx)
 
        memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN);
        if (__cfg80211_mlme_deauth(rdev, dev, bssid,
-                                  NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) {
+                                  NULL, 0, WLAN_REASON_DEAUTH_LEAVING,
+                                  false)) {
                /* whatever -- assume gone anyway */
                cfg80211_unhold_bss(wdev->auth_bsses[idx]);
                cfg80211_put_bss(&wdev->auth_bsses[idx]->pub);
index d3574a4eb3ba1ab837d564c819c50c328aaf2f7e..3416373a9c0c80e91c21f687eb61ec7b91daa626 100644 (file)
@@ -331,11 +331,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
                        struct ieee80211s_hdr *meshdr =
                                (struct ieee80211s_hdr *) (skb->data + hdrlen);
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+                       /* make sure meshdr->flags is on the linear part */
+                       if (!pskb_may_pull(skb, hdrlen + 1))
+                               return -1;
                        if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
-                               memcpy(dst, meshdr->eaddr1, ETH_ALEN);
-                               memcpy(src, meshdr->eaddr2, ETH_ALEN);
+                               skb_copy_bits(skb, hdrlen +
+                                       offsetof(struct ieee80211s_hdr, eaddr1),
+                                       dst, ETH_ALEN);
+                               skb_copy_bits(skb, hdrlen +
+                                       offsetof(struct ieee80211s_hdr, eaddr2),
+                                       src, ETH_ALEN);
                        }
+                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
                }
                break;
        case cpu_to_le16(IEEE80211_FCTL_FROMDS):
@@ -347,9 +354,14 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                if (iftype == NL80211_IFTYPE_MESH_POINT) {
                        struct ieee80211s_hdr *meshdr =
                                (struct ieee80211s_hdr *) (skb->data + hdrlen);
-                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+                       /* make sure meshdr->flags is on the linear part */
+                       if (!pskb_may_pull(skb, hdrlen + 1))
+                               return -1;
                        if (meshdr->flags & MESH_FLAGS_AE_A4)
-                               memcpy(src, meshdr->eaddr1, ETH_ALEN);
+                               skb_copy_bits(skb, hdrlen +
+                                       offsetof(struct ieee80211s_hdr, eaddr1),
+                                       src, ETH_ALEN);
+                       hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
                }
                break;
        case cpu_to_le16(0):
@@ -358,7 +370,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
                break;
        }
 
-       if (unlikely(skb->len - hdrlen < 8))
+       if (!pskb_may_pull(skb, hdrlen + 8))
                return -1;
 
        payload = skb->data + hdrlen;
index a60a2773b49726b01fc86b58a74a432a8f54fc26..96342993cf933237d76c33595497d938ed86ec3c 100644 (file)
@@ -782,16 +782,22 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
                return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
-       default:
+       case NL80211_IFTYPE_MONITOR:
+       case NL80211_IFTYPE_WDS:
+       case NL80211_IFTYPE_MESH_POINT:
                freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
                if (freq < 0)
                        return freq;
                if (freq == 0)
                        return -EINVAL;
+               wdev_lock(wdev);
                mutex_lock(&rdev->devlist_mtx);
-               err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
                mutex_unlock(&rdev->devlist_mtx);
+               wdev_unlock(wdev);
                return err;
+       default:
+               return -EOPNOTSUPP;
        }
 }
 EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
@@ -801,7 +807,6 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
                          struct iw_freq *freq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
-       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
@@ -809,9 +814,9 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
        default:
-               if (!rdev->channel)
+               if (!wdev->channel)
                        return -EINVAL;
-               freq->m = rdev->channel->center_freq;
+               freq->m = wdev->channel->center_freq;
                freq->e = 6;
                return 0;
        }
index 4f5a47091fde623abc20e9ad8abfaea0fc224da3..0ef17bc42bac05996eab6e2dada02fc67953c3dc 100644 (file)
@@ -29,226 +29,226 @@ typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
  * know about.
  */
 static const struct iw_ioctl_description standard_ioctl[] = {
-       [SIOCSIWCOMMIT  - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWCOMMIT)] = {
                .header_type    = IW_HEADER_TYPE_NULL,
        },
-       [SIOCGIWNAME    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWNAME)] = {
                .header_type    = IW_HEADER_TYPE_CHAR,
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWNWID    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWNWID)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
                .flags          = IW_DESCR_FLAG_EVENT,
        },
-       [SIOCGIWNWID    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWNWID)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWFREQ    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWFREQ)] = {
                .header_type    = IW_HEADER_TYPE_FREQ,
                .flags          = IW_DESCR_FLAG_EVENT,
        },
-       [SIOCGIWFREQ    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWFREQ)] = {
                .header_type    = IW_HEADER_TYPE_FREQ,
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWMODE    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWMODE)] = {
                .header_type    = IW_HEADER_TYPE_UINT,
                .flags          = IW_DESCR_FLAG_EVENT,
        },
-       [SIOCGIWMODE    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWMODE)] = {
                .header_type    = IW_HEADER_TYPE_UINT,
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWSENS    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWSENS)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWSENS    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWSENS)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWRANGE   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWRANGE)] = {
                .header_type    = IW_HEADER_TYPE_NULL,
        },
-       [SIOCGIWRANGE   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWRANGE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = sizeof(struct iw_range),
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWPRIV    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWPRIV)] = {
                .header_type    = IW_HEADER_TYPE_NULL,
        },
-       [SIOCGIWPRIV    - SIOCIWFIRST] = { /* (handled directly by us) */
+       [IW_IOCTL_IDX(SIOCGIWPRIV)] = { /* (handled directly by us) */
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = sizeof(struct iw_priv_args),
                .max_tokens     = 16,
                .flags          = IW_DESCR_FLAG_NOMAX,
        },
-       [SIOCSIWSTATS   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWSTATS)] = {
                .header_type    = IW_HEADER_TYPE_NULL,
        },
-       [SIOCGIWSTATS   - SIOCIWFIRST] = { /* (handled directly by us) */
+       [IW_IOCTL_IDX(SIOCGIWSTATS)] = { /* (handled directly by us) */
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = sizeof(struct iw_statistics),
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWSPY     - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWSPY)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = sizeof(struct sockaddr),
                .max_tokens     = IW_MAX_SPY,
        },
-       [SIOCGIWSPY     - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWSPY)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = sizeof(struct sockaddr) +
                                  sizeof(struct iw_quality),
                .max_tokens     = IW_MAX_SPY,
        },
-       [SIOCSIWTHRSPY  - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWTHRSPY)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = sizeof(struct iw_thrspy),
                .min_tokens     = 1,
                .max_tokens     = 1,
        },
-       [SIOCGIWTHRSPY  - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWTHRSPY)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = sizeof(struct iw_thrspy),
                .min_tokens     = 1,
                .max_tokens     = 1,
        },
-       [SIOCSIWAP      - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWAP)] = {
                .header_type    = IW_HEADER_TYPE_ADDR,
        },
-       [SIOCGIWAP      - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWAP)] = {
                .header_type    = IW_HEADER_TYPE_ADDR,
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWMLME    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWMLME)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .min_tokens     = sizeof(struct iw_mlme),
                .max_tokens     = sizeof(struct iw_mlme),
        },
-       [SIOCGIWAPLIST  - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWAPLIST)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = sizeof(struct sockaddr) +
                                  sizeof(struct iw_quality),
                .max_tokens     = IW_MAX_AP,
                .flags          = IW_DESCR_FLAG_NOMAX,
        },
-       [SIOCSIWSCAN    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWSCAN)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .min_tokens     = 0,
                .max_tokens     = sizeof(struct iw_scan_req),
        },
-       [SIOCGIWSCAN    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWSCAN)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_SCAN_MAX_DATA,
                .flags          = IW_DESCR_FLAG_NOMAX,
        },
-       [SIOCSIWESSID   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWESSID)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_ESSID_MAX_SIZE,
                .flags          = IW_DESCR_FLAG_EVENT,
        },
-       [SIOCGIWESSID   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWESSID)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_ESSID_MAX_SIZE,
                .flags          = IW_DESCR_FLAG_DUMP,
        },
-       [SIOCSIWNICKN   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWNICKN)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_ESSID_MAX_SIZE,
        },
-       [SIOCGIWNICKN   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWNICKN)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_ESSID_MAX_SIZE,
        },
-       [SIOCSIWRATE    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWRATE)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWRATE    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWRATE)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWRTS     - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWRTS)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWRTS     - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWRTS)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWFRAG    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWFRAG)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWFRAG    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWFRAG)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWTXPOW   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWTXPOW)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWTXPOW   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWTXPOW)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWRETRY   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWRETRY)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWRETRY   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWRETRY)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWENCODE  - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWENCODE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_ENCODING_TOKEN_MAX,
                .flags          = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
        },
-       [SIOCGIWENCODE  - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWENCODE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_ENCODING_TOKEN_MAX,
                .flags          = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
        },
-       [SIOCSIWPOWER   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWPOWER)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWPOWER   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWPOWER)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWGENIE   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWGENIE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_GENERIC_IE_MAX,
        },
-       [SIOCGIWGENIE   - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWGENIE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_GENERIC_IE_MAX,
        },
-       [SIOCSIWAUTH    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWAUTH)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCGIWAUTH    - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWAUTH)] = {
                .header_type    = IW_HEADER_TYPE_PARAM,
        },
-       [SIOCSIWENCODEEXT - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWENCODEEXT)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .min_tokens     = sizeof(struct iw_encode_ext),
                .max_tokens     = sizeof(struct iw_encode_ext) +
                                  IW_ENCODING_TOKEN_MAX,
        },
-       [SIOCGIWENCODEEXT - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCGIWENCODEEXT)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .min_tokens     = sizeof(struct iw_encode_ext),
                .max_tokens     = sizeof(struct iw_encode_ext) +
                                  IW_ENCODING_TOKEN_MAX,
        },
-       [SIOCSIWPMKSA - SIOCIWFIRST] = {
+       [IW_IOCTL_IDX(SIOCSIWPMKSA)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .min_tokens     = sizeof(struct iw_pmksa),
@@ -262,44 +262,44 @@ static const unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
  * we know about.
  */
 static const struct iw_ioctl_description standard_event[] = {
-       [IWEVTXDROP     - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVTXDROP)] = {
                .header_type    = IW_HEADER_TYPE_ADDR,
        },
-       [IWEVQUAL       - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVQUAL)] = {
                .header_type    = IW_HEADER_TYPE_QUAL,
        },
-       [IWEVCUSTOM     - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVCUSTOM)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_CUSTOM_MAX,
        },
-       [IWEVREGISTERED - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVREGISTERED)] = {
                .header_type    = IW_HEADER_TYPE_ADDR,
        },
-       [IWEVEXPIRED    - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVEXPIRED)] = {
                .header_type    = IW_HEADER_TYPE_ADDR,
        },
-       [IWEVGENIE      - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVGENIE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_GENERIC_IE_MAX,
        },
-       [IWEVMICHAELMICFAILURE  - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVMICHAELMICFAILURE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = sizeof(struct iw_michaelmicfailure),
        },
-       [IWEVASSOCREQIE - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVASSOCREQIE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_GENERIC_IE_MAX,
        },
-       [IWEVASSOCRESPIE        - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVASSOCRESPIE)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = IW_GENERIC_IE_MAX,
        },
-       [IWEVPMKIDCAND  - IWEVFIRST] = {
+       [IW_EVENT_IDX(IWEVPMKIDCAND)] = {
                .header_type    = IW_HEADER_TYPE_POINT,
                .token_size     = 1,
                .max_tokens     = sizeof(struct iw_pmkid_cand),
@@ -450,11 +450,11 @@ void wireless_send_event(struct net_device *      dev,
 
        /* Get the description of the Event */
        if (cmd <= SIOCIWLAST) {
-               cmd_index = cmd - SIOCIWFIRST;
+               cmd_index = IW_IOCTL_IDX(cmd);
                if (cmd_index < standard_ioctl_num)
                        descr = &(standard_ioctl[cmd_index]);
        } else {
-               cmd_index = cmd - IWEVFIRST;
+               cmd_index = IW_EVENT_IDX(cmd);
                if (cmd_index < standard_event_num)
                        descr = &(standard_event[cmd_index]);
        }
@@ -663,7 +663,7 @@ static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
                return NULL;
 
        /* Try as a standard command */
-       index = cmd - SIOCIWFIRST;
+       index = IW_IOCTL_IDX(cmd);
        if (index < handlers->num_standard)
                return handlers->standard[index];
 
@@ -955,9 +955,9 @@ static int ioctl_standard_call(struct net_device *  dev,
        int                                     ret = -EINVAL;
 
        /* Get the description of the IOCTL */
-       if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+       if (IW_IOCTL_IDX(cmd) >= standard_ioctl_num)
                return -EOPNOTSUPP;
-       descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+       descr = &(standard_ioctl[IW_IOCTL_IDX(cmd)]);
 
        /* Check if we have a pointer to user space data or not */
        if (descr->header_type != IW_HEADER_TYPE_POINT) {
@@ -1013,7 +1013,7 @@ static int compat_standard_call(struct net_device *dev,
        struct iw_point iwp;
        int err;
 
-       descr = standard_ioctl + (cmd - SIOCIWFIRST);
+       descr = standard_ioctl + IW_IOCTL_IDX(cmd);
 
        if (descr->header_type != IW_HEADER_TYPE_POINT)
                return ioctl_standard_call(dev, iwr, cmd, info, handler);
index d5c6140f4cb8ee25b80da910b4884b351c0b87c5..9818198add8a21444ba9183bbb8e4fc2c2199491 100644 (file)
@@ -108,7 +108,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
 
        /* SSID is not set, we just want to switch channel */
        if (chan && !wdev->wext.connect.ssid_len) {
-               err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
                goto out;
        }
 
index 36e84e13c6aa9f6167d9b6ba2cf48b72829c2d58..5e86d4e97dceb29f89ae779554b51b3f336705ef 100644 (file)
@@ -453,7 +453,6 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
        struct sock *sk = sock->sk;
        int rc = -ENOPROTOOPT;
 
-       lock_kernel();
        if (level != SOL_X25 || optname != X25_QBITINCL)
                goto out;
 
@@ -465,10 +464,12 @@ static int x25_setsockopt(struct socket *sock, int level, int optname,
        if (get_user(opt, (int __user *)optval))
                goto out;
 
-       x25_sk(sk)->qbitincl = !!opt;
+       if (opt)
+               set_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags);
+       else
+               clear_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags);
        rc = 0;
 out:
-       unlock_kernel();
        return rc;
 }
 
@@ -478,7 +479,6 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
        struct sock *sk = sock->sk;
        int val, len, rc = -ENOPROTOOPT;
 
-       lock_kernel();
        if (level != SOL_X25 || optname != X25_QBITINCL)
                goto out;
 
@@ -496,10 +496,9 @@ static int x25_getsockopt(struct socket *sock, int level, int optname,
        if (put_user(len, optlen))
                goto out;
 
-       val = x25_sk(sk)->qbitincl;
+       val = test_bit(X25_Q_BIT_FLAG, &x25_sk(sk)->flags);
        rc = copy_to_user(optval, &val, len) ? -EFAULT : 0;
 out:
-       unlock_kernel();
        return rc;
 }
 
@@ -583,7 +582,7 @@ static int x25_create(struct net *net, struct socket *sock, int protocol,
        x25->t2    = sysctl_x25_ack_holdback_timeout;
        x25->state = X25_STATE_0;
        x25->cudmatchlength = 0;
-       x25->accptapprv = X25_DENY_ACCPT_APPRV;         /* normally no cud  */
+       set_bit(X25_ACCPT_APPRV_FLAG, &x25->flags);     /* normally no cud  */
                                                        /* on call accept   */
 
        x25->facilities.winsize_in  = X25_DEFAULT_WINDOW_SIZE;
@@ -632,12 +631,12 @@ static struct sock *x25_make_new(struct sock *osk)
        x25->t22        = ox25->t22;
        x25->t23        = ox25->t23;
        x25->t2         = ox25->t2;
+       x25->flags      = ox25->flags;
        x25->facilities = ox25->facilities;
-       x25->qbitincl   = ox25->qbitincl;
        x25->dte_facilities = ox25->dte_facilities;
        x25->cudmatchlength = ox25->cudmatchlength;
-       x25->accptapprv = ox25->accptapprv;
 
+       clear_bit(X25_INTERRUPT_FLAG, &x25->flags);
        x25_init_timers(sk);
 out:
        return sk;
@@ -719,7 +718,7 @@ static int x25_wait_for_connection_establishment(struct sock *sk)
        DECLARE_WAITQUEUE(wait, current);
        int rc;
 
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        for (;;) {
                __set_current_state(TASK_INTERRUPTIBLE);
                rc = -ERESTARTSYS;
@@ -739,7 +738,7 @@ static int x25_wait_for_connection_establishment(struct sock *sk)
                        break;
        }
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
        return rc;
 }
 
@@ -839,7 +838,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout)
        DECLARE_WAITQUEUE(wait, current);
        int rc = 0;
 
-       add_wait_queue_exclusive(sk->sk_sleep, &wait);
+       add_wait_queue_exclusive(sk_sleep(sk), &wait);
        for (;;) {
                __set_current_state(TASK_INTERRUPTIBLE);
                if (sk->sk_shutdown & RCV_SHUTDOWN)
@@ -859,7 +858,7 @@ static int x25_wait_for_data(struct sock *sk, long timeout)
                        break;
        }
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(sk->sk_sleep, &wait);
+       remove_wait_queue(sk_sleep(sk), &wait);
        return rc;
 }
 
@@ -1053,8 +1052,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        makex25->vc_facil_mask &= ~X25_MASK_CALLING_AE;
        makex25->cudmatchlength = x25_sk(sk)->cudmatchlength;
 
-       /* Normally all calls are accepted immediatly */
-       if(makex25->accptapprv & X25_DENY_ACCPT_APPRV) {
+       /* Normally all calls are accepted immediately */
+       if (test_bit(X25_ACCPT_APPRV_FLAG, &makex25->flags)) {
                x25_write_internal(make, X25_CALL_ACCEPTED);
                makex25->state = X25_STATE_3;
        }
@@ -1186,7 +1185,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
         *      If the Q BIT Include socket option is in force, the first
         *      byte of the user data is the logical value of the Q Bit.
         */
-       if (x25->qbitincl) {
+       if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
                qbit = skb->data[0];
                skb_pull(skb, 1);
        }
@@ -1242,7 +1241,7 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
                len = rc;
                if (rc < 0)
                        kfree_skb(skb);
-               else if (x25->qbitincl)
+               else if (test_bit(X25_Q_BIT_FLAG, &x25->flags))
                        len++;
        }
 
@@ -1307,7 +1306,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
                /*
                 *      No Q bit information on Interrupt data.
                 */
-               if (x25->qbitincl) {
+               if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
                        asmptr  = skb_push(skb, 1);
                        *asmptr = 0x00;
                }
@@ -1325,7 +1324,7 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
                skb_pull(skb, x25->neighbour->extended ?
                                X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
 
-               if (x25->qbitincl) {
+               if (test_bit(X25_Q_BIT_FLAG, &x25->flags)) {
                        asmptr  = skb_push(skb, 1);
                        *asmptr = qbit;
                }
@@ -1576,7 +1575,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        rc = -EINVAL;
                        if (sk->sk_state != TCP_CLOSE)
                                break;
-                       x25->accptapprv = X25_ALLOW_ACCPT_APPRV;
+                       clear_bit(X25_ACCPT_APPRV_FLAG, &x25->flags);
                        rc = 0;
                        break;
                }
@@ -1585,7 +1584,8 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                        rc = -EINVAL;
                        if (sk->sk_state != TCP_ESTABLISHED)
                                break;
-                       if (x25->accptapprv)    /* must call accptapprv above */
+                       /* must call accptapprv above */
+                       if (test_bit(X25_ACCPT_APPRV_FLAG, &x25->flags))
                                break;
                        x25_write_internal(sk, X25_CALL_ACCEPTED);
                        x25->state = X25_STATE_3;
index b9ef682230a0cbe675cf42367608ac88ee050a6f..9005f6daeab583458b370a9385f5b7f10d19908c 100644 (file)
@@ -24,6 +24,7 @@
 #include <net/sock.h>
 #include <linux/if_arp.h>
 #include <net/x25.h>
+#include <net/x25device.h>
 
 static int x25_receive_data(struct sk_buff *skb, struct x25_neigh *nb)
 {
@@ -115,19 +116,22 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
        }
 
        switch (skb->data[0]) {
-               case 0x00:
-                       skb_pull(skb, 1);
-                       if (x25_receive_data(skb, nb)) {
-                               x25_neigh_put(nb);
-                               goto out;
-                       }
-                       break;
-               case 0x01:
-                       x25_link_established(nb);
-                       break;
-               case 0x02:
-                       x25_link_terminated(nb);
-                       break;
+
+       case X25_IFACE_DATA:
+               skb_pull(skb, 1);
+               if (x25_receive_data(skb, nb)) {
+                       x25_neigh_put(nb);
+                       goto out;
+               }
+               break;
+
+       case X25_IFACE_CONNECT:
+               x25_link_established(nb);
+               break;
+
+       case X25_IFACE_DISCONNECT:
+               x25_link_terminated(nb);
+               break;
        }
        x25_neigh_put(nb);
 drop:
@@ -148,7 +152,7 @@ void x25_establish_link(struct x25_neigh *nb)
                                return;
                        }
                        ptr  = skb_put(skb, 1);
-                       *ptr = 0x01;
+                       *ptr = X25_IFACE_CONNECT;
                        break;
 
 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
@@ -184,7 +188,7 @@ void x25_terminate_link(struct x25_neigh *nb)
        }
 
        ptr  = skb_put(skb, 1);
-       *ptr = 0x02;
+       *ptr = X25_IFACE_DISCONNECT;
 
        skb->protocol = htons(ETH_P_X25);
        skb->dev      = nb->dev;
@@ -200,7 +204,7 @@ void x25_send_frame(struct sk_buff *skb, struct x25_neigh *nb)
        switch (nb->dev->type) {
                case ARPHRD_X25:
                        dptr  = skb_push(skb, 1);
-                       *dptr = 0x00;
+                       *dptr = X25_IFACE_DATA;
                        break;
 
 #if defined(CONFIG_LLC) || defined(CONFIG_LLC_MODULE)
index 372ac226e648445057f82786e95a7ee64c11cd2d..63178961efac00488d36e7c8fc3d21f00e036e2e 100644 (file)
@@ -273,7 +273,7 @@ static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                        break;
 
                case X25_INTERRUPT_CONFIRMATION:
-                       x25->intflag = 0;
+                       clear_bit(X25_INTERRUPT_FLAG, &x25->flags);
                        break;
 
                case X25_INTERRUPT:
index 52351a26b6fc4b713f034e9b2d7a1990247ca419..d00649fb251d3df8bddafad81508e96d74821eb1 100644 (file)
@@ -148,8 +148,9 @@ void x25_kick(struct sock *sk)
        /*
         *      Transmit interrupt data.
         */
-       if (!x25->intflag && skb_peek(&x25->interrupt_out_queue) != NULL) {
-               x25->intflag = 1;
+       if (skb_peek(&x25->interrupt_out_queue) != NULL &&
+               !test_and_set_bit(X25_INTERRUPT_FLAG, &x25->flags)) {
+
                skb = skb_dequeue(&x25->interrupt_out_queue);
                x25_transmit_link(skb, x25->neighbour);
        }
index e5195c99f71e267e70cb62b3689f7e6f02a809dd..8e69533d2313a63a7a4718898ce12277ca92a432 100644 (file)
@@ -16,7 +16,8 @@ static inline unsigned int __xfrm6_addr_hash(xfrm_address_t *addr)
 
 static inline unsigned int __xfrm4_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
 {
-       return ntohl(daddr->a4 + saddr->a4);
+       u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4;
+       return ntohl((__force __be32)sum);
 }
 
 static inline unsigned int __xfrm6_daddr_saddr_hash(xfrm_address_t *daddr, xfrm_address_t *saddr)
@@ -54,7 +55,7 @@ static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
        case AF_INET6:
                h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
                break;
-       };
+       }
        return (h ^ (h >> 16)) & hmask;
 }
 
@@ -101,7 +102,7 @@ static inline unsigned int __sel_hash(struct xfrm_selector *sel, unsigned short
 
                h = __xfrm6_daddr_saddr_hash(daddr, saddr);
                break;
-       };
+       }
        h ^= (h >> 16);
        return h & hmask;
 }
@@ -118,7 +119,7 @@ static inline unsigned int __addr_hash(xfrm_address_t *daddr, xfrm_address_t *sa
        case AF_INET6:
                h = __xfrm6_daddr_saddr_hash(daddr, saddr);
                break;
-       };
+       }
        h ^= (h >> 16);
        return h & hmask;
 }
index 843e066649cb36834dd186084ff378899c967d31..d965a2bad8d3b9cf993f72eaa372fb791642f3bc 100644 (file)
@@ -37,6 +37,8 @@
 DEFINE_MUTEX(xfrm_cfg_mutex);
 EXPORT_SYMBOL(xfrm_cfg_mutex);
 
+static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
+static struct dst_entry *xfrm_policy_sk_bundles;
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
 static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
@@ -44,12 +46,10 @@ static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
 
 static struct kmem_cache *xfrm_dst_cache __read_mostly;
 
-static HLIST_HEAD(xfrm_policy_gc_list);
-static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
-
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
 static void xfrm_init_pmtu(struct dst_entry *dst);
+static int stale_bundle(struct dst_entry *dst);
 
 static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
                                                int dir);
@@ -156,7 +156,7 @@ static void xfrm_policy_timer(unsigned long data)
 
        read_lock(&xp->lock);
 
-       if (xp->walk.dead)
+       if (unlikely(xp->walk.dead))
                goto out;
 
        dir = xfrm_policy_id2dir(xp->index);
@@ -216,6 +216,35 @@ expired:
        xfrm_pol_put(xp);
 }
 
+static struct flow_cache_object *xfrm_policy_flo_get(struct flow_cache_object *flo)
+{
+       struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
+
+       if (unlikely(pol->walk.dead))
+               flo = NULL;
+       else
+               xfrm_pol_hold(pol);
+
+       return flo;
+}
+
+static int xfrm_policy_flo_check(struct flow_cache_object *flo)
+{
+       struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo);
+
+       return !pol->walk.dead;
+}
+
+static void xfrm_policy_flo_delete(struct flow_cache_object *flo)
+{
+       xfrm_pol_put(container_of(flo, struct xfrm_policy, flo));
+}
+
+static const struct flow_cache_ops xfrm_policy_fc_ops = {
+       .get = xfrm_policy_flo_get,
+       .check = xfrm_policy_flo_check,
+       .delete = xfrm_policy_flo_delete,
+};
 
 /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
  * SPD calls.
@@ -236,6 +265,7 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
                atomic_set(&policy->refcnt, 1);
                setup_timer(&policy->timer, xfrm_policy_timer,
                                (unsigned long)policy);
+               policy->flo.ops = &xfrm_policy_fc_ops;
        }
        return policy;
 }
@@ -247,8 +277,6 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
 {
        BUG_ON(!policy->walk.dead);
 
-       BUG_ON(policy->bundles);
-
        if (del_timer(&policy->timer))
                BUG();
 
@@ -257,63 +285,20 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
 }
 EXPORT_SYMBOL(xfrm_policy_destroy);
 
-static void xfrm_policy_gc_kill(struct xfrm_policy *policy)
-{
-       struct dst_entry *dst;
-
-       while ((dst = policy->bundles) != NULL) {
-               policy->bundles = dst->next;
-               dst_free(dst);
-       }
-
-       if (del_timer(&policy->timer))
-               atomic_dec(&policy->refcnt);
-
-       if (atomic_read(&policy->refcnt) > 1)
-               flow_cache_flush();
-
-       xfrm_pol_put(policy);
-}
-
-static void xfrm_policy_gc_task(struct work_struct *work)
-{
-       struct xfrm_policy *policy;
-       struct hlist_node *entry, *tmp;
-       struct hlist_head gc_list;
-
-       spin_lock_bh(&xfrm_policy_gc_lock);
-       gc_list.first = xfrm_policy_gc_list.first;
-       INIT_HLIST_HEAD(&xfrm_policy_gc_list);
-       spin_unlock_bh(&xfrm_policy_gc_lock);
-
-       hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst)
-               xfrm_policy_gc_kill(policy);
-}
-static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task);
-
 /* Rule must be locked. Release descentant resources, announce
  * entry dead. The rule must be unlinked from lists to the moment.
  */
 
 static void xfrm_policy_kill(struct xfrm_policy *policy)
 {
-       int dead;
-
-       write_lock_bh(&policy->lock);
-       dead = policy->walk.dead;
        policy->walk.dead = 1;
-       write_unlock_bh(&policy->lock);
 
-       if (unlikely(dead)) {
-               WARN_ON(1);
-               return;
-       }
+       atomic_inc(&policy->genid);
 
-       spin_lock_bh(&xfrm_policy_gc_lock);
-       hlist_add_head(&policy->bydst, &xfrm_policy_gc_list);
-       spin_unlock_bh(&xfrm_policy_gc_lock);
+       if (del_timer(&policy->timer))
+               xfrm_pol_put(policy);
 
-       schedule_work(&xfrm_policy_gc_work);
+       xfrm_pol_put(policy);
 }
 
 static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024;
@@ -555,7 +540,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        struct xfrm_policy *delpol;
        struct hlist_head *chain;
        struct hlist_node *entry, *newpos;
-       struct dst_entry *gc_list;
        u32 mark = policy->mark.v & policy->mark.m;
 
        write_lock_bh(&xfrm_policy_lock);
@@ -605,34 +589,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        else if (xfrm_bydst_should_resize(net, dir, NULL))
                schedule_work(&net->xfrm.policy_hash_work);
 
-       read_lock_bh(&xfrm_policy_lock);
-       gc_list = NULL;
-       entry = &policy->bydst;
-       hlist_for_each_entry_continue(policy, entry, bydst) {
-               struct dst_entry *dst;
-
-               write_lock(&policy->lock);
-               dst = policy->bundles;
-               if (dst) {
-                       struct dst_entry *tail = dst;
-                       while (tail->next)
-                               tail = tail->next;
-                       tail->next = gc_list;
-                       gc_list = dst;
-
-                       policy->bundles = NULL;
-               }
-               write_unlock(&policy->lock);
-       }
-       read_unlock_bh(&xfrm_policy_lock);
-
-       while (gc_list) {
-               struct dst_entry *dst = gc_list;
-
-               gc_list = dst->next;
-               dst_free(dst);
-       }
-
        return 0;
 }
 EXPORT_SYMBOL(xfrm_policy_insert);
@@ -671,10 +627,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type,
        }
        write_unlock_bh(&xfrm_policy_lock);
 
-       if (ret && delete) {
-               atomic_inc(&flow_cache_genid);
+       if (ret && delete)
                xfrm_policy_kill(ret);
-       }
        return ret;
 }
 EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
@@ -713,10 +667,8 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type,
        }
        write_unlock_bh(&xfrm_policy_lock);
 
-       if (ret && delete) {
-               atomic_inc(&flow_cache_genid);
+       if (ret && delete)
                xfrm_policy_kill(ret);
-       }
        return ret;
 }
 EXPORT_SYMBOL(xfrm_policy_byid);
@@ -776,7 +728,6 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi
 int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
 {
        int dir, err = 0, cnt = 0;
-       struct xfrm_policy *dp;
 
        write_lock_bh(&xfrm_policy_lock);
 
@@ -794,10 +745,9 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                                     &net->xfrm.policy_inexact[dir], bydst) {
                        if (pol->type != type)
                                continue;
-                       dp = __xfrm_policy_unlink(pol, dir);
+                       __xfrm_policy_unlink(pol, dir);
                        write_unlock_bh(&xfrm_policy_lock);
-                       if (dp)
-                               cnt++;
+                       cnt++;
 
                        xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
                                                 audit_info->sessionid,
@@ -816,10 +766,9 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
                                             bydst) {
                                if (pol->type != type)
                                        continue;
-                               dp = __xfrm_policy_unlink(pol, dir);
+                               __xfrm_policy_unlink(pol, dir);
                                write_unlock_bh(&xfrm_policy_lock);
-                               if (dp)
-                                       cnt++;
+                               cnt++;
 
                                xfrm_audit_policy_delete(pol, 1,
                                                         audit_info->loginuid,
@@ -835,7 +784,6 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info)
        }
        if (!cnt)
                err = -ESRCH;
-       atomic_inc(&flow_cache_genid);
 out:
        write_unlock_bh(&xfrm_policy_lock);
        return err;
@@ -989,32 +937,37 @@ fail:
        return ret;
 }
 
-static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family,
-                             u8 dir, void **objp, atomic_t **obj_refp)
+static struct xfrm_policy *
+__xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, u8 dir)
 {
+#ifdef CONFIG_XFRM_SUB_POLICY
        struct xfrm_policy *pol;
-       int err = 0;
 
-#ifdef CONFIG_XFRM_SUB_POLICY
        pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
-       if (IS_ERR(pol)) {
-               err = PTR_ERR(pol);
-               pol = NULL;
-       }
-       if (pol || err)
-               goto end;
-#endif
-       pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
-       if (IS_ERR(pol)) {
-               err = PTR_ERR(pol);
-               pol = NULL;
-       }
-#ifdef CONFIG_XFRM_SUB_POLICY
-end:
+       if (pol != NULL)
+               return pol;
 #endif
-       if ((*objp = (void *) pol) != NULL)
-               *obj_refp = &pol->refcnt;
-       return err;
+       return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
+}
+
+static struct flow_cache_object *
+xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family,
+                  u8 dir, struct flow_cache_object *old_obj, void *ctx)
+{
+       struct xfrm_policy *pol;
+
+       if (old_obj)
+               xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo));
+
+       pol = __xfrm_policy_lookup(net, fl, family, dir);
+       if (IS_ERR_OR_NULL(pol))
+               return ERR_CAST(pol);
+
+       /* Resolver returns two references:
+        * one for cache and one for caller of flow_cache_lookup() */
+       xfrm_pol_hold(pol);
+
+       return &pol->flo;
 }
 
 static inline int policy_to_flow_dir(int dir)
@@ -1104,8 +1057,6 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
        pol = __xfrm_policy_unlink(pol, dir);
        write_unlock_bh(&xfrm_policy_lock);
        if (pol) {
-               if (dir < XFRM_POLICY_MAX)
-                       atomic_inc(&flow_cache_genid);
                xfrm_policy_kill(pol);
                return 0;
        }
@@ -1132,6 +1083,9 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
                __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);
        }
        if (old_pol)
+               /* Unlinking succeeds always. This is the only function
+                * allowed to delete or replace socket policy.
+                */
                __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);
        write_unlock_bh(&xfrm_policy_lock);
 
@@ -1300,18 +1254,6 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl,
  * still valid.
  */
 
-static struct dst_entry *
-xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short family)
-{
-       struct dst_entry *x;
-       struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
-       if (unlikely(afinfo == NULL))
-               return ERR_PTR(-EINVAL);
-       x = afinfo->find_bundle(fl, policy);
-       xfrm_policy_put_afinfo(afinfo);
-       return x;
-}
-
 static inline int xfrm_get_tos(struct flowi *fl, int family)
 {
        struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
@@ -1327,6 +1269,54 @@ static inline int xfrm_get_tos(struct flowi *fl, int family)
        return tos;
 }
 
+static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *flo)
+{
+       struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
+       struct dst_entry *dst = &xdst->u.dst;
+
+       if (xdst->route == NULL) {
+               /* Dummy bundle - if it has xfrms we were not
+                * able to build bundle as template resolution failed.
+                * It means we need to try again resolving. */
+               if (xdst->num_xfrms > 0)
+                       return NULL;
+       } else {
+               /* Real bundle */
+               if (stale_bundle(dst))
+                       return NULL;
+       }
+
+       dst_hold(dst);
+       return flo;
+}
+
+static int xfrm_bundle_flo_check(struct flow_cache_object *flo)
+{
+       struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
+       struct dst_entry *dst = &xdst->u.dst;
+
+       if (!xdst->route)
+               return 0;
+       if (stale_bundle(dst))
+               return 0;
+
+       return 1;
+}
+
+static void xfrm_bundle_flo_delete(struct flow_cache_object *flo)
+{
+       struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo);
+       struct dst_entry *dst = &xdst->u.dst;
+
+       dst_free(dst);
+}
+
+static const struct flow_cache_ops xfrm_bundle_fc_ops = {
+       .get = xfrm_bundle_flo_get,
+       .check = xfrm_bundle_flo_check,
+       .delete = xfrm_bundle_flo_delete,
+};
+
 static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
 {
        struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
@@ -1349,9 +1339,10 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family)
                BUG();
        }
        xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS);
-
        xfrm_policy_put_afinfo(afinfo);
 
+       xdst->flo.ops = &xfrm_bundle_fc_ops;
+
        return xdst;
 }
 
@@ -1389,6 +1380,7 @@ static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        return err;
 }
 
+
 /* Allocate chain of dst_entry's, attach known xfrm's, calculate
  * all the metrics... Shortly, bundle a bundle.
  */
@@ -1452,7 +1444,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
                        dst_hold(dst);
 
                dst1->xfrm = xfrm[i];
-               xdst->genid = xfrm[i]->genid;
+               xdst->xfrm_genid = xfrm[i]->genid;
 
                dst1->obsolete = -1;
                dst1->flags |= DST_HOST;
@@ -1545,7 +1537,186 @@ xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
 #endif
 }
 
-static int stale_bundle(struct dst_entry *dst);
+static int xfrm_expand_policies(struct flowi *fl, u16 family,
+                               struct xfrm_policy **pols,
+                               int *num_pols, int *num_xfrms)
+{
+       int i;
+
+       if (*num_pols == 0 || !pols[0]) {
+               *num_pols = 0;
+               *num_xfrms = 0;
+               return 0;
+       }
+       if (IS_ERR(pols[0]))
+               return PTR_ERR(pols[0]);
+
+       *num_xfrms = pols[0]->xfrm_nr;
+
+#ifdef CONFIG_XFRM_SUB_POLICY
+       if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW &&
+           pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
+               pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]),
+                                                   XFRM_POLICY_TYPE_MAIN,
+                                                   fl, family,
+                                                   XFRM_POLICY_OUT);
+               if (pols[1]) {
+                       if (IS_ERR(pols[1])) {
+                               xfrm_pols_put(pols, *num_pols);
+                               return PTR_ERR(pols[1]);
+                       }
+                       (*num_pols) ++;
+                       (*num_xfrms) += pols[1]->xfrm_nr;
+               }
+       }
+#endif
+       for (i = 0; i < *num_pols; i++) {
+               if (pols[i]->action != XFRM_POLICY_ALLOW) {
+                       *num_xfrms = -1;
+                       break;
+               }
+       }
+
+       return 0;
+
+}
+
+static struct xfrm_dst *
+xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
+                              struct flowi *fl, u16 family,
+                              struct dst_entry *dst_orig)
+{
+       struct net *net = xp_net(pols[0]);
+       struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
+       struct dst_entry *dst;
+       struct xfrm_dst *xdst;
+       int err;
+
+       /* Try to instantiate a bundle */
+       err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
+       if (err < 0) {
+               if (err != -EAGAIN)
+                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+               return ERR_PTR(err);
+       }
+
+       dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
+       if (IS_ERR(dst)) {
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
+               return ERR_CAST(dst);
+       }
+
+       xdst = (struct xfrm_dst *)dst;
+       xdst->num_xfrms = err;
+       if (num_pols > 1)
+               err = xfrm_dst_update_parent(dst, &pols[1]->selector);
+       else
+               err = xfrm_dst_update_origin(dst, fl);
+       if (unlikely(err)) {
+               dst_free(dst);
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
+               return ERR_PTR(err);
+       }
+
+       xdst->num_pols = num_pols;
+       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
+       xdst->policy_genid = atomic_read(&pols[0]->genid);
+
+       return xdst;
+}
+
+static struct flow_cache_object *
+xfrm_bundle_lookup(struct net *net, struct flowi *fl, u16 family, u8 dir,
+                  struct flow_cache_object *oldflo, void *ctx)
+{
+       struct dst_entry *dst_orig = (struct dst_entry *)ctx;
+       struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
+       struct xfrm_dst *xdst, *new_xdst;
+       int num_pols = 0, num_xfrms = 0, i, err, pol_dead;
+
+       /* Check if the policies from old bundle are usable */
+       xdst = NULL;
+       if (oldflo) {
+               xdst = container_of(oldflo, struct xfrm_dst, flo);
+               num_pols = xdst->num_pols;
+               num_xfrms = xdst->num_xfrms;
+               pol_dead = 0;
+               for (i = 0; i < num_pols; i++) {
+                       pols[i] = xdst->pols[i];
+                       pol_dead |= pols[i]->walk.dead;
+               }
+               if (pol_dead) {
+                       dst_free(&xdst->u.dst);
+                       xdst = NULL;
+                       num_pols = 0;
+                       num_xfrms = 0;
+                       oldflo = NULL;
+               }
+       }
+
+       /* Resolve policies to use if we couldn't get them from
+        * previous cache entry */
+       if (xdst == NULL) {
+               num_pols = 1;
+               pols[0] = __xfrm_policy_lookup(net, fl, family, dir);
+               err = xfrm_expand_policies(fl, family, pols,
+                                          &num_pols, &num_xfrms);
+               if (err < 0)
+                       goto inc_error;
+               if (num_pols == 0)
+                       return NULL;
+               if (num_xfrms <= 0)
+                       goto make_dummy_bundle;
+       }
+
+       new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, dst_orig);
+       if (IS_ERR(new_xdst)) {
+               err = PTR_ERR(new_xdst);
+               if (err != -EAGAIN)
+                       goto error;
+               if (oldflo == NULL)
+                       goto make_dummy_bundle;
+               dst_hold(&xdst->u.dst);
+               return oldflo;
+       }
+
+       /* Kill the previous bundle */
+       if (xdst) {
+               /* The policies were stolen for newly generated bundle */
+               xdst->num_pols = 0;
+               dst_free(&xdst->u.dst);
+       }
+
+       /* Flow cache does not have reference, it dst_free()'s,
+        * but we do need to return one reference for original caller */
+       dst_hold(&new_xdst->u.dst);
+       return &new_xdst->flo;
+
+make_dummy_bundle:
+       /* We found policies, but there's no bundles to instantiate:
+        * either because the policy blocks, has no transformations or
+        * we could not build template (no xfrm_states).*/
+       xdst = xfrm_alloc_dst(net, family);
+       if (IS_ERR(xdst)) {
+               xfrm_pols_put(pols, num_pols);
+               return ERR_CAST(xdst);
+       }
+       xdst->num_pols = num_pols;
+       xdst->num_xfrms = num_xfrms;
+       memcpy(xdst->pols, pols, sizeof(struct xfrm_policy*) * num_pols);
+
+       dst_hold(&xdst->u.dst);
+       return &xdst->flo;
+
+inc_error:
+       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+error:
+       if (xdst != NULL)
+               dst_free(&xdst->u.dst);
+       else
+               xfrm_pols_put(pols, num_pols);
+       return ERR_PTR(err);
+}
 
 /* Main function: finds/creates a bundle for given flow.
  *
@@ -1555,245 +1726,152 @@ static int stale_bundle(struct dst_entry *dst);
 int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl,
                  struct sock *sk, int flags)
 {
-       struct xfrm_policy *policy;
        struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
-       int npols;
-       int pol_dead;
-       int xfrm_nr;
-       int pi;
-       struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
-       struct dst_entry *dst, *dst_orig = *dst_p;
-       int nx = 0;
-       int err;
-       u32 genid;
-       u16 family;
+       struct flow_cache_object *flo;
+       struct xfrm_dst *xdst;
+       struct dst_entry *dst, *dst_orig = *dst_p, *route;
+       u16 family = dst_orig->ops->family;
        u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
+       int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
 
 restart:
-       genid = atomic_read(&flow_cache_genid);
-       policy = NULL;
-       for (pi = 0; pi < ARRAY_SIZE(pols); pi++)
-               pols[pi] = NULL;
-       npols = 0;
-       pol_dead = 0;
-       xfrm_nr = 0;
+       dst = NULL;
+       xdst = NULL;
+       route = NULL;
 
        if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
-               policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
-               err = PTR_ERR(policy);
-               if (IS_ERR(policy)) {
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+               num_pols = 1;
+               pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
+               err = xfrm_expand_policies(fl, family, pols,
+                                          &num_pols, &num_xfrms);
+               if (err < 0)
                        goto dropdst;
+
+               if (num_pols) {
+                       if (num_xfrms <= 0) {
+                               drop_pols = num_pols;
+                               goto no_transform;
+                       }
+
+                       xdst = xfrm_resolve_and_create_bundle(
+                                       pols, num_pols, fl,
+                                       family, dst_orig);
+                       if (IS_ERR(xdst)) {
+                               xfrm_pols_put(pols, num_pols);
+                               err = PTR_ERR(xdst);
+                               goto dropdst;
+                       }
+
+                       spin_lock_bh(&xfrm_policy_sk_bundle_lock);
+                       xdst->u.dst.next = xfrm_policy_sk_bundles;
+                       xfrm_policy_sk_bundles = &xdst->u.dst;
+                       spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
+
+                       route = xdst->route;
                }
        }
 
-       if (!policy) {
+       if (xdst == NULL) {
                /* To accelerate a bit...  */
                if ((dst_orig->flags & DST_NOXFRM) ||
                    !net->xfrm.policy_count[XFRM_POLICY_OUT])
                        goto nopol;
 
-               policy = flow_cache_lookup(net, fl, dst_orig->ops->family,
-                                          dir, xfrm_policy_lookup);
-               err = PTR_ERR(policy);
-               if (IS_ERR(policy)) {
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
+               flo = flow_cache_lookup(net, fl, family, dir,
+                                       xfrm_bundle_lookup, dst_orig);
+               if (flo == NULL)
+                       goto nopol;
+               if (IS_ERR(flo)) {
+                       err = PTR_ERR(flo);
                        goto dropdst;
                }
+               xdst = container_of(flo, struct xfrm_dst, flo);
+
+               num_pols = xdst->num_pols;
+               num_xfrms = xdst->num_xfrms;
+               memcpy(pols, xdst->pols, sizeof(struct xfrm_policy*) * num_pols);
+               route = xdst->route;
+       }
+
+       dst = &xdst->u.dst;
+       if (route == NULL && num_xfrms > 0) {
+               /* The only case when xfrm_bundle_lookup() returns a
+                * bundle with null route, is when the template could
+                * not be resolved. It means policies are there, but
+                * bundle could not be created, since we don't yet
+                * have the xfrm_state's. We need to wait for KM to
+                * negotiate new SA's or bail out with error.*/
+               if (net->xfrm.sysctl_larval_drop) {
+                       /* EREMOTE tells the caller to generate
+                        * a one-shot blackhole route. */
+                       dst_release(dst);
+                       xfrm_pols_put(pols, drop_pols);
+                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
+                       return -EREMOTE;
+               }
+               if (flags & XFRM_LOOKUP_WAIT) {
+                       DECLARE_WAITQUEUE(wait, current);
+
+                       add_wait_queue(&net->xfrm.km_waitq, &wait);
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule();
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&net->xfrm.km_waitq, &wait);
+
+                       if (!signal_pending(current)) {
+                               dst_release(dst);
+                               goto restart;
+                       }
+
+                       err = -ERESTART;
+               } else
+                       err = -EAGAIN;
+
+               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
+               goto error;
        }
 
-       if (!policy)
+no_transform:
+       if (num_pols == 0)
                goto nopol;
 
-       family = dst_orig->ops->family;
-       pols[0] = policy;
-       npols ++;
-       xfrm_nr += pols[0]->xfrm_nr;
-
-       err = -ENOENT;
-       if ((flags & XFRM_LOOKUP_ICMP) && !(policy->flags & XFRM_POLICY_ICMP))
+       if ((flags & XFRM_LOOKUP_ICMP) &&
+           !(pols[0]->flags & XFRM_POLICY_ICMP)) {
+               err = -ENOENT;
                goto error;
+       }
 
-       policy->curlft.use_time = get_seconds();
+       for (i = 0; i < num_pols; i++)
+               pols[i]->curlft.use_time = get_seconds();
 
-       switch (policy->action) {
-       default:
-       case XFRM_POLICY_BLOCK:
+       if (num_xfrms < 0) {
                /* Prohibit the flow */
                XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
                err = -EPERM;
                goto error;
-
-       case XFRM_POLICY_ALLOW:
-#ifndef CONFIG_XFRM_SUB_POLICY
-               if (policy->xfrm_nr == 0) {
-                       /* Flow passes not transformed. */
-                       xfrm_pol_put(policy);
-                       return 0;
-               }
-#endif
-
-               /* Try to find matching bundle.
-                *
-                * LATER: help from flow cache. It is optional, this
-                * is required only for output policy.
-                */
-               dst = xfrm_find_bundle(fl, policy, family);
-               if (IS_ERR(dst)) {
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
-                       err = PTR_ERR(dst);
-                       goto error;
-               }
-
-               if (dst)
-                       break;
-
-#ifdef CONFIG_XFRM_SUB_POLICY
-               if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
-                       pols[1] = xfrm_policy_lookup_bytype(net,
-                                                           XFRM_POLICY_TYPE_MAIN,
-                                                           fl, family,
-                                                           XFRM_POLICY_OUT);
-                       if (pols[1]) {
-                               if (IS_ERR(pols[1])) {
-                                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
-                                       err = PTR_ERR(pols[1]);
-                                       goto error;
-                               }
-                               if (pols[1]->action == XFRM_POLICY_BLOCK) {
-                                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK);
-                                       err = -EPERM;
-                                       goto error;
-                               }
-                               npols ++;
-                               xfrm_nr += pols[1]->xfrm_nr;
-                       }
-               }
-
-               /*
-                * Because neither flowi nor bundle information knows about
-                * transformation template size. On more than one policy usage
-                * we can realize whether all of them is bypass or not after
-                * they are searched. See above not-transformed bypass
-                * is surrounded by non-sub policy configuration, too.
-                */
-               if (xfrm_nr == 0) {
-                       /* Flow passes not transformed. */
-                       xfrm_pols_put(pols, npols);
-                       return 0;
-               }
-
-#endif
-               nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
-
-               if (unlikely(nx<0)) {
-                       err = nx;
-                       if (err == -EAGAIN && net->xfrm.sysctl_larval_drop) {
-                               /* EREMOTE tells the caller to generate
-                                * a one-shot blackhole route.
-                                */
-                               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-                               xfrm_pol_put(policy);
-                               return -EREMOTE;
-                       }
-                       if (err == -EAGAIN && (flags & XFRM_LOOKUP_WAIT)) {
-                               DECLARE_WAITQUEUE(wait, current);
-
-                               add_wait_queue(&net->xfrm.km_waitq, &wait);
-                               set_current_state(TASK_INTERRUPTIBLE);
-                               schedule();
-                               set_current_state(TASK_RUNNING);
-                               remove_wait_queue(&net->xfrm.km_waitq, &wait);
-
-                               nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
-
-                               if (nx == -EAGAIN && signal_pending(current)) {
-                                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-                                       err = -ERESTART;
-                                       goto error;
-                               }
-                               if (nx == -EAGAIN ||
-                                   genid != atomic_read(&flow_cache_genid)) {
-                                       xfrm_pols_put(pols, npols);
-                                       goto restart;
-                               }
-                               err = nx;
-                       }
-                       if (err < 0) {
-                               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
-                               goto error;
-                       }
-               }
-               if (nx == 0) {
-                       /* Flow passes not transformed. */
-                       xfrm_pols_put(pols, npols);
-                       return 0;
-               }
-
-               dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
-               err = PTR_ERR(dst);
-               if (IS_ERR(dst)) {
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
-                       goto error;
-               }
-
-               for (pi = 0; pi < npols; pi++) {
-                       read_lock_bh(&pols[pi]->lock);
-                       pol_dead |= pols[pi]->walk.dead;
-                       read_unlock_bh(&pols[pi]->lock);
-               }
-
-               write_lock_bh(&policy->lock);
-               if (unlikely(pol_dead || stale_bundle(dst))) {
-                       /* Wow! While we worked on resolving, this
-                        * policy has gone. Retry. It is not paranoia,
-                        * we just cannot enlist new bundle to dead object.
-                        * We can't enlist stable bundles either.
-                        */
-                       write_unlock_bh(&policy->lock);
-                       dst_free(dst);
-
-                       if (pol_dead)
-                               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLDEAD);
-                       else
-                               XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
-                       err = -EHOSTUNREACH;
-                       goto error;
-               }
-
-               if (npols > 1)
-                       err = xfrm_dst_update_parent(dst, &pols[1]->selector);
-               else
-                       err = xfrm_dst_update_origin(dst, fl);
-               if (unlikely(err)) {
-                       write_unlock_bh(&policy->lock);
-                       dst_free(dst);
-                       XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR);
-                       goto error;
-               }
-
-               dst->next = policy->bundles;
-               policy->bundles = dst;
-               dst_hold(dst);
-               write_unlock_bh(&policy->lock);
+       } else if (num_xfrms > 0) {
+               /* Flow transformed */
+               *dst_p = dst;
+               dst_release(dst_orig);
+       } else {
+               /* Flow passes untransformed */
+               dst_release(dst);
        }
-       *dst_p = dst;
-       dst_release(dst_orig);
-       xfrm_pols_put(pols, npols);
+ok:
+       xfrm_pols_put(pols, drop_pols);
        return 0;
 
+nopol:
+       if (!(flags & XFRM_LOOKUP_ICMP))
+               goto ok;
+       err = -ENOENT;
 error:
-       xfrm_pols_put(pols, npols);
+       dst_release(dst);
 dropdst:
        dst_release(dst_orig);
        *dst_p = NULL;
+       xfrm_pols_put(pols, drop_pols);
        return err;
-
-nopol:
-       err = -ENOENT;
-       if (flags & XFRM_LOOKUP_ICMP)
-               goto dropdst;
-       return 0;
 }
 EXPORT_SYMBOL(__xfrm_lookup);
 
@@ -1952,9 +2030,16 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                }
        }
 
-       if (!pol)
-               pol = flow_cache_lookup(net, &fl, family, fl_dir,
-                                       xfrm_policy_lookup);
+       if (!pol) {
+               struct flow_cache_object *flo;
+
+               flo = flow_cache_lookup(net, &fl, family, fl_dir,
+                                       xfrm_policy_lookup, NULL);
+               if (IS_ERR_OR_NULL(flo))
+                       pol = ERR_CAST(flo);
+               else
+                       pol = container_of(flo, struct xfrm_policy, flo);
+       }
 
        if (IS_ERR(pol)) {
                XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
@@ -2124,7 +2209,6 @@ EXPORT_SYMBOL(xfrm_dst_ifdown);
 static void xfrm_link_failure(struct sk_buff *skb)
 {
        /* Impossible. Such dst must be popped before reaches point of failure. */
-       return;
 }
 
 static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
@@ -2138,71 +2222,24 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
        return dst;
 }
 
-static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_entry *), struct dst_entry **gc_list_p)
-{
-       struct dst_entry *dst, **dstp;
-
-       write_lock(&pol->lock);
-       dstp = &pol->bundles;
-       while ((dst=*dstp) != NULL) {
-               if (func(dst)) {
-                       *dstp = dst->next;
-                       dst->next = *gc_list_p;
-                       *gc_list_p = dst;
-               } else {
-                       dstp = &dst->next;
-               }
-       }
-       write_unlock(&pol->lock);
-}
-
-static void xfrm_prune_bundles(struct net *net, int (*func)(struct dst_entry *))
+static void __xfrm_garbage_collect(struct net *net)
 {
-       struct dst_entry *gc_list = NULL;
-       int dir;
+       struct dst_entry *head, *next;
 
-       read_lock_bh(&xfrm_policy_lock);
-       for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) {
-               struct xfrm_policy *pol;
-               struct hlist_node *entry;
-               struct hlist_head *table;
-               int i;
+       flow_cache_flush();
 
-               hlist_for_each_entry(pol, entry,
-                                    &net->xfrm.policy_inexact[dir], bydst)
-                       prune_one_bundle(pol, func, &gc_list);
+       spin_lock_bh(&xfrm_policy_sk_bundle_lock);
+       head = xfrm_policy_sk_bundles;
+       xfrm_policy_sk_bundles = NULL;
+       spin_unlock_bh(&xfrm_policy_sk_bundle_lock);
 
-               table = net->xfrm.policy_bydst[dir].table;
-               for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) {
-                       hlist_for_each_entry(pol, entry, table + i, bydst)
-                               prune_one_bundle(pol, func, &gc_list);
-               }
-       }
-       read_unlock_bh(&xfrm_policy_lock);
-
-       while (gc_list) {
-               struct dst_entry *dst = gc_list;
-               gc_list = dst->next;
-               dst_free(dst);
+       while (head) {
+               next = head->next;
+               dst_free(head);
+               head = next;
        }
 }
 
-static int unused_bundle(struct dst_entry *dst)
-{
-       return !atomic_read(&dst->__refcnt);
-}
-
-static void __xfrm_garbage_collect(struct net *net)
-{
-       xfrm_prune_bundles(net, unused_bundle);
-}
-
-static int xfrm_flush_bundles(struct net *net)
-{
-       xfrm_prune_bundles(net, stale_bundle);
-       return 0;
-}
-
 static void xfrm_init_pmtu(struct dst_entry *dst)
 {
        do {
@@ -2260,7 +2297,9 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
                        return 0;
                if (dst->xfrm->km.state != XFRM_STATE_VALID)
                        return 0;
-               if (xdst->genid != dst->xfrm->genid)
+               if (xdst->xfrm_genid != dst->xfrm->genid)
+                       return 0;
+               if (xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
                        return 0;
 
                if (strict && fl &&
@@ -2425,7 +2464,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
 
        switch (event) {
        case NETDEV_DOWN:
-               xfrm_flush_bundles(dev_net(dev));
+               __xfrm_garbage_collect(dev_net(dev));
        }
        return NOTIFY_DONE;
 }
@@ -2531,7 +2570,6 @@ static void xfrm_policy_fini(struct net *net)
        audit_info.sessionid = -1;
        audit_info.secid = 0;
        xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info);
-       flush_work(&xfrm_policy_gc_work);
 
        WARN_ON(!list_empty(&net->xfrm.policy_all));
 
@@ -2757,7 +2795,6 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
                               struct xfrm_migrate *m, int num_migrate)
 {
        struct xfrm_migrate *mp;
-       struct dst_entry *dst;
        int i, j, n = 0;
 
        write_lock_bh(&pol->lock);
@@ -2782,10 +2819,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
                               sizeof(pol->xfrm_vec[i].saddr));
                        pol->xfrm_vec[i].encap_family = mp->new_family;
                        /* flush bundles */
-                       while ((dst = pol->bundles) != NULL) {
-                               pol->bundles = dst->next;
-                               dst_free(dst);
-                       }
+                       atomic_inc(&pol->genid);
                }
        }
 
index add77ecb8ac43cd85e6ebb1f57de839434dbb389..5208b12fbfb4942d4142f79ddb41ccb1420a4c93 100644 (file)
@@ -38,7 +38,6 @@
 static DEFINE_SPINLOCK(xfrm_state_lock);
 
 static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024;
-static unsigned int xfrm_state_genid;
 
 static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
 static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
@@ -924,8 +923,6 @@ static void __xfrm_state_insert(struct xfrm_state *x)
        struct net *net = xs_net(x);
        unsigned int h;
 
-       x->genid = ++xfrm_state_genid;
-
        list_add(&x->km.all, &net->xfrm.state_all);
 
        h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
@@ -971,7 +968,7 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew)
                    (mark & x->mark.m) == x->mark.v &&
                    !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) &&
                    !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family))
-                       x->genid = xfrm_state_genid;
+                       x->genid++;
        }
 }
 
index 6106b72826d374f4d5cbcc1ea8ab1c391bef2917..ba59983aaffee6e3d7f7a0afb241f92d787b152d 100644 (file)
@@ -1741,6 +1741,10 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
        if (err)
                return err;
 
+       err = verify_policy_dir(p->dir);
+       if (err)
+               return err;
+
        if (p->index)
                xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err);
        else {
@@ -1766,13 +1770,9 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
        if (xp == NULL)
                return -ENOENT;
 
-       read_lock(&xp->lock);
-       if (xp->walk.dead) {
-               read_unlock(&xp->lock);
+       if (unlikely(xp->walk.dead))
                goto out;
-       }
 
-       read_unlock(&xp->lock);
        err = 0;
        if (up->hard) {
                uid_t loginuid = NETLINK_CB(skb).loginuid;
@@ -1783,7 +1783,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        } else {
                // reset the timers here?
-               printk("Dont know what to do with soft policy expire\n");
+               WARN(1, "Dont know what to do with soft policy expire\n");
        }
        km_policy_expired(xp, p->dir, up->hard, current->pid);
 
@@ -1883,7 +1883,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
        return 0;
 
 bad_policy:
-       printk("BAD policy passed\n");
+       WARN(1, "BAD policy passed\n");
 free_state:
        kfree(x);
 nomem:
@@ -2385,8 +2385,9 @@ static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
        case XFRM_MSG_FLUSHSA:
                return xfrm_notify_sa_flush(c);
        default:
-                printk("xfrm_user: Unknown SA event %d\n", c->event);
-                break;
+               printk(KERN_NOTICE "xfrm_user: Unknown SA event %d\n",
+                      c->event);
+               break;
        }
 
        return 0;
@@ -2676,7 +2677,8 @@ static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_ev
        case XFRM_MSG_POLEXPIRE:
                return xfrm_exp_policy_notify(xp, dir, c);
        default:
-               printk("xfrm_user: Unknown Policy event %d\n", c->event);
+               printk(KERN_NOTICE "xfrm_user: Unknown Policy event %d\n",
+                      c->event);
        }
 
        return 0;
index df90f31d14bf3430aa6e56581cc47bb4f2b65bcf..9cf2400580a72a586b501c0c5d831473ea49dd77 100644 (file)
@@ -796,6 +796,28 @@ static int do_platform_entry(const char *filename,
        return 1;
 }
 
+static int do_mdio_entry(const char *filename,
+                        struct mdio_device_id *id, char *alias)
+{
+       int i;
+
+       alias += sprintf(alias, MDIO_MODULE_PREFIX);
+
+       for (i = 0; i < 32; i++) {
+               if (!((id->phy_id_mask >> (31-i)) & 1))
+                       *(alias++) = '?';
+               else if ((id->phy_id >> (31-i)) & 1)
+                       *(alias++) = '1';
+               else
+                       *(alias++) = '0';
+       }
+
+       /* Terminate the string */
+       *alias = 0;
+
+       return 1;
+}
+
 /* Looks like: zorro:iN. */
 static int do_zorro_entry(const char *filename, struct zorro_device_id *id,
                          char *alias)
@@ -953,6 +975,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                do_table(symval, sym->st_size,
                         sizeof(struct platform_device_id), "platform",
                         do_platform_entry, mod);
+       else if (sym_is(symname, "__mod_mdio_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct mdio_device_id), "mdio",
+                        do_mdio_entry, mod);
        else if (sym_is(symname, "__mod_zorro_device_table"))
                do_table(symval, sym->st_size,
                         sizeof(struct zorro_device_id), "zorro",